본문 바로가기

programming/Gukbi

국비 교육 72일차 - QnA 게시판

728x90
반응형

프로젝트가 거의 막바지에 다다라서 수업은 오전에 잠깐만 하고 남은 시간은 프로젝트에 전부 썼다.

 

일단 오늘 한 수업은 문의 게시판 만들기 이다. 

 

package com.sist.vo;
/*
 * 	NO         NOT NULL NUMBER         
	NAME       NOT NULL VARCHAR2(34)   
	SUBJECT    NOT NULL VARCHAR2(2000) 
	CONTENT    NOT NULL CLOB           
	PWD        NOT NULL VARCHAR2(10)   
	REGDATE             DATE           
	HIT                 NUMBER         
	GROUP_ID            NUMBER         
	GROUP_STEP          NUMBER         
	GROUP_TAB           NUMBER  
 */
import java.util.*;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class BoardReplyVO {
	private int no, hit, group_id, group_step, group_tab;
	private String name, subject, content, pwd;
	private Date regdate;
}

 테이블을 먼저 만들어 준다. 답변은 하나씩만 달꺼기 때문에 group_id, group_step, group_tab 까지만 컬럼을 만들어 준다. 

 

같은 아이디끼리 붙여서 출력을 해주고, 관리자가 단 답변은 step과 tab에 각각 1을 입력해주면 된다. 

 

먼저 자료실 목록을 출력하는 dao

 

// 자료실 목록 출력 
	   public List<BoardReplyVO> boardReplyListData(int page)
	   {
		   List<BoardReplyVO> list=new ArrayList<BoardReplyVO>();
		   try
		   {
			   getConnection();
			   String sql="SELECT no,subject,name,regdate,hit,group_tab,num "
					     +"FROM (SELECT no,subject,name,regdate,hit,group_tab,rownum as num "
					     +"FROM (SELECT no,subject,name,regdate,hit,group_tab "
					     +"FROM project_board_reply ORDER BY group_id DESC,group_step ASC)) "
					     +"WHERE num BETWEEN ? AND ?";
					    
			   int rowSize=10;
			   int start=(rowSize*page)-(rowSize-1);
			   int end=rowSize*page;
			   ps=conn.prepareStatement(sql);
			   ps.setInt(1, start);
			   ps.setInt(2, end);
			   ResultSet rs=ps.executeQuery();
			   while(rs.next())
			   {
				   BoardReplyVO vo=new BoardReplyVO();
				   vo.setNo(rs.getInt(1));
				   vo.setSubject(rs.getString(2));
				   vo.setName(rs.getString(3));
				   vo.setRegdate(rs.getDate(4));
				   vo.setHit(rs.getInt(5));
				   vo.setGroup_tab(rs.getInt(6));
				   list.add(vo);
			   }
			   rs.close();
		   }catch(Exception ex)
		   {
			   ex.printStackTrace();
		   }
		   finally
		   {
			   disConnection();
		   }
		   return list;
	   }

 

 list는 출력을 해야하는 부분이기 때문에, 페이지를 나눠주고 order by는 group_id desc로 (입력 최신순), group_step은 asc로 (질문-답변순)으로 잡아주고 출력한다. 

 

페이지를 잡아주고, list에 값을 채워 넣어준 뒤 값을 출력한다. 

 

 @RequestMapping("boardreply/list.do")
	  public String boardreply_list(HttpServletRequest request,HttpServletResponse response)
	  {
		  String page=request.getParameter("page");
		  if(page==null)
			  page="1";
		  int curpage=Integer.parseInt(page);
		  BoardReplyDAO dao=BoardReplyDAO.newInstance();
		  List<BoardReplyVO> list=dao.boardReplyListData(curpage);
		  int totalpage=dao.boardReplyTotalPage();
		  
		  request.setAttribute("list", list);
		  request.setAttribute("curpage", curpage);
		  request.setAttribute("totalpage", totalpage);
		  request.setAttribute("main_jsp", "../boardreply/list.jsp");
		  return "../main/main.jsp";
	  }

 위에는 listModel 

page를 입력받아서 list를 받아온다. 

 // 총페이지 구하기
	   public int boardReplyTotalPage()
	   {
		   int total=0;
		   try
		   {
			   getConnection();
			   String sql="SELECT CEIL(COUNT(*)/10.0) FROM project_board_reply";
			   ps=conn.prepareStatement(sql);
			   ResultSet rs=ps.executeQuery();
			   rs.next();
			   total=rs.getInt(1);
			   rs.close();
		   }catch(Exception ex)
		   {
			   // 에러 처리
			   ex.printStackTrace();
		   }
		   finally
		   {
			   // 반환 
			   disConnection();
		   }
		   return total;
	   }

 총페이지 구하는건 이미 많이 했으니 설명 생략

 포인트는 ceil 함수를 사용해서 올려주는 것이다. 

 

