- Save - jsp
<form action="/board/save" method="post" enctype="multipart/form-data">
<table>
<tr>
<th colspan="6"><label for="boardContents">내용</label>
<label for="boardFile" style="float: right">업로드</label>
<input type="file" id="boardFile" name="boardFile" multiple style="display: none"></th>
</tr>
<tr>
<td colspan="6"><textarea id="boardContents" name="boardContents" COLS="104" ROWS="40"></textarea>
</td>
</tr>
<tr>
<th colspan="6">
<input type="submit" style="display: inline" value="등록">
<input type="button" style="display: inline" value="취소" onclick="goindex()">
</th>
</tr>
</table>
</form>
파일 업로드 시에는 form태그의 enctype 이 "multipart/form-data"로 설정되어야 한다
method는 post이어야 한다
input 태그의 type 속성 값을 file로 지정해야 한다
- BoardDTO
@Data
@NoArgsConstructor
public class BoardDTO {
Long id;
String boardWriter;
String boardPass;
String boardTitle;
String boardContents;
Timestamp boardCreateDate;
int boardHits = 0;
int fileAttached = 0;
List<MultipartFile> boardFile;
}
DTO에서는 MultipartFile 타입의 boardfile 필드를 만들어줍니다
MultipartFile는 스프링에서 제공하는 인터페이스이고 이를 타입으로 사용함으로
사용자가 올린 이미지 파일이 DTO에 담겨 서버로 넘어갈 수 있게 됩니다
- Save - Controller
@PostMapping("/save") // /board/save
public String BoardSave(@ModelAttribute BoardDTO boardDTO) throws IOException {
System.out.println("boardDTO = " + boardDTO);
boardService.BoardSave(boardDTO);
return "redirect:/board/";
}
throws IOException
구문 그대로 해석을 해 보면 입출력 예외를 던진다 라는 의미입니다
throws키워드는 실행시간에 예외 에러가 발생했을 경우 해당 예외를 직접처리하지 않고
다른곳에서 처리하도록 예외를 던지겠다라는 의미입니다
원래는 이렇게 처리하면 안되지만 수업진행을 위해 이렇게 처리하셨습니다
- Save - Service
public void BoardSave(BoardDTO boardDTO) throws IOException {
if (boardDTO.getBoardFile().get(0).isEmpty()) { // isEmpty = 파일이 비었다
boardDTO의board file의 0번째 칸이 비었다면
System.out.println("파일없음");
boardDTO.setFileAttached(0);
boardRepository.BoardSave(boardDTO);
FileAttached를 0으로 만들어주고 전과 같이 SAVE를 합니다
} else {
boardDTO의 board file의 0번째 칸이 비어있지 않다면
boardDTO.setFileAttached(1);
FileAttached를 1로 만들어주고
BoardDTO dto = boardRepository.BoardSave(boardDTO);
전과 마찬가지로 save를 진행합니다 대신 저장정보를 리턴받아
dto를 만들어줍니다
for (MultipartFile boardFile : boardDTO.getBoardFile()) {
forEach문을 사용하여 boardDTO에 담긴 파일의 정보를 가져옵니다
String originalFilename = boardFile.getOriginalFilename();
원본 파일의 이름을 따로 받아줍니다
String storedFileName = System.currentTimeMillis() + "-" + originalFilename;
파일의 아부분에 currentTimeMillis를 추가하여 storedFileName을 만들어줍니다
BoardFileDTO boardFileDTO = new BoardFileDTO();
boardFileDTO.setOriginalFileName(originalFilename);
boardFileDTO.setStoredFileName(storedFileName);
boardFileDTO.setBoardId(dto.getId());
이렇게 만들어준 정보들을 BoardFileDTO에 저장해줍니다
어떤 사용자의 파일들인지도 알아야하기 때문에 ID값도 함께 저장합니다
저희가 만든 board는 저장을 하지않으면 id값이 생기지 않기 때문에
위에서 따로 객체를 리턴받았습니다
String savePath = "D:\\springframework_img\\" + storedFileName;
저장할 경로 설정(저장할폴더 + 저장할이름)
boardFile.transferTo(new File(savePath)); // new File()은 자바에서 제공하는 클래스
transferTO를 사용하여 파일을 저장하고 뒤의 new File(savePath)은 경로를 나타냅니다
boardRepository.saveFile(boardFileDTO);
이후 Repository의 saveFile 메소드에 boardFileDTO를 넘겨줍니다
}
}
}
- Save - Repository
public BoardDTO BoardSave(BoardDTO boardDTO) {
sql.insert("Board.Save",boardDTO);
return boardDTO;
}
public void saveFile(BoardFileDTO boardFileDTO) {
sql.insert("Board.saveFile",boardFileDTO);
}
- Save - Mapper
<insert id="Save" parameterType="board" useGeneratedKeys="true" keyProperty="id">
insert into board_table(boardWriter,boardPass,boardTitle,boardContents,fileAttached)
value(#{boardWriter},#{boardPass},#{boardTitle},#{boardContents},#{fileAttached})
</insert>
<insert id="saveFile" parameterType="boardFile">
insert into board_file_table(originalFileName,storedFileName,boardId)
values (#{originalFileName},#{storedFileName},#{boardId})
</insert>
- 참고한 블로그
Multipart란?
1. Multipart란? 웹 클라이언트가 요청을 보낼 때, http 프로토콜의 바디 부분에 데이터를 여러 부분으로 나눠서 보내는 것. 웹 클라이언트가 서버에게 파일을 업로드할 때, http 프로토콜의 바디 부분
codingnotes.tistory.com
- 상세 페이지 - 이미지 출력

- Controller
@GetMapping
public String boardDetail(@RequestParam("id") Long id , Model model){
boardService.updateHits(id);
BoardDTO boardDTO = boardService.boardDetail(id);
id값을 통해 찾아온 객체의 FileAttached가 1이라면
if(boardDTO.getFileAttached() == 1){
파일이 있다는 말이기 때문에
List<BoardFileDTO> boardFileList = boardService.findFile(id);
id값을 통하여 db에서 파일list를 받아온다
model.addAttribute("boardFileList",boardFileList);
이후 모델에 담아 준다
}
model.addAttribute("boardDTO",boardDTO);
당연히 기본정보도 모델에 담아준다
return "boardPages/boardDetail";
}
- Detail .jsp
<c:if test="${boardDTO.fileAttached == 1}">
<tr>
<th colspan="6">image</th>
</tr>
<tr>
<td colspan="6">
<c:forEach items="${boardFileList}" var="boardFile">
<img src="${pageContext.request.contextPath}/upload/${boardFile.storedFileName}" alt=""
절대경로 : 해당웹의 upload저장소(save의 Service에서 설정함)에서
해당이름의 파일을 찾아라는 뜻
style="width: 100px" ; height="100px">
</c:forEach>
</td>
</tr>
</c:if>
롬북의 c태그를 사용하여 if문을 통해 fileAttached가 1이라면
해당 table이 보이도록 설정했다 파일의 정보는 list로 받았기 때문에 forEach문을 돌려 뽑아냈다

servlet-context.xml에서 저장소 위치를 작성해 주어야 이미지를 가 깨지지 않고 정확하게 불러와진다
'나의 수업일지' 카테고리의 다른 글
인천 일보 아카데미 53일차 -비로그인 게시판- List 페이징 기능 (0) | 2023.05.09 |
---|---|
인천 일보 아카데미 53일차 - 비로그인 게시판 - 댓글 기능 (0) | 2023.05.08 |
인천 일보 아카데미 51일차 -1- 비로그인 게시판 만들어보기 (0) | 2023.05.07 |
인천 일보 아카데미 50일차 -2- Email - 중복체크 (개인저장 내용X) (0) | 2023.05.02 |
인천 일보 아카데미 50일차 -1- ajax - json 주고 받기 / ajax - 리턴값 body에 표로 넣기 (@RequestBody) / ajax - ResponseEntity 알아보기 (0) | 2023.05.02 |
- Save - jsp
<form action="/board/save" method="post" enctype="multipart/form-data">
<table>
<tr>
<th colspan="6"><label for="boardContents">내용</label>
<label for="boardFile" style="float: right">업로드</label>
<input type="file" id="boardFile" name="boardFile" multiple style="display: none"></th>
</tr>
<tr>
<td colspan="6"><textarea id="boardContents" name="boardContents" COLS="104" ROWS="40"></textarea>
</td>
</tr>
<tr>
<th colspan="6">
<input type="submit" style="display: inline" value="등록">
<input type="button" style="display: inline" value="취소" onclick="goindex()">
</th>
</tr>
</table>
</form>
파일 업로드 시에는 form태그의 enctype 이 "multipart/form-data"로 설정되어야 한다
method는 post이어야 한다
input 태그의 type 속성 값을 file로 지정해야 한다
- BoardDTO
@Data
@NoArgsConstructor
public class BoardDTO {
Long id;
String boardWriter;
String boardPass;
String boardTitle;
String boardContents;
Timestamp boardCreateDate;
int boardHits = 0;
int fileAttached = 0;
List<MultipartFile> boardFile;
}
DTO에서는 MultipartFile 타입의 boardfile 필드를 만들어줍니다
MultipartFile는 스프링에서 제공하는 인터페이스이고 이를 타입으로 사용함으로
사용자가 올린 이미지 파일이 DTO에 담겨 서버로 넘어갈 수 있게 됩니다
- Save - Controller
@PostMapping("/save") // /board/save
public String BoardSave(@ModelAttribute BoardDTO boardDTO) throws IOException {
System.out.println("boardDTO = " + boardDTO);
boardService.BoardSave(boardDTO);
return "redirect:/board/";
}
throws IOException
구문 그대로 해석을 해 보면 입출력 예외를 던진다 라는 의미입니다
throws키워드는 실행시간에 예외 에러가 발생했을 경우 해당 예외를 직접처리하지 않고
다른곳에서 처리하도록 예외를 던지겠다라는 의미입니다
원래는 이렇게 처리하면 안되지만 수업진행을 위해 이렇게 처리하셨습니다
- Save - Service
public void BoardSave(BoardDTO boardDTO) throws IOException {
if (boardDTO.getBoardFile().get(0).isEmpty()) { // isEmpty = 파일이 비었다
boardDTO의board file의 0번째 칸이 비었다면
System.out.println("파일없음");
boardDTO.setFileAttached(0);
boardRepository.BoardSave(boardDTO);
FileAttached를 0으로 만들어주고 전과 같이 SAVE를 합니다
} else {
boardDTO의 board file의 0번째 칸이 비어있지 않다면
boardDTO.setFileAttached(1);
FileAttached를 1로 만들어주고
BoardDTO dto = boardRepository.BoardSave(boardDTO);
전과 마찬가지로 save를 진행합니다 대신 저장정보를 리턴받아
dto를 만들어줍니다
for (MultipartFile boardFile : boardDTO.getBoardFile()) {
forEach문을 사용하여 boardDTO에 담긴 파일의 정보를 가져옵니다
String originalFilename = boardFile.getOriginalFilename();
원본 파일의 이름을 따로 받아줍니다
String storedFileName = System.currentTimeMillis() + "-" + originalFilename;
파일의 아부분에 currentTimeMillis를 추가하여 storedFileName을 만들어줍니다
BoardFileDTO boardFileDTO = new BoardFileDTO();
boardFileDTO.setOriginalFileName(originalFilename);
boardFileDTO.setStoredFileName(storedFileName);
boardFileDTO.setBoardId(dto.getId());
이렇게 만들어준 정보들을 BoardFileDTO에 저장해줍니다
어떤 사용자의 파일들인지도 알아야하기 때문에 ID값도 함께 저장합니다
저희가 만든 board는 저장을 하지않으면 id값이 생기지 않기 때문에
위에서 따로 객체를 리턴받았습니다
String savePath = "D:\\springframework_img\\" + storedFileName;
저장할 경로 설정(저장할폴더 + 저장할이름)
boardFile.transferTo(new File(savePath)); // new File()은 자바에서 제공하는 클래스
transferTO를 사용하여 파일을 저장하고 뒤의 new File(savePath)은 경로를 나타냅니다
boardRepository.saveFile(boardFileDTO);
이후 Repository의 saveFile 메소드에 boardFileDTO를 넘겨줍니다
}
}
}
- Save - Repository
public BoardDTO BoardSave(BoardDTO boardDTO) {
sql.insert("Board.Save",boardDTO);
return boardDTO;
}
public void saveFile(BoardFileDTO boardFileDTO) {
sql.insert("Board.saveFile",boardFileDTO);
}
- Save - Mapper
<insert id="Save" parameterType="board" useGeneratedKeys="true" keyProperty="id">
insert into board_table(boardWriter,boardPass,boardTitle,boardContents,fileAttached)
value(#{boardWriter},#{boardPass},#{boardTitle},#{boardContents},#{fileAttached})
</insert>
<insert id="saveFile" parameterType="boardFile">
insert into board_file_table(originalFileName,storedFileName,boardId)
values (#{originalFileName},#{storedFileName},#{boardId})
</insert>
- 참고한 블로그
Multipart란?
1. Multipart란? 웹 클라이언트가 요청을 보낼 때, http 프로토콜의 바디 부분에 데이터를 여러 부분으로 나눠서 보내는 것. 웹 클라이언트가 서버에게 파일을 업로드할 때, http 프로토콜의 바디 부분
codingnotes.tistory.com
- 상세 페이지 - 이미지 출력

- Controller
@GetMapping
public String boardDetail(@RequestParam("id") Long id , Model model){
boardService.updateHits(id);
BoardDTO boardDTO = boardService.boardDetail(id);
id값을 통해 찾아온 객체의 FileAttached가 1이라면
if(boardDTO.getFileAttached() == 1){
파일이 있다는 말이기 때문에
List<BoardFileDTO> boardFileList = boardService.findFile(id);
id값을 통하여 db에서 파일list를 받아온다
model.addAttribute("boardFileList",boardFileList);
이후 모델에 담아 준다
}
model.addAttribute("boardDTO",boardDTO);
당연히 기본정보도 모델에 담아준다
return "boardPages/boardDetail";
}
- Detail .jsp
<c:if test="${boardDTO.fileAttached == 1}">
<tr>
<th colspan="6">image</th>
</tr>
<tr>
<td colspan="6">
<c:forEach items="${boardFileList}" var="boardFile">
<img src="${pageContext.request.contextPath}/upload/${boardFile.storedFileName}" alt=""
절대경로 : 해당웹의 upload저장소(save의 Service에서 설정함)에서
해당이름의 파일을 찾아라는 뜻
style="width: 100px" ; height="100px">
</c:forEach>
</td>
</tr>
</c:if>
롬북의 c태그를 사용하여 if문을 통해 fileAttached가 1이라면
해당 table이 보이도록 설정했다 파일의 정보는 list로 받았기 때문에 forEach문을 돌려 뽑아냈다

servlet-context.xml에서 저장소 위치를 작성해 주어야 이미지를 가 깨지지 않고 정확하게 불러와진다
'나의 수업일지' 카테고리의 다른 글
인천 일보 아카데미 53일차 -비로그인 게시판- List 페이징 기능 (0) | 2023.05.09 |
---|---|
인천 일보 아카데미 53일차 - 비로그인 게시판 - 댓글 기능 (0) | 2023.05.08 |
인천 일보 아카데미 51일차 -1- 비로그인 게시판 만들어보기 (0) | 2023.05.07 |
인천 일보 아카데미 50일차 -2- Email - 중복체크 (개인저장 내용X) (0) | 2023.05.02 |
인천 일보 아카데미 50일차 -1- ajax - json 주고 받기 / ajax - 리턴값 body에 표로 넣기 (@RequestBody) / ajax - ResponseEntity 알아보기 (0) | 2023.05.02 |