SpringBoot is the product of a series of problems to simplify the creation, operation, debugging and deployment of Spring applications,
The feature of automatic assembly enables us to pay more attention to the business itself rather than the external XML configuration. We can easily build a WEB project by following the specification and introducing the relevant dependency
In the actual project development, there are often various exceptions in the program, especially for us as the server developers,
Always write the interface to the front-end to call. In the case of division and cooperation, exceptions cannot be avoided. If the wrong information is directly exposed to the user,
This kind of experience can be imagined, and for hackers, detailed exception information often provides a great help
First glance abnormality
A simple exception request interface
@GetMapping("/test1") public String test1() { // This is just a simulation exception. Suppose there is an error in business processing, or a null pointer, etc... int i = 10 / 0; return "test1"; }
Found when opening browser to access it
Or use simulation tools such as postman
If this interface is used by a third party or by your own company's system, see that this kind of error estimation is rampant .
Stupid method (extremely not recommended)
Try catch is used to manually capture exception information, and then return the corresponding Result set. It is believed that many people have seen similar code (such as: encapsulated as Result object);
Although this method indirectly solves the problem of error exposure, the same disadvantages are obvious, increasing a large amount of code, when there are too many exceptions, the corresponding catch layer is more and more,
It is difficult to manage the match between these business exceptions and error codes, so the best way is to control the whole situation through simple configuration .
@GetMapping("/test2") public Map<String, String> test2() { Map<String, String> result = new HashMap<>(16); // TODO Capture all code blocks directly, and then cache try { int i = 10 / 0; result.put("code", "200"); result.put("data", "Specific returned result set"); } catch (Exception e) { result.put("code", "500"); result.put("message", "Request error"); } return result; }
Specific code
Through the above reading, you can roughly understand why it is necessary to catch exceptions globally. Next, let's look at the solutions provided by Spring Boot
Import dependency
Add spring boot starter web dependency to pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
Custom exception
In the application development process, in addition to the system's own exceptions, the exceptions used in different business scenarios are also different. In order to easily handle the global exceptions with the title, define your own exceptions and see how to capture them
/** * Custom exception */ public class CustomException extends RuntimeException { private static final long serialVersionUID = 4564124491192825748L; private int code; public CustomException() { super(); } public CustomException(int code, String message) { super(message); this.setCode(code); } public int getCode() { return code; } public void setCode(int code) { this.code = code; } }
Exception information template
Define the format of returned exception information, so that the style of exception information is more uniform
/** * Exception information template */ public class ErrorResponseEntity { private int code; private String message; public ErrorResponseEntity(int code, String message) { this.code = code; this.message = message; } // ellipsis get/set }
Control layer
Take a closer look at whether the normal code written in peace is the same. Don't worry. Then take a look .
import com.winterchen.exception.CustomException; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class ExceptionController { @GetMapping("/test3") public String test3(Integer num) { // TODO It is necessary to demonstrate whether the parameter is empty to pass @RequestParam(required = true) You can control it if (num == null) { throw new CustomException(400, "num Can not be empty"); } int i = 10 / num; return "result:" + i; } }
Exception handling (critical)
Notes overview
- @ControllerAdvice catches the < wiz ﹣ TMP ﹣ highlight ﹣ tag class = "cm searching" > exception thrown by the Controller layer. If @ ResponseBody return information is added, it is in JSON format.
- @Restcontrolleradvise is the combination of @ controlleradvise and @ ResponseBody.
- @The ExceptionHandler uniformly handles a kind of < wiz ﹣ TMP ﹣ highlight ﹣ tag class = "cm searching" > exception, reducing code repetition rate and complexity.
Create a GlobalExceptionHandler class and add the @ RestControllerAdvice annotation to define the exception notification class. Then add @ ExceptionHandler to the defined method to catch the exception
import com.winterchen.exception.CustomException; import com.winterchen.exception.ErrorResponseEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.context.request.WebRequest; import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Global exception handling */ @RestControllerAdvice public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { /** * You can define more than one @ ExceptionHandler({}) to catch * @param request request * @param e exception * @param response response * @return Response results */ @ExceptionHandler(CustomException.class) public ErrorResponseEntity customExceptionHandler(HttpServletRequest request, final Exception e, HttpServletResponse response) { response.setStatus(HttpStatus.BAD_REQUEST.value()); CustomException exception = (CustomException) e; return new ErrorResponseEntity(exception.getCode(), exception.getMessage()); } /** * Catch RuntimeException exception * If you think it is too troublesome to pass if (e instance of xxxexception) in an exception handler * Then you can write several different exceptionhandlers to handle different exceptions * @param request request * @param e exception * @param response response * @return Response results */ @ExceptionHandler(RuntimeException.class) public ErrorResponseEntity runtimeExceptionHandler(HttpServletRequest request, final Exception e, HttpServletResponse response) { response.setStatus(HttpStatus.BAD_REQUEST.value()); RuntimeException exception = (RuntimeException) e; return new ErrorResponseEntity(400, exception.getMessage()); } /** * General interface mapping exception handler */ @Override protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) { if (ex instanceof MethodArgumentNotValidException) { MethodArgumentNotValidException exception = (MethodArgumentNotValidException) ex; return new ResponseEntity<>(new ErrorResponseEntity(status.value(), exception.getBindingResult().getAllErrors().get(0).getDefaultMessage()), status); } if (ex instanceof MethodArgumentTypeMismatchException) { MethodArgumentTypeMismatchException exception = (MethodArgumentTypeMismatchException) ex; logger.error("Parameter conversion failed, method:" + exception.getParameter().getMethod().getName() + ",Parameters:" + exception.getName() + ",Information:" + exception.getLocalizedMessage()); return new ResponseEntity<>(new ErrorResponseEntity(status.value(), "Parameter conversion failed"), status); } return new ResponseEntity<>(new ErrorResponseEntity(status.value(), "Parameter conversion failed"), status); } }
Main function
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SpringBootExceptionApplication { public static void main(String[] args) { SpringApplication.run(SpringBootExceptionApplication.class, args); } }
test
After completing the preparation, start Chapter17Application. Through the following test results, it can be found that it's really so easy, the code has become clean, and the extensibility has become better
visit http://localhost:8080/test3
{"code":400,"message":"num Can not be empty"}
visit http://localhost:8080/test3?num=0
{"code":400,"message":"/ by zero"}
visit http://localhost:8080/test3?num=5
result:2
Reprint link: http://blog.battcn.com/2018/06/01/springboot/v2-other-exception/