// insert
	   public void boardReplyInsert(BoardReplyVO vo)
	   {
		   try
		   {
			   getConnection();
			   String sql="INSERT INTO project_board_reply(no,name,subject,content,pwd,group_id) "
					     +"VALUES((SELECT NVL(MAX(no)+1,1) FROM project_board_reply),?,?,?,?,"
					   +"(SELECT NVL(MAX(group_id)+1,1) FROM project_board_reply))";
			   ps=conn.prepareStatement(sql);
			   ps.setString(1, vo.getName());
			   ps.setString(2, vo.getSubject());
			   ps.setString(3, vo.getContent());
			   ps.setString(4, vo.getPwd());
			  
			  
			   
			   ps.executeUpdate();
		   }catch(Exception ex)
		   {
			   ex.printStackTrace();
		   }
		   finally
		   {
			   disConnection();
		   }
	   }

 글 입력 메소드 

시퀀스를 따로 만들지 않아서 그냥 max+1을해서 번호를 지정해 줬는데 나중에 혼자 할때는 꼭 시퀀스를 써주자. 

그룹아이디 역시 마찬가지로 max+1을 해줘서 하나씩 올려준다. 

 

 @RequestMapping("boardreply/insert_ok.do")
	  public String boardReply_insert_ok(HttpServletRequest request,HttpServletResponse response)
	  {
		  try
		  {
			  request.setCharacterEncoding("UTF-8");
		  }catch(Exception ex){}
		  String name=request.getParameter("name");
		  String subject=request.getParameter("subject");
		  String content=request.getParameter("content");
		  String pwd=request.getParameter("pwd");
		  
		  BoardReplyVO vo=new BoardReplyVO();
		  vo.setName(name);
		  vo.setSubject(subject);
		  vo.setContent(content);
		  vo.setPwd(pwd);
		  
		  BoardReplyDAO dao=BoardReplyDAO.newInstance();
		  dao.boardReplyInsert(vo);
		  return "redirect:../boardreply/list.do";
	  }

 오라클에 값을 넘겨주는 메소드

VO로 잘 묶어서 메소드에 집어넣어준다. 그러면 글 내용이 오라클에 들어간다. 

// detail
	   public BoardReplyVO boardReplyDetailData(int no)
	   {
		   BoardReplyVO vo=new BoardReplyVO();
		   try
		   {
			   getConnection();
			   String sql="UPDATE project_board_reply SET "
					     +"hit=hit+1 "
					     +"WHERE no=?";
			   ps=conn.prepareStatement(sql);
			   ps.setInt(1, no);
			   ps.executeUpdate();
			   
			   sql="SELECT no,name,subject,content,regdate,hit "
				  +"FROM project_board_reply "
				  +"WHERE no=?";
			   ps=conn.prepareStatement(sql);
			   ps.setInt(1, no);
			   ResultSet rs=ps.executeQuery();
			   rs.next();
			   vo.setNo(rs.getInt(1));
			   vo.setName(rs.getString(2));
			   vo.setSubject(rs.getString(3));
			   vo.setContent(rs.getString(4));
			   vo.setRegdate(rs.getDate(5));
			   vo.setHit(rs.getInt(6));
			   
			   rs.close();
		   }catch(Exception ex)
		   {
			   ex.printStackTrace();
		   }
           finally
           {
        	   disConnection();
           }
		   return vo;
	   }

 디테일 출력 

게시판에서 디테일을 가져올때는 항상 조회수 1을 먼저 증가시키고 내용을 불러오게 한다. 

 

여기까지는 그냥 게시판과 거의 다를게 없다. 

 

이제 다른 부분이 나온다. 글의 group_id를 받아와야 한다. 

