Spring Boot 中提供了默认的异常处理,但是对于应用来说,这些信息并不应该直接返回或者不够明确,需要结合自己的情况进行定制。
自定义处理异常有两种方式:
- org.springframework.web.servlet.HandlerExceptionResolver#resolveException
- org.springframework.web.bind.annotation.RestControllerAdvice或org.springframework.web.bind.annotation.ControllerAdvice和org.springframework.web.bind.annotation.ExceptionHandler注解来实现
当两种方式都实现时,HandlerExceptionResolver要先于ControllerAdvice执行
使用 HandlerExceptionResolver 处理异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| public class CustomExceptionHandlerResolver implements HandlerExceptionResolver {
private static final ObjectMapper OBJECT_MAPPER; static { OBJECT_MAPPER = new ObjectMapper(); OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); OBJECT_MAPPER.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); } @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { String message = "服务器错误"; if (o instanceof HandlerMethod) { if (e instanceof IllegalArgumentException) { message = "参数错误"; } else if (e instanceof SecurityException) { message = "不允许访问"; } else if (e instanceof NullPointerException) { message = "空指针异常"; } } else if (e instanceof NoHandlerFoundException) { message = "未找到相应资源"; } else if (e instanceof HttpMediaTypeNotSupportedException) { message = "请求类型不支持"; } httpServletResponse.setCharacterEncoding(StandardCharsets.UTF_8.name()); httpServletResponse.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); try { httpServletResponse.getWriter() .write( OBJECT_MAPPER.writeValueAsString( CustomResponseContent.builder() .code(500) .status("fail") .message(message) .build() ) ); } catch (IOException ex) { ex.printStackTrace(); } return new ModelAndView(); } }
|
还需要将该配置添加到应用中
1 2 3 4 5 6 7 8
| @Configuration public class CustomWebMvcConfigurer implements WebMvcConfigurer {
@Override public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) { resolvers.add(new CustomExceptionHandlerResolver()); } }
|
使用 RestControllerAdvice/ControllerAdvice 和 ExceptionHandler 处理异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| @RestControllerAdvice @ControllerAdvice public class CustomControllerExceptionResolver {
@ExceptionHandler({NullPointerException.class}) @ResponseBody public ResponseEntity<?> handlerNullPointerException(HttpServletRequest request, Throwable throwable) { CustomResponseContent responseContent = CustomResponseContent.builder() .code(500) .status("fail") .message("空指针异常") .build(); return new ResponseEntity<>(responseContent, HttpStatus.INTERNAL_SERVER_ERROR); } @ExceptionHandler({IllegalArgumentException.class}) @ResponseBody public ResponseEntity<?> handlerIllegalArgumentException(HttpServletRequest request, Throwable throwable) { CustomResponseContent responseContent = CustomResponseContent.builder() .code(400) .status("fail") .message("参数错误") .build(); return new ResponseEntity<>(responseContent, HttpStatus.BAD_REQUEST); } @ExceptionHandler({MethodArgumentNotValidException.class}) @ResponseBody public ResponseEntity<?> handlerMethodArgumentNotValidException(HttpServletRequest request, MethodArgumentNotValidException e) { String errorMessage = e.getBindingResult() .getAllErrors() .stream() .map(f -> ((FieldError) f).getField() + ":" + f.getDefaultMessage()) .collect(Collectors.joining(";")); CustomResponseContent responseContent = CustomResponseContent.builder() .code(400) .status("fail") .message(errorMessage) .build(); return new ResponseEntity<>(responseContent, HttpStatus.BAD_REQUEST); } @ExceptionHandler({Exception.class}) @ResponseBody public ResponseEntity<?> handlerException(HttpServletRequest request, Throwable throwable) { CustomResponseContent responseContent = CustomResponseContent.builder() .code(500) .status("fail") .message(throwable.getMessage()) .build(); return new ResponseEntity<>(responseContent, HttpStatus.INTERNAL_SERVER_ERROR); } }
|
403/404… 等错误
添加了上述的异常处理后,还有一部分异常无法处理,如404 错误,这是因为这些错误的异常处理并不经过异常处理器,而是被转发到 /error的路径下,默认由org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController处理,所以,继承org.springframework.boot.autoconfigure.web.servlet.error.AbstractErrorController并添加相应实现即可自定义处理该异常返回 JSON 数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| @Controller @RequestMapping("/error") public class CustomNoHandlerExceptionResolver extends AbstractErrorController {
public CustomNoHandlerExceptionResolver(ErrorAttributes errorAttributes) { super(errorAttributes); } @Override public String getErrorPath() { return null; } @RequestMapping @ResponseBody public ResponseEntity<?> error(HttpServletRequest request, HttpServletResponse response) { Optional<String> originRequestUri = Optional.ofNullable((String) request.getAttribute("javax.servlet.error.request_uri")); String reasonPhrase = HttpStatus.valueOf(response.getStatus()).getReasonPhrase(); CustomResponseContent responseContent = CustomResponseContent.builder() .code(response.getStatus()) .status("fail") .message(originRequestUri.orElse("/error") + ":" + reasonPhrase) .build(); return new ResponseEntity<>(responseContent, HttpStatus.valueOf(response.getStatus())); } }
|
转载自:https://blog.csdn.net/u013360850/article/details/93101903