2009년 12월 8일 화요일

SpringMVC 에서 파일업로드 처리하기


SpringMVC 에서 파일업로드 처리하기

spring MVC에서 파일 업로드를 구현하기 위해서는 자카르타 commons와 오라일리의 cos 업로드 라이브러리를 사용할 수 있다.

스프링 2.5 버전부터 cos 업로드 라이브러리 지원을 하지 않는다고 한다...

먼저 빈설정파일에 MultipartResolver를 정의하여, request가 MultipartResolver에 의해 처리되게 한다

 

아래에서는 commons의 MultipartResolver를 사용하고, 파일이름 인코이름 인코딩은 EUC-KR, 파일당 최대업로드 사이즈는 10MB,  

임시디렉토리는 c:/temp/ 롤 설정하고 있다.

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
       <property name="defaultEncoding" value="EUC-KR"/>
        <property name="maxUploadSize" value="10000000"/>
        <property name="uploadTempDir" value="uploadTempDir"/>
    </bean>

 

<bean id="uploadTempDir" class="org.springframework.core.io.FileSystemResource">
        <constructor-arg value="c:/temp/"/>
    </bean>

위와 같이 설정하면, 컨트롤러에서 request를 MultipartRequest 로 타입캐스팅하여 , 지원하는 내부메소드를 사용하여 업로드를 구현할 수 있다.

 

  1.     MultipartRequest mRequest = (MultipartRequest)request;

  2.          // iterator를 추출하여, 파일개수에 상관없이 처리할 수 있다.  
  3.         Iterator iter = mRequest.getFileNames();
            //  하나의 파일에 대한 정보를 갖는 클래스를 사용할 수 있다.
            MultipartFile file1 = mRequest.getFile("file1");
           
            String tempName = UUID.randomUUID().toString();
           
            File file = new File(this.uploadPath, tempName);
  4.         // 임시저장 공간에서 file이 명시하는 위치에 파일을 이동시킨다.
            file1.transferTo(file);

 

모델(command) 객체에 List를 선언하고, html에서 name속성을 file[0], file[1], file[2] 과 같이 배열형태로 접근하면,

List 에  MultipartFile 타입으로 파일정보가 담기게 되는데, 이 List를 얻어 업로드 처리를 수행할 수 도 있다.

 

 

SimpleFormController

SimpleFormController는 폼출력과 폼에서 입력한 데이터를 처리하는 작업을 하나의 컨트롤에서 다룰 수 있게 하였다.

메소드가 GET ,  POST  여부에 의해 서로 다른 메소드들의 흐름을 가지고 있다.  꽤 복잡한 흐름을 가지고 있는 것처럼 보이지만,

폼과 폼처리를 한 클래스에서 처리하기 위해 해야할 일들을 잘 분리하여, 필요시 오버라이딩하여 사용할 수 있게 만들어 놓았다.

다음은 중요한 메소드들만 요약한 것이다.

 

 GET 방식으로 요청시

formBackingObject() 메소드가 가장먼저 실행된다.  spring 에서 이 메소드의 디폴트 구현은 Command Class를 생성하여 반환하는 작업을 수행한다.

regist와 edit를 한번에 해주고 싶을 경우는 이 메소드를 오버라이드하여  edit 인 경우 데이터를 DB에서 가져와야 한다.

 

referenceData() 에서는 비지니스 로직 데이터 외에 부가적으로 뷰에서 보여줘야할 데이터가 있을 경우, DB에서 데이터를 가져와 ModelAndView에

담아줄 수 있다. GET 방식의 처리가 다 끝나면  SimpleFormController 빈에서 설정한 formView 로 ModelAndView를 전달한다

 

 

 POST 방식의요청일 경우는 좀더  복잡하다.

formBackingObject() 메소드 호출을 통해, Command Class를 생성하고

onBind(), validate() , onBindAndValidate() 메소드들이 호출되는데, 바인딩시, 유효성 후, 바인딩과 유효성검사가 모두 끝난 후에 무엇인가

해줘야 할 경우 이 메소드들을 재정의하여 사용하면 된다. validate() 메소드를 재정의 하여, 유효성 검사시 에러가 발생하면, formView로 되돌아가게 된다.

