Published 2020. 10. 28. 20:39
728x90
반응형

Multipart에 대한 작업처리자 -> CommonsMultipartResolver라고 생각하면 됨
CommonsMultipartResolver가 파일을 받아다가 upFile에 넣어주는 역할을 함

cos.jar는 MultipartRequest하면 모든 처리가 끝났지만
commons의 작동방식은 upFile이 controller에 넘어왔을때는 아직 메모리상(RAM)에 존재하고 있다가 
직접 설정한 파일명으로 transferTo 메소드를 통해 요청했을때 실제로 저장됨

 
파일 여러개 올리기
BoardController
파라미터 부분을 배열로 바꿔주기 > MultipartFile[] upFiles  


1. 파일을 서버컴퓨터에 저장

String saveDirectory = request.getServletContext().getRealPath("/resources/upload/board"); //저장경로
request.getServletContext().getRealPath("/"); //여기가 web root directory임(src\main/webapp 예전에는 webContent였지만 spring은 아님) 

 

if(!f.isEmpty() && f.getSize() != 0) {   //비어있지 않고 파일사이즈도 0이 아닐때 
1️⃣ 파일명 생성 

>

String renamedFileName = Utils.getRenamedFileName(f.getOriginalFilename());

> common 패키지에 Utils 클래스 만들기 

> getRenamedFileName 메소드 생성 후 내용 작성 

> 파일명 얻어오기!

2️⃣ 메모리의 파일 (서버경로상의 파일)
> File newFile 을 통해 임의의 자바파일객체를 만듦
> f.transferTo(newFile); 을 통해 이동시킴

> 여기까지하면 파일이 저장됨(생성ok)
3️⃣ attachment객체 생성(db 저장을 위한 준비)  
boardNo에 대한 후처리가 attachment 객체에 필요함
왜냐면 boardNo는 FK로 참조하고 있는 값인데 그 값이 없을 수 없음! 
그런데 지금은 board에 글이 등록되지 않았기 때문에(db추가 전) 시퀀스로 boardNo가 생성되지 않은 상태여서 boardNo를 알 수 없음
그래서 후처리 필요함
mapper.xml에서 쿼리안에 쿼리 하나 더 날림 <selectKey>를 이용해 그 안에 작성한 쿼리의 조회 결과를 keyProperty에 담을 수 있음!
> Attachment attach = new Attachment();

> 정보 작성 후 추가해주기

}

 

> board VO에 private List<Attachment> attachList; 로 첨부파일 관리하기!(한 게시물에 들어있는 첨부파일의 정보 board VO의 필드로 관리)
> vo에 필드 설정 후 boardController에 board.setAttachList(attachList); 세팅해주기

 

@PostMapping("/boardEnroll.do")
public String boardEnroll(Board board,
			@RequestParam(value="upFile",required=false) MultipartFile[] upFiles,
			HttpServletRequest request,
			RedirectAttributes redirectAttr) {

	//1. 파일을 서버컴퓨터에 저장
	List<Attachment> attachList  = new ArrayList<>();
	String saveDirectory = request.getServletContext().getRealPath("/resources/upload/board");

	for(MultipartFile f : upFiles) {

		if(!f.isEmpty() && f.getSize() != 0) {

			//1. 파일명 생성
			String renamedFileName = Utils.getRenamedFileName(f.getOriginalFilename());

			//2. 메모리의 파일 -> 서버경로상의 파일 
			File newFile = new File(saveDirectory, renamedFileName); //임의의 자바파일객체를 만들고 이동시킴
			try {
				f.transferTo(newFile);
			} catch (IllegalStateException | IOException e) {
				e.printStackTrace();
			}
            
			//3. attachment객체 생성(db 저장을 위한 준비)
			Attachment attach = new Attachment();
			attach.setOriginalFileName(f.getOriginalFilename());
			attach.setRenamedFileName(renamedFileName);
			attachList.add(attach);
		}
	}
	board.setAttachList(attachList);
    
	//2. 게시글, 첨부파일정보를 DB에 저장
	try {
		int result = boardService.insertBoard(board);
		redirectAttr.addFlashAttribute("msg", "게시글 등록 성공!");
	} catch(Exception e) {
		log.error("게시물 등록 오류", e);
		redirectAttr.addFlashAttribute("msg", "게시글 등록 실패!");

		//예외발생을 spring container에게 전달 : 지정한  예외페이지로 응답처리
		throw e;
	}

	return "redirect:/board/boardList.do";
}

 

 

2. 게시글, 첨부파일정보를 DB에 저장
> insertBoard 해주고 BoardServiceImpl에서 설정 잘 해주기!

(성공하면 다 성공, 실패하면 전체 실패 => 트랜젝션 처리필요)

> Service에서 트랜젝션 설정해줄때 attachment에 들어갈 boardNo가 없음
> boardNo를 위해 mapper.xml에서 쿼리안에 쿼리 하나 더 날림 <selectKey>를 이용해 그 안에 작성한 쿼리의 조회 결과를 keyProperty에 담을 수 있음!
> 이렇게 하면 board객체안에 no가 들어가 있음
> attach.setBoardNo(board.getNo()); 를 해주고 insert해주면 boardNo가 잘 들어가 있을것임
> 이후 insert해주기 result = boardDAO.insertAttachment(attach);

트랜잭션처리 직접 안하고 스프링에서는 트랜잭션 매니저가 알아서 처리해줌
트랜잭션 설정하고 예외만 잘 던져주면 알아서 처리함
jdbc, mybatis에서 각각 Connection객체, SqlSession객체에 대해서 commit/rollback을 했던 것과 달리
spring에서는 트랜잭션관리자가 처리하게됨(IOC)

반응형
복사했습니다!