public int boardReplyGetGroupId(int no)
	   {
		   int gi=0;
		   try
		   {
			   getConnection();
			   String sql="SELECT group_id FROM project_board_reply "
					   +"WHERE no=?";
			   ps=conn.prepareStatement(sql);
			   ps.setInt(1, no);
			   ResultSet rs=ps.executeQuery();
			   rs.next();
			   gi=rs.getInt(1);
			   rs.close();
					   
		   }catch(Exception ex)
		   {
			   
		   }
		   finally
		   {
			   disConnection();
		   }
		   return gi;
	   }

 글의 no를 받아와서 그룹아이디가 어떻게 되는지 확인해준다. 이걸 받아오는 이유는 관리자가 답변한 게시글이 어떤 아이디었는지 확인해주기 위해서이다. 

 

 public void boardReplyReplyInsert(BoardReplyVO vo)
	   {
		   try
		   {
			   getConnection();
			   String sql="INSERT INTO project_board_reply(no,name,subject,content,pwd, group_id, group_step, group_tab) "
					     +"VALUES((SELECT NVL(MAX(no)+1,1) FROM project_board_reply),?,?,?,?,"
					   +"?,1,1)";
			   ps=conn.prepareStatement(sql);
			   ps.setString(1, vo.getName());
			   ps.setString(2, vo.getSubject());
			   ps.setString(3, vo.getContent());
			   ps.setString(4, vo.getPwd());
			   ps.setInt(5, vo.getGroup_id());
			   
			   ps.executeUpdate();
		   }catch(Exception ex)
		   {
			   ex.printStackTrace();
		   }
		   finally
		   {
			   disConnection();
		   }
	   }

 답변하기 버튼을 누르고 답변을 입력하는 메소드

no는 자동증가, group_step과 group_tab은 각각 1로 고정해서 집어넣어준다. (group_id는 입력값으로 받아온다)

 

 public boolean boardReplyCheck(int no)
	   {
		   boolean bCheck=false;
		   try
		   {
			   getConnection();
			   String sql="SELECT COUNT(group_id) FROM project_board_reply "
					   +"WHERE group_id=(SELECT group_id FROM project_board_reply WHERE no=?)";
			   ps=conn.prepareStatement(sql);
			   ps.setInt(1,no);
			   ResultSet rs=ps.executeQuery();
			   int count=rs.getInt(1);
			   if(count==2)
			   {
				   bCheck=true;
			   }
			   
		   }
		   catch(Exception ex)
		   {
			   
		   }
		   finally
		   {
			   disConnection();
		   }
		   return bCheck;
	   }

 

서브쿼리를 사용해서 답변이 달렸는지 아닌지 확인해주는 메소드

글번호를 받아와서 질문한 글의 group_id를 받아온다. 그리고 그 질문글과 같은 group_id인 글이 있는지 없는지 확인해준다. 

 

count가 2면 답변이 이미 있다는 뜻이기 때문에 bCheck를 true로 바꿔주고 리턴한다. 

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style type="text/css">
.mypage_row{
  margin: 0px auto;
  width:960px;
}
</style>
</head>
<body>
	<div class="wrapper row3 mypage_row">
	  <h2 class="sectiontitle">묻고답하기</h2>
	  <div style="height: 500px;width:750px;overflow-y:auto;margin:0px auto">
	   <table class="table">
	     <tr>
	      <td>
	       <a href="../boardreply/insert.do" class="btn btn-sm btn-danger">등록</a>
	      </td>
	     </tr>
	   </table>
	   <table class="table">
	     <tr>
	      <th class="text-center" width=10%>번호</th>
	      <th class="text-center" width=45%>제목</th>
	      <th class="text-center" width=15%>이름</th>
	      <th class="text-center" width=20%>작성일</th>
	      <th class="text-center" width=10%>조회수</th>
	     </tr>
	     <c:forEach var="vo" items="${list }">
	       <tr>
		      <td class="text-center" width=10%>${vo.no }</td>
		      <td class="text-left" width=45%>
		        <c:if test="${vo.group_tab==1 }">
		          &nbsp;&nbsp;
		          <img src="">
		        </c:if>
		        <a href="../boardreply/detail.do?no=${vo.no }">${vo.subject }</a>
		      </td>
		      <td class="text-center" width=15%>${vo.name }</td>
		      <td class="text-center" width=20%>${vo.regdate }</td>
		      <td class="text-center" width=10%>${vo.hit }</td>
	     </tr>
	     </c:forEach>
	   </table>
	   <table class="table">
	     <tr>
	      <td class="text-center">
	        <a href="#" class="btn btn-sm btn-success">이전</a>
	          ${curpage } page / ${ totalpage} pages
	        <a href="#" class="btn btn-sm btn-info">다음</a>
	      </td>
	     </tr>
	   </table>
	  </div>
	</div>
</body>
</html>

 리스트에서 그룹탭이 1이면 공백을 2칸주고 출력한다. 

 

 

