目的:异常处理采用的是枚举型的 ExceptionEnum 枚举类 (特点 和别的公司的不太一样)
我们通常会把 事务 配置在 Service层,当数据库操作失败时让 Service 层抛出运行时异常,Spring 事物管理器就会进行回滚。如此一来,我们的 Controller 层就不得不进行 try-catch Service 层的异常,否则会返回一些不友好的错误信息到客户端。
@ControllerAdvice + @ExceptionHandler 进行全局的 Controller 层异常处理
- 优点:将 Controller 层的异常和数据校验的异常进行统一处理,减少模板代码,减少编码量,提升扩展性和可维护性。
- 缺点:只能处理 Controller 层未捕获(往外抛)的异常,对于 Interceptor(拦截器)层的异常,Spring 框架层的异常,就无能为力了。
一、utils工具类
import com.lenovo.pcsd.bp.businesspartner.vo.ResultVO;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import java.util.List;
public class ResultVOUtil {
public final static Integer ERROR_PARA = 4001;//参数错误
private static final Integer ERROR_CODE_ID_NOT_FOUND = 40002;//对应ID未找到
public static ResultVO errMap(Integer error, Object str, Object object) {
ResultVO resultVO = new ResultVO();
resultVO.setCode(error);
resultVO.setMsg(str);
resultVO.setData(object);
return resultVO;
}
public static ResultVO success(Page pageresult) {
PageUtil result = new PageUtil();
BeanUtils.copyProperties(pageresult, result);
ResultVO resultVO = new ResultVO();
resultVO.setCode(0);
resultVO.setMsg("成功");
resultVO.setData(result);
return resultVO;
}
public static ResultVO success(Object object) {
ResultVO resultVO = new ResultVO();
resultVO.setCode(0);
resultVO.setMsg("成功");
resultVO.setData(object);
return resultVO;
}
public static ResultVO success() {
return success(null);
}
public static ResultVO wrap(Object object, String msg) {
ResultVO resultVO = null;
if (object != null) {
resultVO = ResultVOUtil.success(object);
} else {
resultVO = ResultVOUtil.error(msg);
}
return resultVO;
}
public static ResultVO wrap(Object source, Class type, String msg) {
ResultVO resultVO = null;
if (source != null) {
resultVO = ResultVOUtil.success(source);
} else {
resultVO = ResultVOUtil.error(msg);
}
return resultVO;
}
public static ResultVO wrap(Page object, String msg) {
ResultVO resultVO = null;
if (object != null && object.getNumberOfElements() > 0) {
resultVO = ResultVOUtil.success(object);
} else {
resultVO = ResultVOUtil.error(msg);
}
return resultVO;
}
public static ResultVO wrap(List list, String msg) {
PageUtil pageUtil = new PageUtil(list);
return wrap(pageUtil, msg);
}
public static ResultVO error(Integer code, String msg) {
ResultVO resultVO = new ResultVO();
resultVO.setCode(code);
resultVO.setMsg(msg);
resultVO.setData(new String[]{});
return resultVO;
}
public static ResultVO error(String msg) {
return error(ERROR_CODE_ID_NOT_FOUND, msg);
}
}
二、ResultVo vo类
//import lombok.Data;
import java.io.Serializable;
//@Data
public class ResultVO<T> implements Serializable {
private static final long serialVersionUID = -8655891345041740105L;
public ResultVO(){
}
public ResultVO(Integer error, T msg){
this.code = error;
this.msg = msg;
}
public ResultVO(Integer error, T msg, T data) {
this.code = error;
this.msg = msg;
this.data = data;
}
/** 状态码. */
private Integer code;
/** 提示信息. */
private T msg;
/** 具体内容. */
private T data;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public T getMsg() {
return msg;
}
public void setMsg(T msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
三、AppcationException 类
import java.util.Optional;
public class AppcationException extends RuntimeException {
private IBusinessRuntimeException iBusinessRuntimeException;
private Integer stringcode;
private String message;
public AppcationException() {}
//不需要传参数或者拼接的时候调用的构造方法
public AppcationException(IBusinessRuntimeException iBusinessRuntimeException){
this.iBusinessRuntimeException=iBusinessRuntimeException;
this.stringcode=iBusinessRuntimeException.getCode();
this.message=Optional.ofNullable(iBusinessRuntimeException.getMessage1()).orElse("");
}
//需要拼接时候调用的构造方法
public AppcationException(IBusinessRuntimeException iBusinessRuntimeException,Object message1){
this(iBusinessRuntimeException);
this.message+=message1;
}
public IBusinessRuntimeException getiBusinessRuntimeException() {
return iBusinessRuntimeException;
}
public Integer getCode() {
return stringcode;
}
public void setCode(Integer code) {
this.stringcode = code;
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
@Override
public String toString() {
return super.toString();
}
}
四、ExceptionEnum 枚举类 (特点 和别的公司的不太一样)
/**
* 枚举类,用来存储自定义异常信息
*/
public enum ExceptionEnum implements IBusinessRuntimeException{
INSERTDATADEFEATED(1001,"数据插入失败,"),
NOTFOUNTVALUE(1002,"找不到对应的值"),
UPDATEDATADEFEAIED(1003,"更新数据失败"),
DELETEDATADEFEAIED(1004,"删除数据失败"),
TWOPARAMETERSDONTNULL(1005,"两个参数均不能为空"),
PARAMETERDONTEMPTY(1006,"参数不能为空");
private Integer stringcode;
private String message1;
ExceptionEnum(Integer code,String message1){
this.stringcode=code;
this.message1=message1;
}
@Override
public Integer getCode() {
return stringcode;
}
public void setCode(Integer code) {
this.stringcode = code;
}
@Override
public String getMessage1() {
return message1;
}
public void setMessage1(String message1) {
this.message1 = message1;
}
}
五、IbusinessRuntimeException 接口类
public interface IBusinessRuntimeException {
Integer getCode();
String getMessage1();
}
六、异常处理类
/**
*异常处理类
*/
@ControllerAdvice
@CommonsLog
public class GlobalExceptionHandler{
@InitBinder
public void initBinder(WebDataBinder binder) {}
@ExceptionHandler(value = AppcationException.class)
@ResponseBody
public ResultVO handlerInvoiceException(AppcationException e){
log.error("【业务异常】{}", e);
return ResultVOUtil.error(e.getCode(),e.getMessage());
}
@ExceptionHandler(value = Exception.class)
@ResponseBody
public ResultVO handlerException(Exception e){
log.error("【系统异常】{}", e);
/* return ResultVOUtil.error(0,e.getMessage());*/
return ResultVOUtil.error(1,"未知异常,请联系管理员");
}
public static Logger getLogger() {
return (Logger) log;
}
}
代码详解
@ExceptionHandler 注解声明异常处理方法
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseBody
String handleException(){
return "Exception Deal!";
}
}
方法 handleException() 就会处理所有 Controller 层抛出的 Exception 及其子类的异常
Logger 进行所有的异常日志记录。
@ExceptionHandler(BusinessException.class) 声明了对 BusinessException 业务异常的处理,并获取该业务异常中的错误提示,构造后返回给客户端。
@ExceptionHandler(Exception.class) 声明了对 Exception 异常的处理,起到兜底作用,不管 Controller 层执行的代码出现了什么未能考虑到的异常,都返回统一的错误提示给客户端。
备注:以上 GlobalExceptionHandler 只是返回 Json 给客户端,更大的发挥空间需要按需求情况来做。