文章目录
- springboot默认的错误处理机制
- 默认效果
- 定制错误响应页面
- 如何定制错误页面(有模板的情况下)
- 没有模板的情况下
- 以上都没有错误页面,则直接进入到bootstrap默认错误页面
- 自定义异常类并抛出异常
- 如何定制错误的json数据页面(其他客户端访问)
- 自定义异常&返回定制的json数据
- 增加自适应
- 将定制的数据带出去
- 如何将异常处理器中的错误信息进行显示
springboot默认的错误处理机制
默认效果
1、直接返回错误信息,状态码等,404
2、如果是其他客户端,默认响应一个json数据
定制错误响应页面
如何定制错误页面(有模板的情况下)
- 有模板的情况下;将错误页面命名为错误状态码.html,放在模板引擎文件夹里面的error文件夹下,发生此状态的错误,就会来到对应的页面。
- 可以使用4xx、5xx作为错误页面的文件名来匹配这种类型的错误,优先匹配具体错误代码,如果没有,则使用代号页面
- 页面中可以获取的信息:(defaultErrorAttributes.java)
- timestamp:时间戳
- status:状态码
- error:错误提示
- Exception:异常对象
- message:异常消息
- errors:jsr303数据校验的错误都在这里
- 获取方式
- 使用行内表达式
没有模板的情况下
- 在static文件下下添加error文件下,具体错误页面命名和有模板时一样,但是没有模板的渲染
以上都没有错误页面,则直接进入到bootstrap默认错误页面
自定义异常类并抛出异常
- 先写一个异常类:
package springbootdemo.exception;
public class UserNotExistException extends RuntimeException{
public UserNotExistException() {
super("用户不存在");
}
}
- 在某个请求中抛出异常
package springbootdemo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import springbootdemo.exception.UserNotExistException;
@Controller
public class HelloController {
@ResponseBody
@GetMapping("/hello")
public String hello(@RequestParam("user") String user){
//在hello请求中获取user的值
//当值等于admin的时候,抛出异常
if ("admin".equals(user)) {
throw new UserNotExistException();
}
return "hello,world";
}
}
- 定制html页面,显示异常信息
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>status:[[${status}]]</h2>
<h2>timestamp:[[${timestamp}]]</h2>
<!--显示异常信息-->
<h2>message:[[${message}]]</h2>
<!--显示异常对象-->
<h2>exception:[[${exception}]]</h2>
</body>
</html>
如何定制错误的json数据页面(其他客户端访问)
自定义异常&返回定制的json数据
没有自适应,无论在浏览器端还是其他移动端,都显示一样的数据
- 创建一个异常处理类
package springbootdemo.controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import springbootdemo.exception.UserNotExistException;
import java.util.HashMap;
import java.util.Map;
@ControllerAdvice
public class MyExceptionHandler {
@ResponseBody
//出现异常时,springmvc将会把这个调用这个方法来处理异常
//注解表上要处理哪些异常
@ExceptionHandler({UserNotExistException.class})
public Map<String, Object> handlerException(Exception e){
Map<String,Object> map = new HashMap<>();
//定制返回信息,使用json格式
map.put("code","user not exist");
map.put("message",e.getMessage());
return map;
}
}
增加自适应
basicErrorController类可以处理/error请求,/error请求是自适应的
/error请求自适应:如果浏览器页面,则显示错误页面,如果是其他客户端,则显示json数据
- 修改异常处理方法
@ExceptionHandler({UserNotExistException.class})
public String handlerException(Exception e){
Map<String,Object> map = new HashMap<>();
map.put("code","user not exist");
map.put("message",e.getMessage());
//转发到/error,让它来帮助进行自适应
return "forward:/error";
}
- 缺陷还是存在,出现错误之后又到了默认空白页面
- 原因:错误视图没有解析到
- 错误页面中错误状态码都为200,不是属于错误状态码
- 解决方法:传入自己的错误状态码,不传递默认为200
//basicErrorController类中进行错误状态码的设置
HttpStatus status = this.getStatus(request);
if (status == HttpStatus.NO_CONTENT) {
return new ResponseEntity(status);
} else {
Map<String, Object> body = this.getErrorAttributes(request, this.getErrorAttributeOptions(request, MediaType.ALL));
return new ResponseEntity(body, status);
}
@ExceptionHandler({UserNotExistException.class})
public String handlerException(Exception e, HttpServletRequest request){
Map<String,Object> map = new HashMap<>();
//设置自己的错误状态码,默认为200,不会进入错误页面的解析流程,应该自己设置状态码
/**
* 在AbstractErrorController中使用如下方式设置错误状态码
*Integer statusCode = (Integer)request.getAttribute("javax.servlet.error.status_code");
*/
request.setAttribute("javax.servlet.error.status_code",500);
map.put("code","user not exist");
map.put("message",e.getMessage());
//转发到/error,让它来帮助进行自适应
return "forward:/error";
}
- 解决了自适应的问题,但是我们自己带入的错误数据没有显示(
map.put("code","user not exist"); map.put("message",e.getMessage());
)
将定制的数据带出去
出现错误之后,会来到/error请求,会被basicErrorController类处理,响应出去可以获取的数据是由类中调用了abstractErrorController类(basicErrorController的父类,ErrorController的子类)中的
getErrorAttributes()
方法获取的。basicErrorController(使用了@ConditionalOnMissingBean)在springboot中属于默认处理error请求的类,在没有自定义的情况下,默认使用
- 解决方法
- 完全编写一个ErrorController类(或者abstractErrorController),放在容器中
- 页面上能用的数据,或者是json返回能用的数据都是通过errorAttributes(使用了@ConditionalOnMissingBean).getErrorAttributes得到的,
在springboot中,就是使用defaultErrorAttributes.getErrorAttributes默认进行数据处理,所以,可以自定义一个MyErrorAttributes类
/**
* 在容器中添加自定义的errorattributes,来定制返回信息
*/
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
Map<String, Object> map = super.getErrorAttributes(webRequest, options);
//在这个map中添加自己的错误信息
map.put("author","Zer0");
return map;
}
}
如何将异常处理器中的错误信息进行显示
- 将异常处理器中的信息传递给自定义的errorattribute类中
@ExceptionHandler({UserNotExistException.class})
public String handlerException(Exception e, HttpServletRequest request){
Map<String,Object> map = new HashMap<>();
//设置自己的错误状态码,默认为200,不会进入错误页面的解析流程,应该自己设置状态码
/**
* 在AbstractErrorController中使用如下方式设置错误状态码
*Integer statusCode = (Integer)request.getAttribute("javax.servlet.error.status_code");
*/
request.setAttribute("javax.servlet.error.status_code",500);
map.put("code","user not exist");
map.put("message",e.getMessage());
//将map放到request域中,通过setarttibutes方法进行设置
request.setAttribute("ext",map);
//转发到/error,让它来帮助进行自适应,同时将map带过去
return "forward:/error";
}
- 在MyErrorAttribute类中进行接收
public class MyErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
//这个map是页面和json获取的所有字段
Map<String, Object> map = super.getErrorAttributes(webRequest, options);
//在这个map中添加自己的错误信息
map.put("author","Zer0");
/**
* 通过webRequest(封装之后的requestattribute)对象的getAttribute方法获取异常处理器中的信息
* 两个参数:
* 第一个是要获取的数据名
* 第二个表上从哪里获取数据(session(1)、request(0))
*/
Map<String,Object> ext = (Map<String, Object>) webRequest.getAttribute("ext", 0);
//将信息合并
map.put("ext",ext);
return map;
}