파일 업로드 / 다운로드 의 구조
구현과정
application.properties 에 DB 에 대한 정보가 있다는 가정하에 진행합니다.
dependency 추가 / WebMvcConfig 설정
(1) dependency 추가
<!-- Multipart File -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
HTML
복사
(2) WebMvcConfig 설정
내부 경로를 이용하는게 아니라 외부 경로를 사용하기 때문에 필요한 설정이다.
package multi.second.project.domain.File;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
// url: localhost8080:/list/** 에 접속했을 때에 파일에 접근
// 나중에 화면단의 <img src=...> 에서 src 에 들어간다.
private String connectPath = "/list/**";
// 실제 이미지가 저장되어 있는 외부경로 (file:/// = C:/ 라고 생각하자)
// 끝에 꼭 '/' 로 닫아줘야 한다.
private String resourcePath = "file:///upload/";
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler(connectPath)
.addResourceLocations(resourcePath);
}
}
Java
복사
Entity 생성
package multi.second.project.domain.File;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Data
@Entity
@NoArgsConstructor
public class Files {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
int fno;
String filename;
String fileOriName;
String fileurl;
@Builder
public Files(int fno, String filename, String fileOriName, String fileurl) {
this.fno = fno;
this.filename = filename;
this.fileOriName = fileOriName;
this.fileurl = fileurl;
}
}
Java
복사
DTO 생성
package multi.second.project.domain.File;
import lombok.*;
@Setter
@Getter
@ToString
@NoArgsConstructor
public class FilesDto {
private int fno;
private String filename;
private String fileOriName;
private String fileurl;
public Files toEntity(){
Files build = Files.builder()
.fno(fno)
.filename(filename)
.fileOriName(fileOriName)
.fileurl(fileurl)
.build();
return build;
}
@Builder
public FilesDto(int fno, String filename, String fileOriName, String fileurl) {
this.fno = fno;
this.filename = filename;
this.fileOriName = fileOriName;
this.fileurl = fileurl;
}
}
Java
복사
Repository 생성
package multi.second.project.domain.File;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface FilesRepository extends JpaRepository<Files, Integer> {
}
Java
복사
Service 생성
package multi.second.project.domain.File;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
@Service
public class FilesService {
@Autowired
FilesRepository filesRepository;
// 파일 저장
public void save(Files files) {
Files f = new Files();
f.setFilename(files.getFilename());
f.setFileOriName(files.getFileOriName());
f.setFileurl(files.getFileurl());
filesRepository.save(f);
}
// 파일 다운로드
@Transactional
public List<FilesDto> getFilesList(){
List<Files> files = filesRepository.findAll();
List<FilesDto> fileDtoList = new ArrayList<>();
for(Files file : files){
FilesDto dto = FilesDto.builder()
.fno(file.getFno())
.filename(file.getFilename())
.fileOriName(file.getFileOriName())
.fileurl(file.getFileurl())
.build();
fileDtoList.add(dto);
}
return fileDtoList;
}
}
Java
복사
Controller 생성
package multi.second.project.domain.File;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.List;
@Controller
public class FilesController {
@Autowired
FilesService filesService;
// 파일 업로드 화면
@RequestMapping("/insert")
public String Insert() {
return "insert.html";
}
// 파일 업로드 처리
@RequestMapping("/fileinsert")
public String fileinsert(HttpServletRequest request, @RequestPart MultipartFile files) throws Exception {
Files file = new Files();
String sourceFileName = files.getOriginalFilename();
String sourceFileNameExtension = FilenameUtils.getExtension(sourceFileName).toLowerCase();
File destinationFile;
String destinationFileName;
// 실제 resource 가 저장되는 외부 경로
String fileUrl = "C:/upload/";
do {
destinationFileName = RandomStringUtils.randomAlphanumeric(32) + "." + sourceFileNameExtension;
destinationFile = new File(fileUrl + destinationFileName);
} while (destinationFile.exists());
destinationFile.getParentFile().mkdirs();
files.transferTo(destinationFile);
file.setFilename(destinationFileName);
file.setFileOriName(sourceFileName);
file.setFileurl(fileUrl);
filesService.save(file);
return "redirect:/insert";
}
// 전체 파일 리스트
@GetMapping("/list")
public String list(Model model){
List<FilesDto> filesDtoList = filesService.getFilesList();
model.addAttribute("filesList", filesDtoList);
return "list";
}
}
Java
복사
resource 를 저장하는 경로는 외부경로여야 합니다.
(내부경로(프로젝트 내부)일 경우 배포시 이미지가 엑박으로 뜹니다.)
View 생성
(1) 업로드 화면
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<title>Main</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" href="/css/main_layout.css"/>
</head>
<body>
<form action="/fileinsert" method="post" enctype="multipart/form-data">
<input type="file" name="files">
<button type="submit">보내기</button>
</form>
</body>
</html>
HTML
복사
(2) 다운로드 화면
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<title>Main</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" href="/css/main_layout.css"/>
</head>
<body>
<!-- 반복문을 이용하여 전체 이미지 출력 -->
<!-- 이를 활용하여 단건 처리도 가능하다 -->
<div th:each="files : ${filesList}">
<img th:src="@{/list/} + ${files.filename}">
</div>
</body>
</html>
HTML
복사
결과
•
DB
•
화면출력
◦
위 이미지들의 주소는 다음과 같다
http://localhost:8080/list/N7lZkBpYYPVi4C0dbQTFACbSWTiH6I8h.png
http://localhost:8080/list/DJofU4r8cAwd0VtKTeKBROAq56Sw15PJ.png