파일 업로드하고 파일의 정보 확인

 

1. 뷰 변경하기

board\src\main\resources\templates\board\boardWrite.htm

 

		<form id="frm" name="frm" method="post" action="/board/insertBoard.do" enctype=multipart/form-data>
        .
        .
        .
        			<input type="file" id="files" name="files" multiple="multiple">

 

1: 폼을 이용해서 데이터를 전송할 때 파일도 같이 첨부될 수 있도록 폼의 enctype 속성을 multipart/form-data 로 지정한다.

   또한 폼의 전송 방식은 반드시 post로 지정해야 한다. (파일이 첨부되어 전송되도록 폼의 전송 방식을 post로 지정한다)

5: multiple 속성을 추가하면 하나의 태그에 여러 개의 파일을 첨부할 수 있다. (HTML5 이상에서)

 

 

2. 컨트롤러 변경하기

board\src\main\java\board\board\controller\BoardController.java

	@RequestMapping("/board/insertBoard.do")
	public String insertBoard(BoardDto board, MultipartHttpServletRequest multipartHttpServletRequest) throws Exception{
		boardService.insertBoard_433(board, multipartHttpServletRequest);
		return "redirect:/board/openBoardList.do";
	}

2: MultipartHttpServletRequest 를 파라미터로 추가, MultipartHttpServletRequest 는 ServletRequest를 상속받아 구현된 인터페이스로, 업로드된 파일을 처리하기 위한 여러 가지 메서드를 제공한다.

 

 

3-1. 서비스 변경하기

board\src\main\java\board\board\service\BoardService.java

	void insertBoard_433(BoardDto board, MultipartHttpServletRequest multipartHttpServletRequest) throws Exception;

 

3-2. Impl 변경하기

board\src\main\java\board\board\service\BoardServiceImpl.java

	@Override
	public void insertBoard_433(BoardDto board, MultipartHttpServletRequest multipartHttpServletRequest) throws Exception {
	//	boardMapper.insertBoard_434(board);
		if(ObjectUtils.isEmpty(multipartHttpServletRequest) == false) {
			Iterator<String> iterator = multipartHttpServletRequest.getFileNames();	
			String name;
			Logger log = LoggerFactory.getLogger(this.getClass());
			while(iterator.hasNext()) {
				name = iterator.next();
				log.debug("file fag name : "+name);
				List<MultipartFile> list = multipartHttpServletRequest.getFiles(name);
				for(MultipartFile multipartFile : list) {
					log.debug("start file information");
					log.debug("file name : "+multipartFile.getOriginalFilename());
					log.debug("file size : "+multipartFile.getSize());
					log.debug("file content type : "+multipartFile.getContentType());
					log.debug("end file information");
				}
			}
		}
	}

 

5: 이터레이터를이용해 파일 태그의 이름을 가져옴. HTML에 있는 name

7: log 출력을 위해 추가함.

 

 

 

 

4. 결과 확인

 

 


파일 서버에 저장하기

 

 

1. 첨부파일 DTO 생성

board\src\main\java\board\board\dto\BoardFileDto.java  생성

package board.board.dto;

import lombok.Data;

@Data
public class BoardFileDto {
	private int idx;
	private int boardIdx;
	private String originalFileName;
	private String storedFilePath;
	private long fileSize;
}

 

 

2. 파일 처리를 위한 클래스 생성

board\src\main\java\board\common\FileUtils.java 생성

package board.common;

import java.io.File;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import board.board.dto.BoardFileDto;

@Component
public class FileUtils {
	
	public List<BoardFileDto> parseFileInfo(int boardIdx, MultipartHttpServletRequest multipartHttpServletRequest) throws Exception{
		if(ObjectUtils.isEmpty(multipartHttpServletRequest)){
			return null;
		}
		
		List<BoardFileDto> fileList = new ArrayList<>();
		
		DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyyMMdd"); 
    	ZonedDateTime current = ZonedDateTime.now();
    	String path = "images/"+current.format(format);
    	File file = new File(path);
		if(file.exists() == false){
			file.mkdirs();
		}
		
		Iterator<String> iterator = multipartHttpServletRequest.getFileNames();
		
		String newFileName, originalFileExtension, contentType;
		
		while(iterator.hasNext()){
			List<MultipartFile> list = multipartHttpServletRequest.getFiles(iterator.next());
			for (MultipartFile multipartFile : list){
				if(multipartFile.isEmpty() == false){
					contentType = multipartFile.getContentType();
					if(ObjectUtils.isEmpty(contentType)){
						break;
					}
					else{
						if(contentType.contains("image/jpeg")) {
							originalFileExtension = ".jpg";
						}
						else if(contentType.contains("image/png")) {
							originalFileExtension = ".png";
						}
						else if(contentType.contains("image/gif")) {
							originalFileExtension = ".gif";
						}
						else{
							break;
						}
					}
					
					newFileName = Long.toString(System.nanoTime()) + originalFileExtension;
					BoardFileDto boardFile = new BoardFileDto();
					boardFile.setBoardIdx(boardIdx);
					boardFile.setFileSize(multipartFile.getSize());
					boardFile.setOriginalFileName(multipartFile.getOriginalFilename());
					boardFile.setStoredFilePath(path + "/" + newFileName);
					fileList.add(boardFile);
					
					file = new File(path + "/" + newFileName);
					multipartFile.transferTo(file);
				}
			}
		}
		return fileList;
	}
}

