回顾
我在之前公布了一篇spring对立返回的文章,最初提到是无奈捕捉404异样的,这里咱们先来测试一下
@RestControllerpublic class TestController { @GetMapping("/test") public String insert22() { return "hello"; }}
浏览器申请试一下 http://localhost:8080/xxx 报错
# Whitelabel Error PageThis application has no explicit mapping for /error, so you are seeing this as a fallback.Wed Dec 29 10:14:36 CST 2021There was an unexpected error (type=Not Found, status=404).
springboot的解决形式
springboot解决这个404的异样是在 BasicErrorController
中解决的
@Controller@RequestMapping("${server.error.path:${error.path:/error}}")public class BasicErrorController extends AbstractErrorController { ........... @Override public String getErrorPath() { return null; } @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); } // 蕴含申请头 "Accept": "application/json" 会往这里走 @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); } .............}
只有申请门路/error就能够进去到errorHtml
这个办法,在浏览器申请http://localhost:8080/error就能够进入这个办法
解决方案
我这应用的springboot的版本为2.3.7.RELEASE
计划1:重写/error的申请
这种计划会间接舍弃掉HTML响应形式,然而前后端拆散模式下,后端曾经很少应用ModelAndView了
@Controllerpublic class NoFoundController extends AbstractErrorController { public NoFoundController(ErrorAttributes errorAttributes) { super(errorAttributes); } /** * 默认门路/error,能够通过server.error.path配置 */ @RequestMapping(("${server.error.path:/error}")) public ResponseEntity<Map<String, Object>> notFoundError(HttpServletRequest request, HttpServletResponse response) { Map<String, Object> map = new HashMap<>(3); HttpStatus status = getStatus(request); map.put("code", status.value()); map.put("data", null); map.put("message", status.toString()); return new ResponseEntity<>(map, status); } /** * 在springboot2.3.0新增了server.error.path进行配置,这个废除应用了,之前版本能够间接通过设置这个返回值批改默认/error的门路 */ @Override public String getErrorPath() { return null; }}
计划2:重写BasicErrorController中的错误处理
这种形式无奈将HTML响应的也改成了json返回,申请中要有"Accept": "application/json"
能力走json响应
@Controller@RequestMapping("${server.error.path:${error.path:/error}}")public class MyBasicErrorController extends BasicErrorController { public MyBasicErrorController(ServerProperties serverProperties) { // import org.springframework.boot.web.servlet.error.DefaultErrorAttributes; super(new DefaultErrorAttributes(), serverProperties.getError()); } /** * JSON响应 */ @Override public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) { Map<String, Object> map = new HashMap<>(); HttpStatus status = getStatus(request); map.put("code", status.value()); map.put("data", null); map.put("message", status.toString()); return new ResponseEntity<>(map, status); } /** * HTML响应,依据需要解决本人解决 */ @Override public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { return super.errorHtml(request, response); }}
其中MyBasicErrorController
的构造函数能够参考spring主动拆卸ErrorMvcAutoConfiguration
中的传值
//源码:public class ErrorMvcAutoConfiguration { private final ServerProperties serverProperties; public ErrorMvcAutoConfiguration(ServerProperties serverProperties) { this.serverProperties = serverProperties; } @Bean @ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT) public DefaultErrorAttributes errorAttributes() { // ErrorAttributes return new DefaultErrorAttributes(); } @Bean @ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT) public BasicErrorController basicErrorController(ErrorAttributes errorAttributes, ObjectProvider<ErrorViewResolver> errorViewResolvers) { // serverProperties.getError return new BasicErrorController(errorAttributes, this.serverProperties.getError(), errorViewResolvers.orderedStream().collect(Collectors.toList())); } ........}
最初附上残缺代码:
@Getterpublic class BusinessException extends RuntimeException { private Integer code; public BusinessException(Integer code, String message) { super(message); this.code = code; } public BusinessException(String message) { super(message); }}--------------------------------------------------------------------------------------------@ControllerAdvice@ResponseBody@Slf4jpublic class GlobalException { @ExceptionHandler(value = BusinessException.class) public ResponseModel<Void> businessExceptionError(BusinessException e) { log.error("业务异样", e); if (e.getCode() != null) { return ResponseModel.error(e.getCode(), e.getMessage()); } return ResponseModel.error(e.getMessage()); } @ExceptionHandler(value = Exception.class) public ResponseModel<Void> exceptionError(Exception e) { log.error("零碎异样", e); return ResponseModel.error(); }}--------------------------------------------------------------------------------------------@Getterpublic enum ResponseEnum { SUCCESS(0, "OK"), PARAMETER_ERROR(1,"参数异样"), NO_FOUND(404,"not found"), SYSTEM_ERROR(500, "服务器异样,请分割管理员"); ResponseEnum(Integer code, String message) { this.code = code; this.message = message; } private final Integer code; private final String message;}--------------------------------------------------------------------------------------------public class ResponseModel<T> { private Integer code; private String message; private T data; public ResponseModel(Integer code, String message, T data) { this.code = code; this.message = message; this.data = data; } public static ResponseModel<Void> ok() { return ok(null); } public static <T> ResponseModel<T> ok(T data) { return new ResponseModel<>(ResponseEnum.SYSTEM_ERROR.getCode(), ResponseEnum.SYSTEM_ERROR.getMessage(), data); } public static <T> ResponseModel<T> ok(T data, String message) { return new ResponseModel<>(ResponseEnum.SYSTEM_ERROR.getCode(), message, data); } public static ResponseModel<Void> error(Integer statusCode, String message) { return new ResponseModel<>(statusCode, message, null); } public static ResponseModel<Void> error(String message) { return error(ResponseEnum.SYSTEM_ERROR.getCode(), message); } public static ResponseModel<Void> error() { return error(ResponseEnum.SYSTEM_ERROR.getCode(), ResponseEnum.SYSTEM_ERROR.getMessage()); }}--------------------------------------------------------------------------------------------@Controllerpublic class NoFoundController extends AbstractErrorController { public NoFoundController(ErrorAttributes errorAttributes) { super(errorAttributes); } /** * 默认门路/error,能够通过server.error.path配置 */ @RequestMapping(("${server.error.path:/error}")) public ResponseEntity<Map<String, Object>> notFoundError(HttpServletRequest request, HttpServletResponse response) { Map<String, Object> map = new HashMap<>(3); HttpStatus status = getStatus(request); map.put("code", status.value()); map.put("data", null); map.put("message", status.toString()); return new ResponseEntity<>(map, status); } /** * 在springboot2.3.0新增了server.error.path进行配置,这个废除应用了,之前版本能够间接通过设置这个返回值批改默认/error的门路 */ @Override public String getErrorPath() { return null; }}
感激各位小伙伴浏览到最初,如有谬误,敬请斧正。