20211202 게시판 게시글 상세페이지

DUUUPPAAN·2021년 12월 2일
0

20211122 WAS(TOMCAT), JSP

목록 보기
9/10

·게시판 현재진행중

-전에 교수님이

"게시판에 대한 부분을 완벽하게 이해하고 구축할 수 있다면, 그 사람은 현업에 가도 손색이 없어요" 

라고 하셨다.

그리고 최근에 위의 말을 정말 깊게 공감하고 있다. 어제만해도 인라인 뷰를 두번 사용하는 SELECT가 무려 3개가 들어간 쿼리를 했고, 엄청나게 많은 페이지를 구성하면서 정신이 혼미해질 지경이었다.

그리고 오늘도 마찬가지였다. 큰 틀에서 보면 이해가 가지만 조금만 디테일하게 들어가면 모르겠는 부분이 투성이다. 그래서 꽤나 많이 코드를 들여다본 것 같다.

·인터페이스 작성

-인터페이스를 작성했다. 이유는, 게시글의 노출 수와 보여줄 페이지 수에 대한 상수가 필요했기 때문이다.

public interface BoardFileConfig {
	//페이지에 노출될 게시물 수
	public static final int LIST_COUNT = 2;
	
	//페이징 수
	public static final int PAGE_COUNT = 2;
	
	//원래는 파일 업로드에 대한 것도 넣어야 하지만 오늘은 제외
	
}

-페이징에 대한 공통모듈도 적용했다. 내부를 살펴보면 게시물의 수를 얻어와서 각각의 페이징 처리를 하는 것인데, 상당히 복잡하다. 그래서 이해하는 데 조금 시간이 걸렸다. 리스트 페이지에 페이징 객체를 만들어서 어제 진행하지 못한 부분들을 진행했다.

//페이징 객체 생성
Paging paging = null;

if(totalCount > 0 )
	{
		//검색 결과가 하나 이상 있음.
		//여기가 페이징 처리 추가할 곳
		//매개변수로 경로, 총게시물 수, 노출게시물 수, 페이징 수, 현재 페이지, 현해페이지의 변수 명, 여기서 매개변수를 넘긴다는 것은
		//생성자에 값을 넣어서 전달한다는 뜻임.
		paging = new Paging("/board/list.jsp", totalCount, BoardFileConfig.LIST_COUNT, BoardFileConfig.PAGE_COUNT, curPage, "curPage");
		
		//속성과 값이 짝꿍으로 매개변수로 넘겨야 함
		paging.addParam("searchType", searchType);
		paging.addParam("searchValue", searchValue);
		
		//paging에 이미 startRow가 세팅됨. 위에서
		search.setStartRow(paging.getStartRow());
		search.setEndRow(paging.getEndRow());
		
		
		list = boardDao.boardList(search);
		
	}

-어제는 리스트에 boardList(search)메소드의 결과를 넣어줬는데, 이 때, RNUM의 값들이 정해지지 않아서 해당 쿼리 부분을 주석처리했다. 그러나 페이징 객체를 만들 때 넘긴 생성자의 값들을 통해서 startRow와 endRow, 더 나아가서는 시작 페이지와 마지막 페이지까지도 전부 계산이 되었다. 그래서 해당 값들을 search객체에 해당하는 변수에 값을 세팅해주고 쿼리를 제대로 진행하면, 원하는 수만큼의 게시물을 보여줄 수 있게 된다.

	$(document).ready(function(){	
		$("#btnWrite").on("click", function(){
			document.bbsForm.bbsSeq.value = "";
			//해당 페이지로 간다는 뜻.
			document.bbsForm.action = "/board/write.jsp";
			document.bbsForm.submit();
		});	
		
		   $("#btnSearch").on("click", function(){
			      document.bbsForm.bbsSeq.value = "";
			      document.bbsForm.searchType.value = $("#_searchType").val();
			      document.bbsForm.searchValue.value = $("#_searchValue").val();
			      document.bbsForm.curPage.value = "1";
			      document.bbsForm.action = "/board/list.jsp";
			      document.bbsForm.submit();
			   });

	});
	
	//다음 페이지 누르면 보내는 함수
	//현재 페이지를 매개변수로 받음
	function fn_list(curPage)
	{
		//bbsSeq는 그냥 ""처리 해주면 됨.
		document.bbsForm.bbsSeq.value = "";
		//매개변수로 받은 curPage를 넣어줌
		document.bbsForm.curPage.value = curPage;
		document.bbsForm.action = "/board/list.jsp";
		document.bbsForm.submit();
	}
	
	function fn_view(bbsSeq)
	{
		document.bbsForm.bbsSeq.value = bbsSeq;
		document.bbsForm.action = "/board/view.jsp";
		document.bbsForm.submit();
	}

-스크립트 부분에 jQuery로 각각의 버튼에 대한 기능도 만들었다.

