前言
每个方法中可能会抛出不同的异常,如果都是用try catch去处理,显得非常冗余,可以通过spring提供的@ExceptionHandler注解来实现异常的统一封装和处理
拦截器的实现:
@RestControllerAdvice
public class CommonExceptionHandler {
/**
* 拦截Exception类的异常
*
* @param e
* @return
*/
@ExceptionHandler(Exception.class)
public Object exceptionHandler(Exception e) {
e.printStackTrace();
return Result.result(0, e.getMessage());
}
/**
* 拦截 CommonException 的异常
*
* @param ex
* @return
*/
@ExceptionHandler(CommonException.class)
public Object exceptionHandler(CommonException ex) {
ex.printStackTrace();
return Result.result(ex.getCode(), ex.getMsg());
}
@ExceptionHandler(UnauthorizedException.class)
public Object UnauthorizedExceptionHandler(UnauthorizedException ex) {
return Result.result(ApiResultEnum.UNAUTHORIZED);
}
@ExceptionHandler(AuthorizationException.class)
public Object AuthorizationExceptionHandler(AuthorizationException ex) {
return Result.result(0, ex.getMessage());
}
@ExceptionHandler(AuthenticationException.class)
public Object AuthenticationExceptionHandler(AuthenticationException ex) {
return Result.result(0, ex.getMessage());
}
@ExceptionHandler(ParseException.class)
public Object ParseExceptionHandler(ParseException ex) {
return Result.result(ApiResultEnum.DATE_FORMAT_ERROR);
}
}
原理:比如当触发一个接口后,控制器调用服务类里面的方法saveUserInfo,saveUserInfo调用test1,test1抛出一个运行时异常。
这时就会被**@RestControllerAdvice注解的异常处理类接收到,这个类会根据@ExceptionHandler**指定的异常,映射到对应的方法中。
这样的话控制器和service层都不需要处理异常,全部交由拦截器来处理
并且可以在拦截器中自定义接口处理完异常后返回的数据格式和内容
事务回滚也是可以进行全局配置的,springboot配置全局事物管理如下:
import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@Aspect
@Configuration
public class TransactionAdviceConfig {
/**
* 定义切点路径
*/
private static final String AOP_POINTCUT_EXPRESSION = "execution(* com.jqyd.yundukao..*(..))";
@Autowired
private PlatformTransactionManager transactionManager;
/**
* @description 事务管理配置
*/
@Bean
public TransactionInterceptor TxAdvice() {
// 事务管理规则,承载需要进行事务管理的方法名(模糊匹配)及设置的事务管理属性
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
// 设置第一个事务管理的模式(适用于“增删改”)
RuleBasedTransactionAttribute transactionAttribute1 = new RuleBasedTransactionAttribute();
// 当抛出设置的对应异常后,进行事务回滚(此处设置为“Exception”级别)
transactionAttribute1.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
// 设置隔离级别(存在事务则加入其中,不存在则新建事务)
transactionAttribute1.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// 设置传播行为(读已提交的数据)
transactionAttribute1.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
// 设置第二个事务管理的模式(适用于“查”)
RuleBasedTransactionAttribute transactionAttribute2 = new RuleBasedTransactionAttribute();
// 当抛出设置的对应异常后,进行事务回滚(此处设置为“Exception”级别)
transactionAttribute2.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
// 设置隔离级别(存在事务则挂起该事务,执行当前逻辑,结束后再恢复上下文事务)
transactionAttribute2.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
// 设置传播行为(读已提交的数据)
transactionAttribute2.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
// 设置事务是否“只读”(非必需,只是声明该事务中不会进行修改数据库的操作,可减轻由事务造成的数据库压力,属于性能优化的推荐配置)
transactionAttribute2.setReadOnly(true);
// 建立一个map,用来储存要需要进行事务管理的方法名(模糊匹配)
Map txMap = new HashMap<>();
txMap.put("save*", transactionAttribute1);
txMap.put("update*", transactionAttribute1);
txMap.put("delete*", transactionAttribute1);
txMap.put("agree*", transactionAttribute1);
txMap.put("reject*", transactionAttribute1);
txMap.put("approval*", transactionAttribute1);
txMap.put("query*", transactionAttribute2);
// 注入设置好的map
source.setNameMap(txMap);
// 实例化事务拦截器
return new TransactionInterceptor(transactionManager, source);
}
/**
* @description 利用AspectJExpressionPointcut设置切面
*/
@Bean
public Advisor txAdviceAdvisor() {
// 声明切点要切入的面
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
// 设置需要被拦截的路径
pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
// 设置切面和配置好的事务管理
return new DefaultPointcutAdvisor(pointcut, TxAdvice());
}
}
然后service层使用Transactional注解即可实现事务回滚