Chapter 9, Interceptor exception handling Spring MVC process (emphasis)

Interceptor== (emphasis)==

1. Overview of custom interceptors

Spring MVC can also use interceptors to intercept requests. Users can customize interceptors to achieve specific functions. Customized interceptors can implement Handler Interceptor interface, and can inherit Handler Interceptor Adapter class.

(1) === preHandle():=== This method is called before the business processor processes the request, in which the user request is processed. If the programmer decides that the interceptor will call another interceptor after intercepting the request, or the business processor will process the request, it will return true; if the programmer decides that no other component is needed to process the request, it will return false.

(2) postHandle(): This method is called after the business processor has processed the request, but before the Dispatcher Servlet returns the response to the client, the user request is processed in this method.

(3) After Completion (): This method is called after the Dispatcher Servlet has fully processed the request, and some resource cleaning operations can be performed in this method.

2. Single interceptor

(1) Custom Interceptor

public class FirstHandlerInterceptor implements HandlerInterceptor {
 
@Override
public void afterCompletion(HttpServletRequest arg0,
HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception {
	System.out.println(this.getClass().getName() + " - afterCompletion");
}
 
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2, ModelAndView arg3) throws Exception {
	System.out.println(this.getClass().getName() + " - postHandle");
}
 
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2) throws Exception {
		System.out.println(this.getClass().getName() + " - preHandle");
		return true;
	} 
}

(2) Configuration of interceptors

<mvc:interceptors>
<!-- Declare custom interceptors -->
<bean id="firstHandlerInterceptor"
      class="com.xxj.springmvc.interceptors.FirstHandlerInterceptor"></bean>
</mvc:interceptors>

(3) Breakpoint== (walk by yourself)==

(4) Interceptor method execution sequence (summary)

3. Multiple interceptors

(1) Custom interceptor classes (two)

Both implements the interface Handler Interceptor

public class FirstHandlerInterceptor implements HandlerInterceptor {
 
@Override
public void afterCompletion(HttpServletRequest arg0,
HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
System.out.println(this.getClass().getName() + " - afterCompletion");
}
 
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2, ModelAndView arg3) throws Exception {
System.out.println(this.getClass().getName() + " - postHandle");
}
 
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2) throws Exception {
System.out.println(this.getClass().getName() + " - preHandle");
return true;
}
 
}

public class SecondHandlerInterceptor implements HandlerInterceptor {
 
@Override
public void afterCompletion(HttpServletRequest arg0,
HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
	System.out.println(this.getClass().getName() + " - afterCompletion");
}
 
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2, ModelAndView arg3) throws Exception {
	System.out.println(this.getClass().getName() + " - postHandle");
}
 
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2) throws Exception {
	System.out.println(this.getClass().getName() + " - preHandle");
	return true;
	}
 
}

(2) Configuring custom interceptors

<mvc:interceptors>
<!-- Declare custom interceptors -->
<bean id="firstHandlerInterceptor"
  class="com.xxj.springmvc.interceptors.FirstHandlerInterceptor"></bean>
<!-- Configure Interceptor Reference -->
<mvc:interceptor>                        
	<mvc:mapping path="/empList"/>
		<!-- <mvc:exclude-mapping path="/empList"/> -->
		<bean id="secondHandlerInterceptor"
         class="com.xxj.springmvc.interceptors.SecondHandlerInterceptor">
         </bean>
	</mvc:interceptor>
</mvc:interceptors>

//Both return true:
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - preHandle
com.atguigu.springmvc.interceptors.SecondHandlerInterceptor - preHandle
************************************biz method*******************************
com.atguigu.springmvc.interceptors.SecondHandlerInterceptor - postHandle
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - postHandle
com.atguigu.springmvc.interceptors.SecondHandlerInterceptor - afterCompletion
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - afterCompletion

//Both return false:
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - preHandle

//true,false
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - preHandle
com.atguigu.springmvc.interceptors.SecondHandlerInterceptor - preHandle
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - afterCompletion

//false,true 
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - preHandle

