回顾

我在之前公布了一篇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;    }}

感激各位小伙伴浏览到最初,如有谬误,敬请斧正。