<%
	if(paging != null)
	{	
		//페이징 블럭에 대한 처리
		if(paging.getPrevBlockPage() > 0)
		{
%>
			<li class="page-item"><a class="page-link" href="javascript:void(0)" onclick="fn_list(<%= paging.getPrevBlockPage()%>)">이전블럭</a></li>
			
<%
		}	
		
		//현재 페이지와 curPage가 같으면 클릭할 수 없게 만들기.
		long i;
		//5개씩 게시물이면, 페이지의 갯수를 계산하여 나타내기 위한 반복문
		for(i = paging.getStartPage(); i<= paging.getEndPage(); i++)
		{
			if(paging.getCurPage() != i)
			{
				//현재 페이지가 i와 같지 않으면		
%>
         		<li class="page-item"><a class="page-link" href="javascript:void(0)" onclick="fn_list(<%= i%>)"><%= i %></a></li>

<%
			}
			else
			{	
				//현재 페이지가 i와 같으면			
%>	
        		<li class="page-item active"><a class="page-link" href="javascript:void(0)" style="cursor:default;"><%= i %></a></li>		 	
<%
			}
		}
		
		if(paging.getNextBlockPage() > 0)
		{
			//다음 블럭에 대한 코드
%>
			<li class="page-item"><a class="page-link" href="javascript:void(0)" onclick="fn_list(<%= paging.getNextBlockPage()%>)">다음블럭</a></li>
<%		

		}	
	}
%>         

위의 부분은 페이징 처리에 대한 jsp 코드이다. 내가 현재 있는 페이지의 숫자는 클릭이 불가능하게 만들고, 뒤에 페이지를 이동할 수 있는 블럭이 존재하면 다음 블럭이라는 버튼이 생기고, 이전에 블럭이 존재하면 이전 블럭이라는 버튼이 생기게 코드를 작성한 것이다.

·상세페이지

-게시글을 눌렀을 때, 상세페이지로 이동하고 누른 게시글의 내용을 보여주는 코드를 작성했다. 물론 먼저, 해당 값을 가져오는 쿼리문을 만들었다.

public Board boardSelect(long bbsSeq) 
	{
		Board board = null;
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		StringBuilder sql = new StringBuilder();
		
		sql.append("SELECT  ");
		sql.append("  		BBS_SEQ, ");
		sql.append("  		NVL(B.USER_ID, '') AS USER_ID, ");
		sql.append("  		NVL(B.USER_NAME, '') AS BBS_NAME, ");
		sql.append("  		NVL(B.USER_EMAIL, '') AS BBS_EMAIL, ");
		sql.append("  		NVL(A.BBS_PWD, '') AS BBS_PWD, ");
		sql.append("  		NVL(A.BBS_TITLE, '') AS BBS_TITLE, ");
		sql.append("      NVL(BBS_CONTENT, '') BBS_CONTENT, ");
		sql.append("  		NVL(A.BBS_READ_CNT, 0) AS BBS_READ_CNT, ");
		sql.append("  		NVL(TO_CHAR(A.REG_DATE, 'YYYY.MM.DD HH24:MI:SS'), '') AS REG_DATE ");
		sql.append(" FROM 		");
		sql.append("  		TBL_BOARD A, TBL_USER B ");
		sql.append(" WHERE 	A.BBS_SEQ = ? ");
		sql.append("  		AND A.USER_ID = B.USER_ID ");   
	    
	    try 
	    {
	    	
	    	conn = DBManager.getConnection();
	    	pstmt = conn.prepareStatement(sql.toString());
	    	
	    	pstmt.setLong(1, bbsSeq);
	    	
	    	rs = pstmt.executeQuery();
	    	
	    	if(rs.next()) 
	    	{
	    		board = new Board();
	    		
	    		board.setBbsSeq(rs.getLong("BBS_SEQ"));
	    		board.setUserId(rs.getString("USER_ID"));
	    		board.setBbsName(rs.getString("BBS_NAME"));
	    		board.setBbsEmail(rs.getString("BBS_EMAIL"));
	    		board.setBbsPwd(rs.getString("BBS_PWD"));
	    		board.setBbsTitle(rs.getString("BBS_TITLE"));
	    		board.setBbsContent(rs.getString("BBS_CONTENT"));
	    		board.setBbsReadCnt(rs.getInt("BBS_READ_CNT"));
	    		board.setRegDate(rs.getString("REG_DATE"));
	    	}
	    	
	    }
	    catch(SQLException e) 
	    {
	    	logger.error("[BoardDao] boardSelect SQLException", e);
	    }
	    finally 
	    {
	    	DBManager.close(rs, pstmt, conn);
	    }
	    
		return board;
	}

-게시물을 클릭해서 들어간다는 것은, 해당 게시물 하나만 본다는 뜻이므로, 한개의 board객체만 받으면 된다. 여기서 WHERE 절의 조건이 굉장히 중요한데, 가져올 값이 1개다. 그러니까 일단 1개부터 가져오고 아이디가 같은지 확인하는 것이 훨씬 빠르다. DRIVING table이 기준 테이블임, 기준테이블이 조인을 할 때 조건을 잘 줘야 처리 속도가 빠르다. 지금이야 데이터의 수가 얼마 없지만 나중에는 정말 방대한 데이터와 마주할 수 있다. BBS_SEQ는 심지어 PK여서 인덱스도 있기 때문에, BBS_SEQ를 먼저 찾으면 인덱스를 통해 옵티마이저가 테이블 풀스캔을 하지 않아도 된다.

