文章目录
代码已上传gitee:https://gitee.com/shang_jun_shu/springboot-exception-jsr303.git
其他系列博客
Java异常处理(一)一异常处理流程
java异常处理(二)—从字节码层面看throw关键字及try…catch…finally的实现
java异常处理(四)—还在用if判断校验参数?试试SpringBoot全局异常+JSR303校验吧!
一、引入ErrorController和@ControllerAdivce
共同点:
两者都是Spring项目中的异常处理方式,@ControllerAdivce属于Spring的Web模块,ErrorController接口属于SpringBoot项目
区别:
捕捉异常位置不同:@ControllerAdivce捕捉控制器方法中抛出的异常,像Filter、拦截器的异常是捕捉不到的,ErrorController接口捕捉全局异常,包括控制器方法中抛出的异常
实现方式不同:@ControllerAdivce基于aop,ErrorController基于跳转页即如果有异常发生,会跳转/error页面
注意:如果项目中两者同时存在,@ControllerAdivce注解处理控制器方法中抛出的异常,ErrorController处理未进入控制器方法的异常
二、SpringBoot默认处理异常方式ErrorController
2.1制造异常
首先制造一个未进入控制器方法的异常
最常见的就是404路径找不到
再制造一个控制器方法抛出的异常,如下代码
@GetMapping("/get")
@ResponseBody
public Result getEx(){
throw new RuntimeException();
}
2.2处理异常原理
1.跳转/error路径
一旦请求发生异常,Tomcat中StandardHostValve类的custom方法会重定向到/error路径,并且交给SpringMVC中的DispatcherServlet类去处理
2.定位到BasicErrorController
DispatcherServlet类将/error与BasicErrorController中的方法对应起来,如果用户请求方式是HTML,则定位到errorHtml方法,如果请求方式是json,则定位到error方法
三、自定义全局异常处理类MyErrorController
SpringBoot默认的错误页看着不怎么好看,我们可以自定义异常处理类,继承ErrorController,重写该类的errorHtml和error两个方法
@RestController
public class MyErrorController extends BasicErrorController {
@Autowired
public MyErrorController(ErrorAttributes errorAttributes,
ServerProperties serverProperties,
List<ErrorViewResolver> errorViewResolvers) {
super(errorAttributes, serverProperties.getError(), errorViewResolvers);
}
//处理html请求
@Override
public ModelAndView errorHtml(HttpServletRequest request,
HttpServletResponse response) {
HttpStatus status = getStatus(request);
Map<String, Object> model = getErrorAttributes(
request, isIncludeStackTrace(request, MediaType.TEXT_HTML));
ModelAndView modelAndView = new ModelAndView("myErrorPage", model, status);
return modelAndView;
}
//处理json请求
@Override
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
Map<String, Object> body = getErrorAttributes(request,
isIncludeStackTrace(request, MediaType.ALL));
//可以换成项目中自定义的通信json
Map<String,Object> resultBody=new HashMap<>(16);
resultBody.put("success",false);
resultBody.put("code",body.get("status"));
resultBody.put("msg",body.get("error"));
return new ResponseEntity<>(resultBody, HttpStatus.OK);
}
}
对于html请求可以自定义html页,下面看下json请求结果吧
{
"msg": "Method Not Allowed",
"code": 405,
"success": false
}
四、@ControllerAdivce捕捉异常
4.1@ControllerAdivce的执行顺序
从上图可以知道@ControllerAdivce可以捕捉到aspect和controller方法中的异常
4.2@ControllerAdivce+@ExceptionHandler处理异常
//自定义异常
@Data
public class ServiceException extends RuntimeException {
private Integer code;
public ServiceException(Integer code, String message) {
super(message);
this.code = code;
}
}
//处理异常
@Slf4j
@RestControllerAdvice(annotations = {RestController.class, Controller.class})
public class GlobalExceptionHandler {
@ExceptionHandler(ServiceException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Result handlerException(ServiceException e){
log.error(e.getMessage());
return Result.buildFailure(e.getCode(),e.getMessage());
}
}
4.3请求方法
@Controller
@RequestMapping("/exception")
public class MethodExceptionController {
@GetMapping("/get")
@ResponseBody
public Result getName(@RequestParam String userName){
if(StringUtils.isEmpty(userName)){
throw new ServiceException(10010,"参数错误");
}
return Result.buildSuccess(userName);
}
}
对于参数的校验可以不用if判断,用jsr303即可,参考下一篇
4.4测试结果
http://localhost:8081/exception/get?userName=
{
"success": false,
"code": 10010,
"msg": "参数错误",
"data": null
}
创作不易,觉得有帮助,点个赞吧,您的支持是我最大的动力