본 포스팅의 예제는 STS 또는 Eclipse를 사용하지 않고 Intellij를 통해 구현하고 있습니다.
그래서 기존의 STS(Spring Tool Studio)에서 생성된 Spring 프로젝트의 스프링 관련 설정 파일명과
프로젝트 구조가 약간 다를 수 있습니다.Intellij 스프링 mvc 프로젝트 생성 포스팅을 참고해주시면 감사하겠습니다.
Spring-MVC 기본 개념 및 테스트 예제 관련 포스팅 링크
순서 | 포스팅 제목 |
1 | Intellij에서 Spring MVC Project 생성하기 |
2 | Spring MVC - MariaDB 연결테스트 |
3 | Spring MVC - Mybatis 설정 및 테스트 |
4 | SpringMVC 구조 |
5 | SpringMVC + Mybatis |
6 | Spring MVC Controller 작성 연습 |
7 | Spring Interceptor |
Spring-MVC 게시판 예제 이전 포스팅 링크
1. 게시글 상세보기 구현
1.1 게시글 상세보기 영속 계층 (Persistence Tier) 구현
src/기본패키지/board/persistence 패키지 안에 BoardDAO 인터페이스와 BoardDAOImpl 클래스 안에 아래와 같이 내용을 추가 해주세요.
// 게시글 상세보기
public BoardVo getBoardByNo(int board_no);
// 게시글 상세보기
@Override
@LogException
public BoardVo getBoardByNo(int board_no){
return sqlSession.selectOne(NAMESPACE + ".getBoardByNo", board_no);
}
resources/mappers/board 패키지 안에 BoardSQLMapper.xml 파일 안에 아래와 같이 내용을 추가 해주세요.
<!-- 게시글 상세 조회 -->
<select id="getBoardByNo" resultType="BoardVo">
select * from eden_board where board_no = #{board_no}
</select>
1.2 게시글 상세보기 비지니스 계층 (Business Tier) 구현
src/기본패키지/board/service 패키지 안에 BoardService 인터페이스와 BoardServiceImpl 클래스 안에 아래와 같이 내용을 추가 해주세요.
// 게시글 상세보기
public HashMap<String, Object> getBoard(int board_no);
// 게시글 상세보기
@Override
@LogException
public HashMap<String, Object> getBoard(int board_no) {
BoardVo boardVo = boardDAO.getBoardByNo(board_no);
UserVo userVo = userDAO.getUserByNo(boardVo.getUser_no());
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("userVo", userVo);
map.put("boardVo", boardVo);
return map;
}
1.3 게시글 상세보기 컨트롤러 구현
src/기본패키지/board/controller 패키지 안에 BoardController 클래스 안에 아래와 같이 내용을 추가 해주세요.
// 게시글 상세보기
@PostMapping(value = "detailsPosting")
@LogException
public String detailsPosting(@RequestParam(value = "board_no", defaultValue = "0") int board_no, Model model) {
model.addAttribute("data", boardService.getBoard(board_no));
return "board/detailsPosting";
}
1.4 게시글 상세보기 JSP 파일 작성
web-inf/views/board 패키지 안에 detailsPosting.jsp 파일 생성 후 아래와 같이 내용을 작성 해주세요.
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ include file="../include/head.jsp" %>
<%@ include file="../include/user_menu.jsp" %>
<html>
<body class="hold-transition skin-green-light sidebar-mini" oncopy="return false" oncut="return false"
onpaste="return false">
<div class="wrapper">
<%@ include file="../include/top_menu.jsp" %>
<%@ include file="../include/left_menu.jsp" %>
<div class="content-wrapper">
<section class="content container-fluid">
<div class="col-lg-12">
<%--게시글 내용 영역--%>
<div class="box box-primary">
<%--게시글 제목 영역--%>
<div class="box-header with-border">
<h3 class="box-title">글제목 : ${data.boardVo.board_title}</h3>
<ul class="list-inline pull-right">
<li><span><i class="fa fa-eye"></i>조회수
(${data.boardVo.board_view_count})</span></li>
</ul>
</div>
<%--게시글 내용 영역--%>
<div class="box-body" style="height: 700px">
${fn:replace(fn:replace(fn:escapeXml(data.boardVo.board_content), newLine, "<br/>") , " ", " ")}
</div>
<%--작성자 정보 영역--%>
<div class="box-footer">
<div class="user-block">
<ul class="navbar-custom-menu">
<li class="dropdown messages-menu">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<img class="img-circle img-bordered-sm"
src="${path}/resources/dist/img/profile/${data.userVo.user_image}" alt="user image">
<span>${data.userVo.user_nickname}</span>
<span class="description"><fmt:formatDate pattern="yyyy-MM-dd a HH:mm"
value="${data.boardVo.board_write_date}"/></span>
</a>
<ul class="dropdown-menu">
<li><a href="#">작성 글보기</a></li>
</ul>
</li>
</ul>
</div>
</div>
<div class="box-footer">
<form role="form" method="post">
<input type="hidden" id="boardNo" name="board_no" value="${data.boardVo.board_no}">
<input type="hidden" id="userNo" name="user_no" value="${sessionUser.user_no}">
<input type="hidden" id="categoryNo" name="category_no" value="${data.boardVo.category_no}">
</form>
<button class="btn btn-primary" onclick="postingList(${data.boardVo.category_no})"><i
class="fa fa-list"></i> 목록
</button>
<c:if test="${sessionUser.user_no == data.boardVo.user_no}">
<div class="pull-right">
<button type="submit" class="btn btn-warning modBtn"><i class="fa fa-edit"></i> 수정
</button>
<button type="submit" class="btn btn-danger delBtn"><i class="fa fa-trash"></i> 삭제
</button>
</div>
</c:if>
</div>
</div>
</div>
</section>
</div>
<%@ include file="../include/footer.jsp" %>
</div>
<%@ include file="../include/plugin_js.jsp" %>
</body>
</html>
web-inf/views/board 패키지 안에 postingList.jsp 파일에 아래와 같이 내용을 추가 해주세요.
<form name="detailsForm" role="form" method="post">
<input type="hidden" id="boardNo" name="board_no" value="">
</form>
1.5 게시글 상세보기 JavaScript 작성
webapp/resources/dist/js/board 패키지 안에 relatedBulletin.js 파일 안에 아래와 같이 내용을 추가 해주세요.
function goPage(board_no) {
const form= $("form[name='detailsForm']");
$("#boardNo").attr("value", board_no);
form.attr("action", "../board/detailsPosting");
form.attr("method", "post");
form.submit();
}
1.6 게시글 상세보기 화면 확인
2. 게시글 조회수 증가 구현
2.1 게시글 조회수 증가 테이블 구현
-- 게시글 조회수 테이블
drop table eden_view_page;
create table eden_view_page
(
view_page_no number primary key,
board_no number,
lockup_ip varchar(200),
view_inquiry_time date default sysdate,
constraint eden_view_board_no foreign key(board_no) references eden_board (board_no)
);
-- 게시판 조회수 시퀸스
drop sequence eden_view_page_seq;
create sequence eden_view_page_seq;
2.2 게시글 조회수 클래스 생성
src/기본 패키지/board/domain 패키지 안에 ViewPageVo 클래스 생성 후 아래와 같이 내용을 작성 해주세요,
import java.util.Date;
public class ViewPageVo {
private int view_page_no;
private int board_no;
private String lockup_ip;
private Date view_inquiry_time;
public ViewPageVo() {
super();
}
public ViewPageVo(int view_page_no, int board_no, String lockup_ip, Date view_inquiry_time) {
this.view_page_no = view_page_no;
this.board_no = board_no;
this.lockup_ip = lockup_ip;
this.view_inquiry_time = view_inquiry_time;
}
public int getView_page_no() {
return view_page_no;
}
public void setView_page_no(int view_page_no) {
this.view_page_no = view_page_no;
}
public int getBoard_no() {
return board_no;
}
public void setBoard_no(int board_no) {
this.board_no = board_no;
}
public String getLockup_ip() {
return lockup_ip;
}
public void setLockup_ip(String lockup_ip) {
this.lockup_ip = lockup_ip;
}
public Date getView_inquiry_time() {
return view_inquiry_time;
}
public void setView_inquiry_time(Date view_inquiry_time) {
this.view_inquiry_time = view_inquiry_time;
}
@Override
public String toString() {
return "ViewPageVo{" +
"view_page_no=" + view_page_no +
", board_no=" + board_no +
", lockup_ip='" + lockup_ip + '\'' +
", view_inquiry_time=" + view_inquiry_time +
'}';
}
}
// 게시글 조회수 증가 중복 방지 조회
@Override
@LogException
public List<ViewPageVo> getViewPageList(int boardNo) {
return sqlSession.selectList(NAMESPACE + ".getViewPageList", boardNo);
}
// 게시글 조회수 증가 중복 방지
@Override
@LogException
public void insertViewPage(ViewPageVo viewPageVo) {
sqlSession.insert(NAMESPACE + ".insertViewPage", viewPageVo);
}
// 게시글 조회한 아이피 조회 쿼리
@Override
@LogException
public int selectByLockupIp(String lockup_ip) {
return sqlSession.selectOne(NAMESPACE + ".selectByLockupIp", lockup_ip);
}
// 게시글 중복 증가 방지 게시글 조회
@Override
@LogException
public int selectByViewByBoardNo(int boardNo) {
return sqlSession.selectOne(NAMESPACE + ".selectByViewByBoardNo", boardNo);
}
// 게시글 조회 중복 증가 방지 조회 (게시글번호, 아이피로 조회)
@Override
@LogException
public int selectByViewPage(ViewPageVo viewPageVo) {
return sqlSession.selectOne(NAMESPACE + ".selectByViewPage", viewPageVo);
}
// 게시글 조회수 증가 쿼리
@Override
@LogException
public void increaseReadCount(int boardNo) {
sqlSession.update(NAMESPACE + ".increaseReadCount", boardNo);
}
// 게시글 조회수 증가 쿼리
@Override
@LogException
public void updateViewPage(ViewPageVo param) {
sqlSession.update(NAMESPACE + ".updateViewPage", param);
}
// 게시글 조회수 중복 증가 삭제
@Override
@LogException
public void deleteViewPage(int boardNo) {
sqlSession.delete(NAMESPACE + ".deleteViewPage", boardNo);
}
2.2 게시글 조회수 증가 영속 계층 (Persistence Tier) 구현
src/기본패키지/board/persistence 패키지 안에 BoardDAO 인터페이스와 BoardDAOImpl 클래스 안에 아래와 같이 내용을 추가 해주세요.
// 게시글 조회수 증가 중복 방지
public void insertViewPage(ViewPageVo viewPageVo);
// 게시글 조회수 증가 중복 방지 조회
public List<ViewPageVo> getViewPageList(int boardNo);
// 게시글 조회한 아이피 조회 쿼리
public int selectByLockupIp(String lockup_ip);
// 게시글 중복 증가 방지 게시글 조회
public int selectByViewByBoardNo(int boardNo);
// 게시글 조회 중복 증가 방지 조회 (게시글번호, 아이피로 조회)
public int selectByViewPage(ViewPageVo viewPageVo);
// 게시글 조회수 증가 쿼리
public void increaseReadCount(int boardNo);
public void updateViewPage(ViewPageVo param);
// 게시글 조회수 중복 증가 삭제
public void deleteViewPage(int boardNo);
resources/mappers/board 패키지 안에 BoardSQLMapper.xml 파일에 아래와 같이 내용을 추가 해주세요.
<!-- 게시글 조회수 중복 증가 방지 -->
<insert id="insertViewPage">
insert into eden_view_page (view_page_no, board_no, lockup_ip)
values (eden_view_page_seq.nextval,
#{board_no},
#{lockup_ip})
</insert>
<!-- 게시글 조회수 중복 증가 방지 조회 -->
<select id="getViewPageList" resultType="ViewPageVo">
select * from eden_view_page where board_no = #{boardNo}
</select>
<!-- 게시글 조회한 아이피 -->
<select id="selectByLockupIp" resultType="int">
select count(*) from eden_view_page where lockup_ip = #{lockup_ip}
</select>
<!-- 게시글 조회수 중복 증가 (게시글 조회) -->
<select id="selectByViewByBoardNo" resultType="int">
select count(*) from eden_view_page where board_no = #{boardNo}
</select>
<!-- 게시글 조회수 중복 증가 (게시글, 아이피 조회) -->
<select id="selectByViewPage" resultType="int">
select count(*) from eden_view_page where lockup_ip = #{lockup_ip} and board_no =#{board_no}
</select>
<!-- 게시글 조회수 증가 -->
<update id="increaseReadCount">
update eden_board set board_view_count = board_view_count + 1 where board_no = #{boardNo}
</update>
<update id="updateViewPage">
update eden_view_page set view_inquiry_time = sysdate where lockup_ip = #{lockup_ip} and board_no = #{board_no}
</update>
<!-- 게시글 조회수 중복 증가 방지 삭제 -->
<delete id="deleteViewPage">
delete from eden_view_page where board_no = #{boardNo}
</delete>
2.3 게시글 조회수 증가 비지니스 계층 (Business Tier) 구현
src/기본패키지/board/service 패키지 안에 BoardService 인터페이스와 BoardServiceImpl 클래스 안에 아래와 같이 내용을 추가 해주세요.
// 게시글 조회수 증가 중복 방지
public void insertViewPage(ViewPageVo viewPageVo);
// 게시글 조회수 증가 중복 방지 조회
public List<ViewPageVo> getViewPageList(int boardNo);
// 게시글 조회한 아이피 조회 쿼리
public boolean isSelectByLockupIp(String lockup_ip);
// 게시글 중복 증가 방지 게시글 조회
public boolean isSelectByViewByBoardNo(int boardNo);
// 게시글 조회 중복 증가 방지 조회 (게시글번호, 아이피로 조회)
public boolean isSelectByViewPage(ViewPageVo viewPageVo);
// 게시글 조회수 증가 쿼리
public void increaseReadCount(int boardNo);
public void updateViewPage(ViewPageVo param);
// 게시글 조회수 중복 증가 삭제
public void deleteViewPage(int boardNo);
// 게시글 조회수 증가 중복 방지
@Override
@LogException
public void insertViewPage(ViewPageVo viewPageVo) {
boardDAO.insertViewPage(viewPageVo);
}
// 게시글 조회수 증가 중복 방지 조회
@Override
@LogException
public List<ViewPageVo> getViewPageList(int boardNo) {
return boardDAO.getViewPageList(boardNo);
}
// 게시글 조회한 아이피 조회 쿼리
@Override
@LogException
public boolean isSelectByLockupIp(String lockup_ip) {
return boardDAO.selectByLockupIp(lockup_ip) > 0;
}
// 게시글 중복 증가 방지 게시글 조회
@Override
@LogException
public boolean isSelectByViewByBoardNo(int boardNo) {
return boardDAO.selectByViewByBoardNo(boardNo) > 0;
}
// 게시글 조회 중복 증가 방지 조회 (게시글번호, 아이피로 조회)
@Override
@LogException
public boolean isSelectByViewPage(ViewPageVo viewPageVo) {
return boardDAO.selectByViewPage(viewPageVo) > 0;
}
// 게시글 조회수 증가 쿼리
@Override
@LogException
public void increaseReadCount(int boardNo) {
boardDAO.increaseReadCount(boardNo);
}
@Override
@LogException
public void updateViewPage(ViewPageVo param) {
boardDAO.updateViewPage(param);
}
// 게시글 조회수 중복 증가 삭제
@Override
@LogException
public void deleteViewPage(int boardNo) {
boardDAO.deleteViewPage(boardNo);
}
2.4 게시글 조회수 증가 컨트롤러 구현
src/기본패키지/board/controller 패키지 안에 BoardController 클래스 안에 아래와 같이 내용을 수정 해주세요.
// 게시글 상세보기
@PostMapping(value = "detailsPosting")
@LogException
public String detailsPosting(@RequestParam(value = "board_no", defaultValue = "0") int board_no, Model model, HttpServletRequest request) {
List<ViewPageVo> viewPageVo = boardService.getViewPageList(board_no);
if (boardService.isSelectByViewByBoardNo(board_no)) {
if (!boardService.isSelectByLockupIp(request.getRemoteAddr())) {
ViewPageVo param = new ViewPageVo();
param.setBoard_no(board_no);
param.setLockup_ip(request.getRemoteAddr());
boardService.insertViewPage(param);
boardService.increaseReadCount(board_no);
}
} else {
ViewPageVo param = new ViewPageVo();
param.setBoard_no(board_no);
param.setLockup_ip(request.getRemoteAddr());
boardService.insertViewPage(param);
boardService.increaseReadCount(board_no);
}
for (ViewPageVo param : viewPageVo) {
if (param != null) {
if (boardService.isSelectByLockupIp(request.getRemoteAddr())) {
if (param.getLockup_ip().equals(request.getRemoteAddr())) {
Date writeDate = new Date(System.currentTimeMillis()); // 현재 서버 시간
Date tagetDate = new Date(param.getView_inquiry_time().getTime() + 1000 * 60 * 60 * 24); // 조회한 조회 일자
if (writeDate.after(tagetDate)) {
boardService.increaseReadCount(board_no);
boardService.updateViewPage(param);
}
}
}
}
}
model.addAttribute("data", boardService.getBoard(board_no));
return "board/detailsPosting";
}
2.5 게시글 조회수 증가 화면 확인
3. 정리
이번에는 게시글 조회 시 조회수가 올라가도록 24시간 기준으로 한번씩 증가 하도록 구현 해보았습니다.
기본적으로 조회수 중복 증가 방지를 위해 쿠키를 많이 사용 하나
쿠키 사용시 사용자가 임의로 쿠키 삭제가 가능하여서 쿼리로 구현 해보았습니다.
다음에는 게시글 수정 삭제를 구현 해보겠습니다.
'스프링 프레임워크 > 스프링 MVC' 카테고리의 다른 글
# Spring MVC 게시판 예제 18 : 게시글 좋아요 (0) | 2023.03.15 |
---|---|
# Spring MVC 게시판 예제 17 : 게시글 수정 및 삭제 (0) | 2023.03.13 |
# Spring MVC 게시판 예제 15 : 게시글 작성 (0) | 2023.03.09 |
# Spring MVC 게시판 예제 14 : 게시글 목록 출력 (0) | 2023.03.07 |
# Spring MVC 게시판 예제 13 : 자동 로그인 기능 구현 (0) | 2023.03.07 |
댓글