Springboot global exception handling
1, The default exception handling mechanism of Spring Boot
By default, springboot provides two corresponding methods: ① the browser request header is Accept: text/html, and springboot will default to an html document content, which is "Whitelabel Error Page"; ② The Json format string information will be returned.
Principle:
/** * springboot The result mapping path of program error is provided by default / error, * This / error request will be processed in the BasicErrorController. * Internally, it determines whether the content of Accept in the request header is text/html to distinguish whether the request comes from * Text: accept client automatically send content request header * Or the call of the client interface to decide whether to return the page view or JSON message content. * public static final String TEXT_HTML_VALUE = "text/html"; */ @Controller @RequestMapping("${server.error.path:${error.path:/error}}") public class BasicErrorController extends AbstractErrorController { @RequestMapping(produces = MediaType.TEXT_HTML_VALUE) public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { HttpStatus status = getStatus(request); Map<String, Object> model = Collections .unmodifiableMap(getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.TEXT_HTML))); response.setStatus(status.value()); ModelAndView modelAndView = resolveErrorView(request, response, status, model); return (modelAndView != null) ? modelAndView : new ModelAndView("error", model); } @RequestMapping public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) { HttpStatus status = getStatus(request); if (status == HttpStatus.NO_CONTENT) { return new ResponseEntity<>(status); } Map<String, Object> body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL)); return new ResponseEntity<>(body, status); }
2, How to customize the error page
- Create error directly under / resources/templates HTML can overwrite the error page of the default Whitelabel Error Page
- Different view pages are returned according to different status codes, that is, the corresponding 404500 and other pages. There are two kinds here. The error page can be static HTML (that is, added to any static resource folder) or built using a template. The name of the file should be the exact status code.
– if it is only a static HTML page without error information, create the error directory under resources/public / and the corresponding status code HTML under the error directory
– if it is a dynamic template page, you can bring an error message and create an error directory under resources/templates / - The above situations are summarized as follows:
– error.html will override the default whitelabel Error Page error prompt
– static error pages take precedence over error HTML high
– dynamic template error pages have higher priority than static error pages
3, Handle exceptions through the @ ControllerAdvice annotation
There are two situations:
Local exception handling @ Controller + @ExceptionHandler
Global exception handling @ ControllerAdvice + @ExceptionHandler
1. Local exception handling @ Controller + @ExceptionHandler
The @ ExceptionHandler annotation is mainly used for local exceptions. This annotation is annotated on the method of the class. When the exception defined in this annotation is thrown, this method will be executed. If the class of @ ExceptionHandler is @ Controller, this method only works on this class. If the class of @ ExceptionHandler is annotated with @ ControllerAdvice, this method will work globally.
@Controller public class BaseErrorController extends AbstractController{ private Logger logger = LoggerFactory.getLogger(this.getClass()); @RequestMapping(value="/ex") @ResponseBody public String error(){ int i=5/0; return "ex"; } //Local exception handling @ExceptionHandler(Exception.class) @ResponseBody public String exHandler(Exception e){ // Judge the type of exception except 0, and respond to the exception if(e instanceof ArithmeticException){ return "Exception except 0 occurred"; } // Respond to an unknown exception return "An unknown exception occurred"; } }
This annotation is used for annotation processing methods to handle those specific exceptions. The methods marked by this annotation can have the following parameter types in any order:
-
Throwable, Exception and other Exception objects;
-
ServletRequest,HttpServletRequest,ServletResponse,HttpServletResponse;
-
Session objects such as HttpSession;
-
org.springframework.web.context.request.WebRequest;
-
java.util.Locale;
-
java.io.InputStream,java.io.Reader;
-
java.io.OutputStream,java.io.Writer;
-
org.springframework.ui.Model;
And the method marked by the annotation can have the following return value types:
-
ModelAndView;
-
org.springframework.ui.Model;
-
java.util.Map;
-
org.springframework.web.servlet.View;
-
@Any object marked with the ResponseBody annotation;
-
HttpEntity<?> or ResponseEntity<?>;
-
void;
The above list is incomplete. For more detailed information, please refer to: Spring ExceptionHandler.
2. Global exception handling @ ControllerAdvice + @ExceptionHandler
In spring 3.2, @ ControllerAdvice annotation is added, which can be used to define @ ExceptionHandler, @ InitBinder, @ ModelAttribute and apply to all @ RequestMapping.
In short, errors entering the Controller layer will be handled by @ ControllerAdvice. Errors thrown by interceptors and access to wrong addresses will not be handled by @ ControllerAdvice and will be handled by the default exception handling mechanism of SpringBoot.
4, Custom
1. Customize the returned results
package com.kuen.language.common.to; import org.springframework.http.HttpStatus; import java.util.HashMap; import java.util.Map; /** * @program: Language * @description: Return result object * @author: Kuen.Hou * @create: 2022-03-05 09:59 **/ public class ResultObject extends HashMap<String, Object> { private static final long serialVersionUID = -2227292363737068440L; public ResultObject() { put("code", 0); } @Override public ResultObject put(String key, Object value) { super.put(key, value); return this; } public ResultObject data(Object value) { super.put("data", value); return this; } public static ResultObject error() { return error(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Unknown exception, please contact the administrator"); } public static ResultObject error(String msg) { return error(HttpStatus.INTERNAL_SERVER_ERROR.value(), msg); } public static ResultObject error(int code, String msg) { ResultObject r = new ResultObject(); r.put("code", code); r.put("msg", msg); return r; } public static ResultObject ok() { return new ResultObject(); } public static ResultObject ok(String msg) { ResultObject r = new ResultObject(); r.put("msg", msg); return r; } public static ResultObject ok(Map<String, Object> map) { ResultObject r = new ResultObject(); r.putAll(map); return r; } }
2. Custom exception
package com.kuen.language.multiLanguage.exception; /** * @program: Language * @description: Custom exception * @author: Kuen.Hou * @create: 2022-03-05 10:31 **/ public class CustomException extends RuntimeException { private static final long serialVersionUID = -173110604484282583L; private final String message; private int code = 500; public CustomException(String message) { super(message); this.message = message; } public CustomException(String message, Throwable e) { super(message, e); this.message = message; } public CustomException(String message, int code) { super(message); this.message = message; this.code = code; } public CustomException(String message, int code, Throwable e) { super(message, e); this.message = message; this.code = code; } }
3. Customize the global exception handler
package com.kuen.language.common.handler; import com.kuen.language.common.to.ResultObject; import com.kuen.language.multiLanguage.exception.CustomException; import lombok.extern.slf4j.Slf4j; import org.springframework.ui.Model; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; /** * @program: Language * @description: Custom exception handler * @author: Kuen.Hou * @create: 2022-03-05 10:56 **/ @RestControllerAdvice @Slf4j public class CustomExceptionHandler { /** * Apply to all @ RequestMapping annotation methods and initialize the data binder before its execution * @param binder */ @InitBinder public void initBinder(WebDataBinder binder) { // System.out.println("the request comes in only when there are parameters"); } /** * Bind the value to the Model so that the global @ RequestMapping can get the value * @param model */ @ModelAttribute public void addAttributes(Model model) { // model.addAttribute("author", "Kuen.Hou"); } @ExceptionHandler(Exception.class) public Object handleException(Exception e, HttpServletRequest req){ ResultObject r = new ResultObject(); //Business exception if(e instanceof CustomException){ r.put("code", ((CustomException) e).getCode()); r.put("msg", e.getMessage()); }else{//System abnormality r.put("code","500"); r.put("msg","Unknown exception, please contact the administrator"); } //Use the header in HttpServletRequest to check whether the request is ajax. If it is ajax, return json. If it is non ajax, return view (i.e. ModelAndView) String contentTypeHeader = req.getHeader("Content-Type"); String acceptHeader = req.getHeader("Accept"); String xRequestedWith = req.getHeader("X-Requested-With"); if ((contentTypeHeader != null && contentTypeHeader.contains("application/json")) || (acceptHeader != null && acceptHeader.contains("application/json")) || "XMLHttpRequest".equalsIgnoreCase(xRequestedWith)) { return r; } else { ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("msg", e.getMessage()); modelAndView.addObject("url", req.getRequestURL()); modelAndView.addObject("stackTrace", e.getStackTrace()); modelAndView.setViewName("error"); return modelAndView; } } }