SpringMvc (exception handling)

1. Built in exception handling parser

Open dispatcherservlet properties
File, where you can see some built-in APIs of SpringMvc. After this key is our exception handling parser. There are three default exception handling classes, as shown in the following example:

org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

When parsing exceptions, SpringMvc will search the corresponding processor from the default processor.

1,org. springframework. web. servlet. Handlerexceptionresolver is the default processor in springmvc.

2,org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver handles general exceptions in spring MVC.

3,org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver deals with exceptions of @ ResponseStatus annotation type. The @ ResponseStatus annotation is usually marked on the method, and then the method throws an exception.

4,org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver handles @ ExceptionHandler (such as 404500 and other exceptions in normal times).

5. AbstractHandlerMethodExceptionResolver: it is the parent class of ExceptionHandlerExceptionResolver

6. SimpleMappingExceptionResolver: resolve exceptions through the correspondence between the configured exception class and the view, and directly specify which exceptions to which view.

2. Unified exception handling

2.1. Obtain the exception information of Java processing class and output it

Note: to import the Tomcat dependency package, you can use the commands in the jsp file.
@If the ExceptionHandler annotation is written in the controller, it can only process the methods of the current controller.

@Controller
public class ExceptionController {
    @RequestMapping("/exception01")
    public String exception01(@RequestParam("name") String name){
        System.out.println("Method processing 01");
        return "show";
    }

    @RequestMapping("/exception02")
    public String exception02(@RequestParam("name") String name){
        System.out.println("Method processing 02");
        return "show";
    }

    @ExceptionHandler(Exception.class)
    public ModelAndView handleException(Exception ex){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("error");
        modelAndView.addObject("ex",ex);
        //Logging
        System.out.println(ex.getMessage());
        return modelAndView;
    }
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
        Something went wrong.<br/>
        <%= ((Exception)request.getAttribute("ex")).getMessage() %>
</body>
</html>

2.2. Java exception stack information output

Someone else's code:

public static String getStackTrace(Throwable throwable){
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw);
    try {
        throwable.printStackTrace(pw);
        return sw.toString();
    } finally {
        pw.close();
    }
}

My code:

@ExceptionHandler(Exception.class)
public ModelAndView handleException(Exception ex){
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setViewName("error");
    modelAndView.addObject("ex",ex);
    //Log record and get the complete stack information
    System.out.println(getStackTrace(ex));
    return modelAndView;
}

public static String getStackTrace(Throwable throwable){
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw);
    try {
        throwable.printStackTrace(pw);
        return sw.toString();
    } finally {
        pw.close();
    }
}

Screenshot of error reporting:

2.3. Handling global exceptions

Priority of handling exceptions

1. Global exception
2. Processor exception
3. Specific exceptions in global exceptions
According to the proximity principle, if you have an exception handling method in your current controller, you will use your own
If not, global exception handling will be used. If there are multiple global exception handling
Then it will match exactly to the most accurate one

@When the ControllerAdvice annotation is marked on a class, it represents the handling of global exceptions

@ControllerAdvice
public class GeneralExceptionHandler {

    /**
     * Global exception handling
     * @param ex
     * @return
     */
    @ExceptionHandler(Exception.class)
    public ModelAndView handleException01(Exception ex){
        System.out.println("Global exception handling.");
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("error");
        modelAndView.addObject("ex",ex);
        //Log record and get the complete stack information
        System.out.println(getStackTrace(ex));
        return modelAndView;
    }

    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ModelAndView handleException02(Exception ex){
        System.out.println("Global exception handling, parameter not found.");
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("error");
        modelAndView.addObject("ex",ex);
        //Log record and get the complete stack information
        System.out.println(getStackTrace(ex));
        return modelAndView;
    }

    public static String getStackTrace(Throwable throwable){
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        try {
            throwable.printStackTrace(pw);
            return sw.toString();
        } finally {
            pw.close();
        }
    }
}

2.4. Unified exception handling (json or page)

We can judge when the json request of ajax comes in and when it comes from the page through a variety of ways, because when we do unified exception handling, the handling methods of the two different scenarios will be different,

The pom configuration file for integrating jackson is as follows

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.10.3</version>
</dependency>

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.10.3</version>
</dependency>

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.10.3</version>
</dependency>

It's all written in the code

/* 1,It depends on whether the method requested by the user is a method that needs to return json data
        // Get an annotation on the class
        RestController restController = handlerMethod.getClass().getAnnotation(RestController.class);
        // Get an annotation on the method
        ResponseBody responseBody = handlerMethod.getMethod().getAnnotation(ResponseBody.class);
        // If the current request is ajax, json is returned
        if(restController != null || responseBody != null){}*/package cool.ale.exception;

import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;

/**
 * @author dujlc
 *
 *
 *   Unified exception handling: return both normal requests and ajax requests
 *      Normal request: return view, error message
 *      ajax: Return json
 *      {
 *          code
 *          message
 *      }
 *
 */
@ControllerAdvice
public class GeneralExceptionHandler {

    /**
     * Global exception handling
     * @param ex
     * @return
     */
    @ExceptionHandler(Exception.class)
    public ModelAndView handleException01(HttpServletRequest request,
                                          HttpServletResponse response,
                                          HandlerMethod handlerMethod,
                                          Exception ex) throws IOException {
        System.out.println("Global exception handling.");
        /* 1,It depends on whether the method requested by the user is a method that needs to return json data
        // Get an annotation on the class
        RestController restController = handlerMethod.getClass().getAnnotation(RestController.class);
        // Get an annotation on the method
        ResponseBody responseBody = handlerMethod.getMethod().getAnnotation(ResponseBody.class);
        // If the current request is ajax, json is returned
        if(restController != null || responseBody != null){}*/

        // 2. If the type in the request header contains content type, it contains application/json
        if (!StringUtils.isEmpty(request.getHeader("Content-Type")) && request.getHeader("Content-Type").indexOf("application/json") > -1){
            // It can be output directly in the following way
            //response.getWriter().write("sss");
            // But we usually integrate jackson and return json
            // ModelAndView supports both json return and view return
            // The mapping jackson2jsonview is also done at the bottom of the ResponseBody
            ModelAndView modelAndView = new ModelAndView(new MappingJackson2JsonView());
            // Usually different codes will be returned according to different exceptions. Here, for simplicity, just write an s
            modelAndView.addObject("code", HttpStatus.INTERNAL_SERVER_ERROR.value());
            modelAndView.addObject("message",ex.getMessage());
            return modelAndView;
        }
        else{
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.setViewName("error");
            modelAndView.addObject("ex",ex);
            //Log record and get the complete stack information
            System.out.println(getStackTrace(ex));
            return modelAndView;
        }
    }

    public static String getStackTrace(Throwable throwable){
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        try {
            throwable.printStackTrace(pw);
            return sw.toString();
        } finally {
            pw.close();
        }
    }
}

2.5. Processing 404 pages

1. In the WEB-INF folder, create a 404 HTML file
2. Configure static resource mapping in spring's configuration file

<mvc:resources mapping="/404.html" location="/"></mvc:resources>

3,web. Mapping resources in XML

<error-page>
    <error-code>404</error-code>
    <location>/404.html</location>
</error-page>

Keywords: Java JSP Spring Spring MVC mvc

Added by tabatsoy on Wed, 26 Jan 2022 07:59:33 +0200