Interceptor and three components for Springboot series Spring Boot web development

Posted by itsjames on Sat, 11 May 2019 06:03:36 +0200

1. Interceptors

image

The Interceptor interceptor in Springboot, also known as the interceptor in mvc, omits the xml configuration section.There is no essential difference, all through the implementation of several methods in HandlerInterceptor.The functions of several methods are listed below.

  1. preHandle
    Executed before entering the Habdler method, commonly used for authentication authorization, etc.
  2. postHandle
    Executed before returning to modelAndView after entering the Handler method, typically used to insert public model data, and so on.
  3. afterCompletion
    Final processing, commonly used for log collection, unified follow-up processing, and so on.

1.1 Introducing dependencies

 <!-- Spring Boot web Development Integration -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-json</artifactId>
                    <groupId>org.springframework.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- Ali fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>

        <!-- Lombok tool -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- Import Profile Processor, in Configuration springboot Relevant files will be prompted -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- unit testing -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>

1.2 Writing interceptors

package net.codingme.boot.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * <p>
 * Interceptor
 *
 * @Author niujinpeng
 * @Date 2019/1/6 16:54
 */
@Slf4j
public class LogHandlerInterceptor implements HandlerInterceptor {

    /**
     * Before the request method executes
     * Returning true passes through
     *
     * @param request
     * @param response
     * @param handler
     * @return
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        StringBuffer requestURL = request.getRequestURL();
        log.info("preHandle request URL: " + requestURL.toString());
        return true;
    }

    /**
     * Execute before returning to modelAndView
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        log.info("postHandle Return modelAndView before");
    }

    /**
     * Execute Handler to complete execution of this method
     * @param request
     * @param response
     * @param handler
     * @param ex
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        log.info("afterCompletion After executing the request method and returning completely");
    }
}

1.3 Configure Interceptors

After omitting the interceptor configuration section in the XML, configure the custom interceptor in the way recommended by springboot.

package net.codingme.boot.config;


import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 1.Use FastJSON
 * 2.Configure Time Formatting
 * 3.Solve Chinese garbles
 * 4.Add Custom Interceptor
 *
 * @Author niujinpeng
 * @Date 2018/12/13 15:35
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    /**
     * Custom JSON Converter
     *
     * @param converters
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
        //DateFormatter
        fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
        //Handling Chinese scrambling
        List<MediaType> fastMediaTypes = new ArrayList<>();
        fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);

        converter.setSupportedMediaTypes(fastMediaTypes);
        converter.setFastJsonConfig(fastJsonConfig);
        converters.add(converter);
    }

    /**
     * Add Custom Interceptor
     * .addPathPatterns("/**")  Intercepted Request Path
     * .excludePathPatterns("/user"); Excluded Request Path
     *
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LogHandlerInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/user");
    }
}

2 Section Programming

  1. AOP: Aspect-oriented programming without modifying source code implementation for extended functionality
  2. AOP takes the horizontal extraction mechanism instead of the traditional vertical inheritance system repetitive codes
  3. AOP underlying implementation using dynamic proxy
    • Use dynamic proxy to create interfaces to implement class proxy objects when there is an interface
    • Use dynamic proxy to create subclass proxy objects of classes without interfaces
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

/**
 * <p>
 * Use AOP to record access logs
 * Use @Before to cut in at the beginning of the entry point
 * Use @After to cut in at the end of the entry point
 * Use @AfterReturning to cut in after the entry point return content (which can be used to do some processing on processing return values)
 * Use @Around to cut into content before and after the entry point and control when to execute the entry point's own content
 * Use @AfterThrowing for handling logic after an exception is thrown in the cut-in content section
 * <p>
 * Notes:
 * Aspect:AOP
 * Component: Bean
 * Slf4j: Log output log can be used directly
 * Order: When multiple AOP s cut into the same method, the smaller the priority, the higher the priority.
 * Actions before entry point, from small to large by order value
 * Operation after entry point, from large to small by order value
 *
 * @Author niujinpeng
 * @Date 2019/1/4 23:29
 */

@Aspect
@Component
@Slf4j
@Order(1)
public class LogAspect {
    /**
     * Thread Storage Information
     */
    ThreadLocal<Long> startTime = new ThreadLocal<>();

    /**
     * Define entry points
     * First*: Identify all return types
     * Letter Path: Package Path
     * Two points.: current package and subpackage
     * Second*: All classes
     * Third*: All methods
     * The last two points: all types of parameters
     */
    @Pointcut("execution(public * net.codingme.boot.controller..*.*(..))")
    public void webLog() {
    }

    /**
     * Cut in at the beginning of the entry point
     *
     * @param joinPoint
     */
    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) {
        // Record request time
        startTime.set(System.currentTimeMillis());
        // Get Request Domain
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();

        // Record Request Content
        log.info("Aspect-URL: " + request.getRequestURI().toLowerCase());
        log.info("Aspect-HTTP_METHOD: " + request.getMethod());
        log.info("Aspect-IP: " + request.getRemoteAddr());
        log.info("Aspect-REQUEST_METHOD: " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        log.info("Aspect-Args: " + Arrays.toString(joinPoint.getArgs()));
    }

    /**
     * Processing content after entry point
     */
    @After("webLog()")
    public void doAfter() {

    }

    /**
     * Cut in after the entry point return content (can be used to do some processing on processing return values)
     */
    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) throws Throwable {
        log.info("Aspect-Response: " + ret);
        Long endTime = System.currentTimeMillis();
        log.info("Aspect-SpeedTime: " + (endTime - startTime.get()) + "ms");
    }

}

Access log output for viewing interceptors and AOP s.

