Changing Spring Model Parameters with Handler Interceptor

1. Introduction

In this tutorial we are going to focus on the Spring MVC
HandlerInterceptor. More specifically, we will change Spring MVC’s
model parameters before and after handling a request.

If you want to read about HandlerInterceptor’s basics, check out this
article.

2. Maven Dependencies

In order to use Interceptors, you need to include the following
section in a dependencies section of your pom.xml file:

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

Latest version can be found
here.

This dependency only covers Spring Web so don’t forget to add
spring-core and spring-context for a full web application, and a
logging library of your choice.

3. Custom Implementation

One of the use cases of HandlerInterceptor is adding common/user
specific parameters to a model, which will be available on each
generated view.

In our example, we will use custom interceptor implementation to add
logged user’s username to model parameters. In more complex systems we
may add more specific information like: user avatar path, user location,
etc.

Let’s start with defining our new Interceptor class:

public class UserInterceptor extends HandlerInterceptorAdapter {

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

    ...
}

We extend HandlerInterceptorAdapter, as we only want to implement
preHandle() and postHandle() methods.

As we mentioned before, we want to add logged user’s name to a model.
First of all, we need to check if a user is logged in. We may obtain
this information by checking SecurityContextHolder:

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

When an HttpSession is established, but nobody is logged in, a
username in Spring Security context equals to anonymousUser. Next, we
proceed with implementation of preHandle():

3.1. Method preHandle()

Before handling a request, we cannot access model parameters. In order
to add username, we need to use HttpSession to set parameters:

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

This is crucial if we are using some of this information before handling
a request. As we see, we are checking if a user is logged in and then
add parameters to our request by obtaining its session:

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 =========================");
}

We used SecurityContextHolder to obtain loggedUsername. You may
override Spring Security UserDetails implementation to obtain email
instead of a standard username.

3.2. Method postHandle()

After handling a request, our model parameters are available, so we may
access them to change values or add new ones. In order to do that, we
use the overridden postHandle() method:

@Override
public void postHandle(
  HttpServletRequest req,
  HttpServletResponse res,
  Object o,
  ModelAndView model) throws Exception {

    if (model != null && !isRedirectView(model)) {
        if (isUserLogged()) {
        addToModelUserDetails(model);
    }
    }
}

Let’s take a look at the implementation details.

First of all, it’s better to check if the model is not null. It will
prevent us from encountering a NullPointerException.

Moreover, we may check if a View is not an instance of
RedirectView.

There is no need to add/change parameters after the request is handled
and then redirected, as immediately, the new controller will perform
handling again. To check if the view is redirected, we are introducing
the following method:

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());
}

Finally, we are checking again if a user is logged, and if yes, we are
adding parameters to Spring model:

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 =========================");
}

Please note that logging is very important, as this logic works “behind
the scenes” of our application. It is easy to forget that we are
changing some model parameters on each View without logging it
properly.

4. Configuration

To add our newly created Interceptor into Spring configuration, we
need to override addInterceptors() method inside WebConfig class
that implements WebMvcConfigurer:

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

We may achieve the same configuration by editing our XML Spring
configuration file:

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

From this moment, we may access all user-related parameters on all
generated views.

Please notice, if multiple Spring Interceptors are configured, the
preHandle() method is executed in the order of configuration whereas
postHandle() and afterCompletion() methods are invoked in the
reverse order.

5. Conclusion

This tutorial presents intercepting web requests using Spring MVC’s
HandlerInterceptor in order to provide user information.

In this particular example, we focused on adding logged user’s details
in our web application to model parameters. You may extend this
HandlerInterceptor implementation by adding more detailed information.

All examples and configurations are available here on
GitHub.

5.1. Articles in the Series

All articles of the series:

Leave a Reply

Your email address will not be published.