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

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

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

方案

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

1.自定义异常

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.自定义注解


import java.lang.annotation.*;

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

3.切面编写

切面中那么多的代码,其实就是捕获对应注解下的,指定异常
其他的代码是我要存储到表中

为什么用jdbc?
因为我的项目用的mybatis,但是mybatis事务对运行时一行会全部回滚。
所有我单开了一个事务,这样其他的事务回滚了,但是异常可以正常存表。


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测试

添加注解,抛出指定异常

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

在这里插入图片描述
断点进到切面里面了
在这里插入图片描述
并且表中只保留了异常数据,;另一个事务回滚了

在这里插入图片描述

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谷咕咕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值