이 메소드들이 실행되고 나서, onSubmit() 메소드가 호출되고, 예외없이 끝나게 되면 successView로 ModelAndView와 함께 전달되게 되고,

BindException 타입의 인자 errors에 에러메시지가 담기게 되면, 역시 formView로 되돌아가게 된다.

 

 

iBATIS - SqlMapClientDaoSupport 사용하기

SqlMapClientDaoSupport는 스프링이 기존 SqlMapClient 객체에 예외처리와 트랜잭션 처리를 통합적으로  구현하여,  제공하는 클래스이다.

이 클래스를 사용하면 좀더 깔끔하게 Dao 부분을 작성할 수 있는 장점이 있지만, Dao 부분이 Spring 프레임웍에 종속적이게 된다.

SqlMapClient 빈을 그대로 인젝션 받되.  SqlMapClientDaoSupport에서 SqlMapClient 빈에 예외처리, 트랜잭션 처리 등을 내부적으로 해주는

SqlMapClientTemplate() 메소드를 사용하면 더이상 지저분하게 예외처리를 하지 않아도 되어 깔끔한 코드를 작성할 수 있다.

하지만 이것을 사용하므로 얻게 되는 장점과 단점을 고려하여, 적합한 판단을 내려 사용하자

 

다음은 SqlMapClientTemplate를 사용하는 방법을 보여준다

보는 봐와 같이, SqlMapClient setter를 SqlMapClientDaoSupport를 제공하고 있기 때문에 별도로 setter를 구현할 필요 없다

  1.  public class BoardDaoiBATIS extends SqlMapClientDaoSupport implements BoardDao {
  2.     public void insertBoard(Board board) {
         getSqlMapClientTemplate().insert("kr.co.bit.lecture.board.Board.insertBoard", board);
        }
  3. }

 

  1. <bean id="boardDao" class="kr.co.bit.lecture.board.dao.ibatis.BoardDaoiBATIS">        
      <property name="sqlMapClient" ref="sqlMapClient"/>                                    // 기존과 동일하게 sqlMapClient 빈을 인젝션해주면 됨
     </bean>

 

 

 

DWR 에서 session에 접근하기

DWR 은 자바스크립트 측에서 서버단의 자바객체를 원격으로 호출하는 개념을 가지고 있기 때문에 , session을 사용하여 로그인 여부 검증이 들어가야하는

부분에 대해 제약을 가지고 있다. session 을 service 단에서 사용하면, 특정기술(servlet) 에 종속성이 생겨버린다. 이를 위해 service 객체를 감싸는

serviceDwr을 구현하여 내부에서 session 객체와 service를 사용하여 원하는 기능을 구현하게 할 수 있다.

 

다음은 CommentDwr 클래스 내부에서 CommentService 비지니스 로직 클래스와 session을 사용하여, 회원가입을 처리 하는 코드이다.

 

public Class CommentSeriviceDwr {

private CommentService commentService  

public int regist(Comment comment) {
 
        WebContext webContext = WebContextFactory.get();      // dwr에서 session을 사용할 수 있도록 하는 클래스
        HttpSession session  = webContext.getSession(true);
        if (session == null) {                                                               // session이 invalidate() 되어 있는 경우
            return -1;
        }
        String userId = (String)session.getAttribute(this.sessionUserIdKey);
        if (userId == null) {                                                                 // session 키에 null 처리가 되어 있는 경우
            return -2;
        }

        // 회원가입 처리
        return 0;
    }

}

 

 

 bean 생성 scope 지정하기

디폴트로 bean은 sigleton을 생성되지만, 생성 scope를 변경해 줄 수도 있다.

지정할 수 있는 scope는 총 5개로  singlton, request, session, prototype,  potlet-session 이 있다.

 singleton은 빈을 1개만 생성하며, request와 session은 하나의 request 또는 session 당 빈을 생성해준다.

prototype 는 매번 빈을 생성해주며, 쓰레드에 안전하게 사용할 수 있지만 그만큼 오버헤드가 크다.

potlet-session은....


출처 : http://hiddenviewer.springnote.com/pages/4424691



댓글 없음:

댓글 쓰기