背景
相信大家使用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模式调试哦