카테고리 없음

TIL22.03.24 - Spring : 파일 업로드 및 다운로드 , 파일 저장소 만들기

jmaster 2022. 3. 24. 18:49

파일 업로드 및 다운로드 , 파일 저장소 만들기

  • 파일 업로드 처리
    1. commons-fileupload 라이브러리를 프로젝트에 빌드 처리 pom.xml

 

  1. 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
			}
		}
	}

}