About global exception handling for Web applications, the last article introduced ControllerAdvice combined with @ExceptionHandler to implement global exception management for Web applications.

This post presents another, less common, use of HandlerExceptionResolver to handle exception states by implementing a custom HandlerExceptionResolver

HandlerExceptionResolver HandlerExceptionResolver HandlerExceptionResolver HandlerExceptionResolver HandlerExceptionResolver

I. Environment construction

First of all, it is possible to build a Web application to continue the subsequent test. It is relatively simple to build a Web application with SpringBoot.

Create a Maven project with the following POM file

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.7</version>
    <relativePath/> <! -- lookup parent from update -->
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
    <java.version>1.8</java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.45</version>
    </dependency>
</dependencies>

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </pluginManagement>
</build>
<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>
Copy the code

II. HandlerExceptionResolver

1. Customize exception handling

HandlerExceptionResolver, as its name implies, is a class that handles exceptions. The interface is a method, the callback after an exception occurs, and the exception stack information is carried in the four parameters

@Nullable
ModelAndView resolveException( HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex);
Copy the code

It’s easier to customize our exception handling class, implement the above interface, and then return the complete stack to the caller

public class SelfExceptionHandler implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        String msg = GlobalExceptionHandler.getThrowableStackInfo(ex);

        try {
            response.addHeader("Content-Type"."text/html; charset=UTF-8");
            response.getWriter().append(Custom exception handling!! \n").append(msg).flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null; }}// Stack information is printed as follows
public static String getThrowableStackInfo(Throwable e) {
    ByteArrayOutputStream buf = new ByteArrayOutputStream();
    e.printStackTrace(new java.io.PrintWriter(buf, true));
    String msg = buf.toString();
    try {
        buf.close();
    } catch (Exception t) {
        return e.getMessage();
    }
    return msg;
}
Copy the code

Looking closely at the code implementation above, there are a few things to note

  • To ensure that Chinese is not garbled, we set the return headerresponse.addHeader("Content-Type", "text/html; charset=UTF-8");Without this line, Chinese characters will be garbled
  • We’re a pure back-end application, we don’t want to return the view, we just want to write data back to the output stream of ResponseResponse.getwriter ().append(" Custom exception handling!! \n").append(msg).flush();; If you have a custom error page in your project, you can do so by returningModelAndViewTo determine the error page that was eventually returned
  • The above code will not be directly effective, need to register, can be inWebMvcConfigurerA subclass to implement registration, as shown below
@SpringBootApplication
public class Application implements WebMvcConfigurer {
    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
        resolvers.add(0.new SelfExceptionHandler());
    }

    public static void main(String[] args) { SpringApplication.run(Application.class); }}Copy the code

2. The test case

Let’s still test with the use case from the previous post

@Controller
@RequestMapping(path = "page")
public class ErrorPageRest {

    @ResponseBody
    @GetMapping(path = "divide")
    public int divide(int sub) {
        return 1000/ sub; }}Copy the code

Below are the measured 404 and 500 exceptions, respectively

The 500 exception goes to our custom exception handling class, while 404 still goes to the default error page, so if we need to catch a 404 exception, we still need to add it to the configuration file

When an error occurs, Spring.mvc. Throw-exception-if-no-handler-found =true # Set static resource mapping access path spring.mvc. Static-path-pattern =/statics/** # spring.resources.add-mappings=falseCopy the code

Why does 404 need extra processing?

Here, try to explain the problem in an easy-to-understand way

  • Java Web applications, in addition to returning JSON class data may also return web pages, JS, CSS
  • We’re through@ResponseBodyTo indicate that a URL returns JSON data (usually, regardless of the custom implementation).
  • our@ControllerThrough the@RequestMappingDefines a REST service that returns a static resource
  • What about js, CSS, images, etc., we don’t define a REST service in our Web application
  • So when an HTTP request is received and the URL association mapping is not found, it is not considered to be one by defaultNoHandlerFoundExceptionThrow NoHandlerFoundException (NoHandlerFoundException) This exception indicates that the URL request has no corresponding handler, but we have assigned it a static resource handlerResourceHttpRequestHandler)

For those of you interested in digging deeper, here are the key code locations

/ / enter methods: ` org. Springframework. Web. Servlet. DispatcherServlet# doDispatch `

/ / the debug node
Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
	noHandlerFound(processedRequest, response);
	return;
}

// Core logic
// org.springframework.web.servlet.DispatcherServlet#getHandler
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	if (this.handlerMappings ! =null) {
		for (HandlerMapping hm : this.handlerMappings) {
			if (logger.isTraceEnabled()) {
				logger.trace(
						"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
			}
			HandlerExecutionChain handler = hm.getHandler(request);
			if(handler ! =null) {
				returnhandler; }}}return null;
}
Copy the code

3. Summary

Although this post also introduces a new approach to global exception handling that works just as well as ControllerAdvice, it is not recommended for the following reasons

  • HandlerExceptionResolverIn the way thatControllerAdviceWay brief elegant
  • Officially providedDefaultHandlerExceptionResolverIt is already very powerful, basically covering all kinds of HTTP status codes, and we need to customize it ourselves

II. The other

Web Blog series

  • 191010- Global exception handling in SpringBoot Tutorial Web
  • 190930- Configuration of 404 and 500 exception pages in SpringBoot Tutorial Web
  • 190929- Redirection of the SpringBoot Tutorial Web chapter
  • 190913-SpringBoot tutorial Web returns text, web pages, and image manipulation postures
  • 190905-SpringBoot Series tutorial Web Chinese garble problem solving
  • 190831- How to Customize the Parameter Parser in SpringBoot Tutorial Web
  • 190828- Summary of Post request parameter resolution postures in the Web part of the SpringBoot tutorial series
  • 190824-SpringBoot Tutorial Web chapter summary of Get Request parameter parsing posture
  • 190822- Beetl Environment Setup in SpringBoot Tutorial Web
  • 190820- Thymeleaf Setup for SpringBoot Tutorial Web
  • 190816- Freemaker Environment setup in SpringBoot Tutorial Web
  • 190421-SpringBoot Advanced WEB WebSocket instructions
  • 190327-Spring-resttemplate urlencode parameter parsing exception
  • 190317-Spring MVC web application building based on Java Config without XML configuration
  • 190316-Spring MVC web Application Building based on XML configuration
  • 190213- The temporary upload location XXX is not valid

Program source code

  • Project: github.com/liuyueyi/sp…
  • Project: github.com/liuyueyi/sp…

1. An ashy Blog

As far as the letter is not as good, the above content is purely one’s opinion, due to the limited personal ability, it is inevitable that there are omissions and mistakes, if you find bugs or have better suggestions, welcome criticism and correction, don’t hesitate to appreciate

Below a gray personal blog, record all the study and work of the blog, welcome everyone to go to stroll

  • A grey Blog Personal Blog blog.hhui.top
  • A Grey Blog-Spring feature Blog Spring.hhui.top