BackEnd/Spring

17장. 모델2 방식으로 효율적으로 개발하기 - ③ 답변형 게시판(답글쓰기, 페이징 구현)

제이드Jade 2022. 2. 25. 21:27

답글 쓰기 구현

- 그냥 글쓰기와 같은데 parentNO만 (세션에 저장해서) 넘겨주는 것만 다름

 

<과정>

- view.jsp에서 replyForm.do로 현재글 번호를 parentNO라는 이름으로 바인딩

- replyForm.do에서는 parentNO를 넘겨 받아 세션에 저장 후 replyForm.jsp로 넘겨줌

- replyForm.jsp에서 글 작성 후 addReply.do로 넘겨주고, 여기서 parentNO를 포함해 VO객체를 만들어 service에 넘겨줌

- service에서는 새 글 추가한 메서드였던 dao.insertNewArticle을 호출해서 저장 >> 나는 그냥 service에서 addArticle호출 함

- 다시 컨트롤러에서 돌아와서도 새 글 추가와 기능 수행(사진 업로드 등)

 

- view.jsp

 function fn_reply_form(url, parentNO){
     var form=document.createElement("form");
     form.setAttribute("method","post");
     form.setAttribute("action",url);

     var inputParentNO=document.createElement("input");
     inputParentNO.setAttribute("type","hidden");
     inputParentNO.setAttribute("name","parentNO");
     inputParentNO.setAttribute("value",parentNO);

     form.appendChild(inputParentNO);
     document.body.appendChild(form);
     form.submit();
 }
...
<input type=button value="답글쓰기"  onClick="fn_reply_form('${contextPath}/board/replyForm.do', ${article.articleNO})">

- controller

private void doHandle(HttpServletRequest request, HttpServletResponse response)	throws ServletException, IOException {
...
  HttpSession session;
...
    else if(action.contentEquals("/replyForm.do")) {
        int parentNO=Integer.parseInt(request.getParameter("parentNO"));
        session=request.getSession();
        session.setAttribute("parentNO", parentNO);
        nextPage="/board06/replyForm.jsp";
    }
    else if(action.contentEquals("/addReply.do")) {
        session=request.getSession();
        int parentNO=(int) session.getAttribute("parentNO");
        session.removeAttribute("parentNO");

        Map<String,String> articleMap=upload(request,response);
        String title=articleMap.get("title");
        String content=articleMap.get("content");
        String imageFileName=articleMap.get("imageFileName");

        articleVO.setParentNO(parentNO);
        articleVO.setId("ki");
        articleVO.setTitle(title);
        articleVO.setContent(content);
        articleVO.setImageFileName(imageFileName);

        int articleNO=boardService.addArticle(articleVO);

        if(imageFileName!=null && imageFileName.length()!=0) {
            File srcFile=new File(ARTICLE_IMAGE_REPO+"\\temp\\"+imageFileName);
            File destDir=new File(ARTICLE_IMAGE_REPO+"\\"+articleNO);

            destDir.mkdir();

            FileUtils.moveFileToDirectory(srcFile, destDir, true);

            PrintWriter pw=response.getWriter();
            pw.print("<script> alert('답글을 추가했습니다.'); location.href='"+request.getContextPath()+"/board/listArticles.do' </script>");

            return;
        }
    }

- replyForm.jsp

  <form name="frmReply" method="post"  action="${contextPath}/board/addReply.do"   enctype="multipart/form-data">
  ...
  			<td align="right"> 글쓴이:&nbsp; </td>
			<td><input type="text" size="5" value="ki" disabled /> </td>
            
  ...
  <!--그 외에는 글쓰기 jsp와 동일 -->

 

 

 

페이징 구현

- 글 10개 당 한 페이지(pageNum), 페이지 10개 당 한 섹션(section)!!

- 오라클에서 제공하는 rownum이용

 

- 페이징 기능을 추가한 글 목록 조회 SQL문(dao에서 query문)

SELECT * FROM(
	SELECT ROWNUM as recNum,
	LVL,
	articleNO,
	parentNO,
	title,
	content,
	id,
	writedate
                FROM (
                    SELECT LEVEL as LVL,
                           articleNO,
                           parentNO,
                           title,
                           content,
                           id,
                           writedate
                          From t_board
                          START WITH parentNO=0
                          CONNECT BY PRIOR articleNO=parentNO
                          ORDER SIBLINGS BY articleNO DESC)
    	 )
     where recNum between (section-1)*100+(pageNum-1)*10+1 and (section-1)*100+pageNum*10

>> ROWNUM : 계층형으로 조회된 레코드에서 보이는대로 매겨진 글 번호

>> recNum between ~ and ~ : section과 pageNum으로 recNum 범위를 정해서 그에 맞는 글들을 조회

 

 

<과정>

1) 최초 요청 시 1페이지를 보여줘야 하므로 section과 pageNum 모두 1로 세팅(처음엔 null)

  (ㄴ 그 이후에는 (페이지를 누를때) view.jsp에서 받아옴)

