Zero base spring boot day 8

brief introduction

Today, we mainly learn about global unified exception handling

step

try catch is often used in Web applications, which will lead to the feeling of disordered code structure and is not conducive to debugging code. It will be a good thing if all exceptions can be unified into one module. Then @ ControllerAdvice and @ ExceptionHandler can be used to define a unified exception handling class to achieve global exception capture and handling

@ControllerAdvice: controller enhancement to apply @ ExceptionHandler, @ InitBinder, @ ModelAttribute annotated methods to all @ RequestMapping annotated methods
@ExceptionHandler: exception handler. This annotation is used to handle the defined exception when it occurs

At com.example.backend_template.exception create a new GlobalExceptionHandler class

package com.example.backend_template.exception;

import com.example.backend_template.utils.ResultData;
import com.example.backend_template.utils.ResultUtils;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.NoHandlerFoundException;

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

/**
 * @ClassName GlobalExceptionHandler Global unified exception handling
 * @Description
 * @Author L
 * @Date Create by 2020/7/7
 */
@ControllerAdvice
public class GlobalExceptionHandler {

    /**
     * The request controller exists, but the request HTTP method does not match that provided by the controller
     *
     * @param ex
     * @param request
     * @return
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex, WebRequest request) {
        ResultData<Object> errorBody = ResultUtils.fail(405, "Http Request Method Not Supported!", ex.getLocalizedMessage());
        return new ResponseEntity<>(errorBody, HttpStatus.METHOD_NOT_ALLOWED);
    }

    /**
     * content-type Content setting type is not supported
     *
     * @param ex
     * @param request
     * @return
     */
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    protected ResponseEntity<Object> handleHttpMediaTypeNotSupported(HttpMediaTypeNotSupportedException ex, WebRequest request) {
        ResultData<Object> errorBody = ResultUtils.fail(415, "Http Media Type Not Supported!", ex.getLocalizedMessage());
        return new ResponseEntity<>(errorBody, HttpStatus.UNSUPPORTED_MEDIA_TYPE);
    }

    /**
     * content-type Content setting type is not acceptable
     *
     * @param ex
     * @param request
     * @return
     */
    @ExceptionHandler(HttpMediaTypeNotAcceptableException.class)
    protected ResponseEntity<Object> handleHttpMediaTypeNotAcceptable(HttpMediaTypeNotAcceptableException ex, WebRequest request) {
        ResultData<Object> errorBody = ResultUtils.fail(406, "Http Media Type Not Acceptable!", ex.getLocalizedMessage());
        return new ResponseEntity<>(errorBody, HttpStatus.NOT_ACCEPTABLE);
    }

    /**
     * Missing path parameter
     *
     * @param ex
     * @param request
     * @return
     */
    @ExceptionHandler(MissingPathVariableException.class)
    protected ResponseEntity<Object> handleMissingPathVariable(MissingPathVariableException ex, WebRequest request) {
        ResultData<Object> errorBody = ResultUtils.fail(500, "Missing Path Variable!", ex.getLocalizedMessage());
        return new ResponseEntity<>(errorBody, HttpStatus.INTERNAL_SERVER_ERROR);
    }

    /**
     * Missing request parameter
     *
     * @param ex
     * @param request
     * @return
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    protected ResponseEntity<Object> handleMissingServletRequestParameter(MissingServletRequestParameterException ex, WebRequest request) {
        ResultData<Object> errorBody = ResultUtils.fail(400, "Missing Servlet Request Parameter!", ex.getLocalizedMessage());
        return new ResponseEntity<>(errorBody, HttpStatus.BAD_REQUEST);
    }

    /**
     * Servlet Request binding error
     *
     * @param ex
     * @param request
     * @return
     */
    @ExceptionHandler(ServletRequestBindingException.class)
    protected ResponseEntity<Object> handleServletRequestBindingException(ServletRequestBindingException ex, WebRequest request) {
        ResultData<Object> errorBody = ResultUtils.fail(400, "Servlet Request Binding!", ex.getLocalizedMessage());
        return new ResponseEntity<>(errorBody, HttpStatus.BAD_REQUEST);
    }

    /**
     * Conversion is not supported
     *
     * @param ex
     * @param request
     * @return
     */
    @ExceptionHandler(ConversionNotSupportedException.class)
    protected ResponseEntity<Object> handleConversionNotSupported(ConversionNotSupportedException ex, WebRequest request) {
        ResultData<Object> errorBody = ResultUtils.fail(500, "Conversion Not Supported!", ex.getLocalizedMessage());
        return new ResponseEntity<>(errorBody, HttpStatus.INTERNAL_SERVER_ERROR);
    }

    /**
     * Parameter type matching failed
     *
     * @param ex
     * @param request
     * @return
     */
    @ExceptionHandler(TypeMismatchException.class)
    protected ResponseEntity<Object> handleTypeMismatch(TypeMismatchException ex, WebRequest request) {
        ResultData<Object> errorBody = ResultUtils.fail(400, "Type Mismatch!", ex.getLocalizedMessage());
        return new ResponseEntity<>(errorBody, HttpStatus.BAD_REQUEST);
    }

    /**
     * HTTP Information request unreadable
     *
     * @param ex
     * @param request
     * @return
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex, WebRequest request) {
        ResultData<Object> errorBody = ResultUtils.fail(400, "Http Message Not Readable!", ex.getLocalizedMessage());
        return new ResponseEntity<>(errorBody, HttpStatus.BAD_REQUEST);
    }

    /**
     * HTTP The information request is not writable
     *
     * @param ex
     * @param request
     * @return
     */
    @ExceptionHandler(HttpMessageNotWritableException.class)
    protected ResponseEntity<Object> handleHttpMessageNotWritable(HttpMessageNotWritableException ex, WebRequest request) {
        ResultData<Object> errorBody = ResultUtils.fail(500, "Http Message Not Writable!", ex.getLocalizedMessage());
        return new ResponseEntity<>(errorBody, HttpStatus.INTERNAL_SERVER_ERROR);
    }

