본문 바로가기
Spring

2022-12-13~15 파일업로드

by HTT 2022. 12. 14.

수업 이론 정리

1. pom.xml에 라이브러리를 추가
=> https://mvnrepository.com/
   
2. spring-config.xml에 추가한 라이브러리에서 사용할 빈을 등록
=> <beans:bean id = "multipartResolver" >
   
3. 각각의 jsp 파일을 저장할 수 있는 폴더에 뷰를 생성(수정)하기

4. 각각의 폴더에 있는 XXX-tiles.xml파일에 뷰 정보를 추가하기 
   (화면구조가 달라지면 템플릿을 추가하고 작업)

5. 모든 요청이 스프링MVC내부에서 동작해야하므로 뷰를 response하는 메소드를 컨트롤러에 추가하기(뷰만 response하는 요청은 view-config.xml에 등록가능)
   
6. 뷰에서 요청하는 부분을 처리할 수 있도록 컨트롤러를 만들고 메소드를 추가 

7. 서비스에 메소드를 구현 

8. DAO의 메소드를 구현
 
9. mapper에 sql등록 

10. mybatis-config.xml에 mapper와 dto를 등록 

 

 

파일업로드


HTML폼의 전송방식 

1) application/x-www-form-urlencoded 
  - html에서 폼 데이터를 서버로 전송하기 위한 가장 기본적인 방법 
  - 기존의 사용했던 기본적인 방식
  - 폼에 입력한 내용을 name=value&name=value... 방식으로 전송하는 방법  


2) multipart/form-data (V) 
  - 파일 업로드를 하기 위해서 텍스트와 바이너리데이터를 같이 전송할 수 있어야 한다.
  - 다른 형식의 폼데이터와 첨부파일 데이터를 동시에 전송할 수 있는 형식 
  - <form>태그의 enctype속성에 설정 
  - method는 post로 설정 
 


 
MultipartFile(스프링에서 제공)

- multipart/form-data를 이용하는 경우 DispatcherServlet내부에서 "multipartResolver"로 등록된 빈을 찾아 실행하기 때문에 빈의 id명이 틀리면 동작하지 않는다.
 
1. DTO변경 
- 첨부파일이 저장되어야 하므로 DTO에 컬럼을 추가
- boardfileDTO생성 
 
 2. 컨트롤러 수정 
- 서버에 배포되는 context에 저장될 수 있도록 처리 
1) dto에서 MultipartFile객체들을 추출
2) 파일업로드 서비스로 전달해서 실제 파일이 전송되도록 처리 
3) BoartService로 보내서 DB에 저장되도록 
 
3. 서비스 수정 (BoardService)
- DAO를 호출하는 서비스
 
4. 파일 업로드 기능을 수행하는 서비스를 작성 
- 실제 서버에 저장되도록 
 
5. DAO 수정 

 

 

 

 

실습정리

 

1. 라이브러리 등록

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.2</version>
</dependency>
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>1.4</version>
</dependency>

 

 

2. 빈 등록(spring-config.xml)

<beans:bean id = "multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
	<beans:property name="maxUploadSize" value="4000000" />
</beans:bean>

 

 

 

3-1. (DTO수정, 컨트롤러, 서비스 수정) BoardDTO에 파일업로드관련 멤버변수추가, BoardFileDTO만들기(board_no, originalFilename, storeFilename), BoardController 수정하기

 

- 서비스 수정

public int insert(BoardDTO board, List<BoardFileDTO> boardfiledtolist) {
    dao.insert(board);
    dao.insertFile(boardfiledtolist);
    return 0;
}

=> dao클래스에 정의된 두 개의 메소드를 호출한다. → 게시글 기본정보 저장, 첨부된 파일에 대한 정보 저장

 

 

 

 

@RequestMapping(value = "/board/write.do", method=RequestMethod.POST)
	public String write(BoardDTO board, HttpSession session) throws IllegalStateException, IOException {
		System.out.println("board=>"+board);
		List<MultipartFile> files = board.getFiles();
		String path = WebUtils.getRealPath(session.getServletContext(), "/WEB-INF/upload");
		List<BoardFileDTO> boardfiledtolist = fileuploadService.uploadFiles(files, path);
		int count = 1;
		for(BoardFileDTO boardfiledto : boardfiledtolist) {
			boardfiledto.setBoardFileno(count+"");
			count++;
		}
		service.insert(board, boardfiledtolist);
		return "redirect:/board/list.do?category=all";
	}

 

 

① dto에서 MultipartFile객체 추출

