Languages/java

[JAVA] 파일업로드02_해보기

뱅타 2021. 4. 12. 22:24

앞서 한 것들에게는

검증이 제대로 되어있지 않다.

  1. 저장하려는 폴더가 없다면 어떻게 할 것인가
  1. 실제로 이미지만 올라갈까?
  1. 널체크
  1. 버전을 타고있다.

jsp에서는 이렇게 작성했지만 실제로 넘어가는 값이 image만 있지 않을 가능성이 높다.

이러한 문제들을 한번 잡아보자.

1, 폴더가 없을 시

mkdirs()로 servletContext로 구한 경로의 모든 폴더들을 생성한다.

계층구조의 모든 폴더 생성.

이렇게 실제 폴더가 없을 시 폴더를 만들어 줌으로써 1번 해결.

2. 실제 이미지인가?

jsp에서는 image만 올리게끔 했지만 image가 올라오지 않을 수도 있다.

검증을 해주지 않을 시 오류가 뜨면 서버가 꺼질 수 있다.

타입을 가져와서 image/로 시작되는지 체크

mimetype을 check하고 오류를 상위로 올려준다.

실제 나는 오류를 handlerAdapter에서 잡아준다. (front , command pattern 참고.)

이렇게 작업해 주었기 때문에 해당 서버사이드에서 resp.senderror로 error를 처리 할 필요가 없다.

이렇게 이미지 파일을 검증한다.

3. 널체크하기

이렇게 null check

올라오는 파일이 두개. 그런데 각각 널체크를 하면 두번 해야하기 때문에

processPart 메소드를 생성해서 사용함.

4. 3.1버전에서만 쓸 수 있다.

getSubmittedFileName(); 메서드가 3.1 이상만 쓸 수 있다.

여기 보면

그러니 직접 파싱해 보자.

Content-Disposition을 부분을 들고와서 전처리를 해준다.

이렇게 파싱하고

맨 위에 녀석은 String타입이기 때문에 건너뛰게끔 하자. 오류난다.

이렇게 불러와서 쓰면 된다.

  • 코드
    package kr.or.ddit.fileupload.controller;
    
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Collection;
    
    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    import javax.servlet.http.Part;
    
    import org.apache.commons.lang3.StringUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import kr.or.ddit.mvc.annotation.Controller;
    import kr.or.ddit.mvc.annotation.RequestMapping;
    import kr.or.ddit.mvc.annotation.RequestMethod;
    import kr.or.ddit.mvc.annotation.resolvers.BadRequestException;
    import kr.or.ddit.mvc.annotation.resolvers.RequestParam;
    
    @Controller
    public class FileUploadController {
    	private static final Logger logger = 
    			LoggerFactory.getLogger(FileUploadController.class);
    	@RequestMapping("/fileUpload.do")
    	public String form() {
    		return "fileupload/uploadForm";
    	}
    	
    	@RequestMapping(value="/fileUpload.do", method=RequestMethod.POST)
    	public String upload(
    			@RequestParam("uploader") String uploader,
    			HttpServletRequest req, HttpSession session) throws IOException, ServletException {
    		
    		ServletContext application = req.getServletContext();
    		String saveFolderUrl = "/prodImages";
    		File saveFolder = new File(application.getRealPath(saveFolderUrl));
    		if(!saveFolder.exists()) {
    			saveFolder.mkdirs();
    		}
    		
    		Collection<Part> parts = req.getParts();
    		int index = 1;
    		for(Part tmp : parts) {
    			// 일반 파일이면(텍스트) 건너뛰어야한다.
    			if(tmp.getContentType()==null) {
    				continue;
    			}
    			String saveFileName = processPart(tmp, saveFolder);
    			String saveFileUrl = saveFolderUrl+"/"+saveFileName;
    			session.setAttribute("uploadFile"+index++, saveFileUrl);
    			logger.info("saveFile : {}", saveFileUrl);
    		}
    		
    		logger.info("uploader : {}", uploader);
    		return "redirect:/fileUpload.do";
    	}
    
    	private String getOriginalFilename(Part part) {
    //		Content-Disposition: form-data; name="uploadFile1"; filename="test.jpg"
    		String disposition = part.getHeader("Content-Disposition");
    		int index = disposition.indexOf("\"", disposition.indexOf("filename="));
    		String originalFilename = null;
    		if(index!=-1) {
    			originalFilename = disposition.substring(index).replace("\"", "");
    		}
    		return originalFilename;
    	}
    	
    	private String processPart(Part uploadFile1, File saveFolder) throws IOException {
    		String originalFilename1 = getOriginalFilename(uploadFile1);
    		// 원본 파일이 있는지 부터 검사.
    		if(StringUtils.isNotBlank(originalFilename1)) {
    			String mime1 = uploadFile1.getContentType();
    			if(!mime1.startsWith("image/")) {
    				throw new BadRequestException();
    			}
    			File saveFile1 = new File(saveFolder, originalFilename1);
    			
    			byte[] buffer = new byte[1024];
    			int  cnt = -1;
    			try(
    				InputStream is1 = uploadFile1.getInputStream();	
    				FileOutputStream fos1 = new FileOutputStream(saveFile1);
    			){
    				while((cnt = is1.read(buffer))!=-1) {
    					fos1.write(buffer,  0, cnt);
    				}
    			} // try end
    		}  // if end
    		return originalFilename1;
    	}
    }

위의 작업들을 실제 적용하기 위해서는 중복되는게 코드가 많다

중복되는 코드들을 프론트 컨트롤러에 적용해도 되지만 이미 프론트가 완성된 상황에서는 front controller를 수정하기 부담스럽다.

이때 Decorating Filter Pattern으로 front controller 를 수정하지 않고 사용할 수 있다.

D.F.P

728x90
반응형