This commit is contained in:
开源海哥 2023-04-28 19:59:40 +08:00
commit 5d7da4a2bb
16 changed files with 323 additions and 71 deletions

View File

@ -0,0 +1,29 @@
package com.mybatisflex.annotation;
/**
* 类型支持 insert 监听器
*
* @author snow
* @since 2023/4/28
*/
public abstract class AbstractInsertListener<T> implements InsertListener {
/**
* 该监听器支持的entity类型
*
* @return type
*/
public abstract Class<T> supportType();
public abstract void doInsert(T entity);
@Override
@SuppressWarnings("unchecked")
public void onInsert(Object entity) {
Class<T> supportType = supportType();
if (supportType.isInstance(entity)) {
T object = (T) entity;
doInsert(object);
}
}
}

View File

@ -0,0 +1,28 @@
package com.mybatisflex.annotation;
/**
* 类型支持 update 监听器
*
* @author snow
* @since 2023/4/28
*/
public abstract class AbstractUpdateListener<T> implements UpdateListener {
/**
* 该监听器支持的entity类型
*
* @return type
*/
public abstract Class<T> supportType();
public abstract void doUpdate(T entity);
@Override
@SuppressWarnings("unchecked")
public void onUpdate(Object entity) {
Class<T> supportType = supportType();
if (supportType.isInstance(entity)) {
T object = (T) entity;
doUpdate(object);
}
}
}

View File

