관리 메뉴

공부한것들을 정리하는 블로그 입니다.

7-4. 글 조회수 카운트, session을 이용한 조회수 중복 방지 처리(jsp) : BoardDAO.java, getBoard.jsp 본문

(2019) 사이드 프로젝트/BoardWeb(게시판-MVC1,MVC2,스프링MVC)

7-4. 글 조회수 카운트, session을 이용한 조회수 중복 방지 처리(jsp) : BoardDAO.java, getBoard.jsp

호 두 2019. 6. 28. 11:05
반응형

 

게시판 조회수 중복 방지를 위해서는 쿠키, 세션, ip 3가지 방법이 있습니다.

실제 업무에서는 대개 쿠키를 이용하지만,

 

현재 제 게시물 중 실습7-* 들은 MVC Model1을 기반으로 대부분 session 을 이용하여 단순히 값을 넘기는 정도로만 처리하고 있습니다.

(자세한 설명은 실습8 이후에서 session을 대체할 수 있는 방법들을 소개하면서 진행하려 생각중입니다.)

따라서 이번 실습도 session을 이용한 조회수 중복 방지 처리(jsp)로 진행하도록 하겠습니다.

 

 

 

BoardDAO.java

- 글 조회수 카운트를 위한 updateBoardCnt() 메서드가 최하단에 추가되었습니다.

 

package com.springbook.biz.board.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Repository;

import com.springbook.biz.board.BoardVO;
import com.springbook.biz.common.JDBCUtil;

import hello.printSimpleName;

@Repository("boardDAO")
public class BoardDAO {

	private Connection       		conn = null;
	private PreparedStatement		stmt = null;
	private ResultSet				rs   = null;

	private final String BOARD_INSERT = "insert into board(seq, title, writer, content, regdate) values((select nvl(max(seq),0)+1 from board),?,?,?,sysdate)";
	private final String BOARD_UPDATE = "update board set title=?, content=? where seq=?";
	private final String BOARD_DELETE = "delete board where seq=?";
	private final String BOARD_GET    = "select * from board where seq=?";
	// private final String BOARD_LIST   = "select * from board order by seq desc";
	private final String BOARD_LIST = "select * from board order by seq desc";
	private final String BOARD_LIST_T = "select * from board where title like '%'||?||'%' order by seq desc";
	private final String BOARD_LIST_C = "select * from board where content like '%'||?||'%' order by seq desc";
	private final String BOARD_UPDAT_CNT = "update board set cnt=cnt+1 where seq=?";

	printSimpleName p = new printSimpleName();
	
	public void insertBoard(BoardVO vo) {
		System.out.println("===> JDBC로 insertBoard() 기능 처리");
		try {
			conn = JDBCUtil.getConnection();
			stmt = conn.prepareStatement(BOARD_INSERT);
			stmt.setString(1, vo.getTitle());
			stmt.setString(2, vo.getWriter());
			stmt.setString(3, vo.getContent());
			stmt.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JDBCUtil.close(stmt, conn);
		}
	}

	public void updateBoard(BoardVO vo) {
		System.out.println("===> JDBC로 updateBoard() 기능 처리");
		try {
			conn = JDBCUtil.getConnection();
			stmt = conn.prepareStatement(BOARD_UPDATE);
			stmt.setString(1, vo.getTitle());
			stmt.setString(2, vo.getContent());
			stmt.setInt(3, vo.getSeq());
			stmt.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JDBCUtil.close(stmt, conn);
		}
	}
	
	public void deleteBoard(BoardVO vo) {
		System.out.println("===> JDBC로 deleteBoard() 기능 처리");
		try {
			conn = JDBCUtil.getConnection();
			stmt = conn.prepareStatement(BOARD_DELETE);
			stmt.setInt(1, vo.getSeq());
			stmt.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JDBCUtil.close(stmt, conn);
		}
	}