4. Execution sequence of multiple interceptor methods

(1) On the order of execution

com.xxj.springmvc.interceptors.FirstHandlerInterceptor - preHandle
com.xxj.springmvc.interceptors.SecondHandlerInterceptor – preHandle
************biz method***********
com.xxj.springmvc.interceptors.SecondHandlerInterceptor - postHandle
com.xxj.springmvc.interceptors.FirstHandlerInterceptor - postHandle
com.xxj.springmvc.interceptors.SecondHandlerInterceptor - afterCompletion
com.xxj.springmvc.interceptors.FirstHandlerInterceptor - afterCompletion

The execution sequence of multiple interceptors and the execution of methods: 
	[1]. The execution order of multiple interceptors: according to the configuration order, the first configuration is executed. 
	[2] Implementation of methods:
	     preHanle: In accordance with the execution order of the interceptor
	     PosHandle: Contrary to the execution order of the interceptor
	     afterCompletion: The return value of the preHandle method, contrary to the execution order of the interceptor:
	If true is returned, the delegate request can be executed normally later. 
	If false is returned, the representative request is intercepted and cannot be executed later. 
			If the preHandle of the first interceptor returns false, subsequent operations are not performed
		     If the preHandle of the first interceptor does not return false, the preHandle and afterCompletion of the previous interceptor will execute.

(2) Execution Sequence Diagram

(3) Analyzing the process from the point of view of source code execution

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    if (getInterceptors() != null) {
        for (int i = 0; i < getInterceptors().length; i++) {
            HandlerInterceptor interceptor = getInterceptors()[i];
            if (!interceptor.preHandle(request, response, this.handler)) {
                triggerAfterCompletion(request, response, null);
                return false;
            }
            this.interceptorIndex = i;
        }
    }
	return true;
}

void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
    if (getInterceptors() == null) {
    	return;
    }
    for (int i = getInterceptors().length - 1; i >= 0; i--) {
        HandlerInterceptor interceptor = getInterceptors()[i];
        interceptor.postHandle(request, response, this.handler, mv);
    }
}

void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
throws Exception {
 
    if (getInterceptors() == null) {
        return;
    }
    for (int i = this.interceptorIndex; i >= 0; i--) {
        HandlerInterceptor interceptor = getInterceptors()[i];
        try {
        	interceptor.afterCompletion(request, response, this.handler, ex);
        }catch (Throwable ex2) {
        logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
        }
    }
}

(4) Source code analysis: analysis of the value of interceptor Index

II. Abnormal Handling

1. Overview of exception handling

(1) Spring MVC handles exceptions through Handler Exception Resolver handlers, including handler mapping, data binding, and exceptions that occur when the target method is executed.

(2) Implementation class of Handler Exception Resolver provided by Spring MVC

2,HandlerExceptionResolver

(1) Hadler Exception Resolver assembled by default by Dispatcher Servlet:

(2) Not used mvc:annotation-driven/ To configure:

(3) Use mvc:annotation-driven/ To configure:

3. Exception handling _DefaultHandler Exception Resolver

3.1 Overview of Knowledge

(1) Handling some special exceptions, such as:

  • NoSuchRequestHandlingMethodException,

  • HttpRequestMethodNotSupportedException,

  • HttpMediaTypeNotSupportedException,

  • HttpMediaTypeNotAcceptable Exception, etc.

(2)javadoc

org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
Default implementation of the HandlerExceptionResolver interface that resolves standard Spring exceptions and translates them to corresponding HTTP status codes. 
This exception resolver is enabled by default in the org.springframework.web.servlet.DispatcherServlet.

3.2 Code Example

(1) Add page links: GET requests

<a href="testDefaultHandlerExceptionResolver">
testDefaultHandlerExceptionResolver</a>

Adding processor methods

//@RequestMapping(value="/testDefaultHandlerExceptionResolver")
@RequestMapping(value="/testDefaultHandlerExceptionResolver",method=RequestMethod.POST)  //GET requests are not supported
public String testDefaultHandlerExceptionResolver(){
	System.out.println("testDefaultHandlerExceptionResolver...");
	return "success";
}

