前言我用的spring boot版本号是2.0.1
#1、srping boot几种异常类型
spring boot访问视图接口默认处理异常的是用类BasicErrorController
实现的,源码如下,这里只贴出主要方法:
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
private final ErrorProperties errorProperties;
public BasicErrorController(ErrorAttributes errorAttributes,
ErrorProperties errorProperties) {
this(errorAttributes, errorProperties, Collections.emptyList());
}
public BasicErrorController(ErrorAttributes errorAttributes,
ErrorProperties errorProperties, List errorViewResolvers) {
super(errorAttributes, errorViewResolvers);
Assert.notNull(errorProperties, "ErrorProperties must not be null");
this.errorProperties = errorProperties;
}
@RequestMapping(produces = "text/html")
public ModelAndView errorHtml(HttpServletRequest request,
HttpServletResponse response) {
HttpStatus status = getStatus(request);
Map model = Collections.unmodifiableMap(getErrorAttributes(
request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
//默认设置返回的是error页面
return (modelAndView == null ? new ModelAndView("error", model) : modelAndView);
}
@RequestMapping
@ResponseBody
public ResponseEntity
rest 方法:
//返回视图
@RequestMapping("/index")
public String indexHtml(Model model) {
// Duplicated logic
model.addAttribute("test");
//返回视图名字
return "index";
}
//返回json
@RequestMapping("/errorResTest")
@ResponseBody
public String errorResTest(){
int i = 0;
int j = -1;
int x = j/i;
return "erro";
}
spring boot默认处理异常的方法就是errorHtml
error
方法。可以通过断点来看当用浏览器和client http方法访问rest url视图时分别执行的什么方法。
访问:http://127.0.0.1:8080/index
,http://127.0.0.1:8080/errorResTest
**当用浏览器访问:**不管事执行返回视图的rest方法还是执行返回json的rest方法,异常 执行的都是errorHtml
方法,并且如果templates下没有error.html
页面时,会返回spring boot默认的错误面就是Whitelabel Error Page
。
**用httpclient 访问:**不管事执行返回视图的rest方法还是执行返回json的rest方法,异常执行的都是error
方法,返回的是这样的错误 {protocol=http/1.1, code=500, message=Server Error, url=http://127.0.0.1:8080/errorResTest}
。
以上spring boot默认的异常返回形式,我们一般不会使用,通常都想自定义异常。
如果我们不重写这个类,用默认的类BasicErrorController
来处理异常,那么我们只需要在约定的目录下新建页面就可以了。
如果我们不配置页面默认会返因spring boot的一个异常页面
我用的spring boot版本号是2.0.1
在spring boot默认视图目录下建立一个error.html
页面,就是自动跳转到这个自定义的页面下:
默认目录结构如下:
访问一个不存的url:localhost:8080/fjdasldfjoaewijf
我们希望需要自动跳转到400页面,如果不配置,那么spring boot会自动跳到一个默认的错误页面,spring boot版本2.0.1
直接建立如下页面即可
这时再输入一个不存在的url,那么就是跳转到自定义的404.html
页面
用http client 访问rest join 返回错误
java.lang.RuntimeException: Unexpected code Response{protocol=http/1.1, code=500, message=Server Error, url=http://127.0.0.1:8080/errorResTest}
直接报错,也没有统一的json格式。
官网这样介绍:
一:你可以继承BasicErrorController
来实现
二:你也可以用ControllerAdvice
注解来自定义json返回。下面来具体说一下。
rest接口:
@RequestMapping("/index")
public String errorResTest(){
int i = 0;
int j = -1;
int x = j/i;
return "erro";
}
定义CustomErrorController类
/**
* Created by clock on 2018/4/13.
* 覆盖spring boot默认的异常处理类 继承BasicErrorController
*/
@Controller
public class CustomErrorController extends BasicErrorController {
public CustomErrorController(ServerProperties serverProperties) {
super(new DefaultErrorAttributes(), serverProperties.getError());
}
//通过浏览器访问的url 如果发生异常全部会被浏览并跳转到list.html页面
@Override
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
//请求的状态
HttpStatus status = getStatus(request);
response.setStatus(getStatus(request).value());
Map model = getErrorAttributes(request,
isIncludeStackTrace(request, MediaType.TEXT_HTML));
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
//指定自定义的视图
return(modelAndView == null ? new ModelAndView("list", model) : modelAndView);
}
//通过http client访问的接口如果发生异常会调用这个方法
@Override
public ResponseEntity
errorHtml
方法,返回 templates目录下的list.html页面error
方法,返回错误 。@Test
public void tsetsett(){
String url = "http://127.0.0.1:8080/index";
try {
HttpHelper httpHelper = new HttpHelper();
String josn = new String(httpHelper.get(url),"UTF-8");
System.out.println(josn);
} catch (Exception e) {
e.printStackTrace();
}
}
返回错误,我们可以看到http client的异常虽然被error拦截过,但返回的错误 也不是自定义的,还需要用ControllerAdvice 注解 实现自定义的json错误返回。
在配置完BasicErrorController
后,我们发现在用浏览器访问接口,发生异常时会全部跳转到error.html页面,但如果用http client访问接口,没法实现统一的错误josn串,那么需要用用ControllerAdvice
注解来实现
rest接口定义
//这个rest接口,会抛出一个异常,我们没有捕获,下面定义统一的异常处理
@RequestMapping("/errorResTest")
@ResponseBody
public String errorResTest(){
int i = 0;
int j = -1;
int x = j/i;
return "erro";
}
//抛出一个自定义的异常
@RequestMapping("/throwcustomexcepiont")
@ResponseBody
public String throwCustomExcepiontTest(){
try{
int i = 0;
int j = -1;
int x = j/i;
}catch (Exception e){
throw new CustomException("custom code",e.getMessage());
}
return "erro";
}
//抛出一个自定义的异常
@RequestMapping("/index")
public String throwCustomExcepiontTest(){
try{
int i = 0;
int j = -1;
int x = j/i;
}catch (Exception e){
throw new CustomException("custom code",e.getMessage());
}
return "erro";
}
这个接口运行时肯定会抛出一个异常,并且这个异常我们没有捕获,如果是普通的mvc接口,那么这种异常我们通常会配置一个统一的拦截器,来处理异常统一返回一个错误码,那么spring boot只需要注解就可以完成
@ControllerAdvice//在异常类上添加ControllerAdvice注解
public class CustomExceptionHandler extends ResponseEntityExceptionHandler {
/**
不管是访问返回视图接口,还是返回json串接口,只要抛出的excetion异常全部由这个方法拦截,并统一返回json串
* 统一异常拦截 rest接口
* @param request
* @param ex
* @return
*/
@ExceptionHandler(Exception.class)//Exception 这个是所有异常的父类
//定义异常统一返回json,即使是返回视图的接口
@ResponseBody
Map handleControllerException(HttpServletRequest request, Throwable ex) {
HttpStatus status = getStatus(request);
Map map = new HashMap();
map.put("code", String.valueOf(status.value()));
map.put("msg", ex.getMessage());
//这时会返回我们统一的异常json
return map;
}
private HttpStatus getStatus(HttpServletRequest request) {
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
if (statusCode == null) {
return HttpStatus.INTERNAL_SERVER_ERROR;
}
return HttpStatus.valueOf(statusCode);
}
/**
* 拦截自定义异常 CustomException rest接口
* @param request
* @param ex
* @return
*/
@ExceptionHandler(CustomException.class)
@ResponseBody
Map handleControllerCustomException(HttpServletRequest request, CustomException ex) {
HttpStatus status = getStatus(request);
Map map = new HashMap();
map.put("code", String.valueOf(status.value()));
map.put("msg", "customer error msg");
return map;
}
}
/**
* 拦截抛出CustomViewException 异常的方法并返回视图
* @param request
* @param ex
* @return
*/
@ExceptionHandler(CustomViewException.class)
ModelAndView handleControllerCustomExceptionView(HttpServletRequest request, CustomViewException ex) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("error");
HttpStatus status = getStatus(request);
Map map = new HashMap();
map.put("code", String.valueOf(status.value()));
map.put("msg", "customer error msg");
return modelAndView;
}
}
以上定义完BasicErrorController
和ControllerAdvice
处理异常的主法后。
Exception.class
定义的handle处理,并返回指定的返回形式。定义异常那么由相应的自定义异常handle处理。