yanderong
2026-07-11 1baa21c114f634b8ecc3af64efcfaab6a57a571e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package com.stylefeng.guns.core.intercept;
 
import com.stylefeng.guns.modular.system.dao.UserInfoMapper;
import com.stylefeng.guns.modular.system.model.UserInfo;
import com.stylefeng.guns.modular.system.model.vo.BalanceModifyRecordVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
 
import java.lang.reflect.Field;
import java.util.*;
 
/**
 *  用户余额变更拦截器
 * @author sky
 * @version 1.0.0
 * @since 2026/7/3 12:03
 */
@Slf4j
@Component
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})})
public class BalanceUpdateInterceptor implements Interceptor {
 
    @Autowired
    private ApplicationContext context;
 
    private UserInfoMapper getMapper() {
        return context.getBean(UserInfoMapper.class);
    }
 
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
 
        MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
        Object param = invocation.getArgs()[1];
 
        // 获取SQL类型
        SqlCommandType sqlCommandType = ms.getSqlCommandType();
 
        if (sqlCommandType != SqlCommandType.UPDATE) {
            return invocation.proceed();
        }
        BoundSql boundSql = ms.getBoundSql(param);
        String sql = boundSql.getSql().toLowerCase();
 
        // 只处理 user 表
        if (!sql.contains("t_user")) {
            return invocation.proceed();
        }
 
        // 关键:先执行前查旧值(需要拿 userId)
        Map<String, Long> mapValues = extractUserId(param);
        Long userId = mapValues.get("userId");
        if(Objects.isNull(userId)) {
            return invocation.proceed();
        }
 
        // 查询旧的用户
        UserInfo oldUser = getMapper().selectById(userId);
        // 执行更新
        Object result = invocation.proceed();
        // 查新的用户
        UserInfo newUser = getMapper().selectById(userId);
        Long balanceChangeType = mapValues.get("balanceChangeType");
        if(Objects.nonNull(balanceChangeType)) {
            newUser.setBalanceChangeType(balanceChangeType.intValue());
        }
 
        // 新增余额的变更记录(所有余额的变更记录都需要存)
        if(Objects.nonNull(oldUser) && Objects.nonNull(newUser)) {
            BalanceModifyRecordVo recordVo = BalanceModifyRecordVo.convert(oldUser, newUser);
            Optional.ofNullable(recordVo).ifPresent(getMapper()::insertBalanceModifyRecord);
        }
        return result;
    }
 
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }
 
    @Override
    public void setProperties(Properties properties) {
 
    }
 
    /**
     * 获取用户id
     */
    private Map<String, Long> extractUserId(Object param) {
        Map<String, Long> mapValues = new HashMap<>();
        if (param == null) {
            return mapValues;
        }
 
        // MyBatis ParamMap
        if (param instanceof Map) {
            Map<?, ?> map = (Map<?, ?>) param;
            // 第一种:直接传id
            try{
 
                Object balanceChangeType = map.get("balanceChangeType");
                if (Objects.nonNull(balanceChangeType)) {
                    mapValues.put("balanceChangeType", Long.valueOf(balanceChangeType.toString()));
                }
                Object id = map.get("id");
                if (Objects.nonNull(id)) {
                    mapValues.put("userId", Long.valueOf(id.toString()));
                    return mapValues;
                }
            } catch (Exception e) {
               // log.error("sql中没有id");
            }
 
            // 第二种:MyBatis-Plus update(entity, wrapper)
            Object entity = map.get("param1");
            if (entity == null) {
                entity = map.get("et");
            }
 
            if (entity != null) {
                return extractId(entity, mapValues);
            }
        }
 
        // 直接就是实体
        return extractId(param, mapValues);
    }
 
    private Map<String, Long> extractId(Object obj, Map<String, Long> mapValues) {
        Field field = ReflectionUtils.findField(obj.getClass(), "id");
        if (field == null) {
            return mapValues;
        }
        ReflectionUtils.makeAccessible(field);
        Object value = ReflectionUtils.getField(field, obj);
        mapValues.put("userId", value == null ? null : Long.valueOf(value.toString()));
 
        Field fieldType = ReflectionUtils.findField(obj.getClass(), "balanceChangeType");
        if (fieldType == null) {
            return mapValues;
        }
        ReflectionUtils.makeAccessible(fieldType);
        Object valueType = ReflectionUtils.getField(fieldType, obj);
        mapValues.put("balanceChangeType", valueType == null ? null : Long.valueOf(valueType.toString()));
        return mapValues;
    }
 
}