前言
通常一个web框架中,有大量需要处理的异常。比如业务异常,权限不足等等。前端通过弹出提示信息的方式告诉用户出了什么错误。 通常情况下我们用try…catch…对异常进行捕捉处理,但是在实际项目中对业务模块进行异常捕捉,会造成代码重复和繁杂, 我们希望代码中只有业务相关的操作,所有的异常我们单独设立一个类来处理它。全局异常就是对框架所有异常进行统一管理。 我们在可能发生异常的方法里throw抛给控制器。然后由全局异常处理器对异常进行统一处理。 如此,我们的Controller中的方法就可以很简洁了。
所谓全局异常处理器就是使用@ControllerAdvice
注解。示例如下:
1、统一返回实体定义
/**
* 返回实体类
*/
public class AjaxResult {
private String msg;
private String code;
private Object data;
public AjaxResult() {
}
public static AjaxResult error(String msg){
AjaxResult ajaxResult = new AjaxResult();
ajaxResult.msg=msg;
ajaxResult.code= "500";
return ajaxResult;
}
/**
* 返回错误消息
*
* @param code 错误码
* @param data 错误数据
* @param msg 内容
* @return 错误消息
*/
public static AjaxResult error(String msg, String code, @Nullable Object data){
AjaxResult ajaxResult = new AjaxResult();
ajaxResult.msg=msg;
ajaxResult.code= code;
ajaxResult.data=data;
return ajaxResult;
}
public static AjaxResult success(String msg){
AjaxResult ajaxResult = new AjaxResult();
ajaxResult.msg=msg;
ajaxResult.code="200";
return ajaxResult;
}
public static AjaxResult success(String msg,Object data){
AjaxResult ajaxResult = new AjaxResult();
ajaxResult.msg=msg;
ajaxResult.code="200";
ajaxResult.data=data;
return ajaxResult;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
2、定义异常的捕获
/**
* 定义异常的捕获
*/
public class LoginException extends RuntimeException{
protected final String message;
public LoginException(String message) {
this.message = message;
}
// getMessage() 返回此 throwable 的详细消息字符串
@Override
public String getMessage() {
return message;
}
}
3、全局异常处理
/**
* 全局异常处理器
*
* @RestControllerAdvice 是Controller控制器的增强,其实际就是相当于一个拦截器。
* 作用于controller下的所有RequestMapping,配合着@ExceptionHandler注解全局的指定异常处理
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* @ExceptionHandler 用于处理特定处理程序类和或处理程序方法中的异常的注解。
* 处理指定异常的抛出
*/
@ExceptionHandler(LoginException.class)
public AjaxResult loginException(LoginException e){
e.printStackTrace();
return AjaxResult.error(e.getMessage());
}
}
4、测试访问请求
@RestController
public class LoginController {
@RequestMapping("/login")
public String name(@Param("name") String name){
if (name.isEmpty()){
throw new LoginException("name值为空");
}
return name;
}
}
根据上面代码含义,当我们访问/login,name值为空时就会发生LoginException业务逻辑异常,按照我们之前的全局异常配置以及统一返回实体实例化,访问后会出现AjaxResult格式JSON数据, 下面我们运行项目访问查看效果。
界面输出内容如下所示:
{
"msg": "name值为空",
"code": "500",
"data": null
}
对于一些特殊情况,如接口需要返回json,页面请求返回html可以使用如下方法:
@ExceptionHandler(LoginException.class)
public Object loginException(HttpServletRequest request, LoginException e)
{
log.error(e.getMessage(), e);
if (ServletUtils.isAjaxRequest(request))
{
return AjaxResult.error(e.getMessage());
}
else
{
return new ModelAndView("/error/500");
}
}
全局异常处理器GlobalExceptionHandler
注意:如果全部异常处理返回json,那么可以使用@RestControllerAdvice代替@ControllerAdvice,这样在方法上就可以不需要添加@ResponseBody。
无法捕获异常?
如果您的异常无法捕获,您可以从以下几个方面着手检查
异常是否已被处理,即抛出异常后被catch,打印了日志或抛出了其它异常 异常是否非Controller抛出,即在拦截器或过滤器中出现的异常