Статьи

Использование Spring Interceptors в вашем MVC Webapp

Я подумал, что пришло время взглянуть на механизм перехватчика Spring MVC, который существует уже много лет и является действительно полезным инструментом.

Spring Interceptor делает то, что говорит на жестяной панели: перехватывает входящий HTTP-запрос до того, как он достигнет вашего класса контроллера Spring MVC, или наоборот, перехватывает исходящий HTTP-ответ после того, как он покидает ваш контроллер, но до того, как он возвращается обратно в браузер.

Вы можете спросить, какая польза для вас? Ответ заключается в том, что он позволяет вам выполнять задачи, которые являются общими для каждого запроса или набора запросов, без необходимости вырезать и вставлять код котельной пластины в каждый класс контроллера. Например, вы можете выполнить проверку подлинности пользователя для запроса до того, как он достигнет вашего контроллера, и, в случае успеха, получить некоторые дополнительные сведения о пользователе из базы данных, добавив их в объект HttpServletRequest до вызова вашего контроллера. Затем ваш контроллер может просто получить и использовать эти значения или оставить их для отображения JSP. С другой стороны, если аутентификация не пройдена, вы можете перенаправить пользователя на другую страницу.

Демонстрационный код показывает, как изменить входящий объект HttpServletRequest до того, как он достигнет вашего контроллера. Это просто добавление к запросу простой строки, но, как я уже говорил выше, вы всегда можете сделать вызов базы данных, чтобы получить некоторые данные, которые требуются при каждом запросе … вы даже можете добавить некоторую оптимизацию и сделать кеширование на этом этапе.

public class RequestInitializeInterceptor extends HandlerInterceptorAdapter {

  // Obtain a suitable logger.
  private static Log logger = LogFactory
      .getLog(RequestInitializeInterceptor.class);

  /**
   * In this case intercept the request BEFORE it reaches the controller
   */
  @Override
  public boolean preHandle(HttpServletRequest request,
      HttpServletResponse response, Object handler) throws Exception {
    try {

      logger.info("Intercepting: " + request.getRequestURI());

      // Do some changes to the incoming request object
      updateRequest(request);

      return true;
    } catch (SystemException e) {
      logger.info("request update failed");
      return false;
    }
  }

  /**
   * The data added to the request would most likely come from a database
   */
  private void updateRequest(HttpServletRequest request) {

    logger.info("Updating request object");
    request.setAttribute("commonData",
        "This string is required in every request");
  }

  /** This could be any exception */
  private class SystemException extends RuntimeException {

    private static final long serialVersionUID = 1L;
    // Blank
  }
}

В приведенном выше коде я выбрал самый простой метод реализации, расширив класс HandlerInterceptorAdaptor, переопределив метод preHandle (..). Мой метод preHandle (…) выполняет обработку ошибок, решая, что делать в случае возникновения ошибки, и возвращает false, если это происходит. При возврате false цепочка перехватчика разрывается и ваш класс контроллера не вызывается. Фактическая работа с объектом запроса делегируется в updateRequest (запрос).

Класс HandlerInterceptorAdaptor имеет три метода, каждый из которых является заглушкой и, при желании, может быть проигнорирован. Методы: prehandle (…), postHandle (…) и afterCompletion (…), и дополнительную информацию об этом можно найти в документации по API Spring . Имейте в виду, что это может несколько сбивать с толку, поскольку документация по классам перехватчика обработчика по- прежнему ссылается на классы контроллера MVC по их именам обработчиков Spring 2 . Этот момент легко продемонстрировать, если вы посмотрите на третий параметр prehandle (…) типа Object и вызываемого обработчика. Если вы проверите это в своем отладчике, вы увидите, что это экземпляр вашего класса контроллера. Если вы новичок в этой технике, просто помните, что контроллер == обработчик,

Следующим шагом в реализации перехватчика, как всегда, является добавление чего-либо в конфигурационный файл Spring XML:

<!-- Configures Handler Interceptors --> 
<mvc:interceptors>  
 <!-- This bit of XML will intercept all URLs - which is what you want in a web app -->
 <bean class="marin.interceptor.RequestInitializeInterceptor" />

 <!-- This bit of XML will apply certain URLs to certain interceptors -->
 <!-- 
 <mvc:interceptor>
  <mvc:mapping path="/gb/shop/**"/>
  <bean class="marin.interceptor.RequestInitializeInterceptor" />
 </mvc:interceptor>
  -->
</mvc:interceptors>

Приведенный выше XML демонстрирует либо / или выбор добавления перехватчика ко всем URL-адресам запроса, либо, если вы посмотрите на закомментированный раздел, добавление перехватчика к конкретным URL-адресам запроса, что позволяет вам выбирать, какие URL-адреса подключены к вашему классу перехватчика.

Читатели с орлиными глазами могли заметить, что классы перехватчиков используют наследование и XML-конфигурацию в качестве метода реализации. В эти дни соглашения по конфигурации, этот шаблон начинает выглядеть немного измученным и, вероятно, мог бы сделать с хорошим капитальным ремонтом. Одним из предложений было бы улучшить всю партию, чтобы использовать аннотации, применяя те же методы, которые уже были добавлены в механизм контроллера. Это добавило бы дополнительную гибкость без усложнения использования всех интерфейсов и абстрактных базовых классов. В качестве предложения, будущая реализация класса перехватчиков может выглядеть примерно так:

  @Intercept(value = "/gb/en/*", method = RequestMethod.POST)
  public boolean myAuthenticationHandler(HttpServletRequest request,
      Model model) {
    // Put some code here
  }

На этом мы заканчиваем рассмотрение перехватчиков Spring, следует помнить, что я продемонстрировал только самую базовую реализацию — я могу добавить дополнительные примеры в другой день …

 

От http://www.captaindebug.com/2011/09/using-spring-interceptors-in-your-mvc.html