실습 코드 참조
moonhy7/SpringFramework: Spring Framework 실습 코드 정리 (github.com)
1. 파일 업로드 ( _82_BoardWeb_Spring_MVC_FileUpload )
1. 테이블 생성
CREATE TABLE BOARD_FILE (
SEQ INTEGER,
F_SEQ INTEGER,
ORIGINAL_FILE_NAME VARCHAR(255),
FILE_PATH VARCHAR(500),
FILE_SIZE INTEGER,
CONSTRAINT BOARD_FILE_PK PRIMARY KEY(SEQ, F_SEQ)
);
2. sql-map-config
- settings 태그 추가
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
</configuration>
3. BoardFileVO 클래스 생성
package com.springbook.biz.board;
public class BoardFileVO {
private int seq;
private int fseq;
private String originalFileName;
private String filePath;
private long fileSize;
public int getSeq() {
return seq;
}
public void setSeq(int seq) {
this.seq = seq;
}
public int getFseq() {
return fseq;
}
public void setFseq(int fseq) {
this.fseq = fseq;
}
public String getOriginalFileName() {
return originalFileName;
}
public void setOriginalFileName(String originalFileName) {
this.originalFileName = originalFileName;
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public long getFileSize() {
return fileSize;
}
public void setFileSize(long fileSize) {
this.fileSize = fileSize;
}
@Override
public String toString() {
return "BoardFileVO [seq=" + seq + ", fseq=" + fseq + ", originalFileName=" + originalFileName + ", filePath="
+ filePath + ", fileSize=" + fileSize + "]";
}
}
4. presentation-layer
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 업로드 파일 최대 크기 설정, 기본 값: -1 -> 크기 제한없음 -->
<property name="maxUploadSize" value="-1"></property>
</bean>
5. getBoard.jsp
- multiple 속성 추가, uploadFile -> uploadFiles로 변경
<tr>
<td bgcolor="orange" width="70">업로드</td>
<td align="left">
<input type="file" name="uploadFile" multiple="multiple">
</td>
</tr>
6. FileUtils 생성
- 먼저 common 패키지 JDBCUtil 빼고 다 삭제
- 그 다음 common 패키지에 FileUtils 클래스 생성 (여러개의 파일을 담아서 리스트로 던져줄 객체 생성)
package com.springbook.biz.common;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import com.springbook.biz.board.BoardFileVO;
public class FileUtils {
public List<BoardFileVO> parseFileInfo(int seq, HttpServletRequest request,
MultipartHttpServletRequest mhsr) throws IOException {
if(ObjectUtils.isEmpty(mhsr)) {
return null;
}
List<BoardFileVO> fileList = new ArrayList<BoardFileVO>();
//서버의 절대 경로 얻기
String root_path = request.getSession().getServletContext().getRealPath("/");
String attach_path = "/upload/";
//위 경로의 폴더가 없으면 폴더 생성
File file = new File(root_path + attach_path);
if(file.exists() == false) {
file.mkdir();
}
//파일 이름들을 iterator로 담음
Iterator<String> iterator = mhsr.getFileNames();
while(iterator.hasNext()) {
//파일명으로 파일 리스트 꺼내오기
List<MultipartFile> list = mhsr.getFiles(iterator.next());
//파일 리스트 개수 만큼 리턴할 파일 리스트에 담아주고 생성
for(MultipartFile mf : list) {
BoardFileVO boardFile = new BoardFileVO();
boardFile.setSeq(seq);
boardFile.setFileSize(mf.getSize());
boardFile.setOriginalFileName(mf.getOriginalFilename());
boardFile.setFilePath(root_path + attach_path);
fileList.add(boardFile);
file = new File(root_path + attach_path + mf.getOriginalFilename());
mf.transferTo(file);
}
}
return fileList;
}
}
7. BoardController 수정
@RequestMapping("/insertBoard.do")
//Command 객체 : 사용자가 전송한 데이터를 매핑한 VO를 바로 생성
// 사용자 입력 값이 많아지면 코드가 길어지기 때문에 간략화 가능
// 사용자 입력 input의 name 속성과 VO 멤버변수의 이름을 매핑해주는 것이 중요
public String insertBoard(BoardVO vo, HttpServletRequest request,
MultipartHttpServletRequest mhsr) throws IOException {
System.out.println("글 등록 처리");
//파일 업로드 처리
MultipartFile uploadFile = vo.getUploadFile();
if(!uploadFile.isEmpty()) {
String fileName = uploadFile.getOriginalFilename();
uploadFile.transferTo(new File("C:/Dev211/" + fileName));
}
int seq = BoardService.getBoardSeq();
FileUtils fileUtils = new FileUtils();
List<BoardFileVO> fileList = fileUtils.parseFileInfo(seq, request, mhsr);
boardService.insertBoard(vo);
//화면 네비게이션(게시글 등록 완료 후 게시글 목록으로 이동)
return "redirect:getBoardList.do";
}
8. BoardService 수정
//글 목록 조회
List<BoardVO> getBoardList(BoardVO vo, Criteria cri);
int selectBoardCount(BoardVO vo);
//글 등록 전 등록 될 일련번호 획득
int getBoardSeq();
//디비에 파일 리스트 등록
void insertBoardFileList(List<BoardFileVO> fileList);
9. 실행 결과
- 새글 등록
- 파일 선택
- 글 목록에 추가
- 첨부파일 목록에 추가
2. 파일 수정 및 삭제
1. BoardController
@RequestMapping(value="/getBoard.do")
public String getBoard(BoardVO vo, Model model, Criteria cri) {
System.out.println("글 상세 조회 처리");
System.out.println(cri.getPageNum());
System.out.println(cri.getAmount());
//Model 객체는 RequestServlet 데이터 보관소에 저장
//RequestServlet 데이터 보관소에 저장하는 것과 동일하게 동작
//request.setAttribute("board", boardDAO.getBoard(vo)) == model.addAttribute("board", boardDAO.getBoard(vo))
model.addAttribute("board", boardService.getBoard(vo));
model.addAttribute("criteria", cri);
model.addAttribute("fileList", boardService.getBoardFileList(vo.getSeq()));
return "getBoard.jsp";
}
2. BoardService
//디비에 파일 리스트 등록
void insertBoardFileList(List<BoardFileVO> fileList);
//파일목록 리턴
List<BoardFileVO> getBoardFileList(int seq);
3. BoardServiceImpl
public List<BoardFileVO> getBoardFileList(int seq) {
return boardDAO.getBoardFileList(seq);
}
4. board-mapping
<select id="getBoardFileList" parameterType="int" resultType="boardFile">
SELECT * FROM BOARD_FILE
WHERE SEQ = #{seq}
</select>
5. BoardDAOMybatis
public void insertBoardFileList(List<BoardFileVO> fileList) {
for(BoardFileVO boardFile : fileList) {
mybatis.insert("BoardDAO.insertBoardFileList", boardFile);
}
}
public List<BoardFileVO> getBoardFileList(int seq) {
return mybatis.selectList("BoardDAO.getBoardFileList", seq);
}
public void deleteFile(BoardFileVO vo) {
mybatis.delete("BoardDAO.deleteFile", vo);
}
public void updateFile(BoardFileVO vo) {
mybatis.update("BoardDAO.updateFile", vo);
}
public void deleteFileList(int seq) {
mybatis.delete("BoardDAO.deleteFileList", seq);
}
6. 실행 화면
3. 파일 미업로드 시 발생하는 에러 해결법
1. FileUtils 코드 수정
while(iterator.hasNext()) {
//파일명으로 파일 리스트 꺼내오기
List<MultipartFile> list = mhsr.getFiles(iterator.next());
//파일 리스트 개수 만큼 리턴할 파일 리스트에 담아주고 생성
for(MultipartFile mf : list) {
if(mf.getSize() > 0) {
BoardFileVO boardFile = new BoardFileVO();
boardFile.setSeq(seq);
boardFile.setFileSize(mf.getSize());
boardFile.setOriginalFileName(mf.getOriginalFilename());
boardFile.setFilePath(root_path + attach_path);
fileList.add(boardFile);
file = new File(root_path + attach_path + mf.getOriginalFilename());
mf.transferTo(file);
} else {
fileList = null;
}
}
}
4. 파일 다운로드
1. getBoardList.jsp
<tr>
<td bgcolor="orange">첨부파일 목록</td>
<td>
<c:forEach var="file" items="${fileList }">
<a class="downlink" id="${file.fSeq }" href="${file.originalFileName }">${file.originalFileName }</a>
<button type="button" onclick="deleteFile('${file.fSeq }');">삭제</button>
<br>
</c:forEach>
</td>
</tr>
2. getBoardList.jsp 스크립트에 function 추가
<script>
$(document).ready(function)() {
$(".downlink").click(function(e){
e.preventDefault();
var fileName = $(this).attr("href");
window.location = "fileDown.do?fileName=" + fileName;
});
});
</script>
3. BoardController
@RequestMapping(value="fileDown.do")
@ResponseBody
public ResponseEntity<Resource> fileDown(@RequestParam("fileName") String fileName,
HttpServletRequest request) throws Exception {
//업로드 파일 경로
String path = request.getSession().getServletContext().getRealPath("/") + "/upload/";
//파일경로, 파일명으로 리소스 객체 생성
Resource resource = new FileSystemResource(path + fileName);
//파일 명
String resourceName = resource.getFilename();
//Http헤더에 옵션을 추가하기 위해서 헤더 변수 선언
HttpHeaders headers = new HttpHeaders();
try {
//헤더에 파일명으로 첨부파일 추가
headers.add("Content-Disposition", "attachment; filename=" + new String(resourceName.getBytes("UTF-8"),
"ISO-8859-1"));
} catch(UnsupportedEncodingException e) {
e.printStackTrace();
}
return new ResponseEntity<Resource>(resource, headers, HttpStatus.OK);
}
4. 실행 화면
5. 다운로드된 파일 경로
5. 게시글 삭제시 해당 게시글 첨부파일 남아있는 현상 해결
1. boardService
//게시글 삭제시 해당 게시글의 첨부파일 삭제
void deleteFileList(int seq);
2. boardServiceImpl
public void deleteFileList(int seq) {
boardDAO.deleteFileList(seq);
}
3. BoardDAOMybatis
public void deleteFileList(int seq) {
mybatis.delete("BoardDAO.deleteFileList", seq);
}
4. board-mapping
<delete id="deleteFileList" parameterType="int">
DELETE FROM BOARD_FILE
WHERE SEQ = #{seq}
</delete>
5. boardController
@RequestMapping(value="/deleteBoard.do")
public String deleteBoard(BoardVO vo) {
System.out.println("글 삭제 처리");
boardService.deleteFileList(vo.getSeq());
boardService.deleteBoard(vo);
return "redirect:getBoardList.do";
}
6. 실행 결과
- 첨부파일 목록에 파일들이 있는 상태로 글 삭제를 누른다.
- 그 후 다시 글 등록을 하면 해당 seq로 글 등록이 되므로 파일 목록이 그대로 남아있게 된다.
- 위 코드를 추가하면 이제 글을 삭제했다가 다시 등록을 해도 첨부파일이 남아있지 않게 된다.
'👨💻 2. 웹개발_Back end > 2-6 Spring' 카테고리의 다른 글
[Spring] 8장 스프링 게시판 만들기 - 페이징(Paging) 처리하기 (2) | 2021.11.04 |
---|---|
[Spring] 7장 스프링과 Ajax 연동 - Ajax를 이용한 게시판 검색 기능 구현 / 날짜 형식 설정 및 한글 인코딩 (0) | 2021.11.03 |
[Spring] 6장 스프링과 JPA 연동 - 엔티티 매핑 설정 및 스프링과 JPA 연동 설정 (0) | 2021.11.02 |
[Spring] 5장 JPA 환경설정 - 영속성 유닛 설정과 엔티티 클래스 기본 매핑 및 JPA API (0) | 2021.11.02 |
[Spring] 4장 JPA 개념 - JPA 특징과 프로젝트 생성 및 라이브러리 내려받기 (0) | 2021.11.02 |
댓글