SpringBoot 如何优雅处理- 自定义restful 404 Error

背景

相信大家使用springboot开发的小伙伴,对下面两张截图都不陌生:

但大多数解决自定义404 Not Found- application/json类型的时候,都是通过定义class HttpErrorHandler implements ErrorController,然后在application.properties 中添加两个配置:

spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false

虽然问题得以解决,但是并不优雅,因为:这两句代码添加之后,又会导致静态资源不可使用。

解决办法

定义class CustomErrorController extends BasicErrorController,具体内容:

package org.my.test.exception;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.my.test.dto.ErrorCodeEnum;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

/**
 * 自定义404- NOT FOUND
 * 
 * @author LeoSong
 * @date 2020/08/25
 */
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class CustomErrorController extends BasicErrorController {

    @Value("${server.error.path:${error.path:/error}}")
    private String path;

    public CustomErrorController(ServerProperties serverProperties) {
        super(new DefaultErrorAttributes(), serverProperties.getError());
    }

    /**
     * 覆盖默认的JSON响应
     */
    @Override
    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
        Map<String, Object> body = new HashMap<String, Object>();
        body.put("code", ErrorCodeEnum.NOT_FOUND.getCode());
        body.put("message", ErrorCodeEnum.NOT_FOUND.getMessage());
        return new ResponseEntity<>(body, HttpStatus.OK);
    }

    /**
     * 覆盖默认的HTML响应
     */
    @Override
    public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
        // 请求的状态
        HttpStatus status = getStatus(request);
        Map<String, Object> model =
            Collections.unmodifiableMap(getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
        response.setStatus(status.value());
        ModelAndView modelAndView = resolveErrorView(request, response, status, model);
        // 指定自定义的视图
        return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
    }

}

再次测试,看到json返回已经是我们自定义的结果了。

这样就不会影响我们静态资源映射了。

总结

刚开始处理404问题的时候,访问地址:http://localhost:8080/sss 时,控制台无任何输出,这怎么定位问题呢,臣妾做不到啊!!!

然后果断开启DEBUG模式启动项目,application.properties增加配置 logging.level.root=DEBUG,然后再次访问,果然发现了问题:

细心的小伙伴已经发现了线索,BasicErrorController的处理,打开这个类的源代码,一切豁然开朗。

我们先看下BasicErrorController是在哪里进行配置的。

在IDEA中,查看BasicErrorController的usage,我们发现这个类是在ErrorMvcAutoConfiguration中自动配置的。查看其源码:

可以看出来,只要我们自己配置一个ErrorController,就可以覆盖掉BasicErrorController的行为。

默认的错误路径是/error,我们可以通过以下配置进行覆盖:

server.error.path=/xxx

Springboot默认的日志级别是info级别,可以通过配置开启,大家要研究一个问题的时候,一定要多多用DEBUG模式调试哦

猜你喜欢

转载自blog.csdn.net/qq_26878363/article/details/111692284