Spring全局异常处理 自定义异常
序言
SpringBoot的项目已经对有一定的异常处理了,但是对于我们开发者而言可能就不太合适了,因此我们需要对这些异常进行统一的捕获并处理。SpringBoot中有一个ControllerAdvice 的注解,使用该注解表示开启了全局异常的捕获,我们只需在自定义一个方法使用 ExceptionHandler注解然后定义捕获异常的类型即可对这些捕获的异常进行统一的处理。
@RestControllerAdvice
@RestControllerAdvice是一个组合注解,由@ControllerAdvice、@ResponseBody组成,而@ControllerAdvice继承了@Component,因此@RestControllerAdvice本质上是个Component,用于定义@ExceptionHandler,@InitBinder和@ModelAttribute方法,适用于所有使用@RequestMapping方法。
@RestControllerAdvice的特点:
- 通过@ControllerAdvice注解可以将对于控制器的全局配置放在同一个位置。
- 注解了@RestControllerAdvice的类的方法可以使用@ExceptionHandler、@InitBinder、@ModelAttribute注解到方法上。
- @RestControllerAdvice注解将作用在所有注解了@RequestMapping的控制器的方法上。
- @ExceptionHandler:用于指定异常处理方法。当与@RestControllerAdvice配合使用时,用于全局处理控制器里的异常。
- @InitBinder:用来设置WebDataBinder,用于自动绑定前台请求参数到Model中。
- @ModelAttribute:本来作用是绑定键值对到Model中,当与@ControllerAdvice配合使用时,可以让全局的@RequestMapping都能获得在此处设置的键值对
启动应用后,被 @ExceptionHandler、@InitBinder、@ModelAttribute 注解的方法,都会作用在 被 @RequestMapping 注解的方法上
。
这也是可以配置全局异常的关键所在
创建统一返回体并用枚举定义统一code码
package com.ksxy.common.core.domain;
import java.util.HashMap;
import com.ksxy.common.utils.StringUtils;
/**
* 操作消息提醒
*
* @author ksxy
*/
public class AjaxResult extends HashMap<String, Object>
{
private static final long serialVersionUID = 1L;
/** 状态码 */
public static final String CODE_TAG = "code";
/** 返回内容 */
public static final String MSG_TAG = "msg";
/** 数据对象 */
public static final String DATA_TAG = "data";
/**
* 状态类型
*/
public enum Type
{
/** 成功 */
SUCCESS(0),
/** 警告 */
WARN(301),
/** 错误 */
ERROR(500);
private final int value;
Type(int value)
{
this.value = value;
}
public int value()
{
return this.value;
}
}
/**
* 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
*/
public AjaxResult()
{
}
/**
* 初始化一个新创建的 AjaxResult 对象
*
* @param type 状态类型
* @param msg 返回内容
*/
public AjaxResult(Type type, String msg)
{
super.put(CODE_TAG, type.value);
super.put(MSG_TAG, msg);
}
/**
* 初始化一个新创建的 AjaxResult 对象
*
* @param type 状态类型
* @param msg 返回内容
* @param data 数据对象
*/
public AjaxResult(Type type, String msg, Object data)
{
super.put(CODE_TAG, type.value);
super.put(MSG_TAG, msg);
if (StringUtils.isNotNull(data))
{
super.put(DATA_TAG, data);
}
}
.......
}
创建全局异常处理类
- 权限校验异常:AuthorizationException.class
- 请求方式异常:HttpRequestMethodNotSupportedException.class
- 运行异常:RuntimeException.class
- 系统异常:Exception.class
- 业务异常:BusinessException.class
@RestControllerAdvice
public class GlobalExceptionHandler
{
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
* 权限校验失败 如果请求为ajax返回json,普通请求跳转页面
*/
@ExceptionHandler(AuthorizationException.class)
public Object handleAuthorizationException(HttpServletRequest request, AuthorizationException e)
{
log.error(e.getMessage(), e);
if (ServletUtils.isAjaxRequest(request))
{
return AjaxResult.error(PermissionUtils.getMsg(e.getMessage()));
}
else
{
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("error/unauth");
return modelAndView;
}
}
/**
* 请求方式不支持
*/
@ExceptionHandler({ HttpRequestMethodNotSupportedException.class })
public AjaxResult handleException(HttpRequestMethodNotSupportedException e)
{
log.error(e.getMessage(), e);
return AjaxResult.error("不支持' " + e.getMethod() + "'请求");
}
/**
* 拦截未知的运行时异常
*/
@ExceptionHandler(RuntimeException.class)
public AjaxResult notFount(RuntimeException e)
{
log.error("运行时异常:", e);
return AjaxResult.error("运行时异常:" + e.getMessage());
}
/**
* 系统异常
*/
@ExceptionHandler(Exception.class)
public AjaxResult handleException(Exception e)
{
log.error(e.getMessage(), e);
return AjaxResult.error("服务器错误,请联系管理员");
}
/**
* 业务异常
*/
@ExceptionHandler(BusinessException.class)
public Object businessException(HttpServletRequest request, BusinessException e)
{
log.error(e.getMessage(), e);
if (ServletUtils.isAjaxRequest(request))
{
return AjaxResult.error(e.getMessage());
}
else
{
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("errorMessage", e.getMessage());
modelAndView.setViewName("error/business");
return modelAndView;
}
}
/**
* 自定义验证异常
*/
@ExceptionHandler(BindException.class)
public AjaxResult validatedBindException(BindException e)
{
log.error(e.getMessage(), e);
String message = e.getAllErrors().get(0).getDefaultMessage();
return AjaxResult.error(message);
}
/**
* 演示模式异常
*/
@ExceptionHandler(DemoModeException.class)
public AjaxResult demoModeException(DemoModeException e)
{
return AjaxResult.error("演示模式,不允许操作");
}
}