카테고리 없음
TIL22.03.24 - Spring : 파일 업로드 및 다운로드 , 파일 저장소 만들기
jmaster
2022. 3. 24. 18:49
파일 업로드 및 다운로드 , 파일 저장소 만들기
- 파일 업로드 처리
- commons-fileupload 라이브러리를 프로젝트에 빌드 처리 pom.xml
- Bean Configuration File(servlet-context.xml)에 파일 업로드 기능을 제공한는 클래스 Spring Bean으로 등록
- 파일 업로드 기능을 제공하는 클래스를 Spring Bean으로 등록
- ⇒ beanName은 반드시 multipartResolver로 설정
- maxUploadSize 필드에 업로드 파일의 제한 용량(Byte)을 인젝션 처리
- defaultEncoding 필드에 전달값에 대한 캐릭터셋의 인코딩을 인젝션 처리
<beans:bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
<beans:property name="maxUploadSize" value="20971520"></beans:property>
<beans:property name="defaultEncoding" value="utf-8"></beans:property>
</beans:bean>
- apache-tomcat → webapps→ spring →resource →image 경로에서 확인가능
upload.jsp
- 파일을 입력받아 요청 웹프로그램에게 전달하기 위해 요청 방식(method 속성)은 [post]로 설정하고 전달 형태(enctype 속성)은 [multipart/form-data]로 설정
<form action="upload" method="post" enctype="multipart/form-data">
<table>
<tr>
<td>업로드 이름</td>
<td><input type="text" name="uploadName"></td>
</tr>
<tr>
<td>업로드 파일</td>
<td><input type="file" name="uploadFile"></td>
</tr>
<tr>
<td colspan="2"><button type="submit">파일 업로드</button></td>
</tr>
</table>
</form>
FileController.java
- MultipartHttpServletRequest : [multipart/form-data] 형태로 전달되는 값과 파일을 처리하기 위한 메소드
- MultipartHttpServletRequest.getFile(String parameterName) : 전달된 파일을 전달 받아 MultipartFile 객체로 생성하여 반환하는 메소드
- MultipartFile : 전달된 파일의 정보를 저장한 객체
MultipartFile uploadFile=request.getFile("uploadFile");
- 전달 파일에 대한 유효성 검사
- MultipartFile.isEmpty() : 전달 파일이 없는 경우 true를 반환하는 메소드
if(uploadFile.isEmpty()) {
return "file/fail";
}
- MultipartFile.getContentType() : 전달 파일 형식(MimeType)를 반환하는 메소드
- MultipartFile.getBytes() : 전달 파일 byte 배열(원시데이타)로 반환하는 메소드
- →이력서 프로필 사진 업로드시 사용
System.out.println("파일 형식 = "+uploadFile.getContentType());
System.out.println("파일 크기 = "+uploadFile.getBytes().length);
- 전달 파일을 서버에 저장하기 위한 업로드 디렉토리의 파일 시스템 경로를 반환받아 저장
String uploadDirectory= request.getServletContext().getRealPath("/resources/images");
- 전달파일을 서버에 저장하기 위한 File 객체 생성
- MultipartFile.transferTo(File file) : 전달파일을 서버에 저장하는 메소드
- ⇒ 서버 디렉토리에 업로드 파일과 같은 이름으 파일이 있는 경우 엎어 씌우기를 하여 저장
File file=new File(uploadDirectory, uploadFile.getOriginalFilename());
uploadFile.transferTo(file);
전체 코드
@Controller
public class FileController {
@RequestMapping(value = "/upload", method = RequestMethod.GET)
public String upload() {
return "file/upload";
}
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public String upload(MultipartHttpServletRequest request) throws IOException {
String uploadName=request.getParameter("uploadName");
MultipartFile uploadFile=request.getFile("uploadFile");
if(uploadFile.isEmpty()) {
return "file/fail";
}
System.out.println("파일 형식 = "+uploadFile.getContentType());
System.out.println("파일 크기 = "+uploadFile.getBytes().length);
String uploadDirectory= request.getServletContext().getRealPath("/resources/images");
File file=new File(uploadDirectory, uploadFile.getOriginalFilename());
uploadFile.transferTo(file);
request.setAttribute("uploadName", uploadName);
request.setAttribute("uploadFile", uploadFile.getOriginalFilename());
return "file/upload_ok";
}
파일 이름 중복 처리
- 서버 디렉토리에 전달파일명과 같은 이름의 파일이 존재할 경우 전달 파일명 대신 새로운 이름으로 파일명을 변경하여 업로드 처리
- 필드에 WebApplicationContext 객체(Spring Container)를 저장하도록 인젝션 처리
- @Autowired private WebApplicationContext context;
- WebApplicationContext 객체를 이용하여 ServletContext 객체를 제공받아 서버 디렉토리의 파일 시스템 경로를 반환받아 저장
String uploadDirectory=context.getServletContext().getRealPath("/resources/images");
- 전달파일명을 반환받아 저장
String originalFilename=uploadFile.getOriginalFilename();
File file=new File(uploadDirectory, originalFilename);
- 실제 서버 디렉토리에 저장되는 파일명을 저장하기 위한 변수 선언
- ⇒ 초기값으로 전달파일의 이름을 전달
String uploadFilename=originalFilename;
- 서버 디렉토리에 전달파일과 같은 이름의 파일이 존재할 경우 서버 디렉토리에 저장될 파일명
int i=0;
while(file.exists()) {//서버 디렉토리에 같은 이름의 파일이 있는 경우 반복 처리
i++;
int index=originalFilename.lastIndexOf(".");
uploadFilename=originalFilename.substring(0, index)+"_"+i+originalFilename.substring(index);
file=new File(uploadDirectory, uploadFilename);
}
전체 코드
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public String upload(@RequestParam String uploadName, @RequestParam MultipartFile uploadFile, Model model) throws IllegalStateException, IOException {
if(uploadFile.isEmpty()) {
return "file/upload_fail";
}
String uploadDirectory=context.getServletContext().getRealPath("/resources/images");
String originalFilename=uploadFile.getOriginalFilename();
File file=new File(uploadDirectory, originalFilename);
String uploadFilename=originalFilename;
int i=0;
while(file.exists()) {
i++;
int index=originalFilename.lastIndexOf(".");
uploadFilename=originalFilename.substring(0, index)+"_"+i+originalFilename.substring(index);
file=new File(uploadDirectory, uploadFilename);
}
uploadFile.transferTo(file);
model.addAttribute("uploadName", uploadName);
model.addAttribute("originalFilename", originalFilename);
model.addAttribute("uploadFilename", uploadFilename);
return "file/upload_ok";
}
FileBoard
table 생성 → DTO 생성 → Mapper.xml생성 및 Mapper 인터페이스 생성 → DTO 생성 → Service 생성 → Controller 생성 → JSP 파일 생성
WEB-INF에 파일생성
FileController.java
파일 업로드
@RequestMapping(value = "/file_upload", method = RequestMethod.POST)
public String fileUpload(@ModelAttribute FileBoard fileBoard) throws IllegalStateException, IOException {
if(fileBoard.getFile().isEmpty()) {
return "file/file_upload";
}
String uploadDir=context.getServletContext().getRealPath("/WEB-INF/upload");
//전달 파일명을 반환받아 저장
String origin=fileBoard.getFile().getOriginalFilename();
//업로드 파일명을 고유값(현재 시스템의 타임스템프)으로 저장
// => 업로드 처리된 파일명이 중복되지 않도록 설정
String upload=System.currentTimeMillis()+"";
//DTO 객체의 필드값 변경
fileBoard.setOrigin(origin);
fileBoard.setUpload(upload);
fileBoard.getFile().transferTo(new File(uploadDir, upload));
fileBoardService.addFileBoard(fileBoard);
retu
다운 리스트
@RequestMapping("/file_list")
public String fileList(Model model) {
model.addAttribute("fileBoardList", fileBoardService.getFileBoardList());
return "file/file_list";
}
삭제 메소드
@RequestMapping("/file_delete/{num}")
public String fileDelete(@PathVariable int num) {
FileBoard fileBoard=fileBoardService.getFileBoard(num);
String uploadDir=context.getServletContext().getRealPath("/WEB-INF/upload");
//서버 디렉토리에 저장된 파일 삭제
new File(uploadDir, fileBoard.getUpload()).delete();
//FILEBOARD 테이블에 저장된 자료실 정보 삭제
fileBoardService.removeFileBoard(num);
return "redirect:/file_list";
}
다운로드 처리 메소드
- 요청 처리 메소드에서 반환되는 ViewName을 이용하여 다운로드 프로그램 실행되도록 설정
- ⇒반환되는 ViewName을 이용하여 프로그램이 실행되도록 BeanNameViewResolver 설정 - servlet-context.xml
@RequestMapping("/file_download/{num}")
public String fileDownload(@PathVariable int num, Model model) {
FileBoard fileBoard=fileBoardService.getFileBoard(num);
model.addAttribute("uploadDir", context.getServletContext().getRealPath("/resources/images"));
model.addAttribute("uploadFilename", fileBoard.getUpload());
model.addAttribute("originFilename", fileBoard.getOrigin());
//실행할 Spring Bean의 클래스의 BeanName 반환
return "fileDownload";
}
전체 코드
@Controller
public class FileController {
@Autowired
private WebApplicationContext context;
@Autowired
private FileBoardService fileBoardService;
@RequestMapping(value = "/upload", method = RequestMethod.GET)
public String upload() {
return "file/upload";
}
//방법 1
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public String upload(MultipartHttpServletRequest request) throws IOException {
String uploadName=request.getParameter("uploadName");
MultipartFile uploadFile=request.getFile("uploadFile");
if(uploadFile.isEmpty()) {
return "file/upload_fail";
}
System.out.println("파일 형식 = "+uploadFile.getContentType());
System.out.println("파일 크기 = "+uploadFile.getBytes().length);
String uploadDirectory=request.getServletContext().getRealPath("/resources/images");
File file=new File(uploadDirectory, uploadFile.getOriginalFilename());
uploadFile.transferTo(file);//업로드 처리
request.setAttribute("uploadName", uploadName);
request.setAttribute("uploadFile", uploadFile.getOriginalFilename());
return "file/upload_ok";
}
//방법 2 - 이것을 주로 사용합니다.!
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public String upload(@RequestParam String uploadName, @RequestParam MultipartFile uploadFile, Model model) throws IllegalStateException, IOException {
if(uploadFile.isEmpty()) {
return "file/upload_fail";
}
String uploadDirectory=context.getServletContext().getRealPath("/resources/images");
String originalFilename=uploadFile.getOriginalFilename();
File file=new File(uploadDirectory, originalFilename);
String uploadFilename=originalFilename;
int i=0;
while(file.exists())
i++;
int index=originalFilename.lastIndexOf(".");
uploadFilename=originalFilename.substring(0, index)+"_"+i+originalFilename.substring(index);
file=new File(uploadDirectory, uploadFilename);
}
uploadFile.transferTo(file);
model.addAttribute("uploadName", uploadName);
model.addAttribute("originalFilename", originalFilename);
model.addAttribute("uploadFilename", uploadFilename);
return "file/upload_ok";
}
@RequestMapping(value = "/file_upload", method = RequestMethod.GET)
public String fileUpload() {
return "file/file_upload";
}
@RequestMapping(value = "/file_upload", method = RequestMethod.POST)
public String fileUpload(@ModelAttribute FileBoard fileBoard) throws IllegalStateException, IOException {
if(fileBoard.getFile().isEmpty()) {
return "file/file_upload";
}
String uploadDir=context.getServletContext().getRealPath("/WEB-INF/upload");
String origin=fileBoard.getFile().getOriginalFilename();
String upload=System.currentTimeMillis()+"";
fileBoard.setOrigin(origin);
fileBoard.setUpload(upload);
fileBoard.getFile().transferTo(new File(uploadDir, upload));
fileBoardService.addFileBoard(fileBoard);
return "redirect:/file_list";
}
@RequestMapping("/file_list")
public String fileList(Model model) {
model.addAttribute("fileBoardList", fileBoardService.getFileBoardList());
return "file/file_list";
}
@RequestMapping("/file_delete/{num}")
public String fileDelete(@PathVariable int num) {
FileBoard fileBoard=fileBoardService.getFileBoard(num);
String uploadDir=context.getServletContext().getRealPath("/WEB-INF/upload");
new File(uploadDir, fileBoard.getUpload()).delete();
fileBoardService.removeFileBoard(num);
return "redirect:/file_list";
}
@RequestMapping("/file_download/{num}")
public String fileDownload(@PathVariable int num, Model model) {
FileBoard fileBoard=fileBoardService.getFileBoard(num);
model.addAttribute("uploadDir", context.getServletContext().getRealPath("/resources/images"));
model.addAttribute("uploadFilename", fileBoard.getUpload());
model.addAttribute("originFilename", fileBoard.getOrigin());
return "fileDownload";
}
}
servlet-context
- BeanNameViewResolver: 요청 처리 메소드에서 제공되는 ViewName을 이용하여 같은 이름의 Spring Bean 객체로 실행 메소드를 호출하여 클라이언트에게 응답하는 기능을 제공하는 ViewResolver
- ⇒ JSP 문서를 이용한 응답이 아닌 명령 실행이 실행이 목적의 ViewResolver
- ⇒JSP 문서를 응답하는 ViewResolver보다 우선 순위를 반드시 높도록 설정
- ⇒ pdf, xml 파일로 만드는 기능도 만들 수 있음
<beans:bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
<beans:property name="order" value="1"/>
</beans:bean>
- 파일 다운로드 기능을 제공하는 클래스르 Spring Bean으로 등록
- ⇒ 요청 처리 메소드에서 반환되는 ViewName과 beanName이 같도록 설정
<beans:bean class="xyz.itwill10.util.FileDownload" id="fileDownload"/>
FileDownload.java
- 파일 다운로드 기능을 제공하는 클래스 - Spring Bean 등록
- ⇒ Bean Configuration File(servlet-context.xml)에서 Spring Bean 등록 - Annotation 사용 가능
- BeanNameViewResolver에 의해 실해되는 클래스는 반드시 AbstrcView 클래스를 상속받아 실행
- ⇒renderMergedOutputModel() 메소드를 오버라이드 선언하여 응답 필요한 명령을 작성
- 클라이언트에게 응답할 파일형식 대한 변경 - 파일 다운로드 기능
- AbstractView.setContentType(String mimeType) :응답 파일 형식을 변경하는 메소드
public FileDownload() {
setContentType("application/download; utf-8");
}
- BeamNameViewResolver에 의해 자동 호출되는 메소드
- ⇒ Map 자료형의 매개변수에는 요청 처리 메소드에서 Model 객체에 의해 제공되는 정보 저장
@Override
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
HttpServletResponse response) throws Exception {
}
- Map 객체에 저장된 맵값을 반환받아 저장 - 다운로드 파일 저장
String uploadDir=(String)model.get("uploadDir");
String uploadFilename=(String)model.get("uploadFilename");
String originFilename=(String)model.get("originFilename");
- 다운로드 파일을 이용하여 FIle 객체 생성
File downloadFile=new File(uploadDir, uploadFilename);
- 클라이언트에게 파일을 전달하기 위한 응답정보 변경
response.setContentType(getContentType());
response.setContentLength((int)downloadFile.length());
- 클라이언트에게 저장될 파일명을 전달
originFilename=URLEncoder.encode(originFilename, "utf-8");
response.setHeader("Content-Disposition", "attachement;filename=\\""+originFilename+"\\";");
- 클라이어트에게 원시 데이터를 전달하기 위한 출력스트림을 반환받아 저장
OutputStream out=response.getOutputStream();
- 서버에 저장된 파일을 읽기 위한 입력스트림을 생성하여 저장
in=new FileInputStream(downloadFile);
- FileCopyUtils.copy(InputStream in, OutputStream out) : 입력스트림을 이용하여 원시 데이타를 읽어 출력스트림으로 반복적으로 전달하는 메소드 - 복사
FileCopyUtils.copy(in, out);
전체코드
public class FileDownload extends AbstractView {
public FileDownload() {
setContentType("application/download; utf-8");
}
@Override
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
HttpServletResponse response) throws Exception {
String uploadDir= (String)model.get("uploadDir");
String uploadFilename= (String)model.get("uploadFilename");
String originFilename= (String)model.get("originFilename");
File downloadFile=new File(uploadDir, uploadFilename);
response.setContentType(getContentType());
response.setContentLengthLong((int)downloadFile.length());
originFilename=URLEncoder.encode(originFilename, "utf-8");
response.setHeader("Content-Disposition", "alttachement;filename=\""+originFilename+"\";");
OutputStream out = response.getOutputStream();
FileInputStream in = null;
try in = new FileInputStream(downloadFile);
FileCopyUtils.copy(in, out);
}catch (Exception e) {
// TODO: handle exception
}finally {
try {
in.close();
} catch (Exception e) {
// TODO: handle exception
}
}
}
}