- The default exception handling in Spring
- use
@ResponseStatus
Handle custom exceptions - use
Try {... } catch
Catching exceptions manually - use
@ExceptionHandler
Handle custom exceptions - use
@ControllerAdvice
Annotations handle all exceptions - conclusion
- reference
The default exception handling in Spring
In Spring, some exceptions are mapped to HTTP status codes by default and do not require program handling. The following table lists Spring’s default handling exceptions:
Spring abnormal | The HTTP status code |
---|---|
BindException | 400 – Bad Request |
ConversionNotSupportedException | 500 – Internal Server Error |
HttpMediaTypeNotAcceptableException | 406 – Not Acceptable |
HttpMediaTypeNotSupportedException | 415 – Unsupported Media Type |
HttpMessageNotReadableException | 400 – Bad Request |
HttpMessageNotWritableException | 500 – Internal Server Error |
HttpRequestMethodNotSupportedException | 405 – Method Not Allowed |
MethodArgumentNotValidException | 400 – Bad Request |
MissingServletRequestParameterException | 400 – Bad Request |
MissingServletRequestPartException | 400 – Bad Request |
NoSuchRequestHandlingMethodException | 404 – Not Found |
TypeMismatchException | 400 – Bad Request |
Exceptions in the above table are thrown by Spring itself and returned if problems occur during DispatcherServlet processing or validation. For example, if the DispatcherServlet unable to find a suitable for processing the request method of controller, so will be thrown NoSuchRequestHandlingMethodException abnormalities, the end result is the response of the 404 status code (Not Found).
use@ResponseStatus
Handle custom exceptions
However, it cannot handle custom exceptions thrown from within the application. For example, if a service throws a custom NullOrgException, we add @responseStatus to the NullOrgException exception and specify the status code.
The following code:
package com.rebecca.springmvc.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
/** * Custom exception *@Author: Rebecca
* @Description:
* @Date: Created in 2019/6/14 17:04
* @Modified By:
*/
@ResponseStatus(value = HttpStatus.NO_CONTENT, reason = "No Content")
public class NullOrgException extends RuntimeException {}Copy the code
useTry {... } catch
Catching exceptions manually
Once the above exceptions are defined, any NullOrgException thrown in the application will be caught and mapped to the corresponding status code. So what if the program doesn’t just need a status code, but also the error it generates? At this point, we can no longer treat exceptions as HTTP errors, but as requests.
package com.rebecca.springmvc.controller.exception;
import com.rebecca.springmvc.org.bean.Org;
import com.rebecca.springmvc.org.service.OrgService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
@RequestMapping("test/exception")
public class ExceptionTestController {
private Logger logger = LoggerFactory.getLogger(ExceptionTestController.class);
@Autowired
private OrgService service;
@RequestMapping(value = "orgs", method = RequestMethod.GET)
@ResponseBody
public List<Org> getOrgs (a) {
List<Org> orgs = null;
try {
orgs = service.getOrgs();
} catch (NullOrgException e) {
logger.error("No organization related data!",e);
}
returnorgs; }}Copy the code
For example, the NullOrgException in the above code does not have a default mapping in Spring, so the simplest solution is to try {… } Catch (NullOrgException e) {… }.
use@ExceptionHandler
Handle custom exceptions
The above try {… The} catch approach is bad for code maintenance, but Spring provides a mechanism to map exceptions to HTTP status codes using the @ExceptionHandler annotation. Here’s how it works with the @ExceptionHandler annotation:
package com.rebecca.springmvc.controller.exception;
import com.rebecca.springmvc.org.bean.Org;
import com.rebecca.springmvc.org.service.OrgService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
@RequestMapping("test/exception")
public class ExceptionTestController {
private Logger logger = LoggerFactory.getLogger(ExceptionTestController.class);
@Autowired
private OrgService service;
@RequestMapping(value = "orgs", method = RequestMethod.GET)
@ResponseBody
public List<Org> getOrgs (a) {
List<Org> orgs = service.getOrgs();
return orgs;
}
@ExceptionHandler(NullOrgException.class)
public String handleNullOrgException(a) {
return "No organization related data!"; }}Copy the code
In the code above, we added the @ExceptionHandler annotation to handleNullOrgException(), which will be delegated when a NullOrgException is thrown. It returns a String, but you can change it to another return type to suit your application. For a method annotated with the @ExceptionHandler annotation, it can handle exceptions thrown by all handler methods in the same Controller.
To avoid writing duplicate @ExceptionHandler annotation methods in multiple controllers, we create a base controller class that all controller classes extend to inherit the common @ExceptionHandler method.
use@ControllerAdvice
Annotations handle all exceptions
We said that the @ExceptionHandler annotation can only handle exceptions thrown by all handler methods in a Controller. Is there a way to handle exceptions thrown by handler methods in all controllers without integration?
The answer is: yes! Starting with Spring 3.2, this is definitely possible, and we just need to define it in the controller notification class.
After Spring 3.2, a new solution to this problem was introduced: controller notifications.
ControllerAdvice is any class annotated @ControllerAdvice.
This class may contain one or more methods of the following types:
@ExceptionHandler
Annotation annotation method;@InitBinder
Annotation annotation method;@ModelAttribute
Annotation annotation method.
In a class annotated with @ControllerAdvice, these methods will be applied to methods annotated with @RequestMapping on all controllers throughout the application. The @ControllerAdvice annotation already uses @Component, so classes annotated by the @ControllerAdvice annotation will automatically be scanned by the Component, just like classes annotated by the @Component annotation. One of the most useful scenarios for @ControllerAdvice is to collect all @ExceptionHandler methods into a single class so that all controller exceptions can be handled uniformly in one place. For example, we want to apply NullOrgException handling to all controllers throughout the application. The listing below shows AppWideExceptionHandler, a class annotated with @ControllerAdvice, that does this. This code uses @controllerAdvice to handle exceptions for all controllers:
package com.rebecca.springmvc.controller.exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
/** * Controller notification class *@Author: Rebecca
* @Description:
* @Date: Created in 2019/6/14 16:30
* @Modified By:
*/
@ControllerAdvice // Define the controller class
public class AppWideException {
// Define exception handling methods
@ExceptionHandler(NullOrgException.class)
public String handleNullOrgException(a) {
return "No organization related data!"; }}Copy the code
Now, if any controller method throws DuplicateSpittleException, regardless of the method in which the controller that will be called the duplicateSpittleHandler () method to handle the exception. We can write the @ExceptionHandler annotation method the same way we wrote the @requestMapping annotation method. As shown in Listing 7.10, it returns “error/ Duplicate” as the logical view name, so it presents a user-friendly error page.
conclusion
Exception handling in Spring:
- Specific Spring exceptions are automatically mapped to the specified HTTP status code;
- abnormalCan be added to
@ResponseStatus
Annotations to map to an HTTP status code; - inmethodsCan be added to
@ExceptionHandler
Annotations that are used to handle exceptions. - will
@ExceptionHandler
The annotation exception method is extracted from@ControllerAdvice
In annotated classes, the entire application takes effect (this approach only works with Spring3.2+).
The easiest way to handle an exception is to map it to an HTTP status code and place it in the response.
reference
“Spring Combat Edition 4”