(2) Abnormal errors

(3) Hand the exception to DefaultHandler Exception Resolver

@Override
protected ModelAndView doResolveException(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
 
try {
if (ex instanceof NoSuchRequestHandlingMethodException) {
return handleNoSuchRequestHandlingMethod((NoSuchRequestHandlingMethodException) ex, request, response,
handler);
}
else if (ex instanceof HttpRequestMethodNotSupportedException) {
return handleHttpRequestMethodNotSupported((HttpRequestMethodNotSupportedException) ex, request,
response, handler);
}
else if (ex instanceof HttpMediaTypeNotSupportedException) {
return handleHttpMediaTypeNotSupported((HttpMediaTypeNotSupportedException) ex, request, response,
handler);
}
else if (ex instanceof HttpMediaTypeNotAcceptableException) {
return handleHttpMediaTypeNotAcceptable((HttpMediaTypeNotAcceptableException) ex, request, response,
handler);
}
else if (ex instanceof MissingServletRequestParameterException) {
return handleMissingServletRequestParameter((MissingServletRequestParameterException) ex, request,
response, handler);
}
else if (ex instanceof ServletRequestBindingException) {
return handleServletRequestBindingException((ServletRequestBindingException) ex, request, response,
handler);
}
else if (ex instanceof ConversionNotSupportedException) {
return handleConversionNotSupported((ConversionNotSupportedException) ex, request, response, handler);
}
else if (ex instanceof TypeMismatchException) {
return handleTypeMismatch((TypeMismatchException) ex, request, response, handler);
}
else if (ex instanceof HttpMessageNotReadableException) {
return handleHttpMessageNotReadable((HttpMessageNotReadableException) ex, request, response, handler);
}
else if (ex instanceof HttpMessageNotWritableException) {
return handleHttpMessageNotWritable((HttpMessageNotWritableException) ex, request, response, handler);
}
else if (ex instanceof MethodArgumentNotValidException) {
return handleMethodArgumentNotValidException((MethodArgumentNotValidException) ex, request, response, handler);
}
else if (ex instanceof MissingServletRequestPartException) {
return handleMissingServletRequestPartException((MissingServletRequestPartException) ex, request, response, handler);
}
else if (ex instanceof BindException) {
return handleBindException((BindException) ex, request, response, handler);
}
else if (ex instanceof NoHandlerFoundException) {
return handleNoHandlerFoundException((NoHandlerFoundException) ex, request, response, handler);
}
}
catch (Exception handlerException) {
logger.warn("Handling of [" + ex.getClass().getName() + "] resulted in Exception", handlerException);
}
return null;
}

4. Exception handling _SimpleMapping Exception Resolver

4.1 Overview of Knowledge

(1) If you want to handle all exceptions uniformly, you can use SimpleMapping Exception Resolver, which will be different

Constant class names are mapped to view names, that is, when an exception occurs, the corresponding view is used to report the exception.

4.2 Code Example

(1) Increase page links

<a href="testSimpleMappingExceptionResolver?i=1">testSimpleMappingExceptionResolver</a>

(2) Adding Controller Method

@RequestMapping("/testSimpleMappingExceptionResolver")
public String testSimpleMappingExceptionResolver(@RequestParam("i") int i){
	System.out.println("testSimpleMappingExceptionResolver..."); 
	String[] s = new String[10]; 
	System.out.println(s[i]); 
	return "success";
}

(3) Abnormal situation: the value of parameter i is greater than 10

(4) Configure exception parser: automatically store exception object information in request range

<!-- To configure SimpleMappingExceptionResolver Exception parser -->
<bean id="simpleMappingExceptionResolver"
 class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- exceptionAttribute Default values(adopt ModelAndView Pass it to the page): 
exception   ->  ${requestScope.exception}
public static final String DEFAULT_EXCEPTION_ATTRIBUTE = "exception";
-->
<property name="exceptionAttribute" value="exception"></property>
<property name="exceptionMappings">
	<props>
		<prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>
	</props>
