«1. Введение

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

Если вы хотите прочитать об основах HandlerInterceptor, прочтите эту статью.

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

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

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.3.13</version>
</dependency>

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

Эта зависимость распространяется только на Spring Web, поэтому не забудьте добавить spring-core и spring-context для полноценного веб-приложения, а также библиотеку журналов по вашему выбору.

3. Пользовательская реализация

Одним из вариантов использования HandlerInterceptor является добавление в модель общих/специфических для пользователя параметров, которые будут доступны в каждом сгенерированном представлении.

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

Давайте начнем с определения нашего нового класса Interceptor:

public class UserInterceptor extends HandlerInterceptorAdapter {

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

    ...
}

Мы расширяем HandlerInterceptorAdapter, так как мы хотим реализовать только preHandle () и postHandle().

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

public static boolean isUserLogged() {
    try {
        return !SecurityContextHolder.getContext().getAuthentication()
          .getName().equals("anonymousUser");
    } catch (Exception e) {
        return false;
    }
}

Когда HttpSession установлен, но никто не вошел в систему, имя пользователя в контексте Spring Security равно анонимный пользователь. Далее приступаем к реализации preHandle():

3.1. Метод preHandle()

Перед обработкой запроса мы не можем получить доступ к параметрам модели. Чтобы добавить имя пользователя, нам нужно использовать HttpSession для установки параметров:

@Override
public boolean preHandle(HttpServletRequest request,
  HttpServletResponse response, Object object) throws Exception {
    if (isUserLogged()) {
        addToModelUserDetails(request.getSession());
    }
    return true;
}

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

private void addToModelUserDetails(HttpSession session) {
    log.info("=============== addToModelUserDetails =========================");
    
    String loggedUsername 
      = SecurityContextHolder.getContext().getAuthentication().getName();
    session.setAttribute("username", loggedUsername);
    
    log.info("user(" + loggedUsername + ") session : " + session);
    log.info("=============== addToModelUserDetails =========================");
}

Мы использовали SecurityContextHolder для получения loggedUsername. Вы можете переопределить реализацию Spring Security UserDetails для получения электронной почты вместо стандартного имени пользователя.

3.2. Метод postHandle()

После обработки запроса параметры нашей модели становятся доступными, поэтому мы можем получить к ним доступ для изменения значений или добавления новых. Для этого мы используем переопределенный метод postHandle():

@Override
public void postHandle(
  HttpServletRequest req, 
  HttpServletResponse res,
  Object o, 
  ModelAndView model) throws Exception {
    
    if (model != null && !isRedirectView(model)) {
        if (isUserLogged()) {
        addToModelUserDetails(model);
    }
    }
}

Давайте посмотрим на детали реализации.

Прежде всего, лучше проверить, не является ли модель нулевой. Это предотвратит возникновение исключения NullPointerException.

Более того, мы можем проверить, не является ли View экземпляром RedirectView.

Нет необходимости добавлять/изменять параметры после обработки запроса и последующего перенаправления, так как сразу же новый контроллер снова выполнит обработку. Чтобы проверить, перенаправлено ли представление, мы вводим следующий метод:

public static boolean isRedirectView(ModelAndView mv) {
    String viewName = mv.getViewName();
    if (viewName.startsWith("redirect:/")) {
        return true;
    }
    View view = mv.getView();
    return (view != null && view instanceof SmartView
      && ((SmartView) view).isRedirectView());
}

Наконец, мы снова проверяем, зарегистрирован ли пользователь, и если да, мы добавляем параметры в модель Spring:

private void addToModelUserDetails(ModelAndView model) {
    log.info("=============== addToModelUserDetails =========================");
    
    String loggedUsername = SecurityContextHolder.getContext()
      .getAuthentication().getName();
    model.addObject("loggedUsername", loggedUsername);
    
    log.trace("session : " + model.getModel());
    log.info("=============== addToModelUserDetails =========================");
}

~~ ~ Обратите внимание, что ведение журнала очень важно, так как эта логика работает «за кулисами» нашего приложения. Легко забыть, что мы изменяем некоторые параметры модели в каждом представлении, не регистрируя это должным образом.

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

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

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

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

<mvc:interceptors>
    <bean id="userInterceptor" class="com.baeldung.web.interceptor.UserInterceptor"/>
</mvc:interceptors>

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

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

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

В этом руководстве представлен перехват веб-запросов с использованием Spring MVC HandlerInterceptor для предоставления информации о пользователе.

«В этом конкретном примере мы сосредоточились на добавлении сведений о зарегистрированном пользователе в наше веб-приложение к параметрам модели. Вы можете расширить эту реализацию HandlerInterceptor, добавив более подробную информацию.

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

5.1. Статьи серии

Все статьи серии:

    Введение в Spring MVC Handler Interceptors Изменение параметров модели Spring с помощью Handler Interceptor (эта)