2) section, pageNum를 HashMap에 저장한 것을 매개변수로 담아 service의 listArticles를 호출(dao에서 위의 query문 사용)

3) service/dao에서는 해당 페이지에 존재하는 글 리스트와 현재 존재하는 모든 글의 수를 HashMap에 저장한 것을 반환

4) section, pageNum, 해당 페이지에 존재하는 글들, 현재 존재하는 모든 글 수(페이지 표시를 위함) 이 네개를 HashMap에 저장해 listArticles.jsp를 호출

5) listArticles에서는 모든 글수를 100미만, 100, 100이상인 세 경우로 나뉘어서 페이징을 끝을 화면에 표시

  ㄴ 해당 페이지를 누르면 ~/listArticles.do?section=0?pageNum=0로 전송해서 1)로 돌아감!

 

- controller

if (action == null || action.equals("/listArticles.do")) {
    String _section=request.getParameter("section");
    String _pageNum=request.getParameter("pageNum");
    int section=Integer.parseInt(_section==null ? "1" : _section);
    int pageNum=Integer.parseInt(_pageNum==null ? "1" : _pageNum);

    Map<String,Integer> pagingMap=new HashMap<String,Integer>();
    pagingMap.put("section", section);
    pagingMap.put("pageNum",pageNum);

    Map articlesMap = boardService.listArticles(pagingMap);
    articlesMap.put("section", section);
    articlesMap.put("pageNum", pageNum);

    request.setAttribute("articlesMap", articlesMap);
    nextPage = "/board07/listArticles.jsp";
}

-service

public Map listArticles(Map<String, Integer> pagingMap) {
		List<ArticleVO> articlesList=boardDAO.selectAllArticles(pagingMap);
		int totArticle=boardDAO.selectTotArticles();
		
		Map articlesMap= new HashMap();
		articlesMap.put("articlesList", articlesList);
		articlesMap.put("totArticle", totArticle);
		
		return articlesMap;
	}

- dao

