在SpringBoot项目中,项目出错会有默认的返回页面及返回数据,当使用浏览器访问时会跳转到错误页面
那么如果是其他设备访问会是啥呢,比如手机端,下面通过PostMan演示
可以看到返回的是JSON字符串,所以说SpirngBoot 对于错误处理还是比较好的。
对于错误处理的自动配置在spring-boot-autoconfigure-2.0.6.RELEASE.jar的org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration中有配置
1.通过ErrorMvcAutoConfiguration给容器中添加了一下组件
DefaultErrorAttributes:页面共享错误信息(错误时间,错误状态码等),通过调用getErrorAttributes()方法获得错误信息
BasicErrorController:用来处理ErrorPageCustomizer发出的/error请求
在其方法中又通过两种方式返回不同的数据(这就是为啥通过浏览器请求返回html,通过其他客户端返回json)
那么为啥能区分浏览器或其他客户端呢?因为浏览器在请求头中设置了优先接收html数据
那么是如何响应页面和响应数据的呢 ?通过resolveErrorView(request, response, status, model)返回ModelAndView确定去那个页面,进入到resolveErrorView(request, response, status, model)方法中,查看解析代码
获得所有的ErrorViewResolver,而这个ErrorViewResolver就是下面的DefaultErrorViewResolver组件,去哪个页面就是由它来解析的的,通过DefaultErrorViewResolver组件得知
ErrorPageCustomizer:当系统出现错误时,通过getPath()获得到错误请求路径(/error),来到/error请求进行处理
DefaultErrorViewResolver:解析出现错误时返回到哪个页面
也可以将页面命名为4xx.html或5xx.html,这样以4或5开头的状态码 就会访问到对应页面
2.出现错误步骤,当错误状态码为4xx或5xx等错误时,ErrorPageCustomizer就会生效(定制错误响应规则),来到/error请求,就会被BasicErrorController处理
3.如何定制错误页面?如果有模板引擎的情况下,要想定制返回页面就可以在模板引擎下创建/error/错误状态码.html页面(将页面放在模板引擎的error文件夹下,命名为状态码.html),试想状态码很多,不能所有状态码都建一个页面,所以在DefaultErrorViewResolver中提供了将页面命名为4xx.html或5xx.html解决以4或5开头的状态码错误(提示:优先寻找精确状态码的页面),那么如果页面想要获得错误信息呢?通过组件一DefaultErrorAttributes的getErrorAttributes()可以获得错误信息,SpringBoot默认封状态model/body中,所以在页面上可以通过thymeleaf获取。如果没有模板引擎,默认去静态资源文件夹下找/error/状态码.html,但是没有模板引擎就不能获得错误信息。如果模板引擎文件夹及静态资源文件夹下都没有页面时,就来到SpringBoot默认的提示页面,通过spel表达式解析
4.如何定制错误的json数据?通过异常处理器返回json数据
import java.util.HashMap;
import java.util.Map;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice
public class MyExceptionHandler {
@ExceptionHandler(MyException.class)//捕获自定义异常
@ResponseBody
public Map handlerException(Exception e) {//出现异常时会将异常传递过来
Map map = new HashMap();
map.put("code", "自定义状态码");
map.put("msg", e.getMessage());
return map;
}
}
通过上面一种方法会没有自适应效果,即不管通过浏览器或是其他客户端访问返回的都是json数据,而我们想要通过浏览器访问返回页面,其他客户端访问返回json数据,我们把上面方法改为
@ExceptionHandler(MyException.class)
public String handlerException(Exception e,HttpServletRequest request) {
Map map = new HashMap();
map.put("code", "自定义状态码");
map.put("msg", e.getMessage());
//设置错误状态码,一定要设置,否者就不会进入到自定义页面中
request.setAttribute("javax.servlet.error.status_code", 404);
//将自己的异常信息加入到request
request.setAttribute("extMap", map);
//转发到/error
return "forward:/error";
}
这里一定要加一个javax.servlet.error.status_code,否则无法解析自定义的页面,因为在解析页面时,通过geuStatus()从request中获得javax.servlet.error.status_code
上面已经说过,不管页面还是其它客户端返回的错误信息都是通过org.springframework.boot.autoconfigure.web.servlet.error.AbstractErrorController.getErrorAttributes(HttpServletRequest, boolean)方法返回的,在自定义json返回信息是,如果只是通过上面方式,在返回的json数据中是无法获得我们自定义的信息的,那么我们需要如何做呢?既然页面和json的错误信息都是通过getErrorAttributes(HttpServletRequest, boolean)获取,那么我们就写一个类继承DefaultErrorAttributes(上面提到的组件一),重写getErrorAttributes()方法就可以啦
import java.util.Map;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.WebRequest;
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {
@Override
public Map getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
Map errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace);
Map map = (Map) webRequest.getAttribute("extMap", 0);//0标识从request中获取
errorAttributes.put("tag", "标识");
errorAttributes.put("extMap",map);
return errorAttributes;//返回最终map
}
}
这样通过其他客户端访问返回的信息就有我们自己定义的错误信息了