springboot,全局异常处理,AOP,对所有地方不单单是controller,捕获后事务回滚,但是保存异常发生记录

springboot,全局异常处理,AOP,对所有地方不单单是controller,捕获后事务回滚,但是保存异常发生记录

背景:

业务场景是对外接口调用失败,或者部分代码块执行失败,在系统中能统一记录下来。

方案

  1. 自定义异常
  2. 自定义注解
  3. 编写切面
    在切面中,将异常信息记录到表中。

1.自定义异常

java 复制代码
public class OutApiException extends RuntimeException{
    private String exceptionType;
    private String exceptionInfo;
    private String exceptionParam;
    public OutApiException(String message) {
        super(message);
    }

    public OutApiException(String exceptionType,String exceptionInfo,String exceptionParam,String message) {
        super(message);
        this.exceptionType = exceptionType;
        this.exceptionInfo = exceptionInfo;
        this.exceptionParam = exceptionParam;
    }

    public String getExceptionType() {
        return exceptionType;
    }

    public void setExceptionType(String exceptionType) {
        this.exceptionType = exceptionType;
    }

    public String getExceptionInfo() {
        return exceptionInfo;
    }

    public void setExceptionInfo(String exceptionInfo) {
        this.exceptionInfo = exceptionInfo;
    }

    public String getExceptionParam() {
        return exceptionParam;
    }

    public void setExceptionParam(String exceptionParam) {
        this.exceptionParam = exceptionParam;
    }
}

2.自定义注解

java 复制代码
import java.lang.annotation.*;

@Documented
@Target({ElementType.METHOD, ElementType.TYPE}) //可在类或者方法使用
@Retention(RetentionPolicy.RUNTIME)
public @interface OutApiServiceExceptionCatch {
}

3.切面编写

切面中那么多的代码,其实就是捕获对应注解下的,指定异常

其他的代码是我要存储到表中

为什么用jdbc?

因为我的项目用的mybatis,但是mybatis事务对运行时一行会全部回滚。

所有我单开了一个事务,这样其他的事务回滚了,但是异常可以正常存表。

cpp 复制代码
import com.qygx.framework.exe.OutApiException;
import com.qygx.framework.exe.OutApiServiceExceptionCatch;
import com.qygx.mes.ding.domain.OaTask;
import com.qygx.mes.ding.mapper.OaTaskMapper;
import com.qygx.mes.ding.service.IOaTaskService;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import springfox.documentation.service.ResponseMessage;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

@Component
@Aspect
@Slf4j
public class ServiceExceptionHandler {
    @Autowired
    private IOaTaskService oaTaskService;
    @Autowired
    private SqlSessionFactory sqlSessionFactory;
    @Autowired
    private DataSource dataSource;
    @Around("@annotation(com.qygx.framework.exe.OutApiServiceExceptionCatch)  || @within(com.qygx.framework.exe.OutApiServiceExceptionCatch)")
    public ResponseEntity<String> serviceExceptionHandler(ProceedingJoinPoint proceedingJoinPoint) {
        ResponseMessage returnMsg;
        try {
            returnMsg = (ResponseMessage) proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            log.error("ServiceExcepHandler serviceExcepHandler failed", throwable);
            //单独处理缺少参数异常
            if(throwable instanceof OutApiException) {
                Connection conn = null;
                try {
                    // 从数据源获取连接,并设置自动提交为false
                    conn = dataSource.getConnection();
                    conn.setAutoCommit(false);

                    String sql = "INSERT INTO test(oa_type, param) VALUES (?, ?)";
                    PreparedStatement pstmt = conn.prepareStatement(sql);
                    pstmt.setString(1, "value1");
                    pstmt.setString(2, "value2");
                    pstmt.executeUpdate();
                    conn.commit();
                } catch (Exception e) {
                    if (conn != null) {
                        try {
                            // 如果有异常发生,则回滚事务
                            conn.rollback();
                        } catch (SQLException ex) {
                            log.error("Failed to rollback transaction", ex);
                        }
                    }
                    throw new RuntimeException("Insert operation failed using JDBC", e);
                } finally {
                    if (conn != null) {
                        try {
                            // 关闭数据库连接
                            conn.close();
                        } catch (SQLException ex) {
                            log.error("Failed to close database connection", ex);
                        }
                    }
                }
                throw new RuntimeException();
            }else{
                throw new RuntimeException();
            }
        }
        throw new RuntimeException();
    }

}

4测试

添加注解,抛出指定异常

java 复制代码
@Transactional
    @GetMapping("/test")
    public void testLogin() throws OutApiException {
        OaTask oaTask = new OaTask();
        oaTask.setParam("test0314");
        oaTaskService.insertOaTask(oaTask);
        throw new OutApiException("123");
    }

断点进到切面里面了

并且表中只保留了异常数据,;另一个事务回滚了

相关推荐
2401_857439691 小时前
Spring Boot新闻推荐系统:用户体验优化
spring boot·后端·ux
hong_zc1 小时前
算法【Java】—— 二叉树的深搜
java·算法
进击的女IT2 小时前
SpringBoot上传图片实现本地存储以及实现直接上传阿里云OSS
java·spring boot·后端
Miqiuha2 小时前
lock_guard和unique_lock学习总结
java·数据库·学习
杨半仙儿还未成仙儿3 小时前
Spring框架:Spring Core、Spring AOP、Spring MVC、Spring Boot、Spring Cloud等组件的基本原理及使用
spring boot·spring·mvc
一 乐3 小时前
学籍管理平台|在线学籍管理平台系统|基于Springboot+VUE的在线学籍管理平台系统设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·学习
数云界3 小时前
如何在 DAX 中计算多个周期的移动平均线
java·服务器·前端
阑梦清川3 小时前
Java继承、final/protected说明、super/this辨析
java·开发语言
快乐就好ya5 小时前
Java多线程
java·开发语言
IT学长编程5 小时前
计算机毕业设计 二手图书交易系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·spring boot·毕业设计·课程设计·毕业论文·计算机毕业设计选题·二手图书交易系统