17: 어노테이션을 이용해 FileUtils 클래스를 스프링의 빈으로 등록

28~33: 파일이 업로드될 폴더를 생성한다. ZoneDateTime 은 오늘 날짜를 확인하기 위해 사용(JDK1.8이상)

43~60: 파일 형식을 확인하고 그에 따라 이미지의 확장자를 지정

62: 서버에 저장될 파일 이름을 생성

63~68: 데이터베이스에 저장할 파일 정보를 BoardFileDto에 저장한다.

70~71: 업로드된 파일을 새로운 이름으로 바꾸어 지정된 경로에 저장한다.

 

 

 

3. 서비스 및 매퍼 변경하기

board\src\main\java\board\board\service\BoardServiceImpl.java

	@Autowired
	private FileUtils fileUtils;
    .
    .
    .
    @Override
	public void insertBoard_433(BoardDto board, MultipartHttpServletRequest multipartHttpServletRequest) throws Exception {
		boardMapper.insertBoard_434(board);
		List<BoardFileDto> list = fileUtils.parseFileInfo(board.getBoardIdx(), multipartHttpServletRequest);
		if(CollectionUtils.isEmpty(list) == false){
			boardMapper.insertBoardFileList(list);
		}
	}

9: FileUtils 클래스를 이용해서 업로드된 파일을 서버에 저장하고 파일의 정보를 가져온다.

 

 

board\src\main\java\board\board\mapper\BoardMapper.java 추가

	void insertBoardFileList(List<BoardFileDto> list) throws Exception;

 

4.SQL 변경 및 추가하기

board\src\main\resources\mapper\board\sql-board.xml

	<insert id="insertBoard_434" parameterType="board.board.dto.BoardDto" useGeneratedKeys="true" keyProperty="boardIdx">
    .
    .
    .
    
	<insert id="insertBoardFileList" parameterType="board.board.dto.BoardFileDto">
		<![CDATA[
			INSERT INTO t_file
			(
				board_idx,
				original_file_name,
				stored_file_path,
				file_size,
				creator_id,
				created_datetime
			)
			VALUES
		]]>
		<foreach collection="list" item="item" separator=",">
			(
				#{item.boardIdx},
				#{item.originalFileName},
				#{item.storedFilePath},
				#{item.fileSize},
				'admin',
				NOW()
			)
		</foreach>
	</insert>

19: 파일 목록은 하나 이상이기 때문에 마이바티스의 foreach 문을 사용해 collection의 반복 처리를 한다.

 

 

 

5. 결과 확인

 


첨부된 파일 목록 보여주기

 

1. SQL 추가하기

	<select id="selectBoardFileList" parameterType="int" resultType="board.board.dto.BoardFileDto">
		<![CDATA[
			SELECT
				idx,
				board_idx,
				original_file_name,
				FORMAT(ROUND(file_size / 1024), 0) AS file_size
			FROM
				t_file
			WHERE
				board_idx = #{boardIdx}
				AND deleted_yn = 'N'
		]]>
	</select>

 

2. BoardDto 추가

	private List<BoardFileDto> fileList;

 

3. 서비스 및 매퍼 추가

BoardServiceImpl.java

AS-IS

	public BoardDto selectBoardDetail(int boardIdx) throws Exception{
		boardMapper.updateHitCount(boardIdx);

		BoardDto board = boardMapper.selectBoardDetail(boardIdx);
		
		return board;
	}

TO-BE

 

	public BoardDto selectBoardDetail(int boardIdx) throws Exception{
		BoardDto board = boardMapper.selectBoardDetail(boardIdx);
		List<BoardFileDto> fileList = boardMapper.selectBoardFileList(boardIdx);
		board.setFileList(fileList);
		
		boardMapper.updateHitCount(boardIdx);
		
		return board;
	}

 

BoardMapper.java

	List<BoardFileDto> selectBoardFileList(int boardIdx) throws Exception;

 

4. 뷰 추가

	<div class="file_list">
			<a th:each="list : ${board.fileList}"  th:text="|${list.originalFileName} (${list.fileSize} kb)|"></a>
		</div>

 

 

 

5. 결과 확인

 

 

 

 

 

 

 

'Spring Boot > 4. 파일 업로드와 다운로드' 카테고리의 다른 글

파일 다운로드  (0) 2022.10.31
파일 첨부를 위한 설정  (0) 2022.10.31
복사했습니다!