mirror of
https://gitee.com/mybatis-flex/mybatis-flex.git
synced 2025-12-07 00:58:24 +08:00
Merge branch 'main' of https://github.com/mybatis-flex/mybatis-flex
This commit is contained in:
commit
5d7da4a2bb
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -15,6 +15,6 @@
|
||||
*/
|
||||
package com.mybatisflex.annotation;
|
||||
|
||||
public interface InsertListener {
|
||||
public interface InsertListener extends Listener{
|
||||
void onInsert(Object entity);
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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) {
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
*/
|
||||
package com.mybatisflex.annotation;
|
||||
|
||||
public interface SetListener {
|
||||
public interface SetListener extends Listener {
|
||||
|
||||
Object onSet(Object entity, String property, Object value);
|
||||
}
|
||||
|
||||
@ -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 生成
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
*/
|
||||
package com.mybatisflex.annotation;
|
||||
|
||||
public interface UpdateListener {
|
||||
public interface UpdateListener extends Listener {
|
||||
|
||||
void onUpdate(Object entity);
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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())) {
|
||||
|
||||
@ -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>
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
package com.mybatisflex.test;
|
||||
|
||||
/**
|
||||
* 有年龄的
|
||||
*
|
||||
* @author snow
|
||||
* @since 2023/4/28
|
||||
*/
|
||||
public interface AgeAware {
|
||||
|
||||
void setAge(int age);
|
||||
|
||||
int getAge();
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user