Chapter 6. Internalize Your Store with Interceptor

In all our previous chapters, we have only seen how to map a request to the Controller's method; once the request reaches the Controller method, we execute some logic and return a logical View name, which can be used by the view resolver to resolve Views, but what if we want to execute some logic before actual request processing happens? Similarly, what if we want to execute some other instruction before dispatching the response?

Spring MVC interceptor intercepts the actual request and response. Interceptors are a special web programming technique, where we can execute a certain piece of logic before or after a web request is processed. In this chapter, we are going to learn more about interceptors. After finishing this chapter, you will know:

  • How to configure an interceptor
  • How to add internalization support
  • Data auditing using an interceptor
  • Conditional redirecting using an interceptor

Working with interceptors

As I have already mentioned, interceptors are used to intercept actual web requests before or after processing them. We can relate the concept of interceptors in Spring MVC to the filter concept in Servlet programming. In Spring MVC, interceptors are special classes that must implement the org.springframework.web.servlet.HandlerInterceptor interface. The HandlerInterceptor interface defines three important methods, as follows:

  • preHandle: This method will get called just before the web request reaches the Controller for execution
  • postHandle: This method will get called just after the Controller method execution
  • afterCompletion: This method will get called after the completion of the entire web request cycle

Once we create our own interceptor, by implementing the HandlerInterceptor interface, we need to configure it in our web application context in order for it to take effect.

Time for action - configuring an interceptor

Every web request takes a certain amount of time to get processed by the server. In order to find out how much time it takes to process a web request, we need to calculate the time difference between the starting time and ending time of a web request process. We can achieve that by using the interceptor concept. Let's see how to configure our own interceptor in our project to log the execution time of every web request:

  1. Open pom.xml; you can find pom.xml under the root directory of the project itself.
  2. You will see some tabs at the bottom of the pom.xml file; select the Dependencies tab and click on the Add button in the Dependencies section.
  3. A Select Dependency window will appear; enter Group Id as log4j, Artifact Id as log4j, and Version as 1.2.17, select Scope as compile, click the OK button, and save pom.xml.
  4. Create a class named ProcessingTimeLogInterceptor under the com.packt.webstore.interceptor package in the src/main/java source folder, and add the following code to it:
          package com.packt.webstore.interceptor; 
     
          import javax.servlet.http.HttpServletRequest; 
          import javax.servlet.http.HttpServletResponse; 
     
          import org.apache.log4j.Logger; 
          import org.springframework.web.servlet.HandlerInterceptor; 
          import org.springframework.web.servlet.ModelAndView; 
     
          public class ProcessingTimeLogInterceptor implements 
          HandlerInterceptor { 
        
              private static final Logger LOGGER = 
          Logger.getLogger(ProcessingTimeLogInterceptor.class); 
      
              public boolean preHandle(HttpServletRequest request,     
            HttpServletResponse response, Object handler) { 
                  long startTime = System.currentTimeMillis(); 
                  request.setAttribute("startTime", startTime); 
     
                  return true; 
              } 
      
              public void postHandle(HttpServletRequest request, 
          HttpServletResponse response, Object handler, ModelAndView 
          modelAndView) { 
                String queryString = request.getQueryString() == null ? 
          "" : "?" + request.getQueryString(); 
                  String path = request.getRequestURL() + queryString; 
     
                  long startTime = (Long) 
          request.getAttribute("startTime"); 
                  long endTime = System.currentTimeMillis(); 
             
                  LOGGER.info(String.format("%s millisecond taken to 
          process the request %s.",(endTime - startTime), path)); 
              } 
      
              public void afterCompletion(HttpServletRequest request,
          HttpServletResponse response, Object handler, Exception       
          exceptionIfAny){ 
                 // NO operation.  
              } 
          } 
    
  5. Now open your web application context configuration file WebApplicationContextConfig.java, add the following method to it, and save the file:
          @Override 
          public void addInterceptors(InterceptorRegistry registry) {       
              registry.addInterceptor(new 
              ProcessingTimeLogInterceptor()); 
          } 
    
  6. Create a property file named log4j.properties under the src/main/resources directory, and add the following content. Then, save the file:
          # Root logger option 
          log4j.rootLogger=INFO, file, stdout 
      
          # Direct log messages to a log file 
          log4j.appender.file=org.apache.log4j.RollingFileAppender 
          log4j.appender.file.File= C:\webstore\webstore-
          performance.log 
          log4j.appender.file.MaxFileSize=1MB 
          log4j.appender.file.MaxBackupIndex=1 
          log4j.appender.file.layout=org.apache.log4j.PatternLayout 
          log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd
          HH:mm:ss} %-5p %c{1}:%L - %m%n 
      
          # Direct log messages to stdout 
          log4j.appender.stdout=org.apache.log4j.ConsoleAppender 
          log4j.appender.stdout.Target=System.out 
          log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 
          log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd
          HH:mm:ss} %-5p %c{1}:%L - %m%n 
    
  7. Now run our application, enter the http://localhost:8080/webstore/market/products URL, and navigate to some pages; you should able to see the logging in the console as follows:
    Time for action - configuring an interceptor

    Showing ProcessingTimeLogInterceptor logging messages in the console

  8. Open the file C:webstorewebstore-performance.log; you can see the same log message in the logging file as well.