09:57:15.408  INFO 2836 --- [nio-8080-exec-1] n.c.boot.config.LogHandlerInterceptor    : preHandle request URL: http://localhost:8080/
09:57:15.413  INFO 2836 --- [nio-8080-exec-1] net.codingme.boot.config.LogAspect       : Aspect-URL: /
09:57:15.413  INFO 2836 --- [nio-8080-exec-1] net.codingme.boot.config.LogAspect       : Aspect-HTTP_METHOD: GET
09:57:15.413  INFO 2836 --- [nio-8080-exec-1] net.codingme.boot.config.LogAspect       : Aspect-IP: 0:0:0:0:0:0:0:1
09:57:15.414  INFO 2836 --- [nio-8080-exec-1] net.codingme.boot.config.LogAspect       : Aspect-REQUEST_METHOD: net.codingme.boot.controller.HelloController.index
09:57:15.415  INFO 2836 --- [nio-8080-exec-1] net.codingme.boot.config.LogAspect       : Aspect-Args: []
09:57:15.424  INFO 2836 --- [nio-8080-exec-1] net.codingme.boot.config.LogAspect       : Aspect-Response: Greetings from Spring Boot!SpringBoot Is a spring application program
09:57:15.425  INFO 2836 --- [nio-8080-exec-1] net.codingme.boot.config.LogAspect       : Aspect-SpeedTime: 12ms
09:57:15.436  INFO 2836 --- [nio-8080-exec-1] n.c.boot.config.LogHandlerInterceptor    : postHandle Return modelAndView before
09:57:15.437  INFO 2836 --- [nio-8080-exec-1] n.c.boot.config.LogHandlerInterceptor    : afterCompletion After executing the request method and returning completely

3. Servlet,Filter,Listener

Servlet, Filter, Listener are the core content of Java web, so how do you use them in Springboot?

3.1 Writing Servlet s

package net.codingme.boot.servlet;

import lombok.extern.slf4j.Slf4j;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * <p>
 * @WebServlet(urlPatterns = "/myservlet") // Define access paths
 * @Author niujinpeng
 * @Date 2019/1/24 16:25
 */
@Slf4j
@WebServlet(urlPatterns = "/myservlet")
public class MyServlet extends HttpServlet {

    @Override
    public void init() throws ServletException {
        log.info("Servlet Start Initialization");
        super.init();
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        log.info("Servlet Start processing GET Method");
        PrintWriter writer = resp.getWriter();
        writer.println("Hello Servlet");
        writer.flush();
        writer.close();
    }

    @Override
    protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }

    @Override
    public void destroy() {
        log.info("Servlet Start Destroying");
        super.destroy();
    }
}

3.2 Write Filter

package net.codingme.boot.filter;

import lombok.extern.slf4j.Slf4j;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

/**
 * <p>
 *
 * @Author niujinpeng
 * @Date 2019/1/24 16:35
 */
@Slf4j
@WebFilter(urlPatterns = "/*")
public class MyFilter implements Filter {


    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        log.info("Interceptors begin to intercept");
        filterChain.doFilter(request, response);
    }

}

3.3 Write Listener

package net.codingme.boot.listener;

import lombok.extern.slf4j.Slf4j;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

/**
 * <p>
 *
 * @Author niujinpeng
 * @Date 2019/1/24 16:45
 */
@Slf4j
@WebListener
public class MyListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        log.info("Listener Start Initialization");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        log.info("Listener Start Destroying");
    }
}

3.4 Add to Container

There are two ways to add to a container, the first using annotation scanning.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.ComponentScan;

/**
 * @ServletComponentScan Scan Servlet,Filter,Listener to add to container
 */
@SpringBootApplication
@ServletComponentScan
public class BootApplication {

    public static void main(String[] args) {
        SpringApplication.run(BootApplication.class, args);
    }

}

Or use a configuration class to add to the container.

/**
 * <p>
 * Register Servlet Filter Listener here or use @ServletComponentScan
 *
 * @Author niujinpeng
 * @Date 2019/1/24 16:30
 */
@Configuration
public class WebCoreConfig {

    @Bean
    public ServletRegistrationBean myServlet() {
        return new ServletRegistrationBean<>(new MyServlet());
    }

    @Bean
    public FilterRegistrationBean myFitler() {
        return new FilterRegistrationBean<>(new MyFilter());
    }

    @Bean
    public ServletListenerRegistrationBean myListener() {
        return new ServletListenerRegistrationBean(new MyListener());
    }
    
}

Startup You can see the listener boot in the console.

 11:35:03.744  INFO 8616 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1364 ms
 11:35:03.798  INFO 8616 --- [           main] net.codingme.boot.listener.MyListener    : Listener Start Initialization
 11:35:03.892  INFO 8616 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
 11:35:04.055  INFO 8616 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''

Visit the Servlet to see the interceptor and the Servlet in effect.

 11:36:55.552 INFO 3760 --- [nio-8080-exec-1] net.codingme.boot.servlet.MyServlet: Servlet initialization started
 11:36:55.556 INFO 3760 --- [nio-8080-exec-1] net.codingme.boot.filter.MyFilter: Interceptor begins to intercept
 11:36:55.556 INFO 3760 --- [nio-8080-exec-1] net.codingme.boot.servlet.MyServlet: Servlet starts processing GET methods

The article code has been uploaded to GitHub Spring Boot Web Development-Interception Processing.
The article code has been uploaded to GitHub Spring Boot Web Development - Servlet,Filter,Listener.

<Finish>
This article originates from a personal blog: https://www.codingme.net Please indicate the source for reprinting.

Insert a picture description here

Topics: Spring Lombok Java SpringBoot