첨부파일 등록에 성공했으니 수정과 삭제를 해볼 차례이다.
register.jsp를 참조하여 modify.jsp를 작성하되, 기존의 첨부 파일을 hidden으로 숨겨주고 새롭게 등록될 첨부 파일의 input 태그를 달아준다.
modify.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>자유 게시판</title>
</head>
<body>
<h1>자유게시판 글쓰기</h1>
<img alt="" src="/_fileUpload/${bvo.boardFile }">
<form action="/brd/edit" method="post" enctype="multipart/form-data">
<!-- controller case "edit"에 보낼 bno 값 -->
<input type="hidden" name="bno" value="${bvo.bno }">
<table>
<tr>
<th>제목</th>
<td><input type="text" name="title" value="${bvo.title }"></td>
</tr>
<tr>
<th>내용</th>
<td><textarea rows="10" cols="30" name="content">${bvo.content }</textarea></td>
</tr>
<tr>
<th>첨부파일</th>
<td>
<input type="hidden" name="board_file" value="${bvo.boardFile }">
<!-- accept있어도 모든 파일을 다 올릴 수 있음 / 기능적으로 일을 하지 않음-->
<input type="file" name="new_file">
</td>
</tr>
</table>
<button type="submit">등록</button>
<a href="/brd/list"><button type="button">취소</button></a>
</form>
</body>
</html>
수정 화면
만약 기존의 첨부파일에서 새로운 첨부파일로 교체한다면, 기존의 첨부파일의 데이터는 삭제되어야 한다.
이 과정은 비동기화 작업처리를 할 것이므로 Handler package > FileRemoveHandler class를 생성했다.
FileRemoveHandler.java
package handler;
import java.io.File;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FileRemoveHandler {
private static final Logger log = LoggerFactory.getLogger(FileRemoveHandler.class);
// 파일 이름과 경로를 받아 파일을 삭제하는 메서드
// 리턴타입 int => 잘 삭제 되었다면 1, 아니면 0
public int deleteFile(String boardFileName, String savePath) {
Boolean isDel = false; // 삭제가 잘 되었는지 체크하는 변수
log.info(">>> removeFile method check >>> {}", boardFileName);
File fileDir = new File(savePath);
File removeFile = new File(fileDir+File.separator+boardFileName);
File removeThumbFile = new File(fileDir+File.separator+"th_"+boardFileName);
// 파일이 존재해야 삭제
if(removeFile.exists() || removeThumbFile.exists()) {
isDel = removeFile.delete();
log.info(">>>> fileRemove : " + (isDel ? "Ok" : "Fail"));
if(isDel) {
isDel = removeThumbFile.delete();
log.info(">>>> removeThumbFile : " + (isDel ? "Ok" : "Fail"));
}
}
log.info(">>>> remove Ok");
return isDel ? 1 : 0;
}
}
isDel이 false에서 어떻게 true가 되어서 if 문을 진행하지? 라고 생각할 수도 있다.
isDel은 removeFile.delete() method가 실행되어 파일 삭제에 성공하면 true를 return하게 되므로
이 과정에서 isDel은 true로 저장될 수 있다.
removeThumbFile.delete() method도 마찬가지 이다. (얘는 썸네일 파일을 시도함)
Handler까지 작성을 완료했으니 이제 이것을 controller의 case edit에서 활용해 주어야 한다.
case edit도 기존의 코드를 버리고 새롭게 작성해주어야 하는데 case insert와 유사하게 작성하지만,
차이점은 첨부파일의 수정 유무에 따른 코드이다.
// (구)첨부파일과 (신)첨부파일 구분을 위해 old_file 선언
String old_file = null;
case "board_file":
// 이전 그림 파일의 보관용
old_file = item.getString("utf-8");
break;
case "new_file":
// 새로운 파일은 등록이 될 수도 있고, 안될 수도 있음.
// 새로운 등록파일 있다면...
if(item.getSize() > 0) {
// old_file 삭제 작업
if(old_file != null) {
// 파일 삭제 핸들러를 통해서 파일 삭제 작업 진행
FileRemoveHandler fileHandler = new FileRemoveHandler();
isOk = fileHandler.deleteFile(old_file, savePath);
}
// 새로운 파일에 대한 객체 작업
String fileName = item.getName()
.substring(item.getName().lastIndexOf(File.separator)+1);
log.info("new File Name >>> {}",fileName);
fileName = System.currentTimeMillis()+"_"+fileName;
File uploadFilePath = new File(fileDir+File.separator+fileName);
try {
item.write(uploadFilePath);
bvo.setBoardFile(fileName);
// 썸네일 작업
Thumbnails.of(uploadFilePath).size(75, 75)
.toFile(new File(fileDir+File.separator+"th_"+fileName));
} catch (Exception e) {
log.info("File Write Update Error");
e.printStackTrace();
}
} else {
// 기존 파일은 있지만, 새로운 이미지 파일이 없다면...
bvo.setBoardFile(old_file); // 기존 객체를 bvo에 담기
}
break;
}
BoardController.java
package controller;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import domain.BoardVO;
import domain.MemberVO;
import domain.PagingVO;
import handler.FileRemoveHandler;
import handler.PagingHandler;
import net.coobird.thumbnailator.Thumbnails;
import service.BoardService;
import service.BoardServiceImpl;
@WebServlet("/brd/*")
public class BoardController extends HttpServlet {
// ... (기존 코드)
case "modify":
try {
int bno = Integer.parseInt(request.getParameter("bno"));
// detail에서 생성해둔 getDetail(bno) method를 사용해서 BoardVO 객체에 데이터를 넣어줌
BoardVO bvo = bsv.getDetail(bno);
// 데이터를 받아 온 객체 bvo를 화면에 뿌림
request.setAttribute("bvo", bvo);
destPage = "/board/modify.jsp";
} catch (Exception e) {
log.info(">>> modify error");
e.printStackTrace();
}
break;
case "edit":
try {
savePath = getServletContext().getRealPath("/_fileUpload");
File fileDir= new File(savePath);
DiskFileItemFactory fileItemFactory= new DiskFileItemFactory();
fileItemFactory.setRepository(fileDir);
fileItemFactory.setSizeThreshold(3*1024*1024);
BoardVO bvo = new BoardVO();
ServletFileUpload fileUpload = new ServletFileUpload(fileItemFactory);
List<FileItem>itemList= fileUpload.parseRequest(request);
// (구)첨부파일과 (신)첨부파일 구분을 위해
String old_file = null;
for(FileItem item : itemList) {
switch(item.getFieldName()) {
case "bno" :
bvo.setBno(Integer.parseInt(item.getString("utf-8")));
break;
case "title" :
bvo.setTitle(item.getString("utf-8"));
break;
case "writer":
bvo.setWriter(item.getString("utf-8"));
break;
case "content":
bvo.setContent(item.getString("utf-8"));
break;
case "board_file":
// 이전 그림 파일의 보관용
old_file = item.getString("utf-8");
break;
case "new_file":
// 새로운 파일은 등록이 될 수도 있고, 안될 수도 있음.
// 새로운 등록파일 있다면...
if(item.getSize() > 0) {
// old_file 삭제 작업
if(old_file != null) {
// 파일 삭제 핸들러를 통해서 파일 삭제 작업 진행
FileRemoveHandler fileHandler = new FileRemoveHandler();
isOk = fileHandler.deleteFile(old_file, savePath);
}
// 새로운 파일에 대한 객체 작업
String fileName = item.getName()
.substring(item.getName().lastIndexOf(File.separator)+1);
log.info("new File Name >>> {}",fileName);
fileName = System.currentTimeMillis()+"_"+fileName;
File uploadFilePath = new File(fileDir+File.separator+fileName);
try {
item.write(uploadFilePath);
bvo.setBoardFile(fileName);
// 썸네일 작업
Thumbnails.of(uploadFilePath).size(75, 75)
.toFile(new File(fileDir+File.separator+"th_"+fileName));
} catch (Exception e) {
log.info("File Write Update Error");
e.printStackTrace();
}
} else {
// 기존 파일은 있지만, 새로운 이미지 파일이 없다면...
bvo.setBoardFile(old_file); // 기존 객체를 bvo에 담기
}
break;
}
}
isOk = bsv.modify(bvo);
log.info(">>> eidt >>> " + (isOk > 0 ? "OK" : "FAIL"));
destPage = "list"; // 내부 list case로 이동
// modify.jsp에서 bno 값을 가져온다.
/*
int bno = Integer.parseInt(request.getParameter("bno"));
String title = request.getParameter("title");
String content = request.getParameter("content");
BoardVO bvo = new BoardVO(bno, title, content);
log.info(">>> bvo >>> {}", bvo);
log.info(">>> edit chck 1");
isOk = bsv.modify(bvo);
log.info(">>> eidt >>> "+(isOk > 0 ? "OK" : "FAIL"));
destPage = "list";
*/
} catch (Exception e) {
log.info(">>> edit error");
e.printStackTrace();
}
break;
}
// ... (기존 코드)
}
method를 별도로 추가하거나 수정할 것은 없고 mapper에서 boardFile이 업데이트 될 수 있도록 추가한다.
boardMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="BoardMapper">
<!-- ... (기존 코드) -->
<update id="edit">
update board set title = #{title}, content = #{content},
moddate = now(), boardFile = #{boardFile}
where bno = #{bno}
</update>
<!-- ... (기존 코드) -->
</mapper>
첨부파일을 수정하지 않고 수정 했을 때 화면
첨부파일을 수정했을 때 화면
물론 게시판 리스트의 썸네일 사진들도 모두 똑같이 적용되며 DB 또한 마찬가지 이다.
드디어 대망의 삭제.
삭제는 정말로 간단하다.
파일이 있는 경로를 불러와 파일 이름을 추출하고, 파일이 있다면 파일과 썸네일을 함께 삭제해달라고
코드를 작성하면 된다.
// 댓글, 파일도 같이 삭제
savePath = getServletContext().getRealPath("/_fileUpload");
String boardFileName = bsv.getFileName(bno);
int isDel = 0;
if(boardFileName != null) {
FileRemoveHandler fh = new FileRemoveHandler();
// 해당 파일과 썸네일이 같이 삭제
isDel = fh.deleteFile(boardFileName, savePath);
}
BoardController.java
package controller;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import domain.BoardVO;
import domain.MemberVO;
import domain.PagingVO;
import handler.FileRemoveHandler;
import handler.PagingHandler;
import net.coobird.thumbnailator.Thumbnails;
import service.BoardService;
import service.BoardServiceImpl;
@WebServlet("/brd/*")
public class BoardController extends HttpServlet {
// ... (기존 코드)
case "remove":
try {
// detail.jsp에서 bno 값 받아오기
int bno = Integer.parseInt(request.getParameter("bno"));
// 댓글, 파일도 같이 삭제
savePath = getServletContext().getRealPath("/_fileUpload");
String boardFileName = bsv.getFileName(bno);
int isDel = 0;
if(boardFileName != null) {
FileRemoveHandler fh = new FileRemoveHandler();
// 해당 파일과 썸네일이 같이 삭제
isDel = fh.deleteFile(boardFileName, savePath);
}
isOk = bsv.remove(bno);
log.info(">>> remove check1");
log.info(">>> remove >>> " + (isOk > 0 ? "OK" : "FAIL"));
destPage = "list";
} catch (Exception e) {
log.info(">>> remove error");
e.printStackTrace();
}
break;
case "modify":
try {
int bno = Integer.parseInt(request.getParameter("bno"));
// detail에서 생성해둔 getDetail(bno) method를 사용해서 BoardVO 객체에 데이터를 넣어줌
BoardVO bvo = bsv.getDetail(bno);
// 데이터를 받아 온 객체 bvo를 화면에 뿌림
request.setAttribute("bvo", bvo);
destPage = "/board/modify.jsp";
} catch (Exception e) {
log.info(">>> modify error");
e.printStackTrace();
}
break;
case "edit":
try {
savePath = getServletContext().getRealPath("/_fileUpload");
File fileDir= new File(savePath);
DiskFileItemFactory fileItemFactory= new DiskFileItemFactory();
fileItemFactory.setRepository(fileDir);
fileItemFactory.setSizeThreshold(3*1024*1024);
BoardVO bvo = new BoardVO();
ServletFileUpload fileUpload = new ServletFileUpload(fileItemFactory);
List<FileItem>itemList= fileUpload.parseRequest(request);
// (구)첨부파일과 (신)첨부파일 구분을 위해
String old_file = null;
for(FileItem item : itemList) {
switch(item.getFieldName()) {
case "bno" :
bvo.setBno(Integer.parseInt(item.getString("utf-8")));
break;
case "title" :
bvo.setTitle(item.getString("utf-8"));
break;
case "writer":
bvo.setWriter(item.getString("utf-8"));
break;
case "content":
bvo.setContent(item.getString("utf-8"));
break;
case "board_file":
// 이전 그림 파일의 보관용
old_file = item.getString("utf-8");
break;
case "new_file":
// 새로운 파일은 등록이 될 수도 있고, 안될 수도 있음.
// 새로운 등록파일 있다면...
if(item.getSize() > 0) {
// old_file 삭제 작업
if(old_file != null) {
// 파일 삭제 핸들러를 통해서 파일 삭제 작업 진행
FileRemoveHandler fileHandler = new FileRemoveHandler();
isOk = fileHandler.deleteFile(old_file, savePath);
}
// 새로운 파일에 대한 객체 작업
String fileName = item.getName()
.substring(item.getName().lastIndexOf(File.separator)+1);
log.info("new File Name >>> {}",fileName);
fileName = System.currentTimeMillis()+"_"+fileName;
File uploadFilePath = new File(fileDir+File.separator+fileName);
try {
item.write(uploadFilePath);
bvo.setBoardFile(fileName);
// 썸네일 작업
Thumbnails.of(uploadFilePath).size(75, 75)
.toFile(new File(fileDir+File.separator+"th_"+fileName));
} catch (Exception e) {
log.info("File Write Update Error");
e.printStackTrace();
}
} else {
// 기존 파일은 있지만, 새로운 이미지 파일이 없다면...
bvo.setBoardFile(old_file); // 기존 객체를 bvo에 담기
}
break;
}
}
isOk = bsv.modify(bvo);
log.info(">>> eidt >>> " + (isOk > 0 ? "OK" : "FAIL"));
destPage = "list"; // 내부 list case로 이동
// modify.jsp에서 bno 값을 가져온다.
/*
int bno = Integer.parseInt(request.getParameter("bno"));
String title = request.getParameter("title");
String content = request.getParameter("content");
BoardVO bvo = new BoardVO(bno, title, content);
log.info(">>> bvo >>> {}", bvo);
log.info(">>> edit chck 1");
isOk = bsv.modify(bvo);
log.info(">>> eidt >>> "+(isOk > 0 ? "OK" : "FAIL"));
destPage = "list";
*/
} catch (Exception e) {
log.info(">>> edit error");
e.printStackTrace();
}
break;
}
// ... (기존 코드)
}
파일이름을 가져오는 getFileName(bno) method가 필요하기 때문에
service에서 mapper까지 순차적으로 코드를 작성한다.
BoardService.interface
package service;
import java.util.List;
import domain.BoardVO;
import domain.PagingVO;
public interface BoardService {
List<BoardVO> getList(PagingVO pgvo);
int getTotal(PagingVO pgvo);
int insert(BoardVO bvo);
BoardVO getDetail(int bno);
int remove(int bno);
int modify(BoardVO bvo);
String getFileName(int bno);
}
BoardServiceImpl.java
package service;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import domain.BoardVO;
import domain.PagingVO;
import repository.BoardDAO;
import repository.BoardDAOImpl;
public class BoardServiceImpl implements BoardService {
// ... (기존 코드)
@Override
public String getFileName(int bno) {
log.info(">>>> getFileName check 2");
return bdao.getFileName(bno);
}
}
BoardDAO.interface
package repository;
import java.util.List;
import domain.BoardVO;
import domain.PagingVO;
public interface BoardDAO {
List<BoardVO> selectList(PagingVO pgvo);
int getTotal(PagingVO pgvo);
int insert(BoardVO bvo);
BoardVO getDetail(int bno);
int delete(int bno);
int update(BoardVO bvo);
int readcountUp(int bno);
String getFileName(int bno);
}
BoardDAOImpl.java
package repository;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import domain.BoardVO;
import domain.PagingVO;
import orm.DatabaseBuilder;
public class BoardDAOImpl implements BoardDAO {
// ... (기존 코드)
@Override
public String getFileName(int bno) {
log.info(">>>> getFileName check 3");
return sql.selectOne("BoardMapper.fileName", bno);
}
}
boardMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="BoardMapper">
<!-- ...(기존 구문) -->
<update id="edit">
update board set title = #{title}, content = #{content},
moddate = now(), boardFile = #{boardFile}
where bno = #{bno}
</update>
<update id="readcount">
update board set readcount = readcount + 1
where bno = #{bno}
</update>
<select id="fileName" resultType="String">
select boardFile from board where bno = #{bno}
</select>
<!-- ...(기존 구문) -->
</mapper>
게시물 삭제 전
게시물 삭제 후
[JSP/Servlet] 14. 게시글 파일첨부 - 수정과 삭제
(다음 게시물 예고편)
[JSP/Servlet] 15. 댓글
얼렁뚱땅 주니어 개발자
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!