</property>
</bean>

error.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
 "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body> 
<h3>Error Page</h3> 
${exception }
${requestScope.exception } 
</body>
</html>

(5) Source code analysis

SimpleMappingExceptionResolver    L187 L339  

@Override
protected ModelAndView doResolveException(HttpServletRequest request,
 HttpServletResponse response,Object handler, Exception ex) {
 
    // Expose ModelAndView for chosen error view.
    String viewName = determineViewName(ex, request);
    if (viewName != null) {
    // Apply HTTP status code for error views, if specified.
    // Only apply it if we're processing a top-level request.
    	Integer statusCode = determineStatusCode(request, viewName);
    if (statusCode != null) {
    	applyStatusCodeIfPossible(request, response, statusCode);
    }
    	return getModelAndView(viewName, ex, request);
    }else {
    	return null;
    }
}






/**
 * Return a ModelAndView for the given view name and exception.
 * <p>The default implementation adds the specified exception attribute.
 * Can be overridden in subclasses.
 * @param viewName the name of the error view
 * @param ex the exception that got thrown during handler execution
 * @return the ModelAndView instance
 * @see #setExceptionAttribute
 */
protected ModelAndView getModelAndView(String viewName, Exception ex) {
ModelAndView mv = new ModelAndView(viewName);
    if (this.exceptionAttribute != null) {
        if (logger.isDebugEnabled()) {
            logger.debug("Exposing Exception as model attribute '" + this.exceptionAttribute + "'");
        }
        mv.addObject(this.exceptionAttribute, ex);
    }
        return mv;
}

3. Flow chart solution of Spring MVC= (emphasis)==

1. Flow chart

2. Spring Workflow Description

(1) Users send requests to the server, which are captured by Spring MVC front-end controller Dispatcher Servlet.

(2) Dispatcher Servlet parses the request URL to get the request resource identifier (URI):

Determine the mapping corresponding to the request URI

(1) No:

  • Then determine whether mvc:default-servlet-handler is configured:

  • If not configured, the console newspaper mapping cannot be found, and the client shows 404 errors.

  • If there is a configuration, the target resource (usually static resources, such as JS,CSS,HTML) is executed.

    (2) Existence:

  • Execute the following process

(3) According to the URI, call Handler Mapping to obtain all relevant objects (including handler objects and interceptors corresponding to handler objects) of the handler configuration, and finally return in the form of Handler Execution Chain objects.

(4) Dispatcher Servlet chooses a suitable Handler Adapter according to the acquired Handler.

(5) If the handler adapter is successfully obtained, the preHandler(...) of the interceptor will be executed at this time. ) method [forward]

(6) Extract the model data in Request, fill in Handler and start executing Handler (Controller) method to process requests. During filling in Handler, Spring will do some extra work for you according to your configuration:

(1) HttpMessageConveter: Convert request messages (such as Json, xml, etc.) into an object, and the object into the specified response information.

Data Conversion: Data Conversion of Request Message. For example, String converts to Integer, Double, etc.

(3) Data formatting: data formatting for request messages. For example, converting strings into formatted numbers or formatted dates, etc.

(4) Data validation: validate the validity of data (length, format, etc.) and store the validation results in BindingResult or Error

(7) When the Handler execution is completed, a Model AndView object is returned to the Dispatcher Servlet.

(8) At this point, the execution of the interceptor's postHandle(... ) Method [Reverse]

(9) Select a suitable ViewResolver (which must be ViewResolver registered in Spring container) and return it to Dispatcher Servlet to render it according to Model and View. view

(10) The AfterCompletion method of the interceptor needs to be executed when returned to the client [reverse]

(11) Return the rendering result to the client

3. Source code parsing

3.1 Building Environment

(1) Copy the jar package

​ spring-aop-4.0.0.RELEASE.jar

