From f4b8f9fe072388827399847101e17893b2d5ad61 Mon Sep 17 00:00:00 2001 From: mazhicheng Date: Thu, 25 Jun 2020 21:01:24 +0800 Subject: [PATCH 1/6] =?UTF-8?q?service=E5=A2=9E=E5=8A=A0createOrUpdateN2NR?= =?UTF-8?q?elations=E6=8E=A5=E5=8F=A3=EF=BC=8C=E7=94=A8=E4=BA=8E=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E5=A4=9A=E5=AF=B9=E5=A4=9A=E5=85=B3=E8=81=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/binding/parser/ParserCache.java | 17 ++- .../core/binding/parser/TableLinkage.java | 2 + .../com/diboot/core/service/BaseService.java | 11 ++ .../core/service/impl/BaseServiceImpl.java | 106 ++++++++++++++++-- .../com/diboot/core/util/ContextHelper.java | 16 ++- .../com/diboot/core/util/PropertiesUtils.java | 11 +- .../core/test/binder/TestEntityBinder.java | 2 +- .../test/binder/TestEntityListBinder.java | 2 +- .../core/test/binder/TestFieldBinder.java | 4 +- .../core/test/binder/TestFieldListBinder.java | 2 +- .../core/test/binder/entity/UserRole.java | 8 ++ .../core/test/binder/service/UserService.java | 3 +- .../binder/service/impl/UserServiceImpl.java | 3 +- .../core/test/config/SpringMvcConfig.java | 3 +- .../core/test/service/BaseServiceTest.java | 34 ++++++ 15 files changed, 189 insertions(+), 35 deletions(-) diff --git a/diboot-core/src/main/java/com/diboot/core/binding/parser/ParserCache.java b/diboot-core/src/main/java/com/diboot/core/binding/parser/ParserCache.java index ad9d317..5c8cdaa 100644 --- a/diboot-core/src/main/java/com/diboot/core/binding/parser/ParserCache.java +++ b/diboot-core/src/main/java/com/diboot/core/binding/parser/ParserCache.java @@ -16,12 +16,15 @@ package com.diboot.core.binding.parser; import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.diboot.core.binding.query.BindQuery; import com.diboot.core.binding.query.dynamic.AnnoJoiner; +import com.diboot.core.exception.BusinessException; import com.diboot.core.util.BeanUtils; import com.diboot.core.util.ContextHelper; import com.diboot.core.util.S; import com.diboot.core.util.V; +import com.diboot.core.vo.Status; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.session.SqlSessionFactory; import org.springframework.core.annotation.AnnotationUtils; @@ -174,14 +177,18 @@ public class ParserCache { return tableName; } - /** - * 根据类的entity小驼峰获取EntityClass + * 根据entity类获取mapper实例 * @return */ - public static Class getEntityClassByEntityLowerCaseCamel(String table){ - initTableToLinkageCacheMap(); - return entityLowerCaseCamelEntityClassCacheMap.get(table); + public static BaseMapper getMapperInstance(Class entityClass){ + String tableName = getEntityTableName(entityClass); + TableLinkage linkage = getTableLinkage(tableName); + if(linkage == null){ + throw new BusinessException(Status.FAIL_INVALID_PARAM, "未找到 "+entityClass.getName()+" 的Mapper定义!"); + } + BaseMapper mapper = (BaseMapper) ContextHelper.getBean(linkage.getMapperClass()); + return mapper; } /** diff --git a/diboot-core/src/main/java/com/diboot/core/binding/parser/TableLinkage.java b/diboot-core/src/main/java/com/diboot/core/binding/parser/TableLinkage.java index 4abe66f..18818a2 100644 --- a/diboot-core/src/main/java/com/diboot/core/binding/parser/TableLinkage.java +++ b/diboot-core/src/main/java/com/diboot/core/binding/parser/TableLinkage.java @@ -16,7 +16,9 @@ package com.diboot.core.binding.parser; import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.diboot.core.config.Cons; +import com.diboot.core.entity.BaseEntity; import com.diboot.core.util.BeanUtils; import lombok.Getter; import lombok.Setter; diff --git a/diboot-core/src/main/java/com/diboot/core/service/BaseService.java b/diboot-core/src/main/java/com/diboot/core/service/BaseService.java index b9bb204..0abcfb2 100644 --- a/diboot-core/src/main/java/com/diboot/core/service/BaseService.java +++ b/diboot-core/src/main/java/com/diboot/core/service/BaseService.java @@ -76,6 +76,17 @@ public interface BaseService { */ boolean createEntityAndRelatedEntities(T entity, List relatedEntities, ISetter relatedEntitySetter); + /** + * 创建或更新n-n关联 + * (在主对象的service中调用,不依赖中间表service实现中间表操作) + * @param driverIdGetter 驱动对象getter + * @param driverId 驱动对象ID + * @param followerIdGetter 从动对象getter + * @param followerIdList 从动对象id集合 + * @return + */ + boolean createOrUpdateN2NRelations(SFunction driverIdGetter, Object driverId, SFunction followerIdGetter, List followerIdList); + /** * 更新Entity实体 * @param entity diff --git a/diboot-core/src/main/java/com/diboot/core/service/impl/BaseServiceImpl.java b/diboot-core/src/main/java/com/diboot/core/service/impl/BaseServiceImpl.java index 120cbbe..d8bd04e 100644 --- a/diboot-core/src/main/java/com/diboot/core/service/impl/BaseServiceImpl.java +++ b/diboot-core/src/main/java/com/diboot/core/service/impl/BaseServiceImpl.java @@ -19,10 +19,10 @@ import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.LambdaUtils; import com.baomidou.mybatisplus.core.toolkit.support.SFunction; -import com.baomidou.mybatisplus.core.toolkit.support.SerializedLambda; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.diboot.core.binding.Binder; @@ -32,11 +32,13 @@ import com.diboot.core.binding.binder.FieldBinder; import com.diboot.core.binding.query.dynamic.DynamicJoinQueryWrapper; import com.diboot.core.config.BaseConfig; import com.diboot.core.config.Cons; +import com.diboot.core.exception.BusinessException; import com.diboot.core.mapper.BaseCrudMapper; import com.diboot.core.service.BaseService; import com.diboot.core.util.*; import com.diboot.core.vo.KeyValue; import com.diboot.core.vo.Pagination; +import com.diboot.core.vo.Status; import org.apache.ibatis.reflection.property.PropertyNamer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -80,6 +82,7 @@ public class BaseServiceImpl, T> extends ServiceImpl } @Override + @Transactional(rollbackFor = Exception.class) public boolean createEntityAndRelatedEntities(T entity, List relatedEntities, ISetter relatedEntitySetter) { boolean success = createEntity(entity); if(!success){ @@ -89,13 +92,7 @@ public class BaseServiceImpl, T> extends ServiceImpl if(V.isEmpty(relatedEntities)){ return success; } - Class relatedEntityClass = BeanUtils.getTargetClass(relatedEntities.get(0)); - // 获取关联对象对应的Service - BaseService relatedEntityService = ContextHelper.getBaseServiceByEntity(relatedEntityClass); - if(relatedEntityService == null){ - log.error("未能识别到Entity: {} 的Service实现,请检查!", relatedEntityClass.getName()); - return false; - } + Class relatedEntityClass = relatedEntities.get(0).getClass(); // 获取主键 Object pkValue = getPrimaryKeyValue(entity); String attributeName = BeanUtils.convertToFieldName(relatedEntitySetter); @@ -103,7 +100,20 @@ public class BaseServiceImpl, T> extends ServiceImpl relatedEntities.stream().forEach(relatedEntity->{ BeanUtils.setProperty(relatedEntity, attributeName, pkValue); }); - return relatedEntityService.createEntities(relatedEntities); + // 获取关联对象对应的Service + BaseService relatedEntityService = ContextHelper.getBaseServiceByEntity(relatedEntityClass); + if(relatedEntityService != null){ + return relatedEntityService.createEntities(relatedEntities); + } + else{ + // 查找mapper + BaseMapper mapper = ContextHelper.getBaseMapperByEntity(entity.getClass()); + // 新增关联,无service只能循环插入 + for(RE relation : relatedEntities){ + mapper.insert(relation); + } + return true; + } } @Override @@ -143,6 +153,7 @@ public class BaseServiceImpl, T> extends ServiceImpl } @Override + @Transactional(rollbackFor = Exception.class) public boolean updateEntities(Collection entityList) { if(V.isEmpty(entityList)){ return false; @@ -168,6 +179,67 @@ public class BaseServiceImpl, T> extends ServiceImpl return super.saveOrUpdateBatch(entityList, BaseConfig.getBatchSize()); } + /** + * 更新n-n关联 + * @return + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean createOrUpdateN2NRelations(SFunction driverIdGetter, Object driverId, + SFunction followerIdGetter, List followerIdList) + { + if(driverId == null){ + throw new BusinessException(Status.FAIL_INVALID_PARAM, "主动ID值不能为空!"); + } + // 从getter中获取class和fieldName + com.baomidou.mybatisplus.core.toolkit.support.SerializedLambda lambda = LambdaUtils.resolve(driverIdGetter); + Class middleTableClass = (Class) lambda.getImplClass(); + // 获取主动从动字段名 + String driverFieldName = PropertyNamer.methodToProperty(lambda.getImplMethodName()); + String followerFieldName = convertGetterToFieldName(followerIdGetter); + List n2nRelations = null; + if(V.notEmpty(followerIdList)){ + n2nRelations = new ArrayList<>(followerIdList.size()); + try{ + for(Serializable followerId : followerIdList){ + R relation = middleTableClass.newInstance(); + BeanUtils.setProperty(relation, driverFieldName, driverId); + BeanUtils.setProperty(relation, followerFieldName, followerId); + n2nRelations.add(relation); + } + } + catch (Exception e){ + throw new BusinessException(Status.FAIL_EXCEPTION, e); + } + } + // 删除已有关联 + LambdaQueryWrapper queryWrapper = new QueryWrapper().lambda() + .eq(driverIdGetter, driverId); + // 查找service + BaseService baseService = ContextHelper.getBaseServiceByEntity(middleTableClass); + if(baseService != null){ + // 条件为空,不删除 + baseService.deleteEntities(queryWrapper); + // 添加 + if(V.notEmpty(n2nRelations)){ + baseService.createEntities(n2nRelations); + } + } + else{ + // 查找mapper + BaseMapper mapper = ContextHelper.getBaseMapperByEntity(middleTableClass); + // 条件为空,不删除 + mapper.delete(queryWrapper); + // 新增关联,无service只能循环插入 + if(V.notEmpty(n2nRelations)){ + for(R relation : n2nRelations){ + mapper.insert(relation); + } + } + } + return true; + } + @Override @Transactional(rollbackFor = Exception.class) public boolean updateEntityAndRelatedEntities(T entity, List relatedEntities, ISetter relatedEntitySetter) { @@ -269,6 +341,7 @@ public class BaseServiceImpl, T> extends ServiceImpl } @Override + @Transactional(rollbackFor = Exception.class) public boolean deleteEntities(Collection entityIds) { if(V.isEmpty(entityIds)){ return false; @@ -323,8 +396,7 @@ public class BaseServiceImpl, T> extends ServiceImpl */ @Override public List getValuesOfField(Wrapper queryWrapper, SFunction getterFn){ - SerializedLambda lambda = LambdaUtils.resolve(getterFn); - String fieldName = PropertyNamer.methodToProperty(lambda.getImplMethodName()); + String fieldName = convertGetterToFieldName(getterFn); String columnName = S.toSnakeCase(fieldName); // 优化SQL,只查询当前字段 if(queryWrapper instanceof QueryWrapper){ @@ -559,6 +631,18 @@ public class BaseServiceImpl, T> extends ServiceImpl return BeanUtils.getProperty(entity, pk); } + /** + * 转换SFunction为属性名 + * @param getterFn + * @param + * @return + */ + private String convertGetterToFieldName(SFunction getterFn) { + com.baomidou.mybatisplus.core.toolkit.support.SerializedLambda lambda = LambdaUtils.resolve(getterFn); + String fieldName = PropertyNamer.methodToProperty(lambda.getImplMethodName()); + return fieldName; + } + /*** * 打印警告信息 * @param method diff --git a/diboot-core/src/main/java/com/diboot/core/util/ContextHelper.java b/diboot-core/src/main/java/com/diboot/core/util/ContextHelper.java index dc49268..4daec71 100644 --- a/diboot-core/src/main/java/com/diboot/core/util/ContextHelper.java +++ b/diboot-core/src/main/java/com/diboot/core/util/ContextHelper.java @@ -18,8 +18,10 @@ package com.diboot.core.util; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils; +import com.diboot.core.binding.parser.ParserCache; import com.diboot.core.config.Cons; import com.diboot.core.service.BaseService; import org.apache.ibatis.session.SqlSessionFactory; @@ -88,6 +90,9 @@ public class ContextHelper implements ApplicationContextAware { if (APPLICATION_CONTEXT == null){ APPLICATION_CONTEXT = ContextLoader.getCurrentWebApplicationContext(); } + if(APPLICATION_CONTEXT == null){ + log.warn("无法获取ApplicationContext,请在Spring初始化之后调用!"); + } return APPLICATION_CONTEXT; } @@ -200,11 +205,20 @@ public class ContextHelper implements ApplicationContextAware { } BaseService baseService = ENTITY_BASE_SERVICE_CACHE.get(entity.getName()); if(baseService == null){ - log.error("未能识别到Entity: "+entity.getName()+" 的Service实现!"); + log.info("未能识别到Entity: "+entity.getName()+" 的Service实现!"); } return baseService; } + /** + * 根据Entity获取对应的BaseMapper实现 + * @param entityClass + * @return + */ + public static BaseMapper getBaseMapperByEntity(Class entityClass){ + return ParserCache.getMapperInstance(entityClass); + } + /** * 获取Entity主键 * @return diff --git a/diboot-core/src/main/java/com/diboot/core/util/PropertiesUtils.java b/diboot-core/src/main/java/com/diboot/core/util/PropertiesUtils.java index d7c1768..4d8e7e9 100644 --- a/diboot-core/src/main/java/com/diboot/core/util/PropertiesUtils.java +++ b/diboot-core/src/main/java/com/diboot/core/util/PropertiesUtils.java @@ -27,11 +27,6 @@ import org.springframework.core.env.Environment; @Slf4j public class PropertiesUtils { - /** - * Spring配置环境变量 - */ - private static Environment environment; - /*** * 读取配置项的值 * @param key @@ -39,11 +34,9 @@ public class PropertiesUtils { */ public static String get(String key){ // 获取配置值 + Environment environment = ContextHelper.getApplicationContext().getEnvironment(); if(environment == null){ - environment = ContextHelper.getApplicationContext().getEnvironment(); - } - if(environment == null){ - log.warn("无法获取上下文Environment !"); + log.warn("无法获取上下文Environment,请在Spring初始化之后调用!"); return null; } String value = environment.getProperty(key); diff --git a/diboot-core/src/test/java/diboot/core/test/binder/TestEntityBinder.java b/diboot-core/src/test/java/diboot/core/test/binder/TestEntityBinder.java index d6e5a41..61c8cc5 100644 --- a/diboot-core/src/test/java/diboot/core/test/binder/TestEntityBinder.java +++ b/diboot-core/src/test/java/diboot/core/test/binder/TestEntityBinder.java @@ -54,7 +54,7 @@ public class TestEntityBinder { // 加载测试数据 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.in(User::getId, 1001L, 1002L); - List userList = userService.list(queryWrapper); + List userList = userService.getEntityList(queryWrapper); // 自动绑定 List voList = Binder.convertAndBindRelations(userList, EntityBinderVO.class); // 验证绑定结果 diff --git a/diboot-core/src/test/java/diboot/core/test/binder/TestEntityListBinder.java b/diboot-core/src/test/java/diboot/core/test/binder/TestEntityListBinder.java index b80dc4d..a1b3d04 100644 --- a/diboot-core/src/test/java/diboot/core/test/binder/TestEntityListBinder.java +++ b/diboot-core/src/test/java/diboot/core/test/binder/TestEntityListBinder.java @@ -95,7 +95,7 @@ public class TestEntityListBinder { // 加载测试数据 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.in(User::getId, 1001L, 1002L); - List userList = userService.list(queryWrapper); + List userList = userService.getEntityList(queryWrapper); // 自动绑定 List voList = Binder.convertAndBindRelations(userList, EntityListComplexBinderVO.class); // 验证绑定结果 diff --git a/diboot-core/src/test/java/diboot/core/test/binder/TestFieldBinder.java b/diboot-core/src/test/java/diboot/core/test/binder/TestFieldBinder.java index 41ba885..c00c5f2 100644 --- a/diboot-core/src/test/java/diboot/core/test/binder/TestFieldBinder.java +++ b/diboot-core/src/test/java/diboot/core/test/binder/TestFieldBinder.java @@ -57,7 +57,7 @@ public class TestFieldBinder { // 加载测试数据 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.in(User::getId, 1001L, 1002L); - List userList = userService.list(queryWrapper); + List userList = userService.getEntityList(queryWrapper); // 自动绑定 List voList = Binder.convertAndBindRelations(userList, FieldBinderVO.class); // 验证绑定结果 @@ -79,7 +79,7 @@ public class TestFieldBinder { // 加载测试数据 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.in(User::getId, 1001L, 1002L); - List userList = userService.list(queryWrapper); + List userList = userService.getEntityList(queryWrapper); // 自动绑定 List voList = Binder.convertAndBindRelations(userList, UserVO.class); if(V.notEmpty(voList)){ diff --git a/diboot-core/src/test/java/diboot/core/test/binder/TestFieldListBinder.java b/diboot-core/src/test/java/diboot/core/test/binder/TestFieldListBinder.java index e8d87c9..d5b06dc 100644 --- a/diboot-core/src/test/java/diboot/core/test/binder/TestFieldListBinder.java +++ b/diboot-core/src/test/java/diboot/core/test/binder/TestFieldListBinder.java @@ -84,7 +84,7 @@ public class TestFieldListBinder { // 加载测试数据 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.in(User::getId, 1001L, 1002L); - List userList = userService.list(queryWrapper); + List userList = userService.getEntityList(queryWrapper); // 自动绑定 List voList = Binder.convertAndBindRelations(userList, EntityListComplexBinderVO.class); // 验证绑定结果 diff --git a/diboot-core/src/test/java/diboot/core/test/binder/entity/UserRole.java b/diboot-core/src/test/java/diboot/core/test/binder/entity/UserRole.java index 7803853..45c7802 100644 --- a/diboot-core/src/test/java/diboot/core/test/binder/entity/UserRole.java +++ b/diboot-core/src/test/java/diboot/core/test/binder/entity/UserRole.java @@ -21,6 +21,8 @@ import lombok.Getter; import lombok.Setter; import lombok.experimental.Accessors; +import java.util.Date; + /** * 用户角色 * @author mazc@dibo.ltd @@ -33,6 +35,9 @@ import lombok.experimental.Accessors; public class UserRole extends BaseEntity { private static final long serialVersionUID = 3030761344045195972L; + @TableField(exist = false) + private Long id; + @TableField private Long userId; @@ -42,4 +47,7 @@ public class UserRole extends BaseEntity { @TableField(exist = false) private boolean deleted; + @TableField(exist = false) + private Date createTime; + } diff --git a/diboot-core/src/test/java/diboot/core/test/binder/service/UserService.java b/diboot-core/src/test/java/diboot/core/test/binder/service/UserService.java index 5a011be..9777eff 100644 --- a/diboot-core/src/test/java/diboot/core/test/binder/service/UserService.java +++ b/diboot-core/src/test/java/diboot/core/test/binder/service/UserService.java @@ -16,6 +16,7 @@ package diboot.core.test.binder.service; import com.baomidou.mybatisplus.extension.service.IService; +import com.diboot.core.service.BaseService; import diboot.core.test.binder.entity.User; /** @@ -24,6 +25,6 @@ import diboot.core.test.binder.entity.User; * @version v2.0 * @date 2019/1/5 */ -public interface UserService extends IService { +public interface UserService extends BaseService { } diff --git a/diboot-core/src/test/java/diboot/core/test/binder/service/impl/UserServiceImpl.java b/diboot-core/src/test/java/diboot/core/test/binder/service/impl/UserServiceImpl.java index 97e2706..860ebaf 100644 --- a/diboot-core/src/test/java/diboot/core/test/binder/service/impl/UserServiceImpl.java +++ b/diboot-core/src/test/java/diboot/core/test/binder/service/impl/UserServiceImpl.java @@ -16,6 +16,7 @@ package diboot.core.test.binder.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.diboot.core.service.impl.BaseServiceImpl; import diboot.core.test.binder.entity.User; import diboot.core.test.binder.mapper.UserMapper; import diboot.core.test.binder.service.UserService; @@ -27,6 +28,6 @@ import org.springframework.stereotype.Service; * @version 2018/12/23 */ @Service -public class UserServiceImpl extends ServiceImpl implements UserService { +public class UserServiceImpl extends BaseServiceImpl implements UserService { } diff --git a/diboot-core/src/test/java/diboot/core/test/config/SpringMvcConfig.java b/diboot-core/src/test/java/diboot/core/test/config/SpringMvcConfig.java index da49d60..0df1eb1 100644 --- a/diboot-core/src/test/java/diboot/core/test/config/SpringMvcConfig.java +++ b/diboot-core/src/test/java/diboot/core/test/config/SpringMvcConfig.java @@ -44,7 +44,7 @@ import java.util.List; */ @TestConfiguration @ComponentScan(basePackages={"com.diboot", "diboot.core"}) -@MapperScan({"com.diboot.**.mapper", "diboot.**.mapper"}) +@MapperScan({"com.diboot.core.mapper", "diboot.core.**.mapper"}) public class SpringMvcConfig implements WebMvcConfigurer{ private static final Logger log = LoggerFactory.getLogger(SpringMvcConfig.class); @@ -63,7 +63,6 @@ public class SpringMvcConfig implements WebMvcConfigurer{ // 设置fastjson的序列化参数:禁用循环依赖检测,数据兼容浏览器端(避免JS端Long精度丢失问题) fastJsonConfig.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.BrowserCompatible); - fastJsonConfig.setDateFormat(D.FORMAT_DATETIME_Y4MDHM); converter.setFastJsonConfig(fastJsonConfig); HttpMessageConverter httpMsgConverter = converter; diff --git a/diboot-core/src/test/java/diboot/core/test/service/BaseServiceTest.java b/diboot-core/src/test/java/diboot/core/test/service/BaseServiceTest.java index 7d06e54..a6f3a94 100644 --- a/diboot-core/src/test/java/diboot/core/test/service/BaseServiceTest.java +++ b/diboot-core/src/test/java/diboot/core/test/service/BaseServiceTest.java @@ -30,6 +30,8 @@ import com.diboot.core.util.JSON; import com.diboot.core.util.V; import com.diboot.core.vo.*; import diboot.core.test.StartupApplication; +import diboot.core.test.binder.entity.UserRole; +import diboot.core.test.binder.service.UserService; import diboot.core.test.config.SpringMvcConfig; import org.junit.Assert; import org.junit.Test; @@ -56,6 +58,9 @@ public class BaseServiceTest { @Autowired DictionaryServiceImpl dictionaryService; + @Autowired + UserService userService; + @Test public void testGet(){ // 查询总数 @@ -312,4 +317,33 @@ public class BaseServiceTest { voList = dictionaryService.getViewObjectList(queryWrapper, pagination, DictionaryVO.class); Assert.assertTrue(voList.size() == 1); } + + /** + * 测试n-n的批量新建/更新 + */ + @Test + @Transactional + public void testCreateUpdateN2NRelations(){ + Long userId = 10001L; + LambdaQueryWrapper queryWrapper = new QueryWrapper().lambda().eq(UserRole::getUserId, userId); + + // 新增 + List roleIdList = Arrays.asList(10L, 11L, 12L); + userService.createOrUpdateN2NRelations(UserRole::getUserId, userId, UserRole::getRoleId, roleIdList); + List list = ContextHelper.getBaseMapperByEntity(UserRole.class).selectList(queryWrapper); + Assert.assertTrue(list.size() == roleIdList.size()); + + // 更新 + roleIdList = Arrays.asList(13L); + userService.createOrUpdateN2NRelations(UserRole::getUserId, userId, UserRole::getRoleId, roleIdList); + list = ContextHelper.getBaseMapperByEntity(UserRole.class).selectList(queryWrapper); + Assert.assertTrue(list.size() == 1); + + // 删除 + roleIdList = null; + userService.createOrUpdateN2NRelations(UserRole::getUserId, userId, UserRole::getRoleId, roleIdList); + list = ContextHelper.getBaseMapperByEntity(UserRole.class).selectList(queryWrapper); + Assert.assertTrue(list.size() == 0); + } + } \ No newline at end of file From 1693408b73de378156994fc9bd117b88e89c2ed4 Mon Sep 17 00:00:00 2001 From: mazhicheng Date: Thu, 25 Jun 2020 21:02:15 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E5=88=86=E9=A1=B5=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../diboot/core/starter/CoreAutoConfiguration.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/diboot-core-starter/src/main/java/com/diboot/core/starter/CoreAutoConfiguration.java b/diboot-core-starter/src/main/java/com/diboot/core/starter/CoreAutoConfiguration.java index 8bb6165..8639a24 100644 --- a/diboot-core-starter/src/main/java/com/diboot/core/starter/CoreAutoConfiguration.java +++ b/diboot-core-starter/src/main/java/com/diboot/core/starter/CoreAutoConfiguration.java @@ -18,6 +18,7 @@ package com.diboot.core.starter; import com.alibaba.fastjson.serializer.SerializerFeature; import com.alibaba.fastjson.support.config.FastJsonConfig; import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; +import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; import com.diboot.core.config.Cons; import com.diboot.core.util.DateConverter; import org.mybatis.spring.annotation.MapperScan; @@ -72,7 +73,7 @@ public class CoreAutoConfiguration implements WebMvcConfigurer { } @Bean - @ConditionalOnMissingBean(HttpMessageConverters.class) + @ConditionalOnMissingBean public HttpMessageConverters fastJsonHttpMessageConverters() { FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter(); converter.setDefaultCharset(Charset.forName(Cons.CHARSET_UTF8)); @@ -90,6 +91,16 @@ public class CoreAutoConfiguration implements WebMvcConfigurer { return new HttpMessageConverters(httpMsgConverter); } + /** + * Mybatis-plus分页插件 + */ + @Bean + @ConditionalOnMissingBean + public PaginationInterceptor paginationInterceptor() { + PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); + return paginationInterceptor; + } + /** * 默认支持String-Date类型转换 * @param registry @@ -98,4 +109,5 @@ public class CoreAutoConfiguration implements WebMvcConfigurer { public void addFormatters(FormatterRegistry registry) { registry.addConverter(new DateConverter()); } + } \ No newline at end of file From 8f58dc05d5034912cd1b5291df9c7cf46a31750f Mon Sep 17 00:00:00 2001 From: mazhicheng Date: Thu, 25 Jun 2020 21:09:31 +0800 Subject: [PATCH 3/6] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0service.createOrUpdateN2NRelations=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- diboot-docs/guide/diboot-core/Service接口.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/diboot-docs/guide/diboot-core/Service接口.md b/diboot-docs/guide/diboot-core/Service接口.md index 8fdf0e3..44fb0f8 100644 --- a/diboot-docs/guide/diboot-core/Service接口.md +++ b/diboot-docs/guide/diboot-core/Service接口.md @@ -187,6 +187,26 @@ boolean updateEntityAndRelatedEntities(T entity, List relatedEntities, ISett boolean deleteEntityAndRelatedEntities(T entity, List relatedEntities, ISetter relatedEntitySetter); ~~~ +### createOrUpdateN2NRelations 创建或更新n-n关联 +* since v2.1.0 +```java +/** + * 创建或更新n-n关联 + * (在主动对象的service中调用,不要求中间表有service) + * @param driverIdGetter 驱动对象getter + * @param driverId 驱动对象ID + * @param followerIdGetter 从动对象getter + * @param followerIdList 从动对象id集合 + */ + boolean createOrUpdateN2NRelations(SFunction driverIdGetter, Object driverId, SFunction followerIdGetter, List followerIdList); +``` +使用示例: +~~~java +List roleIdList = Arrays.asList(10L, 11L, 12L); +// 新增/修改/删除(集合为空) 中间表关联关系 +userService.createOrUpdateN2NRelations(UserRole::getUserId, userId, UserRole::getRoleId, roleIdList); +~~~ + ### deleteEntity ```java boolean deleteEntity(Serializable id); From 3c4804a8ea7533ea7e89b19306b5aa6e5512596f Mon Sep 17 00:00:00 2001 From: mazhicheng Date: Fri, 26 Jun 2020 12:35:40 +0800 Subject: [PATCH 4/6] =?UTF-8?q?+=20D.nextDay()=EF=BC=8C=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E4=B8=8B=E4=B8=80=E5=A4=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/diboot/core/util/D.java | 12 ++++++++++++ .../java/diboot/core/test/binder/TestJoinQuery.java | 2 +- .../diboot/core/test/binder/dto/DepartmentDTO.java | 10 +++++----- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/diboot-core/src/main/java/com/diboot/core/util/D.java b/diboot-core/src/main/java/com/diboot/core/util/D.java index 0806702..b5c78bb 100644 --- a/diboot-core/src/main/java/com/diboot/core/util/D.java +++ b/diboot-core/src/main/java/com/diboot/core/util/D.java @@ -141,6 +141,18 @@ public class D extends DateUtils{ return sdf.format(date); } + /** + * 获取日期的下一天 + * @param date 基准日期 + * @return yyyy-MM-dd + */ + public static Date nextDay(Date date){ + if(date == null){ + return null; + } + return addDays(date, 1); + } + /*** * 获取格式化的日期时间 * @param date diff --git a/diboot-core/src/test/java/diboot/core/test/binder/TestJoinQuery.java b/diboot-core/src/test/java/diboot/core/test/binder/TestJoinQuery.java index bae50c2..aae38aa 100644 --- a/diboot-core/src/test/java/diboot/core/test/binder/TestJoinQuery.java +++ b/diboot-core/src/test/java/diboot/core/test/binder/TestJoinQuery.java @@ -59,7 +59,7 @@ public class TestJoinQuery { public void testDateCompaire(){ Department example = departmentService.getSingleEntity(null); DepartmentDTO departmentDTO = new DepartmentDTO(); - departmentDTO.setBegin(example.getCreateTime()); + departmentDTO.setCreateTime(example.getCreateTime()); QueryWrapper queryWrapper = QueryBuilder.toQueryWrapper(departmentDTO); List list = departmentService.getEntityList(queryWrapper); Assert.assertTrue(list.size() >= 1); diff --git a/diboot-core/src/test/java/diboot/core/test/binder/dto/DepartmentDTO.java b/diboot-core/src/test/java/diboot/core/test/binder/dto/DepartmentDTO.java index d375440..0920073 100644 --- a/diboot-core/src/test/java/diboot/core/test/binder/dto/DepartmentDTO.java +++ b/diboot-core/src/test/java/diboot/core/test/binder/dto/DepartmentDTO.java @@ -59,15 +59,15 @@ public class DepartmentDTO extends Department { @DataAccessCheckpoint(type = CheckpointType.ORG) private Long orgId; + // 查询单个日期 @BindQuery(comparison = Comparison.GE, field = "createTime") - private Date begin; + private Date createTime; @BindQuery(comparison = Comparison.LT, field = "createTime") - private Date end; + private Date createTimeEnd; - public void setBegin(Date date){ - this.begin = date; - this.end = D.addDays(date, 1); + private Date getCreateTimeEnd(){ + return D.nextDay(createTime); } } \ No newline at end of file From 969f3e7f822c0b23c192afba5c61b7bd2112b7e2 Mon Sep 17 00:00:00 2001 From: mazhicheng Date: Fri, 26 Jun 2020 13:59:36 +0800 Subject: [PATCH 5/6] =?UTF-8?q?+=20=E6=8E=A5=E5=8F=A3getEntityClassByClass?= =?UTF-8?q?Name?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../diboot/core/binding/parser/ParserCache.java | 15 ++++++++++++--- .../com/diboot/core/binding/query/BindQuery.java | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/diboot-core/src/main/java/com/diboot/core/binding/parser/ParserCache.java b/diboot-core/src/main/java/com/diboot/core/binding/parser/ParserCache.java index 5c8cdaa..f49dbee 100644 --- a/diboot-core/src/main/java/com/diboot/core/binding/parser/ParserCache.java +++ b/diboot-core/src/main/java/com/diboot/core/binding/parser/ParserCache.java @@ -57,9 +57,9 @@ public class ParserCache { */ private static Map entityClassTableCacheMap = new ConcurrentHashMap<>(); /** - * entity类小驼峰-entity类 + * entity类小驼峰实例名-entity类 */ - private static Map> entityLowerCaseCamelEntityClassCacheMap = new ConcurrentHashMap<>(); + private static Map> entityName2EntityClassCacheMap = new ConcurrentHashMap<>(); /** * dto类-BindQuery注解的缓存 */ @@ -124,7 +124,7 @@ public class ParserCache { Class entityClass = Class.forName(entityClassName); TableLinkage linkage = new TableLinkage(entityClass, m); tableToLinkageCacheMap.put(linkage.getTable(), linkage); - entityLowerCaseCamelEntityClassCacheMap.put(entityClass.getSimpleName(), entityClass); + entityName2EntityClassCacheMap.put(entityClass.getSimpleName(), entityClass); } } } @@ -191,6 +191,15 @@ public class ParserCache { return mapper; } + /** + * 根据类的entity类名获取EntityClass + * @return + */ + public static Class getEntityClassByClassName(String className){ + initTableToLinkageCacheMap(); + return entityName2EntityClassCacheMap.get(className); + } + /** * 当前DTO是否有Join绑定 * @param dto dto对象 diff --git a/diboot-core/src/main/java/com/diboot/core/binding/query/BindQuery.java b/diboot-core/src/main/java/com/diboot/core/binding/query/BindQuery.java index 1a5a5f8..960b683 100644 --- a/diboot-core/src/main/java/com/diboot/core/binding/query/BindQuery.java +++ b/diboot-core/src/main/java/com/diboot/core/binding/query/BindQuery.java @@ -20,7 +20,7 @@ import java.lang.annotation.*; /** * 绑定管理器 - * @author Xieshuang + * @author mazc@dibo.ltd * @version v2.0 * @date 2019/7/18 */ From b3c400a4c147775a28aebbff7d0798857aed7bae Mon Sep 17 00:00:00 2001 From: mazhicheng Date: Fri, 26 Jun 2020 18:56:46 +0800 Subject: [PATCH 6/6] =?UTF-8?q?=E5=AD=97=E5=85=B8=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E6=94=AF=E6=8C=81=E5=8F=AF=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=EF=BC=8C=E9=BB=98=E8=AE=A4=E4=B8=8D=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/diboot/file/excel/cache/DictTempCache.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/diboot-file-starter/src/main/java/com/diboot/file/excel/cache/DictTempCache.java b/diboot-file-starter/src/main/java/com/diboot/file/excel/cache/DictTempCache.java index 2fd80c7..eb3cd6f 100644 --- a/diboot-file-starter/src/main/java/com/diboot/file/excel/cache/DictTempCache.java +++ b/diboot-file-starter/src/main/java/com/diboot/file/excel/cache/DictTempCache.java @@ -16,6 +16,7 @@ package com.diboot.file.excel.cache; import com.diboot.core.binding.annotation.BindDict; +import com.diboot.core.config.BaseConfig; import com.diboot.core.service.DictionaryService; import com.diboot.core.util.BeanUtils; import com.diboot.core.util.ContextHelper; @@ -215,7 +216,12 @@ public class DictTempCache { if (cacheTime == null) { return true; } - return (System.currentTimeMillis() - cacheTime) > 600000; + // 过期分钟数 + int expiredMinutes = BaseConfig.getInteger("system.dict.expire", 0); + if(expiredMinutes == 0){ + return true; + } + return (System.currentTimeMillis() - cacheTime) > (expiredMinutes * 60000); } }