6. 사용자 정의 인터셉터 만들기

Beat의 사용자 정의 인터셉터는 다음과 같은 형식으로 만든다.

1. web.annotation에 인터셉터 어노테이션을 만든다. 어노테이션의 형식은 다음과 같다.

  1. /src/web/annotation/SetBoardDao.java 
  2. package web.annotation;

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    import net.kldp.beat.annotation.Beat;

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
  3. @Inherited
    @Beat
    public @interface SetBoardDao {
    }

2. web.controller에 인터셉터 클래스를 만든다. 인터셉터 클래스는 net.kldp.beat.interceptor 패키지의 BeforeInterceptor, AfterInterceptor 중 하나를 구현하여야 하고, intercept메서드를 제공하여야 한다. 이들 인터페이스는 각각 전처리 인터셉터, 후처리 인터셉터로 BeforeInterceptor는 컨트롤러의 execute메서드가 실행되기 직전에 실행되고, AfterInterceptor는 View가 디스패치된 후에 실행된다. 만약 전후처리 인터셉터를 구현하려면, BeforeInterceptor와 AfterInterceptor모두를 구현한다. 주의하여야 할 점은 인터셉터 클래스의 이름은 반드시 Interceptor로 끝나야 한다는 것이다. 예를들어 어노테이션의 이름이 LoginRequired일 경우 인터셉터의 이름은 LoginRequiredInterceptor이어야 한다.
구현해야하는 intercept메서드에는 인자로 컨트롤러 클래스의 객체와 정의된 인터셉터 어노테이션 인스턴스가 넘어온다. intercept메서드는 boolean값을 리턴해야 하는데, 만약 intercept메서드에서 false를 리턴하는 경우, 컨트롤러와 View는 결코 실행되지 않는다. 인터셉터는 투명한 막처럼 겹겹히 실행될 수 있는데, 컨트롤러와 View가 실행되기 위해서는 이들 인터셉터 클래스의 intercept메서드에서 모두 true를 리턴해야 한다. 만약 어느 인터셉터 하나라도 false를 리턴하는 경우, 이들 인터셉터가 모두 실행되면 액션은 자동적으로 끝난다.

  1. /src/web.interceptor/SetBoardDaoInterceptor.java 
  2. package web.interceptor;
  3. import java.lang.annotation.Annotation;
  4. import net.kldp.beat.interceptor.BeforeInterceptor;
  5. import net.kldp.beat.exception.InterceptorException;
  6. import web.aware.SetBoardDaoAware;
  7. import web.dao.BoardDao; 

  8. public class SetBoardDaoInterceptor implements BeforeInterceptor {
  9.     public boolean intercept(Object action, Annotation annotation) throws InterceptorException {
  10.         SetBoardDaoAware aware = (SetBoardDaoAware) action;
  11.         BoardDao dao = new BoardDao(); 
  12.         aware.setBoardDao(dao);
  13.     }
  14. }

3. web.aware 패키지에 인터셉터 인터페이스를 만든다.(옵션) 여기에 작성된 인터페이스를 컨트롤러가 상속받게 함으로써 인터셉터 클래스의 intercept 메서드에서 인자로 주어진 컨트롤러 클래스의 인스턴스를 캐스트 하여 컨트롤러에 의존성을 주입할 수 있다.  필수는 아니지만 Aware 인터페이스는 관습적으로 Aware로 끝난다.  만약 어노테이션의 이름이 LoginRequired일 경우 인터셉터 인터페이스의 이름은 LoginRequiredAware이다.

  1. /src/web/aware/SetBoardDaoAware.java 
  2. package web.aware;
  3. import web.dao.BoardDao; 
  4. public interface SetBoardDaoAware {
  5.     void setBoardDao(BoardDao dao);
  6. }

이로써 사용자 인터셉터를 만들었다. 이 인터셉터는 다음과 같이 컨트롤러에 사용될 수 있다.

  1. /src/web/controller/BoardAction.java 
  2. package web.controller;
  3. import web.annotation.SetBoardDao;
  4. import web.aware.SetBoardDaoAware;
  5. import web.dao.BoardDao; 
  6. @SetBoardDao
  7. public class BoardAction implements SetBoardDaoAware {
  8.     private BoardDao dao;
  9.     public void setBoardDao(BoardDao dao) {
  10.         this.dao = dao;
  11.     }
  12.     public String execute() {
  13.        // Do something
  14.     }
  15. }