public List<ArticleVO> selectAllArticles(Map<String, Integer> pagingMap) {
    List<ArticleVO> articles=new ArrayList();

    try {
        con=dataFactory.getConnection();
        String query="SELECT * FROM( SELECT ROWNUM as recNum,LVL,articleNO,parentNO,title,content,id,writedate\r\n" + 
                "    FROM ( SELECT LEVEL as LVL, articleNO,parentNO,title,content,id,writedate\r\n" + 
                "            From t_board" + 
                "            START WITH parentNO=0" + 
                "            CONNECT BY PRIOR articleNO=parentNO" + 
                "            ORDER SIBLINGS BY articleNO DESC)" + 
                "    	 	)" + 
                "     where recNum between (?-1)*100+(?-1)*10+1 and (?-1)*100+?*10";
        pstmt=con.prepareStatement(query);

        int section=pagingMap.get("section");
        int pageNum=pagingMap.get("pageNum");
        pstmt.setInt(1, section);
        pstmt.setInt(2, pageNum);
        pstmt.setInt(3, section);
        pstmt.setInt(4, pageNum);

        ResultSet rs=pstmt.executeQuery();
        while(rs.next()) {
            ArticleVO articleVO=new ArticleVO();
            articleVO.setLevel(rs.getInt("LVL"));
            articleVO.setArticleNO(rs.getInt("articleNO"));
            articleVO.setParentNO(rs.getInt("parentNO"));
            articleVO.setTitle(rs.getString("content"));
            articleVO.setId(rs.getString("id"));
            articleVO.setWriteDate(rs.getDate("writeDate"));

            articles.add(articleVO);

        }

        rs.close();
        pstmt.close();
        con.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return articles;
}


public int selectTotArticles() {

    try {
        con=dataFactory.getConnection();
        String query="select count(articleNO) from t_board";
        pstmt=con.prepareStatement(query);

        ResultSet rs=pstmt.executeQuery();
        if(rs.next())
            return rs.getInt(1);
        rs.close();
        pstmt.close();
        con.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }

    return 0;
}

- listArticles.jsp

<c:set var="section" value="${articlesMap.section }"/>
<c:set var="pageNum" value="${articlesMap.pageNum }"/>
<c:set var="totArticle" value="${articlesMap.totArticle }"/>
<c:set var="articlesList" value="${articlesMap.articlesList }"/>
...
 <style>
    .no-uline {text-decoration:none;}
   .sel-page{text-decoration:none;color:red;}
   .cls1 {text-decoration:none;}
   .cls2{text-align:center; font-size:30px;}
</style>

</head>
<body>
...
</table>
<div class="cls2">
<c:if test="${totArticle!=null }">
<c:choose>
    <c:when test="${totArticle<100 }">
        <c:forEach var="page" begin="1" end="${totArticle/10 +1 }" step="1"> 
        <%-- /10은 몫, 마지막 페이지를 위해 쓴 것 --%>
            <c:choose>
                <c:when test="${page==pageNum }">
                    <a class="sel-page" href='${contextPath }/board/listArticles.do?section=${section }&pageNum=${pageNum}'">${page }</a>
                </c:when>
                <c:otherwise>
                    <a class="no-uline" href='${contextPath }/board/listArticles.do?section=${section }&pageNum=${pageNum}'>${page }</a>
                </c:otherwise>
            </c:choose>
        </c:forEach>
    </c:when>


    <c:when test="${totArticle==100 }">
        <c:forEach var="page" begin="1" end="10">
            <c:choose>
                <c:when test="${page==pageNum }">
                    <a class="sel-page" href='${contextPath }/board/listArticles.do?section=${section }&pageNum=${pageNum}'">${page }</a>
                </c:when>
                <c:otherwise>
                    <a class="no-uline" href='${contextPath }/board/listArticles.do?section=${section }&pageNum=${pageNum}'>${page }</a>
                </c:otherwise>
            </c:choose>

        </c:forEach>
    </c:when>


    <c:when test="${totArticle>100 }">
        <c:forEach var="page" begin="1" end="10">
            <c:if test="${section>1 && page==1 }">
                <a class="no-uline" href='${contextPath }/board/listArticles.do?section=${section-1 }&pageNum=1'>prev</a>
            </c:if>

            <c:choose>
                <c:when test="${page==pageNum }">
                    <a class="sel-page" href='${contextPath }/board/listArticles.do?section=${section }&pageNum=${page}'">${(section-1)*10+page }</a>
                </c:when>
                <c:otherwise>
                    <a class="no-uline" href='${contextPath }/board/listArticles.do?section=${section }&pageNum=${page}'>${(section-1)*10+page }</a>
                </c:otherwise>
            </c:choose>

            <c:if test="${section<totArticle/100+1 && page==10 }">
                <a class="no-uline" href='${contextPath }/board/listArticles.do?section=${section+1 }&pageNum=1'>next</a>
            </c:if>
        </c:forEach>
    </c:when>
</c:choose>

</c:if>
</div>
<br><br>
<a href="${contextPath}/board/articleForm.do"><p class="cls2">글쓰기</p></a>
</body>
</html>