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
package cn.ibizlab.util.aspect;
import lombok.SneakyThrows;
import cn.ibizlab.util.annotation.VersionCheck;
import cn.ibizlab.util.domain.EntityBase;
import cn.ibizlab.util.errors.BadRequestAlertException;
import cn.ibizlab.util.helper.RuleUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import java.lang.reflect.Field;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
/**
* 数据库版本检查
*/
@Aspect
@Order(50)
@Component
public class VersionCheckAspect
{
private final ExpressionParser parser = new SpelExpressionParser();
private final String IgnoreField = "ignoreversioncheck";
@SneakyThrows
@Before("execution(* cn.ibizlab.*.rest.*.update(..)) && @annotation(versionCheck)")
public void BeforeUpdate(JoinPoint point, VersionCheck versionCheck) {
Object[] args = point.getArgs();
Object id = args[0];
Object dto = args[1];
if(ObjectUtils.isEmpty(id) || ObjectUtils.isEmpty(dto)) {
return;
}
String versionField = versionCheck.versionfield();
if(StringUtils.isEmpty(versionField)) {
return;
}
versionCheck(versionCheck,point.getTarget(), dto, id);
}
@SneakyThrows
@Before("execution(* cn.ibizlab.*.rest.*.updateBy*(..)) && @annotation(versionCheck)")
public void BeforeUpdateBy(JoinPoint point, VersionCheck versionCheck) {
Object[] args = point.getArgs();
if(args.length>=2) {
Object id = args[args.length-2];
Object dto = args[args.length-1];
if(ObjectUtils.isEmpty(id) || ObjectUtils.isEmpty(dto)) {
return;
}
String versionField = versionCheck.versionfield();
if(StringUtils.isEmpty(versionField)) {
return;
}
versionCheck(versionCheck, point.getTarget(), dto, id);
}
}
private void versionCheck(VersionCheck versionCheck, Object resource, Object dto, Object id) {
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("dto", dto);
//忽略版本检查
Expression dtoParamsExp = parser.parseExpression("#dto.extensionparams");
Map dtoParam = dtoParamsExp.getValue(context, Map.class);
if(!ObjectUtils.isEmpty(dtoParam) && !ObjectUtils.isEmpty(dtoParam.get(IgnoreField)) && dtoParam.get(IgnoreField).equals(1)) {
return;
}
Expression newExp = parser.parseExpression(String.format("#dto.%s", versionCheck.versionfield()));
Object newVersion = newExp.getValue(context);
if(ObjectUtils.isEmpty(newVersion)) {
return;
}
//进行版本检查
Object oldVersion = getDBVersion(versionCheck,getService(resource, versionCheck.entity()), id);
if(!ObjectUtils.isEmpty(oldVersion)) {
if(RuleUtils.gt(newVersion, oldVersion)) {
throw new BadRequestAlertException("数据已变更,可能后台数据已被修改,请重新加载数据", "VersionCheckAspect", "versionCheck");
}
}
}
/**
* 获取实体服务对象
* @param resource
* @param entity
* @return
*/
@SneakyThrows
private Object getService(Object resource, String entity) {
Object service = null;
Field[] fields = resource.getClass().getDeclaredFields();
for(Field field : fields) {
if(field.getModifiers()==1 && field.getName().equalsIgnoreCase(String.format("%sService",entity))) {
service = field.get(resource);
break;
}
}
return service;
}
/**
* 获取数据库版本
* @param versionCheck
* @param service
* @param id
* @return
*/
@SneakyThrows
private Object getDBVersion(VersionCheck versionCheck, Object service, Object id) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Timestamp dbVersion = null;
String versionField = versionCheck.versionfield();
if(!ObjectUtils.isEmpty(service)) {
EvaluationContext oldContext = new StandardEvaluationContext();
oldContext.setVariable("service", service);
oldContext.setVariable("id", id);
Expression oldExp = parser.parseExpression("#service.get(#id)");
EntityBase oldEntity = oldExp.getValue(oldContext, EntityBase.class);
Object oldDate = oldEntity.get(versionField);
if(oldDate!=null && oldDate instanceof Timestamp) {
Timestamp db_time = (Timestamp) oldDate;
Date db_date = sdf.parse(sdf.format(db_time));
dbVersion = new Timestamp(db_date.getTime());
}
}
return dbVersion;
}
}