@RequestMapping("boardreply/detail.do")
	  public String boardreply_detail(HttpServletRequest request,HttpServletResponse response)
	  {
		  String no=request.getParameter("no");
		  BoardReplyDAO dao=BoardReplyDAO.newInstance();
		  BoardReplyVO vo=dao.boardReplyDetailData(Integer.parseInt(no));
		  boolean bCheck=dao.boardReplyCheck(Integer.parseInt(no));
		  request.setAttribute("bCheck", bCheck);
		  request.setAttribute("vo", vo);
		  request.setAttribute("main_jsp", "../boardreply/detail.jsp");
		  return "../main/main.jsp";
	  }

 detail은 답변이 있는지 없는지 boardReplyCheck로 true(답변이 있는지),false(답변이 없는지)를 bCheck로 받아온다. 

 

답변하기 버튼을 누르면

@RequestMapping("boardreply/reply.do")
	  public String boardreply_reply(HttpServletRequest request,HttpServletResponse response)
	  {
		  String no=request.getParameter("no");
		  // db연동 
		  BoardReplyDAO dao=BoardReplyDAO.newInstance();
		  int group_id=dao.boardReplyGetGroupId(Integer.parseInt(no));
		  request.setAttribute("group_id", group_id);
		  request.setAttribute("no", no);
		  request.setAttribute("main_jsp", "../boardreply/reply.jsp");
		  return "../main/main.jsp";
	  }

 글번호를 받아오고, group_id 역시 셋팅해준다. 

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style type="text/css">
.mypage_row{
  margin: 0px auto;
  width:960px;
}
</style>
</head>
<body>
   
	<div class="wrapper row3 mypage_row">
	  <h2 class="sectiontitle">답변하기</h2>
	  <div style="height: 500px;width:750px;overflow-y:auto;margin:0px auto">
	  <%--
	     enctype="multipart/form-data" : 파일업로드시에 사용하는 프로토콜
	   --%>
	   <form method=post action="../boardreply/reply_ok.do">
	   <table class="table">
	    <tr>
	      <th width=20% class="text-right">이름</th>
	      <td width=80%>
	        <input type=text name=name size=15 class="input-sm" autocomplete="off" value="관리자" readonly>
	      </td>
	    </tr>
	    <tr>
	      <th width=20% class="text-right">제목</th>
	      <td width=80%>
	        <input type=text name=subject size=50 class="input-sm" autocomplete="off">
	        <input type=hidden name=no value="${no }">
	        <input type=hidden name=group_id value="${group_id }">
	      </td>
	    </tr>
	    <tr>
	      <th width=20% class="text-right">내용</th>
	      <td width=80%>
	        <textarea rows="10" cols="52" name=content autocomplete="off"></textarea>
	      </td>
	    </tr>
	    <tr>
	      <th width=20% class="text-right">비밀번호</th>
	      <td width=80%>
	        <input type=password name=pwd size=10 class="input-sm">
	      </td>
	    </tr>
	    <tr>
	      <td colspan="2" class="text-center">
	        <input type=submit value="답변" class="btn btn-sm btn-danger">
	        <input type=button value="취소" onclick="javascript:history.back()"
	         class="btn btn-sm btn-success"
	        >
	      </td> 
	    </tr>
	   </table>
	   </form>
	  </div>
	</div>
</body>
</html>

 글번호(no)와 group_id는 hidden으로 넘겨준다. 

 

@RequestMapping("boardreply/reply_ok.do")
	  public String boardreply_reply_ok(HttpServletRequest request,HttpServletResponse response)
	  {
		  try
		  {
			  request.setCharacterEncoding("UTF-8");
		  }catch(Exception ex){}
		  String name=request.getParameter("name");
		  String subject=request.getParameter("subject");
		  String content=request.getParameter("content");
		  String pwd=request.getParameter("pwd");
		  String group_id=request.getParameter("group_id");
		  
		  BoardReplyVO vo=new BoardReplyVO();
		  vo.setName(name);
		  vo.setSubject(subject);
		  vo.setContent(content);
		  vo.setPwd(pwd);
		  vo.setGroup_id(Integer.parseInt(group_id));
		  BoardReplyDAO dao=BoardReplyDAO.newInstance();
		  dao.boardReplyReplyInsert(vo);
		  return "redirect:../boardreply/list.do";
	  }

 값을 다 받아와서 저장해주고, list로 넘어가면 완성이다. 

1번의 답변이 3번

사실 화살표 모양 아이콘을 줘야하는데 귀찮아서 안줬다. 

 

 

 

728x90
반응형