Spring boot series (x) unified exception handling and unified result return
Previous recommendation
Spring boot series (I) idea new spring boot project
Introduction to SpringBoot series (2)
Spring boot series (3) configuration file details
Spring boot series (IV) detailed explanation of web static resource configuration
Spring boot series (V) Mybatis integrated full detailed version
Spring boot series (6) integrated tymeleaf detailed Edition
Spring boot series (7) integration interface document swagger, use, test
Spring boot series (8) minutes learn spring boot's multiple cross domain solutions
Spring boot series (9) correct posture for single and multi file upload
Catalog
- 1. Global exception capture and handling
- 2. Unified result return and unified exception
- 3. controller code test and results
- 4. 404 exception special handling.
- 5. Summary
introduction:
in the process of daily development, it is inevitable that some programs will throw exceptions for some reasons, and these exceptions are generally handled by try, catch or throw, throws. This method is also cumbersome for programmers and not very friendly for customers, so we hope that it can not only facilitate programmers to write code, but also improve the user experience without too many exceptions. At this time, global exception handling is very important and convenient, which is a good choice.
1. Global exception capture and handling
because the current mainstream projects are front-end and back-end separation, our exception handling is also described according to front-end and back-end separation.
Springboot also provides good support for exception handling. It provides an @ ControllerAdvice annotation and an @ ExceptionHandler annotation. The former is used to enable global exception capture, and the latter is used to indicate which exceptions are caught and handle those exceptions.
@ControllerAdvice public class MyExceptionHandler { @ExceptionHandler(value =Exception.class) public String exceptionHandler(Exception e){ System.out.println("An exception occurred"+e); return e.getMessage(); } }
the above code means that as long as there is an exception in the code running process, it will be caught and output the exception. Then we write a random code that will generate exceptions, and the exceptions tested are like this.
this is not good for our front-end and back-end separation. The only interaction after the front-end and back-end separation is json. We also want to turn the backend exception into json and return it to the front-end for processing. Let's take a look at unified result processing.
2. Unified result return and unified exception
code:
public class Result<T> { //Success or not private Boolean success; //Status code private Integer code; //Tips private String msg; //data private T data; public Result() { } //Customize the construction method of returned results public Result(Boolean success,Integer code, String msg,T data) { this.success = success; this.code = code; this.msg = msg; this.data = data; } //Custom exception returned results public static Result defineError(DefinitionException de){ Result result = new Result(); result.setSuccess(false); result.setCode(de.getErrorCode()); result.setMsg(de.getErrorMsg()); result.setData(null); return result; } //Results returned by other exception handling methods public static Result otherError(ErrorEnum errorEnum){ Result result = new Result(); result.setMsg(errorEnum.getErrorMsg()); result.setCode(errorEnum.getErrorCode()); result.setSuccess(false); result.setData(null); return result; } }
Note: get and set methods are omitted. In addition, a custom enumeration is included in the method. The code is as follows:
public enum ErrorEnum { // Data operation error definition SUCCESS(200, "nice"), NO_PERMISSION(403,"You don't have permission"), NO_AUTH(401,"Can you log in first"), NOT_FOUND(404, "The resource was not found!"), INTERNAL_SERVER_ERROR(500, "The server is running"), ; /** Error code */ private Integer errorCode; /** error message */ private String errorMsg; ErrorEnum(Integer errorCode, String errorMsg) { this.errorCode = errorCode; this.errorMsg = errorMsg; } public Integer getErrorCode() { return errorCode; } public String getErrorMsg() { return errorMsg; } }
note: enumeration class defines common error codes and error prompt information. Here we have defined a unified result return, in which the static method is used to convert to the specified format of exception return when the program is abnormal.
then we need to customize the exception handling class. The code is as follows:
public class DefinitionException extends RuntimeException{ protected Integer errorCode; protected String errorMsg; public DefinitionException(){ } public DefinitionException(Integer errorCode, String errorMsg) { this.errorCode = errorCode; this.errorMsg = errorMsg; } public Integer getErrorCode() { return errorCode; } public void setErrorCode(Integer errorCode) { this.errorCode = errorCode; } public String getErrorMsg() { return errorMsg; } public void setErrorMsg(String errorMsg) { this.errorMsg = errorMsg; } }
It contains error status code and error prompt information. Then we can customize a global exception handling class to handle all kinds of exceptions, including our own defined Exceptions and internal exceptions. This can simplify a lot of code, without using try and catch for each exception.
@ControllerAdvice public class GlobalExceptionHandler { /** * Handling custom exceptions * */ @ExceptionHandler(value = DefinitionException.class) @ResponseBody public Result bizExceptionHandler(DefinitionException e) { return Result.defineError(e); } /** * Handle other exceptions * */ @ExceptionHandler(value = Exception.class) @ResponseBody public Result exceptionHandler( Exception e) { return Result.otherError(ErrorEnum.INTERNAL_SERVER_ERROR); } }
note: each method is annotated with a @ ResponseBody annotation, which is used to parse the object into json and facilitate the interaction between the front and back ends. You can also use @ ResponseBody to put it on the exception class.
3. controller code test and results
controller code:
@RestController @RequestMapping("/result") public class ResultController { @GetMapping("/getStudent") public Result getStudent(){ Student student = new Student(); student.setAge(21); student.setId(111); student.setName("Learning notes"); Result result = new Result(); result.setCode(200); result.setSuccess(true); result.setData(student); result.setMsg("Student list information"); return result; } @RequestMapping("/getDeException") public Result DeException(){ throw new DefinitionException(400,"I made a mistake"); } @RequestMapping("/getException") public Result Exception(){ Result result = new Result(); int a=1/0; return result; } }
the Student class is the one that has been used before. Contains three properties. The get and set methods are omitted.
public class Student { /** * Unique id */ private Integer id; /** * Full name */ private String name; /** * Age */ private Integer age; }
then start the project to test one by one. First, test the normal data without exception. Browser input: localhost:8095/result/getStudent
you can see that the data is returned to the json string normally. No exception. Then we test the second custom exception handling interface. Browser input localhost:8095/result/getDeException.
you can see that the custom exception was caught and returned a json string. Finally, let's test other exceptions. Browser input: localhost:8095/result/getException
here we have handled the exception and returned to the front end correctly.
as mentioned here, there are many ways to test the interface. You can use postman or the interface test tool provided by idea.
However, you may find a problem. This method can't handle 404 exceptions and can't catch them. What should I do?
4. 404 exception special handling.
by default, SpringBoot does not throw 404 exceptions, so @ ControllerAdvice cannot catch 404 exceptions either. We can use the following configuration to enable this annotation to catch 404 exceptions.
spring.mvc.throw-exception-if-no-handler-found=true spring.resources.add-mappings=false
The first one is to throw an exception directly when 404 exception is found. The second sentence turns off the default static resource path mapping. In this way, 404 errors can also be caught, but this configuration will cause problems in your static resource access, that is, it is not suitable for the situation where the front and back ends are not separated.
5. Summary
this article explains how to handle and capture global exceptions and how to customize exceptions. It also explains the return format of unified results, and the 404, not found exceptions specially handled, which are returned as unified results. If you think this article is useful, like it!