//게시물 조회 시 조회수 증가
	public int boardReadCntPlus(long bbsSeq) 
	{
		int count = 0;
		Connection conn = null;
		PreparedStatement pstmt = null;
		StringBuilder sql = new StringBuilder();
		
		sql.append("UPDATE TBL_BOARD ");
		sql.append(" SET ");
		sql.append(" 		BBS_READ_CNT = BBS_READ_CNT + 1  ");
		sql.append(" WHERE ");
		sql.append(" 		BBS_SEQ = ? ");
	
		try 
		{
			conn = DBManager.getConnection();
			pstmt = conn.prepareStatement(sql.toString());
			
			pstmt.setLong(1, bbsSeq);
			
			count = pstmt.executeUpdate();
		}
		catch(SQLException e) 
	    {
	    	logger.error("[BoardDao] boardReadCntPlus SQLException", e);
	    }
	    finally 
	    {
	    	DBManager.close(pstmt, conn);
	    }
		
		return count;
	}

-만들어 주는 김에, 게시물을 조회했을 때, BBS_READ_CNT값이 올라가는 쿼리도 작성했다.

	//0은 없는 페이지를 보여준다는 뜻
	long bbsSeq = HttpUtil.get(request, "bbsSeq", (long)0);
	String searchType = HttpUtil.get(request, "searchType", "");
	String searchValue = HttpUtil.get(request, "searchValue", "");
	long curPage = HttpUtil.get(request, "curPage", (long)1);
	
	//쿼리를 실행하기 위해서 보드 보드다오 객체 생성
	BoardDao boardDao = new BoardDao();
	Board board = boardDao.boardSelect(bbsSeq);
	
	if(board != null)
	{
		//데이터가 존재하면
		//조회수 증가
		//따로 결과를 받아서 처리할 것이 없음.
		boardDao.boardReadCntPlus(bbsSeq);
		
	}

-조회 결과가 null이 아니면 조회수를 늘리는 쿼리도 같이 진행해준다.

<script>
	$(document).ready(function(){
<% 
		if(board == null)
		{
			//보드객체가 비어있는 경우, 오류창 띄우고 돌려보냄.
%>
			alert("조회하신 게시물이 존재하지 않습니다.");
			document.bbsForm.action = "/board/list.jsp";
			document.bbsForm.submit();
<% 
		}
		else
		{	
			//데이터가 존재할 때에 대한 처리
%>
			
<%			
		}
%>

	});
</script>

jQuery부분에 데이터가 존재하는 경우와 아닌 경우의 처리를 해준다. 그 다음 해당 보드의 setter를 통해서 각각의 값들을 html 안에서 보여주기만 하면 되는데, 문제는, 특히, 내용에 엔터라든지 html에 직접적인 영향을 줄 수 있는 <>특수기호 등에 대한 처리를 해줘야 한다. 그래서 공통모듈을 통해 이 부분을 해결해주었다.
또한, 쿠키 아이디를 얻어와서, 현재 내가 사용하고 있는 아이디가 게시물 작성한 사람의 아이디이면 해당 게시물을 수정하거나 삭제할 수 있도록 버튼이 나타나고, 아니라면 수정 삭제 버튼이 아예 없어지도록 코드를 작성했다.

String cookieUserId = CookieUtil.getValue(request, "USER_ID");
	logger.debug("view.jsp CookieUserID: " + cookieUserId);
    
<% 
	if(StringUtil.equals(cookieUserId, board.getUserId()))
	{
%>
   <button type="button" id="btnUpdate" class="btn btn-secondary">수정</button>
   <button type="button" id="btnDelete" class="btn btn-secondary">삭제</button>
<%
	}
%>

·막상 정리할 때 쓸 내용을 보면....

-별거 없다고 생각할 수 있다. 그러나 실제로 진행하다가 보면 오류도 굉장히 많이 뜨고, 로직을 이해하기가 힘들어서 새로 jsp파일을 생성해서 실제로 전부 따라서도 써보고, 안보고도 써보고 엄청나게 연습했다. 물론 그래도 아직 어려운 부분이 많다. 공통모듈도 굉장히 많아져서 하나하나 열심히 보고는 있는데, 그래도 아직 너무 많이 남았고 어렵다. 모듈을 괜히 코딩 잘하는 사람한테 작성하라고 하는게 아니구나를 뼈져리게 깨닫는 중이다. 월요일부터 목요일까지 비대면 없이 수업에 참여했다... 그리고 내일은 정말정말 집에서 비대면 수업을 하려고 했다. 그런데... 집에 있으면 정말 집중이 안될 것 같다는 생각이 들었다. 요즘 코로나가 다시 심해져서 정말 불안하기는 하지만, 그래도 어쩌겠는가... 열심히 하자. 나는 개발자가 될 것이고, 바뀐 진로지만, 정말 열심히 재밌게 하고 있다. 그러니 좀 더 열심히 하자!!! 할 수 있다.

profile
비전공자란 이름으로 새로운 길을 가려 하는 신입

0개의 댓글