Рубрики
Без рубрики

Введение в Spring MVC HandlerInterceptor

Краткое и практическое руководство по обработчику Spring MVC.

Автор оригинала: baeldung.

1. введение

В этом уроке мы сосредоточимся на понимании Spring MVC HandlerInterceptor и на том, как правильно его использовать.

2. Обработчик Spring MVC

Чтобы понять перехватчик, давайте сделаем шаг назад и посмотрим на отображение обработчика . Это сопоставляет метод с URL-адресом, так что DispatcherServlet сможет вызвать его при обработке запроса.

И DispatcherServlet использует HandlerAdapter для фактического вызова метода.

Теперь, когда мы понимаем общий контекст – вот где появляется перехватчик обработчика . Мы будем использовать HandlerInterceptor для выполнения действий до обработки, после обработки или после завершения (при отображении представления) запроса.

Перехватчик можно использовать для сквозных задач и для того, чтобы избежать повторяющегося кода обработчика, такого как ведение журнала, изменение глобально используемых параметров в модели Spring и т. Д.

В следующих нескольких разделах мы рассмотрим именно это – различия между различными реализациями перехватчиков.

3. Зависимости Maven

Чтобы использовать Перехватчики , вам необходимо включить следующий раздел в раздел зависимости вашего pom.xml файл:


    org.springframework
    spring-web
    5.2.8.RELEASE

Последнюю версию можно найти здесь .

4. Spring HandlerInterceptor

Перехватчики | работающие с отображением обработчика в фреймворке, должны реализовать интерфейс HandlerInterceptor|/.

Этот интерфейс содержит три основных метода:

  • prehandle() – вызывается до выполнения фактического обработчика, но представление еще не создано
  • postHandle() – вызывается после выполнения обработчика
  • afterCompletion() – вызывается после завершения полного запроса и создания представления

Эти три метода обеспечивают гибкость для выполнения всех видов предварительной и последующей обработки.

И краткое примечание – основное различие между HandlerInterceptor и HandlerInterceptorAdapter заключается в том, что в первом случае нам нужно переопределить все три метода: preHandle () , postHandle() и afterCompletion () , тогда как во втором мы можем реализовать только необходимые методы.

Краткое примечание, прежде чем мы пойдем дальше – если вы хотите пропустить теорию и перейти прямо к примерам, перейдите прямо в раздел 5.

Вот как будет выглядеть простая реализация pre Handle() :

@Override
public boolean preHandle(
  HttpServletRequest request,
  HttpServletResponse response, 
  Object handler) throws Exception {
    // your code
    return true;
}

Обратите внимание, что метод возвращает логическое значение, которое сообщает Spring, должен ли запрос быть дополнительно обработан обработчиком ( true ) или нет ( false ).

Далее, у нас есть реализация post Handle() :

@Override
public void postHandle(
  HttpServletRequest request, 
  HttpServletResponse response,
  Object handler, 
  ModelAndView modelAndView) throws Exception {
    // your code
}

Этот метод вызывается сразу после обработки запроса HandlerAdapter , но перед созданием представления.

И, конечно, его можно использовать по – разному-например, мы можем добавить в модель аватар вошедшего в систему пользователя.

Последний метод, который нам нужно реализовать в пользовательской реализации HandlerInterceptor , – это после завершения():

@Override
public void afterCompletion(
  HttpServletRequest request, 
  HttpServletResponse response,
  Object handler, Exception ex) {
    // your code
}

Когда представление успешно сгенерировано, мы можем использовать этот крюк для сбора дополнительной статистики, связанной с запросом.

Последнее замечание, которое следует помнить, заключается в том, что HandlerInterceptor зарегистрирован в DefaultAnnotationHandlerMapping bean, который отвечает за применение перехватчиков к любому классу, помеченному аннотацией @Controller . Кроме того, вы можете указать любое количество перехватчиков в своем веб-приложении.

5. Пользовательский перехватчик регистратора

В этом примере мы сосредоточимся на регистрации в нашем веб-приложении. Прежде всего, наш класс должен расширить HandlerInterceptorAdapter :

public class LoggerInterceptor extends HandlerInterceptorAdapter {
    ...
}

Нам также необходимо включить вход в наш перехватчик:

private static Logger log = LoggerFactory.getLogger(LoggerInterceptor.class);

Это позволяет Log4J отображать журналы, а также указывать, какой класс в данный момент записывает информацию в указанный вывод.

Далее давайте сосредоточимся на пользовательских реализациях перехватчиков:

5.1. Способ предварительной обработки()