또한 다음과 같이 어노테이션을 Aware 인터페이스에 삽입함으로써 액션 클래스에서 Aware인터페이스를 구현하는것 만으로도 어노테이션을 선언한 효과를 나타낼 수 있다.

  1. /src/web/aware/SetBoardDaoAware.java 
  2. package web.aware;
  3. import web.annotation.SetBoardDao;
  4. import web.dao.BoardDao;
  5. @SetBoardDao
  6. public interface SetBoardDaoAware {
  7.     public void setBoardDao(BoardDao dao) {
  8.     }
  9. }

위와같이 Aware 인터페이스에 어노테이션을 선언했다면 컨트롤러 클래스에서 어노테이션을 선언할 필요가 없어진다. 만약 컨트롤러에 같은 어노테이션이 선언된다면 그 어노테이션값은 덮어써진다.

 

또한 사용자 인터셉터역시 net.kldp.beat.system.aware 패키지의 인터페이스를 구현함으로써 서블릿에 종속적인 객체에 접근할 수 있다. 특별한 예외는 ValidationAware이다. 인터셉터에 ValidationInterceptor 지원은 되지 않는다. 또한 파일 업로드 인터셉터인 MultipartInterceptor역시 지원 되지 않는다. 이들 인터셉터는 컨트롤러 클래스에만 지원될 수 있다.

  1. /src/web/controller/LoginRequiredInterceptor.java 
  2. package web.interceptor;
  3. import java.lang.annotation.Annotation;
  4. import java.util.Map;
  5. import net.kldp.beat.system.aware.SessionMapAware;
  6. import net.kldp.beat.interceptor.BeforeInterceptor;
  7. import web.model.User; 
  8. public class LoginRequiredInterceptor implements BeforeInterceptor, SessionMapAware {
  9.     private Map<String, Object> session;
  10.     private void setSession(Map<String, Object> session) {
  11.         this.session = session;
  12.     }
  13.     public boolean intercept(Object action, Annotation annotation) {
  14.         User user = session.get("user");
  15.         // Do something;
  16.     }
  17. }

Session In View 패턴

이전에 언급한것과 같이 BeforeInterceptor와 AfterInterceptor 모두를 구현하는 인터셉터를 정의할 경우 요청을 둘러싸는 인터셉터를 만들 수 있다. 요청이 시작하기전에 자원을 초기화하고, 요청을 끝낼때 자원을 해제하는 용도로 사용될 수 있다. 이를 이용하면 서블릿 필터를 사용하지 않고도, 하이버네이트의 Session In View 패턴을 적용할 수 있다. 다음은 SessionInView 패턴을 이용하는 인터셉터이다.

  1. /src/web/interceptor/SessionInViewInterceptor.java 
  2. package web.interceptor; 
  3. import net.kldp.beat.interceptor.BeforeInterceptor;
  4. import net.kldp.beat.interceptor.AfterInterceptor; 
  5. import net.kldp.beat.exception.InterceptorException;
  6. // import others 
  7. public class SessionInViewInterceptor implements BeforeInterceptor, AfterInterceptor { 
  8.     private boolean flag = false; 
  9.     public boolean intercept(Object action, Annotation annotation) throws InterceptorException { 
  10.         try {
  11.             if(!flag) {
                    //"Starting a database transaction";
  12.                 sf.getCurrentSession().beginTransaction();
  13.                 flag = true; 
  14.             } else { 
  15.                 // "Committing the database transaction";
                    sf.getCurrentSession().getTransaction().commit();
  16.             } 
  17.         } catch (StaleObjectStateException staleEx) {
                throw staleEx;
            } catch (Throwable ex) {
                // Rollback only
                  try {
                    if (sf.getCurrentSession().getTransaction().isActive()) {
                        // "Trying to rollback database transaction after exception";
                        sf.getCurrentSession().getTransaction().rollback();
                    }
                } catch (Throwable rbEx) {
                    // Could not rollback transaction after exception!;
                }
  18.             // Let others handle it... maybe another interceptor for exceptions?
                throw new InterceptorException(ex);
            }

 

< 이전 | 다음 >