mvcPage
WEB-INF
폴더의 board.properties
하단에 다음의 내용을 추가/board/detail.do=kr.board.action.DetailAction
/board/updateForm.do=kr.board.action.UpdateFormAction
/board/update.do=kr.board.action.UpdateAction
/board/deleteFile.do=kr.board.action.DeleteFileAction
css
폴더의 layout.css
하단에 다음의 내용을 추가/* 글 상세 */
.detail-img {
max-width: 500px;
}
DetailAction
생성package kr.board.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import kr.board.dao.BoardDAO;
import kr.board.vo.BoardVO;
import kr.controller.Action;
import kr.util.StringUtil;
public class DetailAction implements Action {
@Override
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 글 번호 반환
int board_num = Integer.parseInt(request.getParameter("board_num"));
BoardDAO dao = BoardDAO.getInstance();
// 조회수 증가
dao.updateReadcount(board_num);
BoardVO board = dao.getBoard(board_num);
// HTML 태그를 허용하지 않음
board.setTitle(StringUtil.useNoHtml(board.getTitle()));
// HTML 태그를 허용하지 않으면서 줄바꿈 처리
board.setContent(StringUtil.useBrNoHtml(board.getContent()));
request.setAttribute("board", board);
// JSP 경로 반환
return "/WEB-INF/views/board/detail.jsp";
}
}
UpdateFormAction
생성package kr.board.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import kr.board.dao.BoardDAO;
import kr.board.vo.BoardVO;
import kr.controller.Action;
public class UpdateFormAction implements Action {
@Override
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpSession session = request.getSession();
Integer user_num = (Integer)session.getAttribute("user_num");
if(user_num==null) { // 로그인되어 있지 않은 경우
return "redirect:/member/loginForm.do";
}
int board_num = Integer.parseInt(request.getParameter("board_num"));
BoardDAO dao = BoardDAO.getInstance();
BoardVO db_board = dao.getBoard(board_num);
if(user_num!=db_board.getMem_num()) { // 로그인한 회원 번호와 작성자 회원 번호가 일치하지 않는 경우
return "/WEB-INF/views/common/notice.jsp";
}
// 로그인한 회원 번호와 작성자 회원 번호가 일치하는 경우
request.setAttribute("board", db_board);
// JSP 경로 반환
return "/WEB-INF/views/board/updateForm.jsp";
}
}
UpdateAction
생성package kr.board.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.oreilly.servlet.MultipartRequest;
import kr.board.dao.BoardDAO;
import kr.board.vo.BoardVO;
import kr.controller.Action;
import kr.util.FileUtil;
public class UpdateAction implements Action {
@Override
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpSession session = request.getSession();
Integer user_num = (Integer)session.getAttribute("user_num");
if(user_num==null) { // 로그인되어 있지 않은 경우
return "redirect:/member/loginForm.do";
}
MultipartRequest multi = FileUtil.createFile(request);
int board_num = Integer.parseInt(multi.getParameter("board_num"));
String filename = multi.getFilesystemName("filename");
BoardDAO dao = BoardDAO.getInstance();
// 수정 전 데이터
BoardVO db_board = dao.getBoard(board_num);
if(user_num!=db_board.getMem_num()) { // 로그인한 회원 번호와 작성자 회원 번호가 일치하지 않는 경우
FileUtil.removeFile(request, filename); // 업로드된 파일이 있으면 파일 삭제
return "/WEB-INF/views/common/notice.jsp";
}
// 로그인한 회원 번호와 작성자 회원 번호가 일치하는 경우
BoardVO board = new BoardVO();
board.setBoard_num(board_num);
board.setTitle(multi.getParameter("title"));
board.setContent(multi.getParameter("content"));
board.setFilename(filename);
board.setIp(request.getRemoteAddr());
// 글 수정
dao.updateBoard(board);
// 전송된 파일이 있을 경우 이전 파일 삭제
if(filename!=null) {
FileUtil.removeFile(request, db_board.getFilename());
}
// JSP 경로 반환
return "redirect:/board/detail.do?board_num=" + board_num;
}
}
DeleteFileAction
생성package kr.board.action;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.codehaus.jackson.map.ObjectMapper;
import kr.board.dao.BoardDAO;
import kr.board.vo.BoardVO;
import kr.controller.Action;
import kr.util.FileUtil;
public class DeleteFileAction implements Action {
@Override
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
Map<String, String> mapAjax = new HashMap<String, String>();
HttpSession session = request.getSession();
Integer user_num = (Integer)session.getAttribute("user_num");
if(user_num==null) { // 로그인되어 있지 않은 경우
mapAjax.put("result", "logout");
}
else { // 로그인되어 있는 경우
int board_num = Integer.parseInt(request.getParameter("board_num"));
BoardDAO dao = BoardDAO.getInstance();
BoardVO db_board = dao.getBoard(board_num);
if(user_num!=db_board.getMem_num()) { // 로그인한 회원 번호와 작성자 회원 번호가 일치하지 않는 경우
mapAjax.put("result", "wrongAccess");
}
else { // 로그인한 회원 번호와 작성자 회원 번호가 일치하는 경우
dao.deleteFile(board_num);
// 파일 삭제
FileUtil.removeFile(request, db_board.getFilename());
mapAjax.put("result", "success");
}
}
// JSON 데이터 생성
ObjectMapper mapper = new ObjectMapper();
String ajaxData = mapper.writeValueAsString(mapAjax);
request.setAttribute("ajaxData", ajaxData);
// JSP 경로 반환
return "/WEB-INF/views/common/ajax_view.jsp";
}
}
board
폴더에 detail.jsp
생성<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>글 상세</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/layout.css">
<style type="text/css">
hr {border-style: solid; color: gray;}
</style>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.6.0.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/board-reply.js"></script>
</head>
<body>
<div class="page-main">
<jsp:include page="/WEB-INF/views/common/header.jsp"/>
<h2>게시판 글 상세</h2>
<ul>
<li>
<label>글 번호</label>
${board.board_num}
</li>
<li>
<label>글 제목</label>
${board.title}
</li>
<li>
<label>작성자</label>
${board.id}
</li>
<li>
<label>조회수</label>
${board.hit}
</li>
</ul>
<hr>
<c:if test="${!empty board.filename}">
<div class="align-center">
<img src="${pageContext.request.contextPath}/upload/${board.filename}" class="detail-img">
<script type="text/javascript">
let img = document.getElementsByClassName('detail-img')[0];
img.src = encodeURI(decodeURI(img.src)); // 파일명에 괄호, 공백 등 특수문자가 사용된 경우 불러오지 못함; encodeURI만 사용하면 %20이 %2520으로 이중 인코딩되므로 이를 해결하기 위해 decodeURI를 먼저 사용; decodeURI만 사용하면 한글 파일명을 불러오지 못함
</script>
</div>
</c:if>
<p>
${board.content}
</p>
<hr>
<div class="align-right">
<c:if test="${!empty board.modify_date}">
최근 수정일 : ${board.modify_date}
</c:if>
작성일 : ${board.reg_date}
<%-- 로그인한 회원 번호와 작성자 회원 번호가 일치해야 수정, 삭제 가능 --%>
<c:if test="${user_num==board.mem_num}">
<input type="button" value="수정" onclick="location.href = 'updateForm.do?board_num=${board.board_num}';">
<input type="button" value="삭제" id="delete_btn">
<script type="text/javascript">
let delete_btn = document.getElementById('delete_btn');
delete_btn.onclick = function() {
let choice = confirm('삭제하시겠습니까?');
if(choice) {
location.replace('delete.do?board_num=${board.board_num}'); // 삭제 후 뒤로가기 방지
}
};
</script>
</c:if>
<input type="button" value="목록" onclick="location.href = 'list.do';">
</div>
<!-- 댓글 시작 -->
<div id="reply_div">
<span class="re-title">댓글 달기</span>
<form id="re_form">
<input type="hidden" name="board_num" value="${board.board_num}" id="board_num">
<textarea rows="3" cols="50" name="re_content" id="re_content" class="rep-content" <c:if test="${empty user_num}">disabled</c:if>><c:if test="${empty user_num}">로그인해야 작성할 수 있습니다.</c:if></textarea>
<c:if test="${!empty user_num}">
<div id="re_first">
<span class="letter-count">300/300</span>
</div>
<div id="re_second" class="align-right">
<input type="submit" value="전송">
</div>
</c:if>
</form>
</div>
<!-- 댓글 목록 출력 시작 -->
<div id="output"></div>
<div class="paging-button" style="display: none;">
<input type="button" value="다음 댓글 보기">
</div>
<div class="loading" style="display: none;">
<img src="${pageContext.request.contextPath}/images/ajax-loader.gif">
</div>
<!-- 댓글 목록 출력 끝 -->
<!-- 댓글 끝 -->
</div>
</body>
</html>
board
폴더에 updateForm.jsp
생성<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>글 수정</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/layout.css">
<style type="text/css">
hr {border-style: solid; color: gray;}
</style>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-3.6.0.min.js"></script>
<script type="text/javascript">
$(function() {
$('#update_form').submit(function() {
if($('#title').val().trim()=='') {
alert('제목을 입력하세요!');
$('#title').val('').focus();
return false;
}
if($('#content').val().trim()=='') {
alert('내용을 입력하세요!');
$('#content').val('').focus();
return false;
}
}); // end of submit
$('#filename').change(function() {
let file = this.files[0];
if(file.size>5*1024*1024) {
alert('5MB까지만 업로드 가능합니다!');
$(this).val('');
}
}); // end of change
});
</script>
</head>
<body>
<div class="page-main">
<jsp:include page="/WEB-INF/views/common/header.jsp"/>
<h2>글 수정</h2>
<form action="update.do" method="post" enctype="multipart/form-data" id="update_form">
<input type="hidden" name="board_num" value="${board.board_num}">
<ul>
<li>
<label for="title">제목</label>
<input type="text" name="title" id="title" value="${board.title}" maxlength="50">
</li>
<li>
<label for="content">내용</label>
<textarea rows="5" cols="30" name="content" id="content">${board.content}</textarea>
</li>
<li>
<label for="filename">파일</label>
<input type="file" name="filename" id="filename" accept="image/jpeg, image/png, image/gif">
<c:if test="${!empty board.filename}">
<br>
<span id="file_detail">
(${board.filename}) 파일이 등록되어 있습니다.
파일을 새로 업로드하면 기존 파일은 삭제됩니다.
<input type="button" value="파일 삭제" id="file_del">
</span>
<script type="text/javascript">
$('#file_del').click(function() {
let choice = confirm('삭제하시겠습니까?');
if(choice) {
$.ajax({
url:'deleteFile.do',
type:'post',
data:{board_num:${board.board_num}}, // JavaScript를 외부 파일(.js)로 삽입하는 경우 EL 표기법 사용 불가하므로 주의
dataType:'json',
cache:false,
timeout:30000,
success:function(param) {
if(param.result=='logout') {
alert('로그인 후 사용하세요!');
}
else if(param.result=='success') {
$('#file_detail').hide();
}
else if(param.result=='worngAccess') {
alert('잘못된 접근입니다!');
}
else {
alert('파일 삭제 오류 발생!');
}
},
error:function() {
alert('네트워크 오류 발생!');
}
}); // end of ajax
}
});
</script>
</c:if>
</li>
</ul>
<div class="align-center">
<input type="submit" value="수정">
<input type="button" value="목록" onclick="location.href = 'list.do';">
</div>
</form>
</div>
</body>
</html>