What just happened?

Our intention was to record the execution time of every request coming to our web application, so we decided to record the execution times in a log file. In order to use a logger, we needed the log4j library, so we added the log4j library as a Maven dependency in step 3.

In step 4, we defined an interceptor class named ProcessingTimeLogInterceptor by implementing the HandlerInterceptor interface. As we already saw, there are three methods that need to be implemented. We will see each method one by one. The first method is preHandle(), which is called before the execution of the Controller method:

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { 
    long startTime = System.currentTimeMillis(); 
    request.setAttribute("startTime", startTime); 
    return true; 
} 

In the previously shown preHandle method, we just set the current time value in the request object for later retrieval. Whenever a request comes to our web application, it first comes through this preHandle method and sets the current time in the request object before reaching the Controller. We are returning true from this method because we want the execution chain to proceed with the next interceptor or the Controller itself. Otherwise, DispatcherServlet assumes that this interceptor has already dealt with the response itself. So if we return false from the preHandle method, the request won't proceed to the Controller or the next interceptor.

The second method is postHandle, which will be called after the Controller method's execution:

public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { 
   String queryString = request.getQueryString() == null ? "" : "?" + request.getQueryString(); 
   String path = request.getRequestURL() + queryString; 
 
   long startTime = (Long) request.getAttribute("startTime"); 
   long endTime = System.currentTimeMillis(); 
       
    LOGGER.info(String.format("%s millisecond taken to process the request %s.",(endTime - startTime), path)); 
} 

In the preceding method, we are simply logging the difference between the current time, which is considered to be the request processing finish time, and the start time, which we got from the request object. Our final method is afterCompletion, which is called after the View is rendered. We don't want to put any logic in this method, that's why I left the method empty.

Tip

If you don't want to implement all the methods from the HandlerInterceptor interface in your interceptor class, you could consider extending your interceptor from org.springframework.web.servlet.handler.HandlerInterceptorAdapter, which is a convenient class provided by Spring MVC as a default implementation of all the methods from the HandlerInterceptor interface.

After creating our ProcessingTimeLogInterceptor, we need to register our interceptor with Spring MVC, which is what we have done in step 5 through the addInterceptors overridden method of WebMvcConfigurerAdapter:

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

In step 6, we have added a log4j.properties file in order to specify some logger-related configurations. You can see we have configured the log file location in log4j.properties as follows:

log4j.appender.file.File= C:\webstore\webstore-performance.log 

Finally, in step 7 we ran our application in order to record some performance logging, and we were able to see that the logger is just working fine via the console. You can open the log file to view the performance logs.

So we understood how to configure an interceptor and saw ProcessingTimeLogInterceptor in action. In the next exercise, we will see how to use some Spring-provided interceptors.

Pop quiz - interceptors

Consider the following interceptor:

public class SecurityInterceptor extends HandlerInterceptorAdapter{ 
 
   @Override 
   public void afterCompletion(HttpServletRequest request,   HttpServletResponse response, Object handler, Exception ex)   throws Exception { 
         // just some code related to after completion 
   } 
} 

Is this SecurityInterceptor class a valid interceptor?

  1. It is not valid because it does not implement the HandlerInterceptor interface.
  2. It is valid because it extends the HandlerInterceptorAdapter class.

Within the interceptor methods, what is the order of execution?

  1. preHandle, afterCompletion, postHandle.
  2. preHandle, postHandle, afterCompletion.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.205.165