2016년 1월 25일 월요일

spring file uplode size 다양하게설정하기

2011년 10월에 네이버블로그에 올렸던 내용을 이곳으로 모아서 게시한다. 최근에 업무에서도 요긴하게 사용했다.

1. 요구사항
- 첨부파일의 크기를 업무별로 다르게 설정해야 한다. 예를 들면 일반게시판에는 20메가, 연계게시판에는 10메가

2. 제약사항
- Spring에서 일반적으로 사용하는 CommonsMultipartResolver에서는 maxUploadSize를 한가지만 지정할 수 있다.
- 제한하고자 하는 크기는 자바 클래스에 상수로 선언하여 사용해야 한다.
- 제한된 크기를 초과하는 경우, 컨트롤러 레이어에서 에러메시지나 에러페이지 등을 제어해야한다. (즉, Spring에서 제공하는 ExceptionResolver 등을 사용하지 않는다)

3. 해결방법
- CommonsMultipartResolver를 상속하여 resolveMultipart() 메서드를 오버라이딩하여 요청 URL에 따라서 각각의 업무클래스에 정의된 maxFileSize 상수로 maxUploadSize를 설정한다.
- super.resolveMultipart(request) 메서드 처리중에 발생한 MaxUploadSizeExceededException을 잡아서 Exception 객체를 attribute로 추가한 request를 리턴하여 컨트롤러 레이어까지 처리흐름이 이어지도록 한다.
public class CustomMultipartResolver extends CommonsMultipartResolver {

        @Override
        public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException {

               // 요청URL의 path에 따라서 결정된 세부업무별로 maxUploadSize 설정
               String url = request.getRequestURI();
               int maxFileSizeMB = 0;
              
               // 게시판
               if( url.startsWith("/au/signbbs/") ) {
                       maxFileSizeMB = AuBoardFileConstant.getMaxFileSize();
               }
               // 연계게시판
               else if( url.startsWith("/au/connect/") ) {
                       maxFileSizeMB = AuBoardFileConstant.getMaxFileSize();
               }
               else {
                       throw new MultipartException("예상치 못한 url에서 파일업로드 시도함. AuMultipartResolver.resolveMultipart()에 추가 필요");
               }
              
               setMaxUploadSize(maxFileSizeMB * 1024 * 1024);
               setMaxInMemorySize(maxFileSizeMB * 1024 * 1024);
              
               try {
                       return super.resolveMultipart(request);
               } catch (MaxUploadSizeExceededException e) {
                       // 파일사이즈초과되어도 에러메시지를 위해서 request 리턴하여 컨트롤러 메서드 호출되도록 한다.
                       request.setAttribute("exception", e);
                       return new DefaultMultipartHttpServletRequest(request, new HashMap(), new HashMap());
               }
        }
}

- 새로 만든 MultipartResolver 클래스를 Spring 설정 xml에 CommonsMultipartResolver 대신 등록한다.
<!-- 세부업무별로 파일업로드 사이즈 제한 -->
<bean id="multipartResolver" class="common.CustomMultipartResolver" />

- 컨트롤러 레이어에서는 request에서 가져온 MultipartFile 객체가 null인 경우를 확인하여 예외처리를 해준다. reqeuest에 MaxUploadSizeExceededException 객체가 있다면 적당한 메시지를 생성하여 UI로 에러메시지를 보내도록 한다.
// request에서 파일을 찾아서 MultipartFile 객체로 생성한다.
MultipartFile file = multipartRequest.getFile("attachfile");

// 최대업로드사이즈 초과 체크
if( file == null ) {
    Exception e = (Exception)multipartRequest.getAttribute("exception");
    if( e instanceof MaxUploadSizeExceededException ) {
       long maxFileSizeMB = (((MaxUploadSizeExceededException)e).getMaxUploadSize() / 1024 / 1024);
       errorMsg = "첨부파일 사이즈는 " + maxFileSizeMB + "M 를 초과할 수 없습니다.";
    }
    Log.error(e, "파일생성 중 예외발생");
    return "/error";
}

4. 활용방안
- 로그인한 회원의 권한에 따라서 크기를 다르게 설정해야 하는 요건의 경우에도 활용가능하다. 이를 테면 관리자 권한이나 수퍼유저의 경우 일반유저보다 큰 파일을 업로드 할 수 있다.

5. 개선할 점
- 요청 URL에 따라서 다른 상수클래스를 사용하는 부분에서 요청 URL이 하드코딩 되어있다. 그런데 명명규칙이 표준화되어 있어서 요청 URL과 상수클래스간에 일정한 규칙이 존재한다면 하드코딩된 부분을 제거할 수 있고, 이후 추가되는 업무에 따른 URL에 대해서도 소스코드 수정없이 적용이 가능할 것이다.

6. 참고

댓글 없음:

댓글 쓰기