    /**
     * Parameter verification error
     *
     * @param ex
     * @param request
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, WebRequest request) {
        ResultData<Object> errorBody = ResultUtils.fail(400, "Method Argument Not Valid!", ex.getLocalizedMessage());
        return new ResponseEntity<>(errorBody, HttpStatus.BAD_REQUEST);
    }

    /**
     * Some request information is missing
     *
     * @param ex
     * @param request
     * @return
     */
    @ExceptionHandler(MissingServletRequestPartException.class)
    protected ResponseEntity<Object> handleMissingServletRequestPart(MissingServletRequestPartException ex, WebRequest request) {
        ResultData<Object> errorBody = ResultUtils.fail(400, "Missing Servlet Request Part!", ex.getLocalizedMessage());
        return new ResponseEntity<>(errorBody, HttpStatus.BAD_REQUEST);
    }

    /**
     * Parameter binding error
     *
     * @param ex
     * @param request
     * @return
     */
    @ExceptionHandler(BindException.class)
    protected ResponseEntity<Object> handleBindException(BindException ex, WebRequest request) {
        ResultData<Object> errorBody = ResultUtils.fail(400, "Bind Exception!", ex.getLocalizedMessage());
        return new ResponseEntity<>(errorBody, HttpStatus.BAD_REQUEST);
    }

    /**
     * The controller cannot be found according to the request url, i.e. 404 exception
     *
     * @param ex
     * @param request
     * @return
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    protected ResponseEntity<Object> handleNoHandlerFoundException(NoHandlerFoundException ex, WebRequest request) {
        ResultData<Object> errorBody = ResultUtils.fail(404, "No Handler Found!", ex.getLocalizedMessage());
        return new ResponseEntity<>(errorBody, HttpStatus.NOT_FOUND);
    }

    /**
     * Asynchronous request timeout
     *
     * @param ex
     * @param request
     * @return
     */
    @ExceptionHandler(AsyncRequestTimeoutException.class)
    protected ResponseEntity<Object> handleAsyncRequestTimeoutException(AsyncRequestTimeoutException ex, WebRequest request) {
        ResultData<Object> errorBody = ResultUtils.fail(503, "Async Request Timeout!", ex.getLocalizedMessage());
        return new ResponseEntity<>(errorBody, HttpStatus.SERVICE_UNAVAILABLE);
    }

    /**
     * Other non unified exceptions are handled by the following handle to produce writable network exceptions
     *
     * @param ex
     * @param request
     * @return
     */
    @ExceptionHandler(Exception.class)
    protected ResponseEntity<Object> handleAllExceptions(Exception ex, WebRequest request) {
        ResultData<Object> errorBody = ResultUtils.fail(500, "Server Error!", ex.getLocalizedMessage());
        return new ResponseEntity<>(errorBody, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

The above 15 exception handling methods include the exceptions that may be thrown by spring MVC when processing requests. In fact, they are all in ResponseEntityExceptionHandler. You can inherit them and use them directly. My idea is to rewrite the methods of the parent class (for the unification of data return types). Then, do not inherit at all and write them directly. Here, in addition to these 15 exceptions, There is also a handleAllExceptions to handle other non unified exceptions. At this time, in addition to these common exceptions, we also have many business exceptions. Please write a simple example

At com.example.backend_template.exception create a new UserNotFoundException class

package com.example.backend_template.exception;

/**
 * @ClassName UserNotFoundException
 * @Description 
 * @Author L
 * @Date Create by 2020/7/7
 */
public class UserNotFoundException extends RuntimeException {

    public UserNotFoundException() {
        super();
    }

    public UserNotFoundException(final String message) {
        super(message);
    }

    public UserNotFoundException(final Throwable cause) {
        super(cause);
    }

    public UserNotFoundException(final String message, final Throwable cause) {
        super(message, cause);
    }
}

Add the following methods to the GlobalExceptionHandler class

    //The following are custom exceptions
    /**
     * The user was not found
     *
     * @param ex
     * @param request
     * @return
     */
    @ExceptionHandler(UserNotFoundException.class)
    protected ResponseEntity<Object> handleUserNotFoundException(UserNotFoundException ex, WebRequest request) {
        ResultData<Object> errorBody = ResultUtils.fail(404, "User Not Found",ex.getLocalizedMessage());
        return new ResponseEntity<>(errorBody, HttpStatus.NOT_FOUND);
    }


test

Change the root method of SecurityController class to the following code, start the project and access http://localhost:8080/

    @RequestMapping("/")
    public String root() {
        throw new AsyncRequestTimeoutException();
//        return "redirect:/index";
    }

The following content shows that our global exceptions are unified and the returned data format is unified. Remember to change back to the SecurityController class after the test

Of course, we can also try to throw other exceptions to test whether we can return unified results, such as the custom UserNotFoundException exception

For other exceptions, the following results will be uniformly replied here. At this time, it should be noted that in the production environment, throwing exceptions all the time will cause big problems, let alone 500. If you can't solve it for a while, we can report network exceptions. We don't know who came up with this operation

I hope everyone can stick to learning. Life is not easy to see and cherish
Original link: Because the place I want to go is far away, the things I want to buy are not very expensive, and the people I like are also excellent

Keywords: Redis Spring Boot Cache

Added by robtbs on Wed, 17 Nov 2021 12:43:53 +0200