Этот метод вызывается перед обработкой запроса; он возвращает true, , чтобы позволить фреймворку отправить запрос дальше методу обработчика (или следующему перехватчику). Если метод возвращает false , Spring предполагает, что запрос был обработан и дальнейшая обработка не требуется.

Мы можем использовать хук для регистрации информации о параметрах запросов: откуда поступает запрос и т. Д.

В нашем примере мы регистрируем эту информацию с помощью простого регистратора Log4J:

@Override
public boolean preHandle(
  HttpServletRequest request,
  HttpServletResponse response, 
  Object handler) throws Exception {
    
    log.info("[preHandle][" + request + "]" + "[" + request.getMethod()
      + "]" + request.getRequestURI() + getParameters(request));
    
    return true;
}

Как мы видим, мы регистрируем некоторую основную информацию о запросе.

В случае, если мы столкнемся здесь с паролем, нам, конечно, нужно будет убедиться, что мы его не зарегистрируем.

Простой вариант-заменить пароли и любые другие конфиденциальные данные звездочками.

Вот краткое описание того, как это можно сделать:

private String getParameters(HttpServletRequest request) {
    StringBuffer posted = new StringBuffer();
    Enumeration e = request.getParameterNames();
    if (e != null) {
        posted.append("?");
    }
    while (e.hasMoreElements()) {
        if (posted.length() > 1) {
            posted.append("&");
        }
        String curr = (String) e.nextElement();
        posted.append(curr + "=");
        if (curr.contains("password") 
          || curr.contains("pass")
          || curr.contains("pwd")) {
            posted.append("*****");
        } else {
            posted.append(request.getParameter(curr));
        }
    }
    String ip = request.getHeader("X-FORWARDED-FOR");
    String ipAddr = (ip == null) ? getRemoteAddr(request) : ip;
    if (ipAddr!=null && !ipAddr.equals("")) {
        posted.append("&_psip=" + ipAddr); 
    }
    return posted.toString();
}

Наконец, мы стремимся получить исходный IP-адрес HTTP-запроса.

Вот простая реализация:

private String getRemoteAddr(HttpServletRequest request) {
    String ipFromHeader = request.getHeader("X-FORWARDED-FOR");
    if (ipFromHeader != null && ipFromHeader.length() > 0) {
        log.debug("ip from proxy - X-FORWARDED-FOR : " + ipFromHeader);
        return ipFromHeader;
    }
    return request.getRemoteAddr();
}

5.2. Способ послеоперационной обработки()

Этот хук запускается, когда HandlerAdapter вызывает обработчик, но DispatcherServlet еще не отрисовал представление.

Мы можем использовать этот метод для добавления дополнительных атрибутов в ModelAndView или для определения времени, необходимого методу обработчика для обработки запроса клиента.

В нашем случае мы просто регистрируем запрос непосредственно перед тем, как DispatcherServlet будет отображать представление.

@Override
public void postHandle(
  HttpServletRequest request, 
  HttpServletResponse response,
  Object handler, 
  ModelAndView modelAndView) throws Exception {
    
    log.info("[postHandle][" + request + "]");
}

5.3. Метод после завершения()

Когда запрос завершен и представление визуализировано, мы можем получить данные запроса и ответа, а также информацию об исключениях, если таковые имели место:

@Override
public void afterCompletion(
  HttpServletRequest request, HttpServletResponse response,Object handler, Exception ex) 
  throws Exception {
    if (ex != null){
        ex.printStackTrace();
    }
    log.info("[afterCompletion][" + request + "][exception: " + ex + "]");
}

6. Конфигурация

Чтобы добавить наши перехватчики в конфигурацию Spring, нам нужно переопределить addInterceptors() метод внутри Web Config класса, реализующего WebMvcConfigurer:

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new LoggerInterceptor());
}

Мы можем достичь той же конфигурации, отредактировав наш файл конфигурации XML Spring:


    

Если эта конфигурация активна, перехватчик будет активен, и все запросы в приложении будут правильно регистрироваться.

Обратите внимание, что если настроено несколько перехватчиков Spring, метод preHandle() выполняется в порядке конфигурации, тогда как методы postHandle() и afterCompletion() вызываются в обратном порядке.

Если мы используем Spring Boot вместо vanilla Spring, мы должны иметь в виду, чтобы не аннотировать наш класс конфигурации с помощью @EnableWebMvc , или мы потеряем автоматические конфигурации загрузки.

7. Заключение

Этот учебник представляет собой краткое введение в перехват HTTP-запросов с помощью перехватчика обработчика Spring MVC.

Все примеры и конфигурации доступны здесь на GitHub .