diff --git a/pom.xml b/pom.xml
index f3f01479..8cb41c8e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,7 +12,7 @@
com.codingapi.springboot
springboot-parent
- 2.1.0
+ 2.1.1
https://github.com/codingapi/springboot-framewrok
springboot-parent
diff --git a/springboot-starter-data-fast/pom.xml b/springboot-starter-data-fast/pom.xml
index 861c4da6..18e7a0ea 100644
--- a/springboot-starter-data-fast/pom.xml
+++ b/springboot-starter-data-fast/pom.xml
@@ -5,7 +5,7 @@
springboot-parent
com.codingapi.springboot
- 2.1.0
+ 2.1.1
4.0.0
diff --git a/springboot-starter-id-generator/pom.xml b/springboot-starter-id-generator/pom.xml
index 09e4c5ce..a703134a 100644
--- a/springboot-starter-id-generator/pom.xml
+++ b/springboot-starter-id-generator/pom.xml
@@ -5,7 +5,7 @@
springboot-parent
com.codingapi.springboot
- 2.1.0
+ 2.1.1
4.0.0
diff --git a/springboot-starter-security-jwt/pom.xml b/springboot-starter-security-jwt/pom.xml
index 62ceda6c..01c2fa90 100644
--- a/springboot-starter-security-jwt/pom.xml
+++ b/springboot-starter-security-jwt/pom.xml
@@ -6,7 +6,7 @@
springboot-parent
com.codingapi.springboot
- 2.1.0
+ 2.1.1
springboot-starter-security-jwt
diff --git a/springboot-starter/pom.xml b/springboot-starter/pom.xml
index 6a103129..8a2794b4 100644
--- a/springboot-starter/pom.xml
+++ b/springboot-starter/pom.xml
@@ -5,7 +5,7 @@
com.codingapi.springboot
springboot-parent
- 2.1.0
+ 2.1.1
springboot-starter
diff --git a/springboot-starter/src/main/java/com/codingapi/springboot/framework/domain/field/FieldChangeEvent.java b/springboot-starter/src/main/java/com/codingapi/springboot/framework/domain/field/FieldChangeEvent.java
new file mode 100644
index 00000000..f5409926
--- /dev/null
+++ b/springboot-starter/src/main/java/com/codingapi/springboot/framework/domain/field/FieldChangeEvent.java
@@ -0,0 +1,46 @@
+package com.codingapi.springboot.framework.domain.field;
+
+import com.codingapi.springboot.framework.event.IEvent;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 实体字段变更事件
+ */
+@Setter
+@Getter
+@ToString(exclude = {"entity"})
+public class FieldChangeEvent implements IEvent {
+
+ /**
+ * 实体对象
+ */
+ private Object entity;
+
+ /**
+ * 实体类名称
+ */
+ private String simpleName;
+
+ /**
+ * 时间戳
+ */
+ private long timestamp;
+
+ /**
+ * 字段名称
+ */
+ private String fieldName;
+ /**
+ * 旧的值
+ */
+ private Object oldValue;
+ /**
+ * 新的值
+ */
+ private Object newValue;
+
+
+
+}
diff --git a/springboot-starter/src/main/java/com/codingapi/springboot/framework/domain/field/FieldProxyFactory.java b/springboot-starter/src/main/java/com/codingapi/springboot/framework/domain/field/FieldProxyFactory.java
new file mode 100644
index 00000000..5a9884b7
--- /dev/null
+++ b/springboot-starter/src/main/java/com/codingapi/springboot/framework/domain/field/FieldProxyFactory.java
@@ -0,0 +1,19 @@
+package com.codingapi.springboot.framework.domain.field;
+
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * 实体代理工厂
+ */
+public class FieldProxyFactory {
+
+ public static T create(Class entityClass, Object... args) {
+ FieldValueInterceptor interceptor = null;
+ try {
+ interceptor = new FieldValueInterceptor(entityClass, args);
+ } catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ return (T) interceptor.createProxy();
+ }
+}
diff --git a/springboot-starter/src/main/java/com/codingapi/springboot/framework/domain/field/FieldValueInterceptor.java b/springboot-starter/src/main/java/com/codingapi/springboot/framework/domain/field/FieldValueInterceptor.java
new file mode 100644
index 00000000..8d9cf58c
--- /dev/null
+++ b/springboot-starter/src/main/java/com/codingapi/springboot/framework/domain/field/FieldValueInterceptor.java
@@ -0,0 +1,126 @@
+package com.codingapi.springboot.framework.domain.field;
+
+import com.codingapi.springboot.framework.event.EventPusher;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
+import org.springframework.cglib.proxy.Enhancer;
+import org.springframework.cglib.proxy.MethodInterceptor;
+import org.springframework.cglib.proxy.MethodProxy;
+
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 实体代理
+ */
+@Slf4j
+public class FieldValueInterceptor implements MethodInterceptor {
+
+ // 目标类
+ private final Class> targetClass;
+ // 目标类构造函数参数类型
+ private final Class>[] parameterTypes;
+ // 目标类构造函数参数
+ private final Object[] args;
+
+ // 目标类实例
+ private final Object target;
+ // 目标类属性描述
+ private final PropertyDescriptor[] propertyDescriptors;
+ // 目标类属性值
+ private final Map fields;
+
+ public FieldValueInterceptor(Class> targetClass, Object... args) throws NoSuchMethodException,
+ InvocationTargetException, InstantiationException, IllegalAccessException {
+ this.targetClass = targetClass;
+ this.args = args;
+ this.parameterTypes = new Class>[args.length];
+ for (int i = 0; i < args.length; i++) {
+ parameterTypes[i] = args[i].getClass();
+ }
+ this.target = targetClass.getConstructor(parameterTypes).newInstance(args);
+ this.propertyDescriptors = BeanUtils.getPropertyDescriptors(targetClass);
+ this.fields = new HashMap<>();
+ }
+
+
+ /**
+ * 创建代理
+ * @return 代理对象
+ */
+ public Object createProxy() {
+ Enhancer enhancer = new Enhancer();
+ enhancer.setSuperclass(targetClass);
+ enhancer.setCallback(this);
+ return enhancer.create(parameterTypes, args);
+ }
+
+
+ /**
+ * 拦截方法
+ * @param obj 代理对象
+ * @param method 方法
+ * @param args 参数
+ * @param proxy 代理
+ * @return 方法返回值
+ * @throws Throwable 异常
+ */
+ @Override
+ public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
+ // 更新函数肯定有参数,如果没有参数,直接返回
+ if (method.getParameterCount() <= 0) {
+ return method.invoke(target, args);
+ }
+
+ if(fields.isEmpty()){
+ this.readFields();
+ }
+ Object result = method.invoke(target, args);
+ this.compareAndUpdateField();
+ return result;
+ }
+
+ /**
+ * 读取Entity字段
+ * @throws InvocationTargetException InvocationTargetException
+ * @throws IllegalAccessException InvocationTargetException
+ */
+ private void readFields() throws InvocationTargetException, IllegalAccessException {
+ for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
+ String name = propertyDescriptor.getName();
+ Object value = propertyDescriptor.getReadMethod().invoke(target);
+ fields.put(name, value);
+ }
+ }
+
+ /**
+ * 对比字段
+ * @throws InvocationTargetException InvocationTargetException
+ * @throws IllegalAccessException InvocationTargetException
+ */
+ private void compareAndUpdateField() throws InvocationTargetException, IllegalAccessException {
+ for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
+ String name = propertyDescriptor.getName();
+ Object newValue = propertyDescriptor.getReadMethod().invoke(target);
+ Object oldValue = fields.get(name);
+ if (!newValue.equals(oldValue)) {
+ pushEvent(name, oldValue, newValue);
+ }
+ fields.put(name, newValue);
+ }
+ }
+
+ private void pushEvent(String field, Object oldValue, Object newValue) {
+ FieldChangeEvent event = new FieldChangeEvent();
+ event.setEntity(target);
+ event.setSimpleName(targetClass.getSimpleName());
+ event.setFieldName(field);
+ event.setOldValue(oldValue);
+ event.setNewValue(newValue);
+ event.setTimestamp(System.currentTimeMillis());
+ EventPusher.push(event);
+ }
+}
diff --git a/springboot-starter/src/test/java/com/codingapi/springboot/framework/domain/Demo.java b/springboot-starter/src/test/java/com/codingapi/springboot/framework/domain/Demo.java
index 7b69f319..3b50686b 100644
--- a/springboot-starter/src/test/java/com/codingapi/springboot/framework/domain/Demo.java
+++ b/springboot-starter/src/test/java/com/codingapi/springboot/framework/domain/Demo.java
@@ -10,6 +10,7 @@ public class Demo implements JsonSerializable, MapSerializable {
@Getter
private long id;
+
@Getter
private String name;
@@ -21,7 +22,7 @@ public Demo(String name) {
public void changeName(String name) {
String beforeName = this.name;
this.name = name;
- //push event
+// push event
EventPusher.push(new DemoChangeEvent(beforeName, name));
}
diff --git a/springboot-starter/src/test/java/com/codingapi/springboot/framework/domain/FieldProxyFactoryTest.java b/springboot-starter/src/test/java/com/codingapi/springboot/framework/domain/FieldProxyFactoryTest.java
new file mode 100644
index 00000000..735ea767
--- /dev/null
+++ b/springboot-starter/src/test/java/com/codingapi/springboot/framework/domain/FieldProxyFactoryTest.java
@@ -0,0 +1,15 @@
+package com.codingapi.springboot.framework.domain;
+
+import com.codingapi.springboot.framework.domain.field.FieldProxyFactory;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class FieldProxyFactoryTest {
+
+ @Test
+ void createEntity() {
+ Demo demo = FieldProxyFactory.create(Demo.class, "test");
+ demo.changeName("123");
+ }
+}
\ No newline at end of file
diff --git a/springboot-starter/src/test/java/com/codingapi/springboot/framework/handler/EntityFiledChangeHandler.java b/springboot-starter/src/test/java/com/codingapi/springboot/framework/handler/EntityFiledChangeHandler.java
new file mode 100644
index 00000000..d4e7043d
--- /dev/null
+++ b/springboot-starter/src/test/java/com/codingapi/springboot/framework/handler/EntityFiledChangeHandler.java
@@ -0,0 +1,14 @@
+package com.codingapi.springboot.framework.handler;
+
+import com.codingapi.springboot.framework.domain.field.FieldChangeEvent;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Handler
+public class EntityFiledChangeHandler implements IHandler{
+
+ @Override
+ public void handler(FieldChangeEvent event) {
+ log.info("field change event -> {}",event);
+ }
+}