异常处理的要求
1.传统的页面跳转模式的系统:(控制器+view解析器+JSP)
出现异常后,应该记录异常信息,发送异常信息,跳转到错误显示页面。
2.基于REST API的系统
返回错误信息(JSON格式),前端框架接收到异常的JSON数据,显示在页面上。
Spring MVC异常处理的机制
1.处理单个Controller的异常机制。
2.处理所有Controller的异常机制
处理单个Controller的异常机制
在控制器类内定义异常处理方法。使用@ExceptionHandler进行标注。
@Controller
@RequestMapping("/controller")
public class Controller {
private IService service=null;
@Autowired
public void setService(IService service) {
this.service = service;
}
//异常处理的方法
@ExceptionHandler
public String exceptionProcess(Exception ex,Model model) throws Exception{
return "error/error";
}
}
处理所有控制器抛出异常的处理机制
需要单独编写一个控制器的异常处理切面类,并使用如下2个注解类。
1.@ControllerAdvice: 用于标注传统的控制器类, 适用于页面跳转。
2.@RestControllerAdvice: 用于REST API的控制器切面。
编写传统的控制器切面类
- 编写控制器异常切面类,标注@ControllerAdvice.
- 定义一个或多个异常处理方法,标注@ExceptionHandler
@ControllerAdvice(assignableTypes=Controller.class)
public class ControllerExceptionAdvice {
@ExceptionHandler
public String exceptionProcess(Exception ex,Model model) {
System.out.println("all:"+ex);
return "error/error";
}
@ExceptionHandler({RuntimeException.class,IOException.class})
public String RTAndIOExceptionProcess(Exception ex,Model model) {
System.out.println("part:"+ex);
return "error/error";
}
}
编写Rest API的控制器切面类
- 编写控制器异常切面类,标注@RestControllerAdvice.
- 定义一个或多个异常处理方法,标注@ExceptionHandler
@RestControllerAdvice(assignableTypes= {Controller.class})
public class RestControllerExceptionAdvice {
@ExceptionHandler
public ExceptionResultModel exceptionProcess(Exception ex) {
ExceptionResultModel er=new ExceptionResultModel();
er.setExMessage(ex.getMessage());
er.setExTime(new Date());
return er;
}
@ExceptionHandler({RuntimeException.class,IOException.class})
public ExceptionResultModel RTAndIOExceptionProcess(Exception ex) {
ExceptionResultModel er=new ExceptionResultModel();
er.setExMessage(ex.getMessage());
er.setExTime(new Date());
return er;
}
}
对异常的限定捕获
在@ExceptionHandler中加入具体要捕获的异常
语法:@ExceptionHandler({异常类.class, 异常类.class})
案例:
//相当于只catch(RuntimeException re)和catch(IOException ioe)
@ExceptionHandler({RuntimeException.class,IOException.class})
public String runtimeexceptionProcess(Exception ex,Model model) throws Exception{
System.out.println("所有控制器异常方法01。。。。");
model.addAttribute("errorObject",ex);
return "error/error";
}
//所有异常处理的方法,相当于catch(Exception E)
@ExceptionHandler
public String exceptionProcess(Exception ex,Model model) throws Exception{
System.out.println("所有控制器异常方法02。。。。");
model.addAttribute("errorObject",ex);
return "error/error";
}
对REST API控制器的异常处理
1. 编写一个REST 控制器的异常处理Advice类,标注@RestControllerAdvice
@RestControllerAdvice=@ControllerAdvice+@ResponseBody
2.在REST异常处理切面类中定义异常处理方法,并使用@ExceptionHandler标注。
案例:
@RestControllerAdvice("com.neusoft.oa.restcontroller")
public class RestControllerExceptionAdvice {
//异常处理的方法
@ExceptionHandler
public ExceptionResult exceptionProcess(Exception ex,Model model) throws Exception{
System.out.println("所有REST控制器异常方法。。。。");
ExceptionResult result=new ExceptionResult();
result.setErrorMessasge(ex.getMessage());
result.setErrorDate(new Date());
result.setEx(ex);
return result;
}
}
对于REST Controller Advice异常处理方法的返回值,推荐使用一个JavaBean类对象,封装各种异常信息。
例如定义一个异常结果的JavaBean类,如下:
public class ExceptionResult {
private String errorMessasge=null;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private Date errorDate=null;
private Exception ex=null;
public String getErrorMessasge() {
return errorMessasge;
}
public void setErrorMessasge(String errorMessasge) {
this.errorMessasge = errorMessasge;
}
public Date getErrorDate() {
return errorDate;
}
public void setErrorDate(Date errorDate) {
this.errorDate = errorDate;
}
public Exception getEx() {
return ex;
}
public void setEx(Exception ex) {
this.ex = ex;
}
}
该类作为REST异常处理方法的返回值类型。
ControllerAdvice对拦截目标的限定
1.属性:annotations限定指定的注解类。
// Target all Controllers annotated with @RestController
@ControllerAdvice(annotations = RestController.class)
public class ExampleAdvice1 {}
2.属性:basePackages指定包名对象控制器类进行限定。
该属性是默认属性,可以省略。
不省略模式:
指定一个包:
@ControllerAdvice(basePackages="org.my.pkg")
指定多个包:
@ControllerAdvice(basePackages={"org.my.pkg", "org.my.other.pkg"})}.
省略模式:
指定单个包:
@ControllerAdvice("org.example.controllers")
public class ExampleAdvice2 {}
指定多个包:
@ControllerAdvice({”com.neusoft.oa.hr.controller”,”com.neusoft.oa.erp.controller”})
public class ExampleAdvice2 {}
3.通过assignableTypes属性限定指定的控制器类。
// Target all Controllers assignable to specific classes
@ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class})
public class ExampleAdvice3 {}