在日常开发中发生了异常,往往是需要通过一个统一的异常处理处理所有异常,来保证客户端能够收到友好的提示。SpringBoot在页面 发生异常的时候会自动把请求转到/error,SpringBoot内置了一个BasicErrorController
对异常进行统一的处理,当然也可以自定义这个路径。
自定义的错误页面
我们会发现无论是发生什么错误,SpringBoot都会返回一个状态码以及一个错误页面,这个错误页面是怎么来的呢?
我们来看看SpringBoot错误处理模块的源码就会非常清楚,默认的发生错误,它会将请求转发到BasicErrorController控制器来处理请求,下面是该controller类的源码:
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
private final ErrorProperties errorProperties;
/**
* Create a new {@link BasicErrorController} instance.
* @param errorAttributes the error attributes
* @param errorProperties configuration properties
*/
public BasicErrorController(ErrorAttributes errorAttributes,
ErrorProperties errorProperties) {
this(errorAttributes, errorProperties,
Collections.<ErrorViewResolver>emptyList());
}
/**
* Create a new {@link BasicErrorController} instance.
* @param errorAttributes the error attributes
* @param errorProperties configuration properties
* @param errorViewResolvers error view resolvers
*/
public BasicErrorController(ErrorAttributes errorAttributes,
ErrorProperties errorProperties, List<ErrorViewResolver> errorViewResolvers) {
super(errorAttributes, errorViewResolvers);
Assert.notNull(errorProperties, "ErrorProperties must not be null");
this.errorProperties = errorProperties;
}
@Override
public String getErrorPath() {
return this.errorProperties.getPath();
}
@RequestMapping(produces = "text/html")
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 ? new ModelAndView("error", model) : modelAndView);
}
@RequestMapping
@ResponseBody
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
Map<String, Object> body = getErrorAttributes(request,
isIncludeStackTrace(request, MediaType.ALL));
HttpStatus status = getStatus(request);
return new ResponseEntity<Map<String, Object>>(body, status);
}
从上面的源码我们可以看到,它有两个RequestMapping方法来映射错误请求,为什么会是两个呢?其实errorHtml方法映射的是浏览器发送来的请求,而error方法映射的是不是浏览器而是其他软件app客户端发送的错误请求。
在resources/public/error/ 下定义404.html,500.html或者在templates/error/下定义404.html,500.html;
注意:templates/error/ 这个的优先级比较 resources/public/error/高
400.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>404</title>
</head>
<body>
亲,您所访问的页面不存在
</body>
</html>
500.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>500</title>
</head>
<body>
服务器内部错误
</body>
</html>
不过注意的是上面的这种自定义页面的方式只在浏览器端有效,而不是浏览器发送的请求不会生效。因此下面我们就讲一下如何自定义异常处理来解决这个问题。
自定义异常处理
1,定义个exception类,yonglai
package com.cx.springbootdemo.exception;
public class UserNotExistException extends RuntimeException{
private static final long serialVersionUID = 1L;
private String id;
public UserNotExistException(String id) {
super("user not exist");
this.id=id;
}
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
加上@ControllerAdvice注解将会处理controller层抛出的对应的异常,这里我们处理controller抛出的UserNotExistException自定义异常,并且将错误信息以及用户id以json串的格式返回给客户。
接着,我们在controller的请求方法中抛出这个异常,会看到在浏览器中的异常是我们自定义的异常返回的json数据。
Controller层代码:
// @GetMapping("/user/{id:\\d+}")
@RequestMapping(value="/user/{id:\\d+}",method=RequestMethod.GET)
public User get(@PathVariable String id) {
throw new UserNotExistException(id);
}