Spring

[FileUpload] 파일 업로드

sujin7837 2022. 4. 22. 15:06
반응형

File Upload

pom.xml 파일 설정 : 의존성 주입

<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>

 

servlet-context.xml 파일 설정

<beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
	<beans:property name="defaultEncoding" value="UTF-8" />
    <beans:property name="maxUploadSize" value="52428800" />	<!-- 50MB -->
    <beans:property name="maxInMemorySize" value="1048576" />	<!-- 1MB -->
</beans:bean>
  • maxUploadSize : 최대 업로드 가능한 파일의 바이트 크기
  • maxInMemorySize : 디스크에 임시 파일을 생성하기 전에 메모리에 보관할 수 있는 최대 바이트 크기

 

form 설정

 <form id="writeform" class="text-left mb-3" method="post" enctype="multipart/form-data" action="">
    <!-- <div class="form-group">
        <label for="userid">작성자ID:</label>
        <input type="text" class="form-control" id="userid" name="userid" placeholder="작성자ID...">
    </div> -->
    <div class="form-group">
        <label for="subject">제목:</label>
        <input type="text" class="form-control" id="subject" name="subject" placeholder="제목...">
    </div>
    <div class="form-group">
        <label for="content">내용:</label>
        <textarea class="form-control" rows="15" id="content" name="content"></textarea>
    </div>
    <div class="form-group" align="left">
        <label for="upfile">파일:</label>
        <input type="file" class="form-control-file border" name="upfile" multiple="multiple">
    </div>
    <div class="text-center">
        <button type="button" id="registerBtn" class="btn btn-outline-primary">글작성</button>
        <button type="reset" class="btn btn-outline-danger">초기화</button>
    </div>
</form>
  • form의 메서드는 반드시 post로 해줍니다.
  • form 태그 안에 enctype="multipart/form-data" 설정을 해줍니다.
  • 업로드 할 파일의 input 태그의 타입을 file로 설정합니다.
  • 업로드 할 파일을 파라미터로 받아오기 위해 input 태그 안에 name을 설정합니다. 

 

자바 클래스 생성

public class BoardDto {
	.....
    
    private List<FileInfoDto> fileInfos;
}

파일을 하나만 저장하려면 FileInfoDto, 여러 개 저장하려면 리스트로 만들어줍니다.

public class FileInfoDto {
	private String saveFolder;
    private originFile;
    private String saveFile;
    
    ...(getter, setter 등)
}
  • saveFolder : 서버 상의 저장할 폴더
  • originFile : 원본 파일의 이름
  • saveFile : 실제 저장할 파일의 이름
// controller

@PostMapping("/register")
	public String register(BoardDto boardDto, @RequestParam("upfile") MultipartFile[] files, Model model,
			HttpSession session, RedirectAttributes redirectAttributes)
			throws Exception {
		UserDto userDto = (UserDto) session.getAttribute("userinfo");
		boardDto.setUserId(userDto.getUserId());

		// FileUpload 관련 설정.
		logger.debug("MultipartFile.isEmpty : {}", files[0].isEmpty());
		if (!files[0].isEmpty()) {
        	// 내 컴퓨터 경로 밑에 /upload/yyMMdd(파일 이름을 오늘 날짜로 설정) 경로로 파일이 생성됨
			String realPath = servletContext.getRealPath("/upload");
            // 현재 작업중인 프로젝트의 /resources/img 경로로 파일이 생성됨
//			String realPath = servletContext.getRealPath("/resources/img");
			String today = new SimpleDateFormat("yyMMdd").format(new Date());
			String saveFolder = realPath + File.separator + today;
			logger.debug("저장 폴더 : {}", saveFolder);
			File folder = new File(saveFolder);
            // 폴더가 존재하지 않으면 폴더를 생성
			if (!folder.exists())
				folder.mkdirs();
			List<FileInfoDto> fileInfos = new ArrayList<FileInfoDto>();
            // 파일의 개수만큼 반복문을 돌며 파일 업로드 진행
			for (MultipartFile mfile : files) {
				FileInfoDto fileInfoDto = new FileInfoDto();
				String originalFileName = mfile.getOriginalFilename();
				if (!originalFileName.isEmpty()) {
					String saveFileName = UUID.randomUUID().toString()
							+ originalFileName.substring(originalFileName.lastIndexOf('.'));
					fileInfoDto.setSaveFolder(today);
					fileInfoDto.setOriginFile(originalFileName);
					fileInfoDto.setSaveFile(saveFileName);
					logger.debug("원본 파일 이름 : {}, 실제 저장 파일 이름 : {}", mfile.getOriginalFilename(), saveFileName);
					mfile.transferTo(new File(folder, saveFileName));
				}
				fileInfos.add(fileInfoDto);
			}
			boardDto.setFileInfos(fileInfos);
		}

		guestBookService.registerArticle(guestBookDto);
		redirectAttributes.addAttribute("pg", 1);
		redirectAttributes.addAttribute("key", "");
		redirectAttributes.addAttribute("word", "");
		redirectAttributes.addFlashAttribute("msg", "글작성 성공!!!");
		return "redirect:/guestbook/list";
//		return "redirect:/guestbook/list?pg=1&key=&word=";
	}
  • /upload/yyMMdd(파일 이름) 경로로 파일이 만들어집니다.
  • mfile.transferTo(new File(folder, saveFileName)); -> folder에 saveFileName 이름으로 파일을 전송함

Transactional

// BoardServiceImpl.java

@Override
@Transactional
public void registerArticle(BoardDto boardDto) throws Exception {
	if(boardDto.getSubject() == null || boardDto.getContext() ==null) {
    	throw new Exception();
    }
    BoardMapper boardMapper = sqlSession.getMapper(BoardMapper.class);
    boardMapper.registerArticle(boardDto);
    boardMapper.fileRegister(boardDto);
}

@Transactional을 사용하게 되면 Exception 발생 시 자동으로 roll back 되고, Exception이 발생하지 않을 시 자동으로 commit 됩니다.

 

MyBatis 사용 시 xml을 이용한 파일 업로드

board.xml

<insert id="registerArticle" parameterType="BoardDto">
	insert into board (userid, subject, content, regtime)
    values (#{userid}, #{subject}, #{content}, now())
	<selectKey order="AFTER" resultType="int" keyProperty="articleno">
		select last_insert_id() 
	</selectKey>
</insert>

<insert id="fileRegister" parameterType="BoardDto">
	insert into file_info (articleno, savefolder, originfile, savefile)
    values 
	<foreach collection="fileInfos" item="fileinfo" separator=", ">
		(#{articleno}, #{fileinfo.saveFolder}, #{fileinfo.originFile}, #{fileinfo.saveFile})
	</foreach>
</insert>

<resultMap type="BoardDto" id="boardList">
    <result column="articleno" property="articleno"/>
    <result column="userid" property="userid"/>
    <result column="subject" property="subject"/>
    <result column="content" property="content"/>
    <result column="regtime" property="regtime"/>
    <collection column="articleno" property="fileInfos" javaType="list" ofType="FileInfoDto" select="fileInfoList" />
</resultMap>

BoardDto의 값들이 자동으로 하나씩 들어가게 됩니다. 여기서 정확한 표현은 아니지만,,, 이해하자면 ${} 에는 컬럼명, #{} 에는 Dto에 선언된 변수명이 들어간다는 개념으로 볼 수 있습니다.

반응형