	public BoardVO getBoard(BoardVO vo) {
		System.out.println("===> JDBC로 getBoard() 기능 처리");
		BoardVO board = null;
		try {
			conn = JDBCUtil.getConnection();

			stmt = conn.prepareStatement(BOARD_GET);
			stmt.setInt(1, vo.getSeq());
			rs = stmt.executeQuery();
			if(rs.next()) {
				board = new BoardVO();
				board.setSeq(rs.getInt("SEQ"));
				board.setTitle(rs.getString("TITLE"));
				board.setWriter(rs.getString("WRITER"));
				board.setContent(rs.getString("CONTENT"));
				board.setRegDate(rs.getDate("REGDATE"));
				board.setCnt(rs.getInt("CNT"));
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JDBCUtil.close(stmt, conn);
		}
		return board;
	}

//	public List<BoardVO> getBoardList(BoardVO vo) {
//		System.out.println("===> JDBC로 getBoardList() 기능 처리");
//		List<BoardVO> boardList = new ArrayList<BoardVO>();
//		try {
//			conn = JDBCUtil.getConnection();
//			stmt = conn.prepareStatement(BOARD_LIST);
//			rs = stmt.executeQuery();
//			while(rs.next()) {
//				BoardVO board = new BoardVO();
//				board.setSeq(rs.getInt("SEQ"));
//				board.setTitle(rs.getString("TITLE"));
//				board.setWriter(rs.getString("WRITER"));
//				board.setContent(rs.getString("CONTENT"));
//				board.setRegDate(rs.getDate("REGDATE"));
//				board.setCnt(rs.getInt("CNT"));
//				boardList.add(board);
//			}
//		} catch (Exception e) {
//			e.printStackTrace();
//		} finally {
//			JDBCUtil.close(stmt, conn);
//		}
//		return boardList;
//	}
	
//	public List<BoardVO> getBoardListFromSearch(BoardVO vo) {
	public List<BoardVO> getBoardList(BoardVO vo) {
		System.out.println("===> JDBC로 getBoardList() 기능 처리");
		List<BoardVO> boardList = new ArrayList<BoardVO>();
		String flagBoardListFromSearch = "N";
		try {
			conn = JDBCUtil.getConnection();
			
			if (vo.getSearchCondition() != null && vo.getSearchKeyword() != null) {
				flagBoardListFromSearch = "Y";
			}
			
			if("Y".equals(flagBoardListFromSearch) && vo.getSearchCondition().equals("TITLE")) {
				stmt = conn.prepareStatement(BOARD_LIST_T);
				stmt.setString(1, vo.getSearchKeyword());
			} else if("Y".equals(flagBoardListFromSearch) && vo.getSearchCondition().equals("CONTENT") ) {
				stmt = conn.prepareStatement(BOARD_LIST_C);
				stmt.setString(1, vo.getSearchKeyword());
			} else {
				stmt = conn.prepareStatement(BOARD_LIST);
			}
			
			rs = stmt.executeQuery();
			while(rs.next()) {
				BoardVO board = new BoardVO();
				board.setSeq(rs.getInt("SEQ"));
				board.setTitle(rs.getString("TITLE"));
				board.setWriter(rs.getString("WRITER"));
				board.setContent(rs.getString("CONTENT"));
				board.setRegDate(rs.getDate("REGDATE"));
				board.setCnt(rs.getInt("CNT"));
				boardList.add(board);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JDBCUtil.close(stmt, conn);
		}
		return boardList;
	}
	
	public void updateBoardCnt(BoardVO vo) {
		System.out.println("===> JDBC로 updateBoardCnt() 기능 처리");
		try {
			conn = JDBCUtil.getConnection();
			stmt = conn.prepareStatement(BOARD_UPDAT_CNT);
			stmt.setInt(1, vo.getSeq());
			stmt.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JDBCUtil.close(stmt, conn);
		}
	}

	
}

 

 

 

getBoard.jsp

- 글 상세보기 페이지 상단에 있는 페이지 디렉터에 조회수 중복 방지를 위한 로직이 추가되었습니다.

- session을 이용하여 간단히 처리하였고, session = 글 고유번호(seq) + 쿠키(cookies) 로 구성되어 있습니다.

- 처음 조회수를 올린 후 해당 session값은 session ex에 저장됩니다. 이 session ex가 중복 카운트를 방지하기 위한 validation check 비교문에 이용됩니다.

- 39라인에 cnt +1 해준 이유는 가시적으로 사용자 편의성을 위해서입니다. (view에서 볼때 조회수 1이 선추가 된 모습을 보여주기 위해) 해당로직이 없다면 목록을 클릭해도 조회수는 그대로고 f5로 새로고침 또는 글목록으로 나가야 비로수 조회수가 올라간 모습을 볼 수 있을 것입니다. 하단에서 boardDAO.getBoard()를 재실행시키거나 ajax를 이용하여 동적으로 처리하면 해결 가능하지만 전자는 자원이 너무 비효율적으로 소모되고 후자는 다음번 실습때 진행하도록 하겠습니다.

 

( * 참고 : A.equals(B) 함수를 쓸때는 A부분에 not null 값이 오도록 하자. 왜냐하면 equals()도 함수이므로 A위치에 null이 오면 NullPointerException 에러가 납니다. )

 

<%@ page import="com.springbook.biz.board.impl.BoardDAO" %>
<%@ page import="com.springbook.biz.board.BoardVO" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
 <%
	// 저장된 쿠키 불러오기
	Cookie[] cookieFromRequest = request.getCookies();
	String cookieValue = null;
	for(int i = 0 ; i<cookieFromRequest.length; i++) {
		// 요청정보로부터 쿠키를 가져온다.
		cookieValue = cookieFromRequest[0].getValue();	// 테스트라서 추가 데이터나 보안사항은 고려하지 않으므로 1번째 쿠키만 가져옴	
	}
	
	// 글 목록 -> 글 상세 : 글번호(seq)
 	String seq = request.getParameter("seq");
 	
 	// 쿠키 세션 입력
	if (session.getAttribute(seq+":cookie") == null) {
	 	session.setAttribute(seq+":cookie", seq + ":" + cookieValue);
	} else {
		session.setAttribute(seq+":cookie ex", session.getAttribute(seq+":cookie"));
		if (!session.getAttribute(seq+":cookie").equals(seq + ":" + cookieValue)) {
		 	session.setAttribute(seq+":cookie", seq + ":" + cookieValue);
		}
	}
 
 	BoardVO vo = new BoardVO();
 	vo.setSeq(Integer.parseInt(seq));
 	
 	BoardDAO boardDAO = new BoardDAO();
 	// 글 상세 조회
 	BoardVO  board    = boardDAO.getBoard(vo);

 	// 조회수 카운트
 	if (!session.getAttribute(seq+":cookie").equals(session.getAttribute(seq+":cookie ex"))) {
 		boardDAO.updateBoardCnt(vo);
	 	// 가시적으로  조회수 1 추가해줌
	 	board.setCnt(board.getCnt() + 1);
 	}
 	
 	//System.out.println("중복방지 111 = " + session.getAttribute(seq+":cookie") );
 	//System.out.println("중복방지 222 = " + session.getAttribute(seq+":cookie ex") );
 	//System.out.println("중복방지 333 = " + session.toString() );
 	//for(int i = 0; i < session.getValueNames().length; i++){
 	//	System.out.println("중복방지 444 = " + session.getValueNames()[i].toString() );
 	//}
 	
 %> 
   
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>글 상세</title>
</head>
<body>
	<center>
		<h1>글 상세</h1>
		<a href="logout_proc.jsp">log out</a>
		<hr>
		<form action="updateBoard_proc.jsp" method="post">
			<table border="1" cellpadding="0" cellspacing="0">
				<tr>
					<td bgcolor="orange" width="70">제목</td>
					<td align="left">
						<input name="title" type="text" value="<%= board.getTitle() %>">
					</td>
				</tr>
				<tr>
					<td bgcolor="orange">작성자</td>
					<td align="left"><%= board.getWriter() %></td>
				</tr>
				<tr>
					<td bgcolor="orange">내용</td>
					<td align="left">
						<textarea name="content" cols="40" rows="10"><%= board.getContent() %></textarea>
					</td>
				</tr>
				<tr>
					<td bgcolor="orange">등록일</td>
					<td align="left"><%= board.getRegDate() %></td>
				</tr>
				<tr>
					<td bgcolor="orange">조회수</td>
					<td align="left"><%= board.getCnt() %></td>
				</tr>
				<tr>
					<td colspan="2" align="center">
						<input type="submit" value="글 수정" />
					</td>
				</tr>
			</table>
			<input name="seq" type="hidden" value="<%= board.getSeq() %>" />
		</form>
		<hr>
		<a href="insertBoard.jsp">글 등록</a>&nbsp;&nbsp;&nbsp;
		<a href="deleteBoard_proc.jsp?seq=<%= board.getSeq() %>">글 삭제</a>&nbsp;&nbsp;&nbsp;
		<a href="getBoardList.jsp">글 목록</a>
	</center>
</body>
</html>

 

 

 

 

실습화면 : 

반응형
Comments