@ -15,6 +15,6 @@
*/
package com.mybatisflex.annotation;
public interface InsertListener {
public interface InsertListener extends Listener{
void onInsert(Object entity);
}

View File

@ -0,0 +1,25 @@
package com.mybatisflex.annotation;
/**
* 监听器
*
* @author snow
* @since 2023/4/28
*/
public interface Listener extends Comparable<Listener> {
/**
* 多个监听器时的执行顺序
* <p>值越小越早触发执行</p>
*
* @return order
*/
default int order() {
return Integer.MAX_VALUE;
}
@Override
default int compareTo(Listener other) {
return order() - other.order();
}
}

View File

@ -15,7 +15,7 @@
*/
package com.mybatisflex.annotation;
public class NoneListener implements InsertListener, UpdateListener, SetListener {
public final class NoneListener implements InsertListener, UpdateListener, SetListener {
@Override
public void onInsert(Object entity) {

View File

@ -15,7 +15,7 @@
*/
package com.mybatisflex.annotation;
public interface SetListener {
public interface SetListener extends Listener {
Object onSet(Object entity, String property, Object value);
}

View File

@ -15,7 +15,10 @@
*/
package com.mybatisflex.annotation;
import java.lang.annotation.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@ -44,17 +47,17 @@ public @interface Table {
/**
* 监听 entity insert 行为
*/
Class<? extends InsertListener> onInsert() default NoneListener.class;
Class<? extends InsertListener>[] onInsert() default {};
/**
* 监听 entity update 行为
*/
Class<? extends UpdateListener> onUpdate() default NoneListener.class;
Class<? extends UpdateListener>[] onUpdate() default {};
/**
* 监听 entity 的查询数据的 set 行为用户主动 set 不会触发
*/
Class<? extends SetListener> onSet() default NoneListener.class;
Class<? extends SetListener>[] onSet() default {};
/**
* 在某些场景下我们需要手动编写 Mapper可以通过这个注解来关闭 APT Mapper 生成

View File

@ -15,7 +15,7 @@
*/
package com.mybatisflex.annotation;
public interface UpdateListener {
public interface UpdateListener extends Listener {
void onUpdate(Object entity);

View File

@ -16,13 +16,15 @@
package com.mybatisflex.core;
import com.mybatisflex.annotation.InsertListener;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.SetListener;
import com.mybatisflex.annotation.UpdateListener;
import com.mybatisflex.core.dialect.DbType;
import com.mybatisflex.annotation.KeyType;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ -157,16 +159,66 @@ public class FlexGlobalConfig {
return entitySetListeners.get(entityClass);
}
/**
* 获取支持该 {@code entityClass} 的set监听器
* <p>当registerClass是entityClass的本身或其超类时则视为支持</p>
*
* @param entityClass 实体class
* @return UpdateListener
*/
public List<SetListener> getSupportedSetListener(Class<?> entityClass) {
List<SetListener> list = new ArrayList<>();
for (Class<?> registerClass : entitySetListeners.keySet()) {
if (registerClass.isAssignableFrom(entityClass)) {
list.add(entitySetListeners.get(registerClass));
}
}
return list;
}
public UpdateListener getUpdateListener(Class<?> entityClass) {
return entityUpdateListeners.get(entityClass);
}
/**
* 获取支持该 {@code entityClass} 的update监听器
* <p>当registerClass是entityClass的本身或其超类时则视为支持</p>
*
* @param entityClass 实体class
* @return UpdateListener
*/
public List<UpdateListener> getSupportedUpdateListener(Class<?> entityClass) {
List<UpdateListener> list = new ArrayList<>();
for (Class<?> registerClass : entityUpdateListeners.keySet()) {
if (registerClass.isAssignableFrom(entityClass)) {
list.add(entityUpdateListeners.get(registerClass));
}
}
return list;
}
public InsertListener getInsertListener(Class<?> entityClass) {
return entityInsertListeners.get(entityClass);
}
/**
* 获取支持该 {@code entityClass} 的insert监听器
* <p>当registerClass是entityClass的本身或其超类时则视为支持</p>
*
* @param entityClass 实体class
* @return InsertListener
*/
public List<InsertListener> getSupportedInsertListener(Class<?> entityClass) {
List<InsertListener> list = new ArrayList<>();
for (Class<?> registerClass : entityInsertListeners.keySet()) {
if (registerClass.isAssignableFrom(entityClass)) {
list.add(entityInsertListeners.get(registerClass));
}
}
return list;
}
public Object getNormalValueOfLogicDelete() {
return normalValueOfLogicDelete;

View File

@ -86,9 +86,9 @@ public class TableInfo {
private Map<String, ColumnInfo> columnInfoMapping = new HashMap<>();
private Map<String, String> propertyColumnMapping = new HashMap<>();
private InsertListener onInsertListener;
private UpdateListener onUpdateListener;
private SetListener onSetListener;
private List<InsertListener> onInsertListener;
private List<UpdateListener> onUpdateListener;
private List<SetListener> onSetListener;
private final ReflectorFactory reflectorFactory = new BaseReflectorFactory() {
@ -233,27 +233,27 @@ public class TableInfo {
}
public InsertListener getOnInsertListener() {
public List<InsertListener> getOnInsertListener() {
return onInsertListener;
}
public void setOnInsertListener(InsertListener onInsertListener) {
public void setOnInsertListener(List<InsertListener> onInsertListener) {
this.onInsertListener = onInsertListener;
}
public UpdateListener getOnUpdateListener() {
public List<UpdateListener> getOnUpdateListener() {
return onUpdateListener;
}
public void setOnUpdateListener(UpdateListener onUpdateListener) {
public void setOnUpdateListener(List<UpdateListener> onUpdateListener) {
this.onUpdateListener = onUpdateListener;
}
public SetListener getOnSetListener() {
public List<SetListener> getOnSetListener() {
return onSetListener;
}
public void setOnSetListener(SetListener onSetListener) {
public void setOnSetListener(List<SetListener> onSetListener) {
this.onSetListener = onSetListener;
}
@ -675,7 +675,7 @@ public class TableInfo {
Object rowValue = row.get(rowKey);
Object value = ConvertUtil.convert(rowValue, metaObject.getSetterType(columnInfo.property));
if (onSetListener != null) {
value = onSetListener.onSet(instance, columnInfo.property, value);
value = invokeOnSetListener(instance, columnInfo.getProperty(), value);
}
metaObject.setValue(columnInfo.property, value);
}
@ -689,7 +689,7 @@ public class TableInfo {
Object rowValue = row.get(rowKey);
Object value = ConvertUtil.convert(rowValue, metaObject.getSetterType(columnInfo.property));
if (onSetListener != null) {
value = onSetListener.onSet(instance, columnInfo.property, value);
value = invokeOnSetListener(instance, columnInfo.getProperty(), value);
}
metaObject.setValue(columnInfo.property, value);
fillValue = true;
@ -773,63 +773,49 @@ public class TableInfo {
public void invokeOnInsertListener(Object entity) {
if (onInsertListener != null) {
onInsertListener.onInsert(entity);
return;
List<InsertListener> list = onInsertListener;
if (list == null) {
list = new ArrayList<>();
}
InsertListener globalInsertListener = null;
Class<?> registerClass = entityClass;
while (globalInsertListener == null && registerClass != Object.class && registerClass != null) {
globalInsertListener = FlexGlobalConfig.getDefaultConfig().getInsertListener(registerClass);
registerClass = registerClass.getSuperclass();
}
if (globalInsertListener != null) {
globalInsertListener.onInsert(entity);
// 全局监听器
List<InsertListener> globalListeners = FlexGlobalConfig.getDefaultConfig().getSupportedInsertListener(entityClass);
if (globalListeners != null) {
list.addAll(globalListeners);
}
Collections.sort(list);
list.forEach(insertListener -> insertListener.onInsert(entity));
}
public void invokeOnUpdateListener(Object entity) {
if (onUpdateListener != null) {
onUpdateListener.onUpdate(entity);
return;
List<UpdateListener> list = onUpdateListener;
if (list == null) {
list = new ArrayList<>();
}
UpdateListener globalUpdateListener = null;
Class<?> registerClass = entityClass;
while (globalUpdateListener == null && registerClass != Object.class && registerClass != null) {
globalUpdateListener = FlexGlobalConfig.getDefaultConfig().getUpdateListener(registerClass);
registerClass = registerClass.getSuperclass();
}
if (globalUpdateListener != null) {
globalUpdateListener.onUpdate(entity);
// 全局监听器
List<UpdateListener> globalListeners = FlexGlobalConfig.getDefaultConfig().getSupportedUpdateListener(entityClass);
if (globalListeners != null) {
list.addAll(globalListeners);
}
Collections.sort(list);
list.forEach(insertListener -> insertListener.onUpdate(entity));
}
public Object invokeOnSetListener(Object entity, String property, Object value) {
if (onSetListener != null) {
return onSetListener.onSet(entity, property, value);
List<SetListener> list = onSetListener;
if (list == null) {
list = new ArrayList<>();
}
SetListener globalSetListener = null;
Class<?> registerClass = entityClass;
while (globalSetListener == null && registerClass != Object.class && registerClass != null) {
globalSetListener = FlexGlobalConfig.getDefaultConfig().getSetListener(registerClass);
registerClass = registerClass.getSuperclass();
// 全局监听器
List<SetListener> globalListeners = FlexGlobalConfig.getDefaultConfig().getSupportedSetListener(entityClass);
if (globalListeners != null) {
list.addAll(globalListeners);
}
if (globalSetListener != null) {
return globalSetListener.onSet(entity, property, value);
Collections.sort(list);
for (SetListener setListener : list) {
value = setListener.onSet(entity, property, value);
}
return value;
}
}

View File

@ -42,6 +42,7 @@ import java.time.*;
import java.time.chrono.JapaneseDate;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
public class TableInfoFactory {
@ -120,16 +121,28 @@ public class TableInfoFactory {
tableInfo.setSchema(table.schema());
tableInfo.setCamelToUnderline(table.camelToUnderline());
if (table.onInsert() != NoneListener.class) {
tableInfo.setOnInsertListener(ClassUtil.newInstance(table.onInsert()));
if (table.onInsert().length > 0) {
List<InsertListener> insertListeners = Arrays.stream(table.onInsert())
.filter(listener -> listener != NoneListener.class)
.map(ClassUtil::newInstance)
.collect(Collectors.toList());
tableInfo.setOnInsertListener(insertListeners);
}
if (table.onUpdate() != NoneListener.class) {
tableInfo.setOnUpdateListener(ClassUtil.newInstance(table.onUpdate()));
if (table.onUpdate().length > 0) {
List<UpdateListener> updateListeners = Arrays.stream(table.onUpdate())
.filter(listener -> listener != NoneListener.class)
.map(ClassUtil::newInstance)
.collect(Collectors.toList());
tableInfo.setOnUpdateListener(updateListeners);
}
if (table.onSet() != NoneListener.class) {
tableInfo.setOnSetListener(ClassUtil.newInstance(table.onSet()));
if (table.onSet().length > 0) {
List<SetListener> setListeners = Arrays.stream(table.onSet())
.filter(listener -> listener != NoneListener.class)
.map(ClassUtil::newInstance)
.collect(Collectors.toList());
tableInfo.setOnSetListener(setListeners);
}
if (StringUtil.isNotBlank(table.dataSource())) {

View File

@ -93,6 +93,12 @@
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.22.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -10,8 +10,8 @@ import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Table(value = "tb_account",dataSource = "ds2",onSet = AccountOnSetListener.class)
public class Account extends BaseAccount implements Serializable {
@Table(value = "tb_account", dataSource = "ds2", onSet = AccountOnSetListener.class)
public class Account extends BaseAccount implements Serializable, AgeAware {
private static final long serialVersionUID = 1L;
@ -26,7 +26,7 @@ public class Account extends BaseAccount implements Serializable {
@NotBlank
private Date birthday;
@Column(typeHandler = Fastjson2TypeHandler.class,isLarge = true)
@Column(typeHandler = Fastjson2TypeHandler.class, isLarge = true)
private Map<String, Object> options;
@Column(isLogicDelete = true)
@ -49,10 +49,12 @@ public class Account extends BaseAccount implements Serializable {
this.userName = userName;
}
@Override
public int getAge() {
return age;
}
@Override
public void setAge(int age) {
this.age = age;
}

View File

@ -0,0 +1,14 @@
package com.mybatisflex.test;
/**
* 有年龄的
*
* @author snow
* @since 2023/4/28
*/
public interface AgeAware {
void setAge(int age);
int getAge();
}

View File

@ -0,0 +1,28 @@
package com.mybatisflex.test;
import com.mybatisflex.annotation.InsertListener;
/**
* 年龄处理监听器
*
* @author snow
* @since 2023/4/28
*/
public class AgeHandleListener implements InsertListener {
@Override
public void onInsert(Object entity) {
if (entity instanceof AgeAware) {
AgeAware ageAware = (AgeAware) entity;
int age = ageAware.getAge();
if (age < 0) {
ageAware.setAge(0);
}
}
}
@Override
public int order() {
return 10;
}
}

View File

@ -0,0 +1,66 @@
package com.mybatisflex.test;
import com.mybatisflex.annotation.AbstractInsertListener;
import com.mybatisflex.core.FlexGlobalConfig;
import com.mybatisflex.core.MybatisFlexBootstrap;
import org.apache.ibatis.logging.stdout.StdOutImpl;
import org.assertj.core.api.WithAssertions;
import org.junit.Test;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import javax.sql.DataSource;
import java.util.Date;
/**
* 监听器测试
*
* @author snow
* @since 2023/4/28
*/
public class ListenerTest implements WithAssertions {
// 注册父类接口监听器
@Test
public void onInsertInterface() throws Exception {
DataSource dataSource = new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("schema.sql")
.build();
// 注册全局监听器
FlexGlobalConfig defaultConfig = FlexGlobalConfig.getDefaultConfig();
defaultConfig.registerInsertListener(new AgeHandleListener(), AgeAware.class);
defaultConfig.registerInsertListener(new AbstractInsertListener<AgeAware>() {
@Override
public Class<AgeAware> supportType() {
return AgeAware.class;
}
@Override
public void doInsert(AgeAware entity) {
entity.setAge(entity.getAge() + 1);
}
@Override
public int order() {
return 20;
}
}, Account.class);
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
.setLogImpl(StdOutImpl.class)
.setDataSource(dataSource)
.addMapper(AccountMapper.class)
.start();
AccountMapper accountMapper = bootstrap.getMapper(AccountMapper.class);
Account account = new Account();
account.setAge(-2);
account.setUserName("on insert");
account.setBirthday(new Date());
accountMapper.insert(account);
Account one = accountMapper.selectOneById(account.getId());
assertThat(one.getAge()).isEqualTo(1);
}
}