@RequestMapping(value = "/board/write.do", method=RequestMethod.POST)
public String write(BoardDTO board, HttpSession session) throws IllegalStateException, IOException {
		
	List<MultipartFile> files = board.getFiles();

=> MultipartFile정보를 추출한다.

 

Multipart란?
웹 클라이언트가 요청을 보낼 때, http 프로토콜의 바디 부분에 데이터를 여러 부분으로 나눠서 보내는 것.웹 클라이언트가 서버에게 파일을 업로드할 때, http 프로토콜의 바디 부분에 파일정보를 담아서 전송을 하는데, 파일을 한번에 여러개 전송을 하면 body 부분에 파일이 여러개의 부분으로 연결되어 전송된다. 이렇게 여러 부분으로 나뉘어서 전송되는 것을 Multipart data라고 한다.보통 파일을 전송할 때 사용한다.  출처

 

 

 

② 파일업로드 서비스로 전달해서 실제 파일이 전송되도록 처리

* 서버가 인식하는 위치

\java\work\springwork\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\erp\WEB-INF\upload

String path = WebUtils.getRealPath(session.getServletContext(), "/WEB-INF/upload");

=> 실제 서버의 경로를 추출하기 서버에 배포되는 실제 경로와 context에 대한 정보를 담고 있는 ServletContext객체를 추출한다.

서버가 인식하는 경로를 추출하기 위해 WebUtil클래스의 getRealPath() 메소드를 사용해 실제 서버에 배포된 위치를 구한다.

+ 업로드될 서버의 경로 지정

 

 

 

 

3-2. BoardService로 보내서 DB에 저장되도록 처리

List<BoardFileDTO> boardfiledtolist = fileuploadService.uploadFiles(files, path);
		int count = 1;
		for(BoardFileDTO boardfiledto : boardfiledtolist) {
			boardfiledto.setBoardFileno(count+"");
			count++;
		}
		service.insert(board, boardfiledtolist);
		return "redirect:/board/list.do?category=all";

=> 업로드한 파일이 저장될 수 있도록 처리해주는 FileUploadLogic클래스의 uploadFiles메소드 호출하여 파일이름 받아오기.

 

 

 

 

3-3. uploadFiles 메소드작성

@Service
public class FileUploadLogic {	
	public List<BoardFileDTO> uploadFiles(List<MultipartFile> multipartFiles, String path) throws IllegalStateException, IOException {
		List<BoardFileDTO> filedtolist = new ArrayList<BoardFileDTO>();
		for (MultipartFile multipartFile : multipartFiles) {

=> 파일을 업로드한 후 이 정보를 BoardfileDTO로 변환해서 리턴하기(넘겨받은 file들을 MultipartFile타입 변수"multipartFile"에 담는 과정).

 

 

if(!multipartFile.isEmpty()) {

~~~~~~~ file이 존재할 때 아래의 과정이 실행된다 ~~~~~~~

 

 

 

- 클라이언트가 업로드한 파일명

String originalFilename = multipartFile.getOriginalFilename();

 

 

- 서버에서 식별할 수 있도록 파일명을 변경

String storeFilename = createStoreFilename(originalFilename);
//클라이언트가 입력한 파일명을 중복없는 이름으로 변경
// UUID - 32자리의 16진수로 표기
private String createStoreFilename(String originalFilename) {
    int pos = originalFilename.lastIndexOf(".");
    String ext = originalFilename.substring(pos+1);
    String uuid = UUID.randomUUID().toString(); 
    return uuid+"."+ext;
}

=> 클라이언트가 업로드한 파일명을 "originalFilename"변수에 담고, 이 정보를 createStoreFilename메소드를 호출하며 넘겨준다. 서버에 저장되는 (겹칠 일이 거의 없는)파일명+확장자를 받아와 "storeFilename"변수에 담아주고 파일명을 실제 경로에 저장해주면 된다.

 

UUID란?
범용 고유 식별자(Universally Unique Identifiers)로 클라이언트가 입력한 파일명을 중복없는 이름으로 변경해준다.
32자리의 16진수로 표기

* UUID클래스의 randomUUID() 메소드로 UUID 값을 가져오는데 UUID형태이기 때문에 toString() 메소드를 사용하여 String으로 바꿔준다.

 

 

 

- File객체를 실제 경로에 저장하는 작업 

			multipartFile.transferTo(new File(path+File.separator+storeFilename)); 
                             				  //path : 서버가 인식하는 위치
			filedtolist.add(new BoardFileDTO(originalFilename, storeFilename));
		}
	}
	return filedtolist;
}

=> File객체를 사용하기 위해 객체생성 해준 뒤 transferTo() 메소드를 이용해 파일을 저장한다. BoardFileDTO타입으로 변환 후 리턴.

 

path : H:\java\work\springwork\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\erp\WEB-INF\upload

File.separator : \ (파일 구분자. 역슬래시)

storeFilename : 범용 고유 식별자.확장자

 

 

 

- 파일업로드

 

호출된 메소드의 작업이 끝나고 다시 컨트롤러 3-2 과정으로 돌아와서 코드를 보면,

 

List<BoardFileDTO> boardfiledtolist = fileuploadService.uploadFiles(files, path);
int count = 1;
for(BoardFileDTO boardfiledto : boardfiledtolist) {
	boardfiledto.setBoardFileno(count+"");
	count++;
}

=> " boardfileno "라는 멤버변수가 있는데, 이 변수는 한 게시글에 2개 이상의 파일이 올라왔을 때 식별할 번호를 붙여준 것이다.

업로드된 파일의 boardfileno의 값을 셋팅해준다.

 

 

 

- 게시글에 대한 일반적인 정보와 첨부되는 파일의 정보를 db에 저장하기

service.insert(board, boardfiledtolist);
}

 

 

 

댓글