​ spring-beans-4.0.0.RELEASE.jar
​ spring-context-4.0.0.RELEASE.jar
​ spring-core-4.0.0.RELEASE.jar
​ spring-expression-4.0.0.RELEASE.jar
​ commons-logging-1.1.3.jar
​ spring-web-4.0.0.RELEASE.jar
​ spring-webmvc-4.0.0.RELEASE.jar

(2) Configuring web.xml

<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

(3) configuration file spring mvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
 
<!-- Setting up packages for scanning components -->
<context:component-scan base-package="com.xxj.springmvc"/>
 
<!-- Configuration view parser -->
<bean id="internalResourceViewResolver"
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
 
</beans>

3.2 Writing Hello World

(1) Page Links

<a href="helloworld">Hello World</a>

(2) Controller method

package com.xxj.springmvc.handler;
 
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
 
@Controller
public class HelloWorldHandler { 
    @RequestMapping("/helloworld")
    public String testHello(){ 
        System.out.println("Hello,SpringMVC..."); 
        return "success";
    } 
}

(3) Success Page

<h3>Success Page</h3>

3.3 Debug experiment

(1) Normal process, running results

(2) No configurationmvc:default-servlet-handler/ Test, report 404 directly

​ ① http://localhost:8080/SpringMVC_09_WorkFlow/helloworld2

April 20, 2016 11:53:19 a.m. org. spring framework. web. servlet. PageNotFound no Handler Found
 Warning: No mapping found for HTTP request with URI [/Spring MVC_09_WorkFlow/helloworld2] in Dispatcher Servlet with name'Spring Dispatcher Servlet'

​ ② http://localhost:8080/SpringMVC_09_WorkFlow/test.html

April 20, 2016 11:54:16 a.m. org. spring framework. web. servlet. PageNotFound no Handler Found
 Warning: No mapping found for HTTP request with URI [/Spring MVC_09_WorkFlow/test.html] in Dispatcher Servlet with name'Spring Dispatcher Servlet'

(3) Configurationmvc:default-servlet-handler/ Testing, looking for target resources

(4) There are still errors in the test. At this time, it is necessary to configure:mvc:annotation-driven/ Otherwise, mapping resolution is not good.

3.4 Debug process analysis

(1) Handler Execution Chain mappedHandler, including interceptors and processor methods;

DispatcherServlet L902 916

org.springframework.web.servlet.HandlerExecutionChain
Handler execution chain, consisting of handler object and any handler interceptors. Returned by
 HandlerMapping's HandlerMapping.getHandler method.

(2)HandlerMapping

 org.springframework.web.servlet.HandlerMapping
Interface to be implemented by objects that define a mapping between requests and handler objects. 
This class can be implemented by application developers, although this is not necessary, as org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping and org.springframework.web.servlet.handler.SimpleUrlHandlerMapping are included in the framework. The former is the default if no HandlerMapping bean is registered in the application context. 
HandlerMapping implementations can support mapped interceptors but do not have to. A handler will always be wrapped in a HandlerExecutionChain instance, optionally accompanied by some HandlerInterceptor instances. The DispatcherServlet will first call each HandlerInterceptor's preHandle method in the given order, finally invoking the handler itself if all preHandle methods have returned true. 
The ability to parameterize this mapping is a powerful and unusual capability of this MVC framework. For example, it is possible to write a custom mapping based on session state, cookie state or many other variables. No other MVC framework seems to be equally flexible. 
Note: Implementations can implement the org.springframework.core.Ordered interface to be able to specify a sorting order and thus a priority for getting applied by DispatcherServlet. Non-Ordered instances get treated as lowest priority.

(3) No configurationmvc:default-servlet-handler/mvc:annotation-driven/ To send a request path that does not have a resource, mappedHandler is null

http://localhost:8080/SpringMVC_09_WorkFlow/helloworld2

(4) Configurationmvc:default-servlet-handler/mvc:annotation-driven/ Send a request path that does not have a resource

3.5 Breakpoint== (Walk by yourself)==

Keywords: Spring xml Java JSP

Added by Lord Brar on Tue, 10 Sep 2019 14:35:28 +0300