diff --git a/diboot-core-starter/pom.xml b/diboot-core-starter/pom.xml index b147da86371ab3eaa26d9f77dffdc5b90e9f3fef..031b43fd97840835d30a88e9f91cb7b93bd47317 100644 --- a/diboot-core-starter/pom.xml +++ b/diboot-core-starter/pom.xml @@ -7,11 +7,11 @@ com.diboot diboot-root - 2.6.0 + 2.7.0 diboot-core-spring-boot-starter - 2.6.0 + 2.7.0 jar diboot core starter project diff --git a/diboot-core-starter/src/main/java/com/diboot/core/cache/DynamicRedisCacheManager.java b/diboot-core-starter/src/main/java/com/diboot/core/cache/DynamicRedisCacheManager.java index 40d52de8ae360c3857758a0771af38459a6f5efb..f4c1ff9a6db047ea7fa2b275a99b060851e7053d 100644 --- a/diboot-core-starter/src/main/java/com/diboot/core/cache/DynamicRedisCacheManager.java +++ b/diboot-core-starter/src/main/java/com/diboot/core/cache/DynamicRedisCacheManager.java @@ -19,6 +19,8 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.cache.Cache; import org.springframework.data.redis.cache.RedisCacheManager; +import java.util.concurrent.Callable; + /** * 动态数据Redis缓存 * @author JerryMa @@ -41,6 +43,12 @@ public class DynamicRedisCacheManager implements BaseCacheManager{ return cache != null? cache.get(objKey, tClass) : null; } + @Override + public T getCacheObj(String cacheName, Object objKey, Callable initSupplier) { + Cache cache = redisCacheManager.getCache(cacheName); + return cache != null ? cache.get(objKey, initSupplier) : null; + } + @Override public String getCacheString(String cacheName, Object objKey) { return getCacheObj(cacheName, objKey, String.class); @@ -52,6 +60,7 @@ public class DynamicRedisCacheManager implements BaseCacheManager{ cache.put(objKey, obj); } + @Override public void putCacheObj(String cacheName, Object objKey, Object obj, int expireMinutes) { // 暂不支持redis按cache设置不同过期时间 this.putCacheObj(cacheName, objKey, obj); diff --git a/diboot-core-starter/src/main/java/com/diboot/core/service/impl/DictionaryServiceExtImpl.java b/diboot-core-starter/src/main/java/com/diboot/core/service/impl/DictionaryServiceExtImpl.java index e09b60b46236698d0655bd99dd3f199fefed563c..561baf29c9da459381e4a38791e39230eed76f3e 100644 --- a/diboot-core-starter/src/main/java/com/diboot/core/service/impl/DictionaryServiceExtImpl.java +++ b/diboot-core-starter/src/main/java/com/diboot/core/service/impl/DictionaryServiceExtImpl.java @@ -189,19 +189,28 @@ public class DictionaryServiceExtImpl extends BaseServiceImpl entityList = super.getEntityList(queryWrapper); Map map = entityList.stream().collect(Collectors.toMap(Dictionary::getItemValue, Dictionary::getItemName)); for (Object item : voList) { - String value = BeanUtils.getStringProperty(item, getFieldName); + Object value = BeanUtils.getProperty(item, getFieldName); if (V.isEmpty(value)) { continue; } - String label = map.get(value); - if (label == null && value.contains(S.SEPARATOR)) { - ArrayList labelList = new ArrayList<>(); - for (String key : value.split(S.SEPARATOR)) { - labelList.add(map.get(key)); + Object label = map.get(value); + if (label == null) { + if(value instanceof String && ((String)value).contains(S.SEPARATOR)) { + List labelList = new ArrayList<>(); + for (String key : ((String)value).split(S.SEPARATOR)) { + labelList.add(map.get(key)); + } + label = S.join(labelList); + } + else if(value instanceof Collection) { + List labelList = new ArrayList<>(); + for (Object key : (Collection)value) { + labelList.add(map.get((String)key)); + } + label = labelList; } - label = S.join(labelList); } - if (S.isNotEmpty(label)) { + if (V.notEmpty(label)) { BeanUtils.setProperty(item, setFieldName, label); } } diff --git a/diboot-core-starter/src/main/java/com/diboot/core/starter/CoreAutoConfig.java b/diboot-core-starter/src/main/java/com/diboot/core/starter/CoreAutoConfig.java index ca79e4a6268a086d538d461cd1544462604df63b..4ddc9b7f680e5ed268b5e0dc47c873f806662cbe 100644 --- a/diboot-core-starter/src/main/java/com/diboot/core/starter/CoreAutoConfig.java +++ b/diboot-core-starter/src/main/java/com/diboot/core/starter/CoreAutoConfig.java @@ -176,7 +176,13 @@ public class CoreAutoConfig implements WebMvcConfigurer { public void addFormatters(FormatterRegistry registry) { registry.addConverter(new Date2LocalDateConverter()); registry.addConverter(new Date2LocalDateTimeConverter()); + registry.addConverter(new LocalDate2DateConverter()); + registry.addConverter(new LocalDateTime2DateConverter()); + registry.addConverter(new SqlDate2LocalDateConverter()); + registry.addConverter(new SqlDate2LocalDateTimeConverter()); registry.addConverter(new String2DateConverter()); + registry.addConverter(new String2LocalDateConverter()); + registry.addConverter(new String2LocalDateTimeConverter()); registry.addConverter(new String2BooleanConverter()); registry.addConverter(new Timestamp2LocalDateTimeConverter()); } diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/TestCountBinder.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/TestCountBinder.java index 05e96c6640c403064781244ca861ddea0033af69..839d073e9e5d0197df8dffab5438e3b3b55067c4 100644 --- a/diboot-core-starter/src/test/java/diboot/core/test/binder/TestCountBinder.java +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/TestCountBinder.java @@ -24,7 +24,8 @@ import diboot.core.test.binder.entity.Department; import diboot.core.test.binder.entity.User; import diboot.core.test.binder.service.DepartmentService; import diboot.core.test.binder.service.UserService; -import diboot.core.test.binder.vo.*; +import diboot.core.test.binder.vo.CountSimpleVO; +import diboot.core.test.binder.vo.EntityListComplexVO; import diboot.core.test.config.SpringMvcConfig; import org.junit.Assert; import org.junit.Test; diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/TestDeepBinder.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/TestDeepBinder.java index b1e60bdbe5e2458708356deebfbedd55e2e9b8c1..bd919754f0273f8578a6b99541afcff640a7739f 100644 --- a/diboot-core-starter/src/test/java/diboot/core/test/binder/TestDeepBinder.java +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/TestDeepBinder.java @@ -23,6 +23,7 @@ import diboot.core.test.StartupApplication; import diboot.core.test.binder.entity.Department; import diboot.core.test.binder.service.DepartmentService; import diboot.core.test.binder.vo.DeepBindVO; +import diboot.core.test.binder.vo.DepartmentVO; import diboot.core.test.config.SpringMvcConfig; import org.junit.Assert; import org.junit.Test; @@ -81,8 +82,12 @@ public class TestDeepBinder { if(vo.getId().equals(10001L)){ Assert.assertTrue(vo.getChildren().size() == 3); // 验证深度绑定 - Assert.assertTrue(vo.getChildren().get(0).getOrganizationVO() != null); - Assert.assertTrue(vo.getChildren().get(1).getOrganizationVO() != null); + List children = vo.getChildren(); + Assert.assertTrue(children.get(0).getOrganizationVO() != null); + Assert.assertTrue(children.get(1).getOrganizationVO() != null); + // 测试第4层 + Assert.assertTrue(children.get(0).getOrganizationVO().getManagerGenderLabel() != null); + Assert.assertTrue(children.get(1).getOrganizationVO().getManagerGenderLabel() != null); } else if(vo.getId().equals(10003L)){ Assert.assertTrue(vo.getChildren().size() == 2); @@ -90,7 +95,7 @@ public class TestDeepBinder { Assert.assertTrue(vo.getChildren().get(0).getOrganizationVO() != null); } else if(vo.getId().equals(10005L)){ - Assert.assertTrue(vo.getChildren() == null); + Assert.assertTrue(V.isEmpty(vo.getChildren())); } System.out.println(JSON.stringify(vo)); } diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/TestDictBinder.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/TestDictBinder.java index e95c94498177c131e8f0bb70248df0d53253de20..b5050e8b495ccd66e05fda3c2f225354ec5712a7 100644 --- a/diboot-core-starter/src/test/java/diboot/core/test/binder/TestDictBinder.java +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/TestDictBinder.java @@ -22,7 +22,9 @@ import com.diboot.core.util.JSON; import com.diboot.core.util.V; import diboot.core.test.StartupApplication; import diboot.core.test.binder.entity.User; +import diboot.core.test.binder.service.CustomerService; import diboot.core.test.binder.service.UserService; +import diboot.core.test.binder.vo.CustomerVO; import diboot.core.test.binder.vo.UserVO; import diboot.core.test.config.SpringMvcConfig; import org.junit.Assert; @@ -32,6 +34,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; import java.util.List; @@ -49,6 +52,9 @@ public class TestDictBinder { @Autowired UserService userService; + @Autowired + CustomerService customerService; + @Test public void testBinder(){ // 加载测试数据 @@ -72,4 +78,15 @@ public class TestDictBinder { System.out.println(JSON.stringify(singleVO)); } + @Test + @Transactional + public void testDictList() { + List customers = customerService.getViewObjectList(null, null, CustomerVO.class); + for(CustomerVO customerVO : customers) { + if(V.notEmpty(customerVO.getExtjsonarr())){ + Assert.assertTrue(customerVO.getChannelLabels().size() == customerVO.getExtjsonarr().size()); + } + } + } + } diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/TestEntityBinder.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/TestEntityBinder.java index 61c8cc5602c148dc7c151ab3a91b989419e77252..74531c80d8966f5d7645b4add58f34582985d333 100644 --- a/diboot-core-starter/src/test/java/diboot/core/test/binder/TestEntityBinder.java +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/TestEntityBinder.java @@ -67,6 +67,9 @@ public class TestEntityBinder { Assert.assertNotNull(vo.getOrganizationVO()); System.out.println(JSON.stringify(vo.getOrganizationVO())); System.out.println(JSON.stringify(vo)); + if(vo.getId().equals(1004L)){ + Assert.assertNotNull(vo.getDepartment().getExtjsonarr()); + } } // 单个entity接口测试 EntityBinderVO singleVO = BeanUtils.convert(userList.get(0), EntityBinderVO.class); @@ -80,4 +83,22 @@ public class TestEntityBinder { System.out.println(JSON.stringify(singleVO)); } + @Test + public void testBindEntityJsonArray(){ + // 加载测试数据 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.in(User::getId, 1001L, 1004L); + List userList = userService.getEntityList(queryWrapper); + // 自动绑定 + List voList = Binder.convertAndBindRelations(userList, EntityBinderVO.class); + for(EntityBinderVO vo : voList){ + // 验证直接关联和通过中间表间接关联的绑定 + Assert.assertEquals(vo.getDepartmentId(), vo.getDepartment2().getId()); + Assert.assertNotNull(vo.getDepartment2().getOrgId()); + if(vo.getId().equals(1004L)){ + Assert.assertNotNull(vo.getDepartment2().getExtjsonarr()); + } + } + } + } diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/TestEntityListBinder.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/TestEntityListBinder.java index aa60c715d4fbcae50770fca1ecb05669e6e18be6..72ea7e7069000ac8058c4a9ae07b3cf415f1ede5 100644 --- a/diboot-core-starter/src/test/java/diboot/core/test/binder/TestEntityListBinder.java +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/TestEntityListBinder.java @@ -20,6 +20,7 @@ import com.diboot.core.binding.Binder; import com.diboot.core.entity.Dictionary; import com.diboot.core.service.DictionaryService; import com.diboot.core.util.JSON; +import com.diboot.core.util.S; import com.diboot.core.util.V; import com.diboot.core.vo.DictionaryVO; import diboot.core.test.StartupApplication; @@ -141,14 +142,16 @@ public class TestEntityListBinder { for(SimpleSplitVO vo : voList){ // 验证通过中间表间接关联的绑定 Assert.assertTrue(V.notEmpty(vo.getManagers())); - System.out.println(JSON.stringify(vo)); + //System.out.println(JSON.stringify(vo)); if(vo.getCharacter().contains(",")){ - String[] valueArr = vo.getCharacter().split(","); + String[] valueArr = S.clearNonConst(vo.getCharacter()).split(","); if(valueArr[0].equals(valueArr[1])){ Assert.assertTrue(vo.getManagers().size() == 1); + Assert.assertTrue(vo.getManagersByJson().size() == 1); } else{ Assert.assertTrue(vo.getManagers().size() > 1); + Assert.assertTrue(vo.getManagersByJson().size() > 1); } } else{ @@ -172,10 +175,11 @@ public class TestEntityListBinder { // 验证通过中间表间接关联的绑定 if(vo.getManagerId().equals(1001L)){ Assert.assertTrue(vo.getManagerPhotos().size() == 1); - Assert.assertEquals(1, vo.getManagerPhotoList().size()); + Assert.assertEquals(2, vo.getManagerPhotoList().size()); } else{ Assert.assertTrue(vo.getManagerPhotos().size() == 2); + Assert.assertTrue(V.isEmpty(vo.getManagerPhotoList())); } System.out.println(JSON.stringify(vo)); } diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/TestFieldListBinder.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/TestFieldListBinder.java index 107f938c4b3c9c88910868e85b49de70b8aa7fab..bfe0b08fd1cb1fe3e1ac962672a2315370f9f2d0 100644 --- a/diboot-core-starter/src/test/java/diboot/core/test/binder/TestFieldListBinder.java +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/TestFieldListBinder.java @@ -18,6 +18,7 @@ package diboot.core.test.binder; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.diboot.core.binding.Binder; import com.diboot.core.util.JSON; +import com.diboot.core.util.S; import com.diboot.core.util.V; import diboot.core.test.StartupApplication; import diboot.core.test.binder.entity.DemoTest; @@ -142,12 +143,14 @@ public class TestFieldListBinder { Assert.assertTrue(V.notEmpty(vo.getManagerNames())); System.out.println(JSON.stringify(vo)); if(vo.getCharacter().contains(",")){ - String[] valueArr = vo.getCharacter().split(","); + String[] valueArr = S.clearNonConst(vo.getCharacter()).split(","); if(valueArr[0].equals(valueArr[1])){ Assert.assertTrue(vo.getManagerNames().size() == 1); + Assert.assertTrue(vo.getManagerNamesByJson().size() == 1); } else{ Assert.assertTrue(vo.getManagerNames().size() > 1); + Assert.assertTrue(vo.getManagerNamesByJson().size() > 1); } } else{ diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/TestJsonArrayBinder.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/TestJsonArrayBinder.java new file mode 100644 index 0000000000000000000000000000000000000000..46c71236c95120000e4c2c17038fa919f3da85f3 --- /dev/null +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/TestJsonArrayBinder.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2015-2020, www.dibo.ltd (service@dibo.ltd). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package diboot.core.test.binder; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.diboot.core.binding.Binder; +import com.diboot.core.util.JSON; +import com.diboot.core.util.V; +import diboot.core.test.StartupApplication; +import diboot.core.test.binder.entity.User; +import diboot.core.test.binder.service.UserService; +import diboot.core.test.binder.vo.UserJsonVO; +import diboot.core.test.config.SpringMvcConfig; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.List; + +/** + * 测试JsonArray绑定 + * @author mazc@dibo.ltd + * @version v2.7.0 + * @date 2022/09/09 + */ +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = {SpringMvcConfig.class}) +@SpringBootTest(classes = {StartupApplication.class}) +public class TestJsonArrayBinder { + + @Autowired + UserService userService; + + /** + * 验证jsonarray字段的条件绑定 + */ + @Test + public void testJsonArrayBinder(){ + // 需要先确保queryWrapper.in()支持jsonarray + // 加载测试数据 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.in(User::getId, 1001L, 1002L); + List entityList = userService.getEntityList(queryWrapper); + // 自动绑定 + List voList = Binder.convertAndBindRelations(entityList, UserJsonVO.class); + // 验证绑定结果 + Assert.assertTrue(V.notEmpty(voList)); + for(UserJsonVO vo : voList){ + // 验证直接关联的绑定 + System.out.println(JSON.stringify(vo)); + } + } + +} diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/TestLeadExtConditionBinder.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/TestLeadExtConditionBinder.java index 8ba5a02f0db6331dd7128a7fd0bc5cfd14fb7951..3d70cf1486696ea74ae2cd8dbdfdee57d02c3607 100644 --- a/diboot-core-starter/src/test/java/diboot/core/test/binder/TestLeadExtConditionBinder.java +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/TestLeadExtConditionBinder.java @@ -22,7 +22,6 @@ import com.diboot.core.util.V; import diboot.core.test.StartupApplication; import diboot.core.test.binder.entity.User; import diboot.core.test.binder.service.UserService; -import diboot.core.test.binder.vo.FieldBinderVO; import diboot.core.test.binder.vo.UserExtVO; import diboot.core.test.config.SpringMvcConfig; import org.junit.Assert; diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/dto/DepartmentDTO.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/dto/DepartmentDTO.java index 7679ff3445fd472a509b3928ebdb4322a0b3b463..882f63f2b2d5717764cbd063bea4b5e405635234 100644 --- a/diboot-core-starter/src/test/java/diboot/core/test/binder/dto/DepartmentDTO.java +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/dto/DepartmentDTO.java @@ -18,6 +18,7 @@ package diboot.core.test.binder.dto; import com.baomidou.mybatisplus.annotation.TableField; import com.diboot.core.binding.query.BindQuery; import com.diboot.core.binding.query.Comparison; +import com.diboot.core.binding.query.Strategy; import com.diboot.core.util.D; import diboot.core.test.binder.entity.Department; import diboot.core.test.binder.entity.Organization; @@ -43,11 +44,11 @@ public class DepartmentDTO implements Serializable { private Long parentId; - @BindQuery(comparison = Comparison.CONTAINS) + @BindQuery(comparison = Comparison.LIKE, strategy = Strategy.IGNORE_EMPTY) private String name; // 绑定join查询 - @BindQuery(comparison = Comparison.STARTSWITH, entity = Organization.class, field = "name", condition = "this.org_id=id") + @BindQuery(comparison = Comparison.STARTSWITH, strategy = Strategy.INCLUDE_NULL, entity = Organization.class, field = "name", condition = "this.org_id=id") private String orgName; // 绑定join查询 diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/entity/Customer.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/entity/Customer.java new file mode 100644 index 0000000000000000000000000000000000000000..2845e7526cb7818ee118b37e67af3630db189cdb --- /dev/null +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/entity/Customer.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2015-2020, www.dibo.ltd (service@dibo.ltd). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package diboot.core.test.binder.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import com.diboot.core.entity.BaseEntity; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * @author mazc@dibo.ltd + * @version v2.0 + * @date 2019/1/30 + */ +@Getter +@Setter +@Accessors(chain = true) +@TableName(autoResultMap = true) +public class Customer extends BaseEntity { + private static final long serialVersionUID = 5650761344045195972L; + + @TableField + private String realname; + + @TableField + private String cellphone; + + /** + * JSON数组 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List extjsonarr; + +} diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/entity/Department.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/entity/Department.java index 03abb0876f098985eee7278cb4cfa1aa50099bc5..d8da8cac63d60db4323100c503264af94009c576 100644 --- a/diboot-core-starter/src/test/java/diboot/core/test/binder/entity/Department.java +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/entity/Department.java @@ -16,6 +16,8 @@ package diboot.core.test.binder.entity; import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import com.diboot.core.binding.query.BindQuery; import com.diboot.core.binding.query.Comparison; import com.diboot.core.binding.query.Strategy; @@ -25,6 +27,9 @@ import lombok.Getter; import lombok.Setter; import lombok.experimental.Accessors; +import java.util.LinkedHashMap; +import java.util.List; + /** * Department * @author mazc@dibo.ltd @@ -34,6 +39,7 @@ import lombok.experimental.Accessors; @Getter @Setter @Accessors(chain = true) +@TableName(autoResultMap = true) public class Department extends BaseEntity { private static final long serialVersionUID = -4849732665419794547L; @@ -51,4 +57,17 @@ public class Department extends BaseEntity { @TableField("`character`") private String character; + + /** + * JSON数组 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List extjsonarr; + + /** + * JSON对象 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private LinkedHashMap extjsonobj; + } diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/entity/MyStrIdBaseEntity.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/entity/MyStrIdBaseEntity.java new file mode 100644 index 0000000000000000000000000000000000000000..0dc30a89b6acc5eb81052a220fe185d9efab0e1a --- /dev/null +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/entity/MyStrIdBaseEntity.java @@ -0,0 +1,19 @@ +package diboot.core.test.binder.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.diboot.core.entity.AbstractEntity; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +/** +* 自定义String类型id的BaseEntity +*/ +@Getter @Setter @Accessors(chain = true) +public abstract class MyStrIdBaseEntity extends AbstractEntity { + + @TableId(value = "ID_", type = IdType.ASSIGN_UUID) + private String id; + +} diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/entity/Organization.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/entity/Organization.java index dcea77b9c409f24381d3e0f42e548f892bc5b8cd..c67224b1ae7d38c583d2f2b52ac902a2739a932e 100644 --- a/diboot-core-starter/src/test/java/diboot/core/test/binder/entity/Organization.java +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/entity/Organization.java @@ -36,7 +36,7 @@ public class Organization extends BaseEntity { @TableField private Long parentId; - @TableField + //@TableField private String name; @TableField diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/entity/StrIdTest.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/entity/StrIdTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0b8f893c5109620eb6216f853b86319330a23f28 --- /dev/null +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/entity/StrIdTest.java @@ -0,0 +1,29 @@ +package diboot.core.test.binder.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; +import org.hibernate.validator.constraints.Length; + +/** +* String类型id的Entity定义 +*/ +@Getter @Setter @Accessors(chain = true) +public class StrIdTest extends MyStrIdBaseEntity { + + /** + * 类型 + */ + @Length(max=255, message="类型长度应小于255") + @TableField(value = "TYPE_") + private String type; + + /** + * 用户ID + */ + @Length(max=255, message="用户ID长度应小于255") + @TableField(value = "USER_ID_") + private String userId; + +} diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/entity/TestRegion.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/entity/TestRegion.java index 6a09f189ffddaa30d7c8aa22b50ecd9f2e0145cc..4a813e7f3c173fbb670e4f02e6a0e9ae05b2d906 100644 --- a/diboot-core-starter/src/test/java/diboot/core/test/binder/entity/TestRegion.java +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/entity/TestRegion.java @@ -19,14 +19,10 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.diboot.core.entity.BaseEntity; -import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Getter; import lombok.Setter; import lombok.experimental.Accessors; -import org.hibernate.validator.constraints.Length; -import javax.validation.constraints.NotNull; -import java.time.LocalDateTime; import java.util.List; /** diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/entity/User.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/entity/User.java index 43c7712b954f162dc35695e242232a7cacced234..f18957329667c0168b902011549a1972d0bc7267 100644 --- a/diboot-core-starter/src/test/java/diboot/core/test/binder/entity/User.java +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/entity/User.java @@ -16,7 +16,6 @@ package diboot.core.test.binder.entity; import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableName; import com.diboot.core.data.copy.Accept; import com.diboot.core.entity.BaseEntity; import com.diboot.core.util.D; @@ -50,10 +49,10 @@ public class User extends BaseEntity { @TableField private String gender; - //@JsonFormat(pattern = D.FORMAT_DATE_Y4MD) + @JsonFormat(pattern = D.FORMAT_DATE_Y4MD) private Date birthdate; - @JsonFormat(pattern = D.FORMAT_DATE_Y4MD) + @JsonFormat(pattern = D.FORMAT_DATETIME_Y4MDHMS) private LocalDateTime localDatetime; @TableField("`character`") diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/mapper/CustomerMapper.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/mapper/CustomerMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..fad9b2622cd3451ed901eeb1198d1cd2dda1140f --- /dev/null +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/mapper/CustomerMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015-2020, www.dibo.ltd (service@dibo.ltd). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package diboot.core.test.binder.mapper; + +import com.diboot.core.mapper.BaseCrudMapper; +import diboot.core.test.binder.entity.Customer; +import org.apache.ibatis.annotations.Mapper; + +/** + * 客户Mapper + * @author mazc@dibo.ltd + * @version 2018/12/22 + */ +@Mapper +public interface CustomerMapper extends BaseCrudMapper { + +} + diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/mapper/StrIdTestMapper.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/mapper/StrIdTestMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..2dadf47e45f7cf9737bc0e6c237aa22ea1b35474 --- /dev/null +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/mapper/StrIdTestMapper.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015-2020, www.dibo.ltd (service@dibo.ltd). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package diboot.core.test.binder.mapper; + +import com.diboot.core.mapper.BaseCrudMapper; +import diboot.core.test.binder.entity.StrIdTest; +import org.apache.ibatis.annotations.Mapper; + +/** + * StrIdTest Mapper + * @author mazc@dibo.ltd + * @version 2018/12/22 + */ +@Mapper +public interface StrIdTestMapper extends BaseCrudMapper { + +} + diff --git a/diboot-iam-starter/src/main/java/com/diboot/iam/jwt/BaseJwtAuthToken.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/service/CustomerService.java similarity index 65% rename from diboot-iam-starter/src/main/java/com/diboot/iam/jwt/BaseJwtAuthToken.java rename to diboot-core-starter/src/test/java/diboot/core/test/binder/service/CustomerService.java index 15e72d8f2b5aaf9c95151cd78409d0e5667f87f7..4c801172715c051af4e41df80fb779e985c46898 100644 --- a/diboot-iam-starter/src/main/java/com/diboot/iam/jwt/BaseJwtAuthToken.java +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/service/CustomerService.java @@ -13,21 +13,17 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.diboot.iam.jwt; +package diboot.core.test.binder.service; -import com.diboot.iam.shiro.IamAuthToken; -import lombok.Getter; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; +import com.diboot.core.service.BaseService; +import diboot.core.test.binder.entity.Customer; /** - * @author Yangzhao + * 客户相关Service + * @author mazc@dibo.ltd * @version v2.0 - * @date 2019/6/6 + * @date 2019/1/5 */ -@Deprecated -@Getter @Setter -@Slf4j -public class BaseJwtAuthToken extends IamAuthToken { - private static final long serialVersionUID = -3455501467921544790L; +public interface CustomerService extends BaseService { + } diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/service/DepartmentService.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/service/DepartmentService.java index ff27917c88056d98012dc2aa21d3f04b92911078..19aae88b6245173771bf1ac6a80f715362f51f3a 100644 --- a/diboot-core-starter/src/test/java/diboot/core/test/binder/service/DepartmentService.java +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/service/DepartmentService.java @@ -15,8 +15,9 @@ */ package diboot.core.test.binder.service; +import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.extension.service.IService; +import com.diboot.core.service.BaseService; import com.diboot.core.vo.Pagination; import diboot.core.test.binder.dto.DepartmentDTO; import diboot.core.test.binder.entity.Department; @@ -29,7 +30,15 @@ import java.util.List; * @version v2.0 * @date 2019/1/30 */ -public interface DepartmentService extends IService { +public interface DepartmentService extends BaseService { + + /** + * 获取指定条件的Entity集合 + * @param queryWrapper + * @return + * @throws Exception + */ + List list(Wrapper queryWrapper); List getDepartmentSqlList(QueryWrapper queryWrapper, Pagination pagination); } diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/service/StrIdTestService.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/service/StrIdTestService.java new file mode 100644 index 0000000000000000000000000000000000000000..e56cc662d37ce3082b8f06baf9aa60911b891dd7 --- /dev/null +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/service/StrIdTestService.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015-2020, www.dibo.ltd (service@dibo.ltd). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package diboot.core.test.binder.service; + +import com.diboot.core.service.BaseService; +import diboot.core.test.binder.entity.StrIdTest; + +/** + * StrIdTest相关Service + * @author mazc@dibo.ltd + * @version 2022/9/19 + */ +public interface StrIdTestService extends BaseService { + +} diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/service/impl/CustomerServiceImpl.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/service/impl/CustomerServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..a2c3dc4c6156e9e9b6ee8a19ba19f5ec4a1978e0 --- /dev/null +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/service/impl/CustomerServiceImpl.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015-2020, www.dibo.ltd (service@dibo.ltd). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package diboot.core.test.binder.service.impl; + +import com.diboot.core.service.impl.BaseServiceImpl; +import diboot.core.test.binder.entity.Customer; +import diboot.core.test.binder.mapper.CustomerMapper; +import diboot.core.test.binder.service.CustomerService; +import org.springframework.stereotype.Service; + +/** + * 员工相关Service + * @author mazc@dibo.ltd + * @version 2018/12/23 + */ +@Service +public class CustomerServiceImpl extends BaseServiceImpl implements CustomerService { + +} diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/service/impl/DepartmentServiceImpl.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/service/impl/DepartmentServiceImpl.java index a30f64b3a0b092aca312cca4d035c98a71a1a291..8f19a291635007802928994fc838d3d73d397462 100644 --- a/diboot-core-starter/src/test/java/diboot/core/test/binder/service/impl/DepartmentServiceImpl.java +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/service/impl/DepartmentServiceImpl.java @@ -15,8 +15,9 @@ */ package diboot.core.test.binder.service.impl; +import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.diboot.core.service.impl.BaseServiceImpl; import com.diboot.core.vo.Pagination; import diboot.core.test.binder.dto.DepartmentDTO; import diboot.core.test.binder.entity.Department; @@ -35,7 +36,12 @@ import java.util.List; */ @Slf4j @Service -public class DepartmentServiceImpl extends ServiceImpl implements DepartmentService { +public class DepartmentServiceImpl extends BaseServiceImpl implements DepartmentService { + + @Override + public List list(Wrapper queryWrapper) { + return getEntityList(queryWrapper); + } @Override public List getDepartmentSqlList(QueryWrapper queryWrapper, Pagination pagination) { diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/service/impl/StrIdTestServiceImpl.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/service/impl/StrIdTestServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..eede0c2810761561d7442078ebee4aa4c34438d4 --- /dev/null +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/service/impl/StrIdTestServiceImpl.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015-2020, www.dibo.ltd (service@dibo.ltd). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package diboot.core.test.binder.service.impl; + +import com.diboot.core.service.impl.BaseServiceImpl; +import diboot.core.test.binder.entity.StrIdTest; +import diboot.core.test.binder.mapper.StrIdTestMapper; +import diboot.core.test.binder.service.StrIdTestService; +import org.springframework.stereotype.Service; + +/** + * StrIdTest关Service + * @author mazc@dibo.ltd + * @version 2022/9/19 + */ +@Service +public class StrIdTestServiceImpl extends BaseServiceImpl implements StrIdTestService { + +} diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/vo/CustomerVO.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/vo/CustomerVO.java new file mode 100644 index 0000000000000000000000000000000000000000..12918546d1f1c7b7bded89ddb613ae143ece4f56 --- /dev/null +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/vo/CustomerVO.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015-2020, www.dibo.ltd (service@dibo.ltd). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package diboot.core.test.binder.vo; + +import com.diboot.core.binding.annotation.BindDict; +import diboot.core.test.binder.entity.Customer; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * + * + * @author mazc@dibo.ltd + * @version v2.0 + * @date 2019/06/22 + */ +@Getter +@Setter +@Accessors(chain = true) +public class CustomerVO extends Customer { + + @BindDict(type = "MESSAGE_CHANNEL", field = "extjsonarr") + private List channelLabels; + +} diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/vo/DepartmentVO.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/vo/DepartmentVO.java index e98de17be12b3d5ab6adc611f773aa3af4079d0e..c2520664707e03e5c9db52c059d3fecd3724d1e0 100644 --- a/diboot-core-starter/src/test/java/diboot/core/test/binder/vo/DepartmentVO.java +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/vo/DepartmentVO.java @@ -54,7 +54,7 @@ public class DepartmentVO { private Department department; // 关联Entity,赋值给VO - @BindEntity(entity = Organization.class, condition = "this.org_id=id") // AND ... + @BindEntity(entity = Organization.class, condition = "this.org_id=id", deepBind = true) // AND ... private OrganizationVO organizationVO; @BindEntityList(entity = Department.class, condition = "this.id=parent_id AND this.name IS NOT NULL") // AND ... diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/vo/EntityBinderVO.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/vo/EntityBinderVO.java index ff1944b14251eed4fe40fe308081638034365e78..cac1c9f4a1fac49061a674f662b1e7ef63c20f67 100644 --- a/diboot-core-starter/src/test/java/diboot/core/test/binder/vo/EntityBinderVO.java +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/vo/EntityBinderVO.java @@ -34,7 +34,7 @@ import lombok.experimental.Accessors; public class EntityBinderVO extends User { private static final long serialVersionUID = 3526115343377985725L; - // 字段关联,相同条件的entity+condition将合并为一条SQL查询 + // 实体关联,支持附加条件 @BindEntity(entity= Department.class, condition="this.department_id=id AND name like '发'") // AND is_deleted=1 private Department department; @@ -42,4 +42,8 @@ public class EntityBinderVO extends User { @BindEntity(entity = Organization.class, condition = "this.department_id=department.id AND department.org_id=id AND parent_id=0") // AND ... private OrganizationVO organizationVO; + // 实体关联 + @BindEntity(entity= Department.class, condition="this.department_id=id") // AND is_deleted=1 + private Department department2; + } \ No newline at end of file diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/vo/SimpleSplitVO.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/vo/SimpleSplitVO.java index 299817abab769dcbdc5782b16418c02a735cc8d5..fe1ca2c3463c5a42d2753e89ef2491e769ef2177 100644 --- a/diboot-core-starter/src/test/java/diboot/core/test/binder/vo/SimpleSplitVO.java +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/vo/SimpleSplitVO.java @@ -43,10 +43,17 @@ public class SimpleSplitVO extends Department { //@BindEntityList(entity = User.class, condition="this.character=id", splitBy= Cons.SEPARATOR_COMMA) private List managers; - // ,拆分的id值绑定 @BindFieldList(entity = User.class, field = "username", condition="this.`character`=id", splitBy= Cons.SEPARATOR_COMMA) //@BindFieldList(entity = User.class, field = "username", condition="this.character=id", splitBy= Cons.SEPARATOR_COMMA) private List managerNames; + // JsonArray的id值绑定 + @BindEntityList(entity = User.class, condition="this.extjsonarr=id") + private List managersByJson; + + // JSONArray的id值绑定 + @BindFieldList(entity = User.class, field = "username", condition="this.extjsonarr=id") + private List managerNamesByJson; + } diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/vo/UserExtVO.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/vo/UserExtVO.java index be86b4e4cfad65617e93d68a1ac3646d38b32b3b..a8b44aabe45839ecd475e5e489b2489ce054e069 100644 --- a/diboot-core-starter/src/test/java/diboot/core/test/binder/vo/UserExtVO.java +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/vo/UserExtVO.java @@ -17,11 +17,7 @@ package diboot.core.test.binder.vo; import com.diboot.core.binding.annotation.BindField; import com.diboot.core.binding.annotation.BindFieldList; -import com.diboot.core.binding.query.BindQuery; -import com.diboot.core.binding.query.Comparison; -import com.diboot.core.binding.query.Strategy; import diboot.core.test.binder.entity.Department; -import diboot.core.test.binder.entity.Organization; import diboot.core.test.binder.entity.Role; import diboot.core.test.binder.entity.User; import lombok.Getter; diff --git a/diboot-core-starter/src/test/java/diboot/core/test/binder/vo/UserJsonVO.java b/diboot-core-starter/src/test/java/diboot/core/test/binder/vo/UserJsonVO.java new file mode 100644 index 0000000000000000000000000000000000000000..ef07d63fd25a319d22e491949efc653ff16abb18 --- /dev/null +++ b/diboot-core-starter/src/test/java/diboot/core/test/binder/vo/UserJsonVO.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015-2020, www.dibo.ltd (service@dibo.ltd). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package diboot.core.test.binder.vo; + +import com.diboot.core.binding.annotation.BindEntityList; +import com.diboot.core.binding.annotation.BindFieldList; +import diboot.core.test.binder.entity.Department; +import diboot.core.test.binder.entity.User; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * + * + * @author mazc@dibo.ltd + * @version v2.7.0 + * @date 2022/09/09 + */ +@Getter +@Setter +@Accessors(chain = true) +public class UserJsonVO extends User { + private static final long serialVersionUID = 3526115343377985709L; + + // 字段关联,附加更多条件 + @BindFieldList(entity= Department.class, field="name", condition="this.id=extjsonarr") + private List deptNames; + + // 字段关联,附加更多条件 + @BindEntityList(entity= Department.class, condition="this.id=extjsonarr") + private List departments; + +} \ No newline at end of file diff --git a/diboot-core-starter/src/test/java/diboot/core/test/config/SpringMvcConfig.java b/diboot-core-starter/src/test/java/diboot/core/test/config/SpringMvcConfig.java index a6f5fc89ceff9fc16149ef205378a0db86c21fdd..36be126991585c1ec9ad18ddbb31622a2d69abbf 100644 --- a/diboot-core-starter/src/test/java/diboot/core/test/config/SpringMvcConfig.java +++ b/diboot-core-starter/src/test/java/diboot/core/test/config/SpringMvcConfig.java @@ -22,9 +22,7 @@ import com.diboot.core.handler.DataAccessControlInterceptor; import com.diboot.core.util.ContextHelper; import com.diboot.core.util.D; import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; @@ -43,7 +41,6 @@ import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.format.FormatterRegistry; -import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @@ -54,7 +51,6 @@ import java.time.LocalDateTime; import java.time.LocalTime; import java.time.format.DateTimeFormatter; import java.util.Date; -import java.util.List; import java.util.TimeZone; /*** @@ -145,6 +141,8 @@ public class SpringMvcConfig implements WebMvcConfigurer { registry.addConverter(new Date2LocalDateConverter()); registry.addConverter(new Date2LocalDateTimeConverter()); registry.addConverter(new String2DateConverter()); + registry.addConverter(new String2LocalDateConverter()); + registry.addConverter(new String2LocalDateTimeConverter()); registry.addConverter(new String2BooleanConverter()); registry.addConverter(new Timestamp2LocalDateTimeConverter()); } diff --git a/diboot-core-starter/src/test/java/diboot/core/test/query/TestJoinQuery.java b/diboot-core-starter/src/test/java/diboot/core/test/query/TestJoinQuery.java index 4f1ffde54f5094f62e1a7d8262a5187d26a487a5..e60bb362d8cefda33b1d5d943f2359b49b5fdba5 100644 --- a/diboot-core-starter/src/test/java/diboot/core/test/query/TestJoinQuery.java +++ b/diboot-core-starter/src/test/java/diboot/core/test/query/TestJoinQuery.java @@ -19,14 +19,17 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.diboot.core.binding.Binder; import com.diboot.core.binding.JoinsBinder; import com.diboot.core.binding.QueryBuilder; +import com.diboot.core.binding.query.dynamic.ExtQueryWrapper; import com.diboot.core.config.Cons; import com.diboot.core.vo.Pagination; import diboot.core.test.StartupApplication; import diboot.core.test.binder.dto.DepartmentDTO; import diboot.core.test.binder.dto.UserDTO; import diboot.core.test.binder.entity.Department; +import diboot.core.test.binder.entity.StrIdTest; import diboot.core.test.binder.entity.User; import diboot.core.test.binder.service.DepartmentService; +import diboot.core.test.binder.service.StrIdTestService; import diboot.core.test.binder.service.UserService; import diboot.core.test.binder.vo.DepartmentVO; import diboot.core.test.config.SpringMvcConfig; @@ -60,6 +63,9 @@ public class TestJoinQuery { @Autowired UserService userService; + @Autowired + StrIdTestService strIdTestService; + @Test public void testDateCompaire(){ Department example = departmentService.list(null).get(0); @@ -85,6 +91,7 @@ public class TestJoinQuery { queryWrapper = QueryBuilder.toQueryWrapper(departmentDTO); list = Binder.joinQueryList(queryWrapper, Department.class); Assert.assertTrue(list.size() > 0); + } @Test @@ -118,6 +125,11 @@ public class TestJoinQuery { public void testDynamicSqlQuery(){ // 初始化DTO,测试不涉及关联的情况 DepartmentDTO dto = new DepartmentDTO(); + //dto.setOrgName(""); + ExtQueryWrapper query = QueryBuilder.toDynamicJoinQueryWrapper(dto); + List departmentList = query.queryList(Department.class); + Assert.assertTrue(departmentList.size() > 3); + dto.setParentId(10001L); // 验证 转换后的wrapper可以直接查询 @@ -132,12 +144,9 @@ public class TestJoinQuery { List builderResultList = QueryBuilder.toDynamicJoinQueryWrapper(dto).queryList(Department.class); Assert.assertTrue(builderResultList.size() == 3); - // 初始化DTO - dto = new DepartmentDTO(); dto.setParentId(10001L); - dto.setParentName("产品部"); - //boolean类型 dto.setOrgName("苏州帝博"); + dto.setParentName("产品部"); // 验证直接查询指定字段 List fields = Arrays.asList("parentId", "parentName", "orgName"); @@ -156,6 +165,9 @@ public class TestJoinQuery { // 不分页 3条结果 List list = JoinsBinder.queryList(queryWrapper, Department.class); Assert.assertTrue(list.size() == 3); + Department departmentFirst = departmentService.getSingleEntity(queryWrapper); + Assert.assertTrue(departmentFirst.getId().equals(list.get(0).getId())); + // 不分页,直接用wrapper查 list = QueryBuilder.toDynamicJoinQueryWrapper(dto).queryList(Department.class); Assert.assertTrue(list.size() == 3); @@ -181,6 +193,8 @@ public class TestJoinQuery { // 第二页 1条结果 list = Binder.joinQueryList(queryWrapper, Department.class, pagination); Assert.assertTrue(list.size() == 1); + + } /** @@ -229,6 +243,44 @@ public class TestJoinQuery { Assert.assertTrue(userList.size() > 0); } + @Test + public void testDynamicSqlQueryWithOrders(){ + // 初始化DTO,测试不涉及关联的情况 + DepartmentDTO dto = new DepartmentDTO(); + dto.setParentId(10001L); + dto.setOrgName("苏州"); + + // 分页 + Pagination pagination = new Pagination(); + pagination.setPageSize(2); + pagination.setPageIndex(1); + // 测试排序 + pagination.setOrderBy("orgName:DESC,parentName"); + + // 验证 转换后的wrapper可以直接查询 + QueryWrapper queryWrapper = QueryBuilder.toDynamicJoinQueryWrapper(dto, pagination); + // 第二页 1条结果 + List departments = departmentService.getEntityList(queryWrapper, pagination); + Assert.assertTrue(departments.size() == pagination.getPageSize()); + } + + @Test + public void testIgnoreEmptyDynamicSqlQuery(){ + // 初始化DTO,测试不涉及关联的情况 + DepartmentDTO dto = new DepartmentDTO(); + // builder直接查询,不分页 3条结果 + List builderResultList = departmentService.getEntityList(QueryBuilder.toQueryWrapper(dto)); + Assert.assertTrue(builderResultList.size() == 6); + + dto.setName(""); + builderResultList = departmentService.getEntityList(QueryBuilder.toQueryWrapper(dto)); + Assert.assertTrue(builderResultList.size() == 6); + + dto.setOrgName(""); + builderResultList = departmentService.getEntityList(QueryBuilder.toQueryWrapper(dto)); + Assert.assertTrue(builderResultList.size() == 6); + } + @Test public void testBindQueryGroup(){ DepartmentDTO departmentDTO = new DepartmentDTO(); @@ -272,6 +324,17 @@ public class TestJoinQuery { Assert.assertTrue(sql.contains("LIMIT 1")); } + @Test + public void testStringIdBuildQuery(){ + StrIdTest strIdTest = new StrIdTest(); + strIdTest.setId("123"); + strIdTest.setType("A"); + QueryWrapper queryWrapper = QueryBuilder.toDynamicJoinQueryWrapper(strIdTest); + String sql = queryWrapper.getExpression().getSqlSegment(); + System.out.println(sql); + Assert.assertTrue(sql.contains("ID_ =")); + } + /** * 构建检测是否有删除字段的sql * @param middleTable diff --git a/diboot-core-starter/src/test/java/diboot/core/test/service/BaseServiceTest.java b/diboot-core-starter/src/test/java/diboot/core/test/service/BaseServiceTest.java index d44bccc7d40b6ec3459b3a707b06302fafa9185e..e94bb7e7de5af8385982eea7ec9ac9ddab1f2e0a 100644 --- a/diboot-core-starter/src/test/java/diboot/core/test/service/BaseServiceTest.java +++ b/diboot-core-starter/src/test/java/diboot/core/test/service/BaseServiceTest.java @@ -25,19 +25,20 @@ import com.diboot.core.binding.QueryBuilder; import com.diboot.core.binding.RelationsBinder; import com.diboot.core.binding.cache.BindingCacheManager; import com.diboot.core.binding.parser.EntityInfoCache; +import com.diboot.core.binding.query.dynamic.ExtQueryWrapper; import com.diboot.core.config.BaseConfig; import com.diboot.core.data.access.DataAccessInterface; import com.diboot.core.entity.Dictionary; import com.diboot.core.service.impl.DictionaryServiceExtImpl; import com.diboot.core.util.*; import com.diboot.core.vo.*; +import com.fasterxml.jackson.core.type.TypeReference; import diboot.core.test.StartupApplication; -import diboot.core.test.binder.entity.CcCityInfo; -import diboot.core.test.binder.entity.Department; -import diboot.core.test.binder.entity.User; -import diboot.core.test.binder.entity.UserRole; +import diboot.core.test.binder.dto.UserDTO; +import diboot.core.test.binder.entity.*; import diboot.core.test.binder.service.CcCityInfoService; import diboot.core.test.binder.service.DepartmentService; +import diboot.core.test.binder.service.OrganizationService; import diboot.core.test.binder.service.UserService; import diboot.core.test.binder.vo.SimpleDictionaryVO; import diboot.core.test.config.SpringMvcConfig; @@ -46,6 +47,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.transaction.annotation.Transactional; @@ -72,6 +74,12 @@ public class BaseServiceTest { @Autowired DepartmentService departmentService; + @Autowired + JdbcTemplate jdbcTemplate; + + @Autowired + OrganizationService organizationService; + @Test public void testGet(){ // 查询总数 @@ -193,9 +201,20 @@ public class BaseServiceTest { IPage dictionaryPage = dictionaryService.page(dp, queryWrapper); - PagingJsonResult pagingJsonResult = new PagingJsonResult(dictionaryPage); + PagingJsonResult pagingJsonResult = new JsonResult().data(dictionaryPage.getRecords()).bindPagination(new Pagination()); Assert.assertTrue(V.notEmpty(pagingJsonResult)); Assert.assertTrue(pagingJsonResult.getPage().getOrderBy().equals("id:DESC")); + + PagingJsonResult> pagingJsonResult2 = new PagingJsonResult(dictionaryPage); + String jsonStr = JSON.stringify(pagingJsonResult2); + System.out.println(jsonStr); + Assert.assertTrue(pagingJsonResult2.getPage().getOrderBy().equals("id:DESC")); + + PagingJsonResult> pagingJsonResult3 = JSON.parseObject(jsonStr, + new TypeReference>>() {} + ); + Assert.assertTrue(pagingJsonResult3.getPage() != null); + Assert.assertTrue(pagingJsonResult3.getData() != null); } /** @@ -319,6 +338,22 @@ public class BaseServiceTest { String val = dictionaryService.getValueOfField(Dictionary::getId, 2L, Dictionary::getItemValue); Assert.assertTrue("M".equals(val)); System.out.println(val); + + // 初始化DTO,测试不涉及关联的情况 + UserDTO dto = new UserDTO(); + dto.setUsername("张三"); + // builder直接查询,不分页 3条结果 + ExtQueryWrapper queryWrapper = QueryBuilder.toDynamicJoinQueryWrapper(dto); + List values = userService.getValuesOfField(queryWrapper, User::getUsername); + Assert.assertTrue(values.size() == 1); + dto.setUsername(null); + + dto.setDeptId(10002L); + dto.setDeptName("研发组"); + dto.setOrgName("苏州帝博"); + queryWrapper = QueryBuilder.toDynamicJoinQueryWrapper(dto); + List values2 = userService.getValuesOfField(queryWrapper, User::getUsername); + Assert.assertTrue(values2.size() == 2); } @Test @@ -353,6 +388,12 @@ public class BaseServiceTest { pagination.setPageIndex(2); voList = dictionaryService.getViewObjectList(queryWrapper, pagination, DictionaryVO.class); Assert.assertTrue(voList.size() == 1); + + // 测试 ORDER BY name + pagination = new Pagination(); + pagination.setOrderBy("name:DESC"); + List organizations = organizationService.getEntityList(null, pagination); + Assert.assertTrue(organizations != null && organizations.get(0).getName().contains("苏州帝博")); } @Test @@ -508,4 +549,29 @@ public class BaseServiceTest { //ContextHelper.getBean(CcCityInfoService.class).removeById(cityInfo.getId()); } + @Test + public void testJdbcTemplate(){ + List> mapList = jdbcTemplate.queryForList("SELECT * FROM department"); + Assert.assertTrue(mapList != null); + System.out.println(mapList); + + List objList = jdbcTemplate.queryForList("SELECT id FROM department", Long.class); + Assert.assertTrue(objList != null); + Assert.assertTrue(objList.get(0) != null); + + jdbcTemplate.execute("UPDATE department SET name='A' WHERE id=0"); + } + + @Test + public void testJson() { + List departments = departmentService.getEntityList(null); + Assert.assertTrue(departments != null); + for(Department dept : departments) { + if(V.notEmpty(dept.getCharacter()) && dept.getCharacter().contains(",")){ + Assert.assertTrue(dept.getExtjsonarr().size() == S.split(dept.getCharacter()).length); + Assert.assertTrue(dept.getExtjsonobj() != null); + } + } + } + } diff --git a/diboot-core-starter/src/test/java/diboot/core/test/service/EnhancedConversionService2.java b/diboot-core-starter/src/test/java/diboot/core/test/service/EnhancedConversionService2.java index d07f718d796e84ad72a00cb416d574415ce96950..61c3071cab7e48fb18b8211edfab439e726af307 100644 --- a/diboot-core-starter/src/test/java/diboot/core/test/service/EnhancedConversionService2.java +++ b/diboot-core-starter/src/test/java/diboot/core/test/service/EnhancedConversionService2.java @@ -15,9 +15,8 @@ */ package diboot.core.test.service; -import com.diboot.core.converter.*; +import com.diboot.core.converter.EnhancedConversionService; import org.springframework.context.annotation.Primary; -import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.stereotype.Component; /** diff --git a/diboot-core-starter/src/test/java/diboot/core/test/util/ContextHelperTest.java b/diboot-core-starter/src/test/java/diboot/core/test/util/ContextHelperTest.java index 1c1226dc78488ecebc751843fe121ed546d85f58..9d96bb8cc38cc01a7e8a16b1fc7304b87d5dd379 100644 --- a/diboot-core-starter/src/test/java/diboot/core/test/util/ContextHelperTest.java +++ b/diboot-core-starter/src/test/java/diboot/core/test/util/ContextHelperTest.java @@ -20,7 +20,6 @@ import com.diboot.core.util.BeanUtils; import com.diboot.core.util.ContextHelper; import diboot.core.test.StartupApplication; import diboot.core.test.binder.entity.DemoTest; -import diboot.core.test.binder.service.DemoTestService; import diboot.core.test.binder.service.impl.DemoTestServiceImpl; import diboot.core.test.config.SpringMvcConfig; import org.junit.Assert; diff --git a/diboot-core-starter/src/test/java/diboot/core/test/util/JsonTest.java b/diboot-core-starter/src/test/java/diboot/core/test/util/JsonTest.java index 50cea70c490be67db449996e367e3242bbfd3ced..b00545e5c5ec0bf6f4ecb7fc26730c6a3f44fd46 100644 --- a/diboot-core-starter/src/test/java/diboot/core/test/util/JsonTest.java +++ b/diboot-core-starter/src/test/java/diboot/core/test/util/JsonTest.java @@ -48,7 +48,13 @@ public class JsonTest { @Test public void testJsonDateConvert(){ - User user = new User(); + String json = "{\"id\":123,\"birthdate\":\"1988-09-12\", \"localDatetime\":\"1998-09-12 12:12:20\"}"; + User user = JSON.toJavaObject(json, User.class); + Assert.assertTrue(user.getId() != null); + Assert.assertTrue(user.getBirthdate() != null); + Assert.assertTrue(user.getLocalDatetime() != null); + + user = new User(); user.setId(123L); user.setUsername("zhangs").setCreateTime(new Date()); user.setBirthdate(D.convert2Date("1988-09-12 12:34")); diff --git a/diboot-core-starter/src/test/resources/unittest-dm.sql b/diboot-core-starter/src/test/resources/unittest-dm.sql index ab06b46253255abc9e1371c6472c7185a84395b9..8324129c7d0c7b9b3eda6019a62bbd904a9ce1a2 100644 --- a/diboot-core-starter/src/test/resources/unittest-dm.sql +++ b/diboot-core-starter/src/test/resources/unittest-dm.sql @@ -154,7 +154,7 @@ CREATE TABLE demo_test_join ( ); -- 初始化样例数据 -INSERT INTO department (id, parent_id, org_id, name, character) VALUES (10001, 0, 100001, '产品部', 'WW'), (10002, 10001, 100001, '研发组', '1001'), (10003, 10001, 100001, '测试组', '1001,1002'), +INSERT INTO department (id, parent_id, org_id, name, character) VALUES (10001, 0, 100001, '产品部', 'WW'), (10002, 10001, 100001, '研发组', '1001'), (10003, 10001, 100001, '测试组', '[1001,1002]'), (10004, 10001, 100001, '市场部', '1001,1002'), (10005, 10003, 100001, '自动化测试', null), (10006, 10003, 100001, '功能测试', null); INSERT INTO dictionary (id, parent_id, app_module, type, item_name, item_value) VALUES (1, 0, '', 'GENDER', '性别', null), (2, 1, '', 'GENDER', '男', 'M'), (3, 1, '', 'GENDER', '女', 'F'); SET IDENTITY_INSERT organization ON; diff --git a/diboot-core-starter/src/test/resources/unittest-mysql.sql b/diboot-core-starter/src/test/resources/unittest-mysql.sql index 80cece06068c9f68fa6ff65cedd82e0dc5e9bbd4..fefb62f770313ffed6cf16b5763b4d4415015727 100644 --- a/diboot-core-starter/src/test/resources/unittest-mysql.sql +++ b/diboot-core-starter/src/test/resources/unittest-mysql.sql @@ -26,6 +26,8 @@ create table department org_id bigint not null comment '单位ID', name varchar(50) not null comment '名称', extdata varchar(100) null comment '扩展字段', + extjsonarr JSON null comment '扩展Json数组', + extjsonobj JSON null comment '扩展json对象', `character` varchar(100) null comment '关键字', is_deleted tinyint(1) default 0 not null comment '已删除', create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间' @@ -154,10 +156,32 @@ CREATE TABLE `demo_test_join` ( `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间' ) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='关联测试'; +create table customer +( + id bigint unsigned not null comment 'ID' primary key, + realname varchar(50) not null comment '名称', + cellphone varchar(50) not null comment '电话', + extjsonarr JSON null comment '扩展json对象', + is_deleted tinyint(1) default 0 not null comment '已删除', + create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间' +) + comment '客户' charset=utf8mb4; + +INSERT INTO customer (id, realname, cellphone, extjsonarr) +VALUES (10001, '张三', '13800001111', '["WEBSOCKET","EMAIL"]'), (10002, '李四', '13800002222', '["TEXT_MESSAGE"]'); + -- 初始化样例数据 -INSERT INTO department (id, parent_id, org_id, name, `character`) VALUES (10001, 0, 100001, '产品部', 'WW'), (10002, 10001, 100001, '研发组', '1001'), (10003, 10001, 100001, '测试组', '1001,1002'), - (10004, 10001, 100001, '市场部', '1001,1002'), (10005, 10003, 100001, '自动化测试', null), (10006, 10003, 100001, '功能测试', null); +INSERT INTO department (id, parent_id, org_id, name, `character`, extjsonobj, extjsonarr) +VALUES (10001, 0, 100001, '产品部', 'WW', null, null), (10002, 10001, 100001, '研发组', '1001', null, null), + (10003, 10001, 100001, '测试组', '[1001,1002]', '{"id": 1001, "name": "TEST"}', '[1001,1002]'), (10004, 10001, 100001, '市场部', '1001,1002', '{"id": 1001, "name": "TEST"}', '[1001,1002]'), + (10005, 10003, 100001, '自动化测试', null, null, null), (10006, 10003, 100001, '功能测试', null, null, null); INSERT INTO dictionary (id, parent_id, app_module, type, item_name, item_value) VALUES (1, 0, '', 'GENDER', '性别', null), (2, 1, '', 'GENDER', '男', 'M'), (3, 1, '', 'GENDER', '女', 'F'); +INSERT INTO dictionary +(id, parent_id, tenant_id, app_module, `type`, item_name, item_value, description, extdata, sort_id, is_editable, is_deletable) +VALUES(10050, 0, 0, NULL, 'MESSAGE_CHANNEL', '发送通道', NULL, 'message发送通道', NULL, 99, 1, 1), + (10051, 10050, 0, NULL, 'MESSAGE_CHANNEL', '站内信', 'WEBSOCKET', NULL, NULL, 0, 1, 1), + (10052, 10050, 0, NULL, 'MESSAGE_CHANNEL', '短信', 'TEXT_MESSAGE', NULL, NULL, 1, 1, 1), + (10053, 10050, 0, NULL, 'MESSAGE_CHANNEL', '邮件', 'EMAIL', NULL, NULL, 2, 1, 1); INSERT INTO organization (id, parent_id, name, telphone, manager_id) VALUES (100001, 0, '苏州帝博', '0512-62988949', 1001), (100002, 0, '成都帝博', '028-62988949', 1002); INSERT INTO role (id, name, code) VALUES (101, '管理员', 'ADMIN'), (102, '操作员', 'OPERATOR'); INSERT INTO user (id, department_id, username, gender, `character`) VALUES (1001, 10002, '张三', 'M', 'test123456'), (1002, 10002, '李四', 'F', 'test123456,test234567'), (1003, 10001, '王五', 'M', 'WW'); diff --git a/diboot-core/pom.xml b/diboot-core/pom.xml index 22d0b45d4dbf40079be0f5fd8e6636ea48b9558d..660937a2150293eb061fdb0b79fbbdc605b2bd5d 100644 --- a/diboot-core/pom.xml +++ b/diboot-core/pom.xml @@ -7,11 +7,11 @@ com.diboot diboot-root - 2.6.0 + 2.7.0 diboot-core - 2.6.0 + 2.7.0 jar diboot core project @@ -60,7 +60,7 @@ org.springframework.cloud spring-cloud-openfeign-core - 3.1.2 + 3.1.3 provided diff --git a/diboot-core/src/main/java/com/diboot/core/binding/Binder.java b/diboot-core/src/main/java/com/diboot/core/binding/Binder.java index bb5644026b4b29f59d69b0f8e94c3e9c83065738..11a33facbd72716659f9e3ef23e2cbd138822bed 100644 --- a/diboot-core/src/main/java/com/diboot/core/binding/Binder.java +++ b/diboot-core/src/main/java/com/diboot/core/binding/Binder.java @@ -35,7 +35,7 @@ public class Binder { * @return * @throws Exception */ - public static E joinQueryOne(QueryWrapper queryWrapper, Class entityClazz){ + public static T joinQueryOne(QueryWrapper queryWrapper, Class entityClazz){ return JoinsBinder.queryOne(queryWrapper, entityClazz); } @@ -46,7 +46,7 @@ public class Binder { * @return * @throws Exception */ - public static List joinQueryList(QueryWrapper queryWrapper, Class entityClazz){ + public static List joinQueryList(QueryWrapper queryWrapper, Class entityClazz){ return JoinsBinder.queryList(queryWrapper, entityClazz); } @@ -58,7 +58,7 @@ public class Binder { * @return * @throws Exception */ - public static List joinQueryList(QueryWrapper queryWrapper, Class entityClazz, Pagination pagination){ + public static List joinQueryList(QueryWrapper queryWrapper, Class entityClazz, Pagination pagination){ return JoinsBinder.queryList(queryWrapper, entityClazz, pagination); } @@ -69,7 +69,7 @@ public class Binder { * @param * @return */ - public static VO convertAndBindRelations(E entity, Class voClass){ + public static VO convertAndBindRelations(T entity, Class voClass){ return RelationsBinder.convertAndBind(entity, voClass); } @@ -81,7 +81,7 @@ public class Binder { * @param * @return */ - public static List convertAndBindRelations(List entityList, Class voClass){ + public static List convertAndBindRelations(List entityList, Class voClass){ return RelationsBinder.convertAndBind(entityList, voClass); } diff --git a/diboot-core/src/main/java/com/diboot/core/binding/JoinsBinder.java b/diboot-core/src/main/java/com/diboot/core/binding/JoinsBinder.java index 43c00eaf75bffa9b86bd288b589c5215b96a0aff..3a5da0d0f82abd3faa333ca1f0218917802845a5 100644 --- a/diboot-core/src/main/java/com/diboot/core/binding/JoinsBinder.java +++ b/diboot-core/src/main/java/com/diboot/core/binding/JoinsBinder.java @@ -23,6 +23,7 @@ import com.diboot.core.binding.helper.ServiceAdaptor; import com.diboot.core.binding.parser.ParserCache; import com.diboot.core.binding.query.dynamic.AnnoJoiner; import com.diboot.core.binding.query.dynamic.DynamicJoinQueryWrapper; +import com.diboot.core.binding.query.dynamic.DynamicSqlProvider; import com.diboot.core.config.BaseConfig; import com.diboot.core.config.Cons; import com.diboot.core.data.ProtectFieldHandler; @@ -55,8 +56,8 @@ public class JoinsBinder { * @return * @throws Exception */ - public static E queryOne(QueryWrapper queryWrapper, Class entityClazz){ - List list = executeJoinQuery(queryWrapper, entityClazz, null, true); + public static T queryOne(QueryWrapper queryWrapper, Class entityClazz){ + List list = executeJoinQuery(queryWrapper, entityClazz, null, true); if(V.notEmpty(list)){ return list.get(0); } @@ -70,7 +71,7 @@ public class JoinsBinder { * @return * @throws Exception */ - public static List queryList(QueryWrapper queryWrapper, Class entityClazz){ + public static List queryList(QueryWrapper queryWrapper, Class entityClazz){ return queryList(queryWrapper, entityClazz, null); } @@ -82,7 +83,7 @@ public class JoinsBinder { * @return * @throws Exception */ - public static List queryList(QueryWrapper queryWrapper, Class entityClazz, Pagination pagination){ + public static List queryList(QueryWrapper queryWrapper, Class entityClazz, Pagination pagination){ return executeJoinQuery(queryWrapper, entityClazz, pagination, false); } @@ -94,7 +95,7 @@ public class JoinsBinder { * @return * @throws Exception */ - private static List executeJoinQuery(QueryWrapper queryWrapper, Class entityClazz, Pagination pagination, boolean limit1){ + private static List executeJoinQuery(QueryWrapper queryWrapper, Class entityClazz, Pagination pagination, boolean limit1){ // 非动态查询,走BaseService if(queryWrapper instanceof DynamicJoinQueryWrapper == false){ IService iService = ContextHelper.getIServiceByEntity(entityClazz); @@ -140,11 +141,15 @@ public class JoinsBinder { } ProtectFieldHandler protectFieldHandler = ContextHelper.getBean(ProtectFieldHandler.class); // 转换查询结果 - List entityList = new ArrayList<>(); + List entityList = new ArrayList<>(); for(Map colValueMap : mapList){ Map fieldValueMap = new HashMap<>(); // 格式化map for(Map.Entry entry : colValueMap.entrySet()){ + if(entry.getKey().startsWith(DynamicSqlProvider.PLACEHOLDER_COLUMN_FLAG)) { + log.debug("忽略查询占位字段 {}", entry.getKey()); + continue; + } String fieldName = S.toLowerCaseCamel(entry.getKey()); // 如果是布尔类型,检查entity中的定义是Boolean/boolean if(entry.getValue() instanceof Boolean && S.startsWithIgnoreCase(entry.getKey(),"is_")){ @@ -163,7 +168,7 @@ public class JoinsBinder { } // 绑定map到entity try{ - E entityInst = entityClazz.newInstance(); + T entityInst = entityClazz.newInstance(); BeanUtils.bindProperties(entityInst, fieldValueMap); if (protectFieldHandler != null) { BeanWrapper beanWrapper = BeanUtils.getBeanWrapper(entityInst); @@ -188,7 +193,7 @@ public class JoinsBinder { * @param queryWrapper * @param pagination */ - private static void formatOrderBy(DynamicJoinQueryWrapper queryWrapper, Class entityClazz, Pagination pagination){ + private static void formatOrderBy(DynamicJoinQueryWrapper queryWrapper, Class entityClazz, Pagination pagination){ // 如果是默认id排序,检查是否有id字段 if(pagination.isDefaultOrderBy()){ // 优化排序 @@ -237,4 +242,4 @@ public class JoinsBinder { return ContextHelper.getBean(DynamicQueryMapper.class); } -} +} \ No newline at end of file diff --git a/diboot-core/src/main/java/com/diboot/core/binding/QueryBuilder.java b/diboot-core/src/main/java/com/diboot/core/binding/QueryBuilder.java index de940ce417e8b5377bfdb9c64b70705cc9f93185..bb0b1d36efaf108cee957a4d2f0dc8fa5283b38b 100644 --- a/diboot-core/src/main/java/com/diboot/core/binding/QueryBuilder.java +++ b/diboot-core/src/main/java/com/diboot/core/binding/QueryBuilder.java @@ -18,7 +18,6 @@ package com.diboot.core.binding; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableLogic; import com.baomidou.mybatisplus.core.conditions.ISqlSegment; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.segments.NormalSegmentList; import com.diboot.core.binding.parser.ParserCache; @@ -34,6 +33,7 @@ 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.Pagination; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,7 +65,18 @@ public class QueryBuilder { * @return */ public static QueryWrapper toQueryWrapper(DTO dto){ - return dtoToWrapper(dto, null); + return dtoToWrapper(dto, null, null); + } + + /** + * Entity或者DTO对象转换为QueryWrapper + * @param dto + * @param pagination 分页 + * @param + * @return + */ + public static QueryWrapper toQueryWrapper(DTO dto, Pagination pagination){ + return dtoToWrapper(dto, null, pagination); } /** @@ -76,7 +87,19 @@ public class QueryBuilder { * @return */ public static QueryWrapper toQueryWrapper(DTO dto, Collection fields){ - return dtoToWrapper(dto, fields); + return dtoToWrapper(dto, fields, null); + } + + /** + * Entity或者DTO对象转换为QueryWrapper + * @param dto + * @param fields 指定参与转换的属性值 + * @param pagination 分页 + * @param + * @return + */ + public static QueryWrapper toQueryWrapper(DTO dto, Collection fields, Pagination pagination){ + return dtoToWrapper(dto, fields, pagination); } /** @@ -86,41 +109,43 @@ public class QueryBuilder { * @return */ public static ExtQueryWrapper toDynamicJoinQueryWrapper(DTO dto){ - return toDynamicJoinQueryWrapper(dto, null); + return toDynamicJoinQueryWrapper(dto, null, null); } /** * Entity或者DTO对象转换为QueryWrapper * @param dto - * @param fields 指定参与转换的属性值 + * @param pagination 分页 * @param * @return */ - public static ExtQueryWrapper toDynamicJoinQueryWrapper(DTO dto, Collection fields){ - QueryWrapper queryWrapper = dtoToWrapper(dto, fields); - if(!(queryWrapper instanceof DynamicJoinQueryWrapper)){ - return (ExtQueryWrapper)queryWrapper; - } - return (DynamicJoinQueryWrapper)queryWrapper; + public static ExtQueryWrapper toDynamicJoinQueryWrapper(DTO dto, Pagination pagination){ + return toDynamicJoinQueryWrapper(dto, null, pagination); } /** - * Entity或者DTO对象转换为LambdaQueryWrapper + * Entity或者DTO对象转换为QueryWrapper * @param dto + * @param * @return */ - public static LambdaQueryWrapper toLambdaQueryWrapper(DTO dto){ - return (LambdaQueryWrapper) toQueryWrapper(dto).lambda(); + public static ExtQueryWrapper toDynamicJoinQueryWrapper(DTO dto, Collection fields){ + return toDynamicJoinQueryWrapper(dto, fields, null); } /** - * Entity或者DTO对象转换为LambdaQueryWrapper + * Entity或者DTO对象转换为QueryWrapper * @param dto * @param fields 指定参与转换的属性值 + * @param * @return */ - public static LambdaQueryWrapper toLambdaQueryWrapper(DTO dto, Collection fields){ - return (LambdaQueryWrapper) toQueryWrapper(dto, fields).lambda(); + public static ExtQueryWrapper toDynamicJoinQueryWrapper(DTO dto, Collection fields, Pagination pagination){ + QueryWrapper queryWrapper = dtoToWrapper(dto, fields, pagination); + if(!(queryWrapper instanceof DynamicJoinQueryWrapper)){ + return (ExtQueryWrapper)queryWrapper; + } + return (DynamicJoinQueryWrapper)queryWrapper; } /** @@ -129,10 +154,10 @@ public class QueryBuilder { * @param dto * @return */ - private static QueryWrapper dtoToWrapper(DTO dto, Collection fields) { + private static QueryWrapper dtoToWrapper(DTO dto, Collection fields, Pagination pagination) { QueryWrapper wrapper; // 转换 - LinkedHashMap fieldValuesMap = extractNotNullValues(dto, fields); + LinkedHashMap fieldValuesMap = extractNotNullValues(dto, fields, pagination); if (V.isEmpty(fieldValuesMap)) { return new QueryWrapper<>(); } @@ -238,14 +263,15 @@ public class QueryBuilder { */ private static void buildQuery(QueryWrapper wrapper, BindQuery bindQuery, String columnName, Object value) { Comparison comparison = bindQuery != null ? bindQuery.comparison() : Comparison.EQ; + if(value == null) { + if(bindQuery != null && bindQuery.strategy().equals(Strategy.INCLUDE_NULL) && comparison.equals(Comparison.EQ)) { + wrapper.isNull(columnName); + } + return; + } switch (comparison) { case EQ: - if(value == null && bindQuery != null && bindQuery.strategy().equals(Strategy.INCLUDE_NULL)) { - wrapper.isNull(columnName); - } - else{ - wrapper.eq(columnName, value); - } + wrapper.eq(columnName, value); break; case IN: if (value.getClass().isArray()) { @@ -339,10 +365,11 @@ public class QueryBuilder { * @param * @return */ - private static LinkedHashMap extractNotNullValues(DTO dto, Collection fields){ + private static LinkedHashMap extractNotNullValues(DTO dto, Collection fields, Pagination pagination){ Class dtoClass = dto.getClass(); // 转换 List declaredFields = BeanUtils.extractAllFields(dtoClass); + List extractOrderFieldNames = extractOrderFieldNames(pagination); // 结果map:<字段名,字段对象和值> LinkedHashMap resultMap = new LinkedHashMap<>(declaredFields.size()); for (Field field : declaredFields) { @@ -384,7 +411,22 @@ public class QueryBuilder { continue; } BindQuery bindQuery = field.getAnnotation(BindQuery.class); - if (value != null || (bindQuery != null && bindQuery.strategy().equals(Strategy.INCLUDE_NULL))) { + Strategy strategy = bindQuery != null? bindQuery.strategy() : Strategy.IGNORE_EMPTY; + boolean collectThisField = false; + // INCLUDE_NULL策略,包含null也收集 + if(strategy.equals(Strategy.INCLUDE_NULL)) { + collectThisField = true; + } + else if(strategy.equals(Strategy.IGNORE_EMPTY) && V.notEmpty(value)) { + collectThisField = true; + } + else if(strategy.equals(Strategy.INCLUDE_EMPTY) && value != null) { + collectThisField = true; + } + else if(extractOrderFieldNames.contains(fieldName)) { + collectThisField = true; + } + if (collectThisField) { resultMap.put(fieldName, new FieldAndValue(field, value)); } } @@ -428,4 +470,27 @@ public class QueryBuilder { } return false; } + + /** + * 是否为排序字段 + * @param pagination + * @return + */ + private static List extractOrderFieldNames(Pagination pagination) { + if (pagination == null || V.isEmpty(pagination.getOrderBy())) { + return Collections.emptyList(); + } + // 解析排序 + // orderBy=shortName:DESC,age:ASC,birthdate + String[] orderByFields = S.split(pagination.getOrderBy()); + List orderFields = new ArrayList<>(orderByFields.length); + for (String field : orderByFields) { + if (field.contains(":")) { + field = S.substringBefore(field, ":"); + } + orderFields.add(field); + } + return orderFields; + } + } diff --git a/diboot-core/src/main/java/com/diboot/core/binding/RelationsBinder.java b/diboot-core/src/main/java/com/diboot/core/binding/RelationsBinder.java index f753c62b275e5d87186a9fe20ad0b193eac53612..f74bef982310a439e99946412dc758a6423c6059 100644 --- a/diboot-core/src/main/java/com/diboot/core/binding/RelationsBinder.java +++ b/diboot-core/src/main/java/com/diboot/core/binding/RelationsBinder.java @@ -179,6 +179,16 @@ public class RelationsBinder { List deepBindEntityAnnoList = bindAnnotationGroup.getDeepBindEntityAnnotations(); List deepBindEntitiesAnnoList = bindAnnotationGroup.getDeepBindEntityListAnnotations(); if(deepBindEntityAnnoList != null || deepBindEntitiesAnnoList != null){ + if(V.notEmpty(deepBindEntityAnnoList)){ + FieldAnnotation firstAnnotation = deepBindEntityAnnoList.get(0); + log.debug("执行深度绑定: {}({}) for field {}", firstAnnotation.getAnnotation().annotationType().getSimpleName(), + firstAnnotation.getFieldClass().getSimpleName(), firstAnnotation.getFieldName()); + } + if(deepBindEntitiesAnnoList != null) { + FieldAnnotation firstAnnotation = deepBindEntitiesAnnoList.get(0); + log.debug("执行深度绑定: {}({}) for field {}", firstAnnotation.getAnnotation().annotationType().getSimpleName(), + firstAnnotation.getFieldClass().getSimpleName(), firstAnnotation.getFieldName()); + } DeepRelationsBinder.deepBind(voList, deepBindEntityAnnoList, deepBindEntitiesAnnoList); } } diff --git a/diboot-core/src/main/java/com/diboot/core/binding/binder/BaseBinder.java b/diboot-core/src/main/java/com/diboot/core/binding/binder/BaseBinder.java index 66015409e0967e94614f6c8a91bb626c0813a866..68539b5f7878804d73d606c802e08907dd782a9b 100644 --- a/diboot-core/src/main/java/com/diboot/core/binding/binder/BaseBinder.java +++ b/diboot-core/src/main/java/com/diboot/core/binding/binder/BaseBinder.java @@ -36,6 +36,7 @@ import org.slf4j.LoggerFactory; import java.lang.reflect.Field; import java.util.*; +import java.util.stream.Collectors; /** * 关系绑定Binder父类 @@ -316,8 +317,7 @@ public abstract class BaseBinder { // 构建查询条件 if (V.notEmpty(annoObjectJoinOnList)) { String refObjJoinOnCol = refObjJoinCols.get(i); - List unpackAnnoObjectJoinOnList = V.notEmpty(this.splitBy) ? ResultAssembler.unpackValueList(annoObjectJoinOnList, this.splitBy) - : annoObjectJoinOnList; + List unpackAnnoObjectJoinOnList = ResultAssembler.unpackValueList(annoObjectJoinOnList, this.splitBy); queryWrapper.in(refObjJoinOnCol, unpackAnnoObjectJoinOnList); if (remoteBindDTO != null) { remoteBindDTO.setRefJoinCol(refObjJoinOnCol).setInConditionValues(unpackAnnoObjectJoinOnList); diff --git a/diboot-core/src/main/java/com/diboot/core/binding/binder/EntityListBinder.java b/diboot-core/src/main/java/com/diboot/core/binding/binder/EntityListBinder.java index 9df5025bb6a3cabbbc6c3274502f5bcec485aac6..0057f25b5a840d82ef435b5d54cf5075f3e1f792 100644 --- a/diboot-core/src/main/java/com/diboot/core/binding/binder/EntityListBinder.java +++ b/diboot-core/src/main/java/com/diboot/core/binding/binder/EntityListBinder.java @@ -21,14 +21,12 @@ import com.diboot.core.binding.helper.ResultAssembler; import com.diboot.core.config.Cons; import com.diboot.core.exception.InvalidUsageException; import com.diboot.core.util.BeanUtils; +import com.diboot.core.util.S; import com.diboot.core.util.V; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; /** * Entity集合绑定实现 @@ -145,16 +143,10 @@ public class EntityListBinder extends EntityBinder { if(obj == null){ continue; } - String valStr = String.valueOf(obj); - List ent = entityMap.get(valStr); - if(ent != null){ - for (T item : ent) { - valueList.add(cloneOrConvertBean(item)); - } - } - else if(V.notEmpty(splitBy) && valStr.contains(splitBy)){ - for(String key : valStr.split(splitBy)){ - ent = entityMap.get(key); + // 兼容JsonArray + if(obj instanceof Collection) { + for(Object key : (Collection)obj){ + List ent = entityMap.get(S.valueOf(key)); if(ent != null){ for (T item : ent) { valueList.add(cloneOrConvertBean(item)); @@ -162,6 +154,25 @@ public class EntityListBinder extends EntityBinder { } } } + else { + String valStr = S.clearNonConst(String.valueOf(obj)); + List ent = entityMap.get(valStr); + if(ent != null){ + for (T item : ent) { + valueList.add(cloneOrConvertBean(item)); + } + } + else if(V.notEmpty(splitBy) && valStr.contains(splitBy)){ + for(String key : valStr.split(splitBy)){ + ent = entityMap.get(key); + if(ent != null){ + for (T item : ent) { + valueList.add(cloneOrConvertBean(item)); + } + } + } + } + } } valueEntityListMap.put(entry.getKey(), valueList); } diff --git a/diboot-core/src/main/java/com/diboot/core/binding/binder/remote/RemoteBindingManager.java b/diboot-core/src/main/java/com/diboot/core/binding/binder/remote/RemoteBindingManager.java index b767bc8ec5183695df81387cc477ffeb81d2e53b..29d69feaf9dddde466fc660636d58e50b91f5545 100644 --- a/diboot-core/src/main/java/com/diboot/core/binding/binder/remote/RemoteBindingManager.java +++ b/diboot-core/src/main/java/com/diboot/core/binding/binder/remote/RemoteBindingManager.java @@ -73,7 +73,7 @@ public class RemoteBindingManager { * 获取实例 * @return */ - private static RemoteBindingProvider getRemoteBindingProvider(String module){ + private synchronized static RemoteBindingProvider getRemoteBindingProvider(String module){ if(MODULE_PROVIDER_MAP == null){ MODULE_PROVIDER_MAP = new ConcurrentHashMap<>(); } diff --git a/diboot-core/src/main/java/com/diboot/core/binding/cache/BindingCacheManager.java b/diboot-core/src/main/java/com/diboot/core/binding/cache/BindingCacheManager.java index c05c5d4a3b465dc4d293462f062d1933c89cca53..1030d7185a08d7637ebdb63addd56438c313124e 100644 --- a/diboot-core/src/main/java/com/diboot/core/binding/cache/BindingCacheManager.java +++ b/diboot-core/src/main/java/com/diboot/core/binding/cache/BindingCacheManager.java @@ -26,6 +26,8 @@ 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.util.init.BeanInitUtils; +import com.diboot.core.util.init.BeanInitializer; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.session.SqlSessionFactory; import org.springframework.context.annotation.Primary; @@ -45,10 +47,6 @@ import java.util.*; @SuppressWarnings({"JavaDoc","rawtypes", "unchecked"}) @Slf4j public class BindingCacheManager { - /** - * 实体相关定义缓存管理器 - */ - private static StaticMemoryCacheManager cacheManager; /** * 类-EntityInfo缓存key */ @@ -74,17 +72,21 @@ public class BindingCacheManager { */ private static final String CACHE_NAME_CLASS_NAME2FLDMAP = "CLASS_NAME2FLDMAP"; - private static synchronized StaticMemoryCacheManager getCacheManager(){ - if(cacheManager == null){ - cacheManager = new StaticMemoryCacheManager( + /** + * CacheManager 初始化器 + */ + private static final BeanInitializer CACHE_MANAGER_INITIALIZER = BeanInitUtils.lazyInit(() -> + new StaticMemoryCacheManager( CACHE_NAME_CLASS_ENTITY, CACHE_NAME_TABLE_ENTITY, CACHE_NAME_CLASS_PROP, CACHE_NAME_ENTITYNAME_CLASS, CACHE_NAME_CLASS_FIELDS, - CACHE_NAME_CLASS_NAME2FLDMAP); - } - return cacheManager; + CACHE_NAME_CLASS_NAME2FLDMAP) + ); + + private static StaticMemoryCacheManager getCacheManager() { + return CACHE_MANAGER_INITIALIZER.get(); } /** @@ -92,7 +94,7 @@ public class BindingCacheManager { * @param tableName * @return */ - public static synchronized EntityInfoCache getEntityInfoByTable(String tableName){ + public static EntityInfoCache getEntityInfoByTable(String tableName) { initEntityInfoCache(); return getCacheManager().getCacheObj(CACHE_NAME_TABLE_ENTITY, tableName, EntityInfoCache.class); } @@ -102,7 +104,7 @@ public class BindingCacheManager { * @param entityClazz * @return */ - public static synchronized EntityInfoCache getEntityInfoByClass(Class entityClazz){ + public static EntityInfoCache getEntityInfoByClass(Class entityClazz) { initEntityInfoCache(); return getCacheManager().getCacheObj(CACHE_NAME_CLASS_ENTITY, entityClazz.getName(), EntityInfoCache.class); } @@ -112,12 +114,8 @@ public class BindingCacheManager { * @param beanClazz * @return */ - public static synchronized PropInfo getPropInfoByClass(Class beanClazz){ - PropInfo propInfo = getCacheManager().getCacheObj(CACHE_NAME_CLASS_PROP, beanClazz.getName(), PropInfo.class); - if(propInfo == null){ - propInfo = initPropInfoCache(beanClazz); - } - return propInfo; + public static PropInfo getPropInfoByClass(Class beanClazz) { + return getCacheManager().getCacheObj(CACHE_NAME_CLASS_PROP, beanClazz.getName(), () -> new PropInfo(beanClazz)); } /** @@ -125,7 +123,7 @@ public class BindingCacheManager { * @param tableName * @return */ - public static synchronized PropInfo getPropInfoByTable(String tableName){ + public static PropInfo getPropInfoByTable(String tableName) { Class entityClass = getEntityClassByTable(tableName); if(entityClass != null){ return getPropInfoByClass(entityClass); @@ -138,7 +136,7 @@ public class BindingCacheManager { * @param tableName * @return */ - public static synchronized Class getEntityClassByTable(String tableName){ + public static Class getEntityClassByTable(String tableName) { EntityInfoCache entityInfoCache = getEntityInfoByTable(tableName); return entityInfoCache != null? entityInfoCache.getEntityClass() : null; } @@ -149,7 +147,7 @@ public class BindingCacheManager { * @param classSimpleName * @return */ - public static synchronized Class getEntityClassBySimpleName(String classSimpleName){ + public static Class getEntityClassBySimpleName(String classSimpleName) { initEntityInfoCache(); return getCacheManager().getCacheObj(CACHE_NAME_ENTITYNAME_CLASS, classSimpleName, Class.class); } @@ -159,7 +157,7 @@ public class BindingCacheManager { * @param table * @return */ - public static synchronized BaseMapper getMapperByTable(String table){ + public static BaseMapper getMapperByTable(String table) { EntityInfoCache entityInfoCache = getEntityInfoByTable(table); if(entityInfoCache != null){ return entityInfoCache.getBaseMapper(); @@ -172,7 +170,7 @@ public class BindingCacheManager { * @param entityClazz * @return */ - public static synchronized BaseMapper getMapperByClass(Class entityClazz){ + public static BaseMapper getMapperByClass(Class entityClazz) { EntityInfoCache entityInfoCache = getEntityInfoByClass(entityClazz); if(entityInfoCache != null){ return entityInfoCache.getBaseMapper(); @@ -185,13 +183,8 @@ public class BindingCacheManager { * @param beanClazz * @return */ - public static synchronized List getFields(Class beanClazz){ - List fields = getCacheManager().getCacheObj(CACHE_NAME_CLASS_FIELDS, beanClazz.getName(), List.class); - if(fields == null){ - fields = BeanUtils.extractAllFields(beanClazz); - getCacheManager().putCacheObj(CACHE_NAME_CLASS_FIELDS, beanClazz.getName(), fields); - } - return fields; + public static List getFields(Class beanClazz) { + return getCacheManager().getCacheObj(CACHE_NAME_CLASS_FIELDS, beanClazz.getName(), () -> BeanUtils.extractAllFields(beanClazz)); } /** @@ -199,14 +192,9 @@ public class BindingCacheManager { * @param beanClazz * @return */ - public static synchronized List getFields(Class beanClazz, Class annotation){ + public static List getFields(Class beanClazz, Class annotation) { String key = S.joinWith(Cons.SEPARATOR_COMMA, beanClazz.getName(), annotation.getName()); - List fields = getCacheManager().getCacheObj(CACHE_NAME_CLASS_FIELDS, key, List.class); - if(fields == null){ - fields = BeanUtils.extractFields(beanClazz, annotation); - getCacheManager().putCacheObj(CACHE_NAME_CLASS_FIELDS, key, fields); - } - return fields; + return getCacheManager().getCacheObj(CACHE_NAME_CLASS_FIELDS, key, () -> BeanUtils.extractFields(beanClazz, annotation)); } /** @@ -214,24 +202,17 @@ public class BindingCacheManager { * @param beanClazz * @return */ - public static Map getFieldsMap(Class beanClazz){ - Map fieldsMap = getCacheManager().getCacheObj(CACHE_NAME_CLASS_NAME2FLDMAP, beanClazz.getName(), Map.class); - if(fieldsMap == null){ - List fields = getFields(beanClazz); - fieldsMap = BeanUtils.convertToStringKeyObjectMap(fields, "name"); - getCacheManager().putCacheObj(CACHE_NAME_CLASS_NAME2FLDMAP, beanClazz.getName(), fieldsMap); - } - return fieldsMap; + public static Map getFieldsMap(Class beanClazz) { + return getCacheManager().getCacheObj(CACHE_NAME_CLASS_NAME2FLDMAP, beanClazz.getName(), + () -> BeanUtils.convertToStringKeyObjectMap(getFields(beanClazz), "name") + ); } /** - * 初始化 + * entity相关信息初始化器, 不返回有意义的值, 仅仅为了线程安全地初始化缓存 */ - private static void initEntityInfoCache() { + private static final BeanInitializer ENTITY_INFO_CACHE_INITIALIZER = BeanInitUtils.lazyInit(() -> { StaticMemoryCacheManager cacheManager = getCacheManager(); - if (cacheManager.isUninitializedCache(CACHE_NAME_CLASS_ENTITY) == false) { - return; - } // 初始化有service的entity缓存 Map serviceMap = ContextHelper.getApplicationContext().getBeansOfType(IService.class); Set uniqueEntitySet = new HashSet<>(); @@ -291,18 +272,15 @@ public class BindingCacheManager { } } } - uniqueEntitySet = null; - } + return null; + }); /** - * 初始化bean的属性缓存 - * @param beanClazz - * @return + * 初始化 */ - private static PropInfo initPropInfoCache(Class beanClazz) { - PropInfo propInfoCache = new PropInfo(beanClazz); - getCacheManager().putCacheObj(CACHE_NAME_CLASS_PROP, beanClazz.getName(), propInfoCache); - return propInfoCache; + private static void initEntityInfoCache() { + // 初始化entity相关的缓存 + ENTITY_INFO_CACHE_INITIALIZER.get(); } } diff --git a/diboot-core/src/main/java/com/diboot/core/binding/helper/DeepRelationsBinder.java b/diboot-core/src/main/java/com/diboot/core/binding/helper/DeepRelationsBinder.java index 550dc4961f25c5a7ef3a8449c9a3c0524e6c4ac6..af07eb8a17fe0d2d8ca72997a5217952d5669cd2 100644 --- a/diboot-core/src/main/java/com/diboot/core/binding/helper/DeepRelationsBinder.java +++ b/diboot-core/src/main/java/com/diboot/core/binding/helper/DeepRelationsBinder.java @@ -47,7 +47,7 @@ public class DeepRelationsBinder { for(FieldAnnotation anno : deepBindEntityAnnoList){ String entityFieldName = anno.getFieldName(); List entityList = BeanUtils.collectToList(voList, entityFieldName); - RelationsBinder.bind(entityList, false); + RelationsBinder.bind(entityList, true); } } if(V.notEmpty(deepBindEntitiesAnnoList)){ @@ -60,7 +60,7 @@ public class DeepRelationsBinder { allEntityList.addAll(entityList); } } - RelationsBinder.bind(allEntityList, false); + RelationsBinder.bind(allEntityList, true); } } } diff --git a/diboot-core/src/main/java/com/diboot/core/binding/helper/ResultAssembler.java b/diboot-core/src/main/java/com/diboot/core/binding/helper/ResultAssembler.java index 2ad7a3daa6fb908ab9fc0ae48a848f8264c79b6e..3b127981b16a70fb888e1da82128d53705cf60f5 100644 --- a/diboot-core/src/main/java/com/diboot/core/binding/helper/ResultAssembler.java +++ b/diboot-core/src/main/java/com/diboot/core/binding/helper/ResultAssembler.java @@ -45,29 +45,44 @@ public class ResultAssembler { if(V.isEmpty(fromList) || V.isEmpty(valueMatchMap)){ return; } - StringBuilder sb = new StringBuilder(); try{ for(E object : fromList){ + List matchKeys = null; BeanWrapper beanWrapper = BeanUtils.getBeanWrapper(object); - sb.setLength(0); for(int i=0; i 0){ - sb.append(Cons.SEPARATOR_COMMA); + Object fieldValueObj = BeanUtils.getProperty(object, getterFields[i]); + if(fieldValueObj == null) { + continue; + } + if(fieldValueObj instanceof Collection) { + if(matchKeys == null) { + matchKeys = new ArrayList(); + } + matchKeys.addAll((Collection) fieldValueObj); + } + else { + if(matchKeys == null) { + matchKeys = new ArrayList(getterFields.length); + } + matchKeys.add(S.clearNonConst(S.valueOf(fieldValueObj))); } - sb.append(fieldValue); + } + if(matchKeys == null) { + continue; } // 查找匹配Key - String matchKey = sb.toString(); + String matchKey = S.join(matchKeys); if(valueMatchMap.containsKey(matchKey)){ // 赋值 beanWrapper.setPropertyValue(setterFieldName, valueMatchMap.get(matchKey)); } - else if(V.notEmpty(splitBy) && getterFields.length == 1 && matchKey.contains(splitBy)){ - String[] keys = matchKey.split(splitBy); - List matchedValues = new ArrayList(keys.length); - for(String key : keys){ - Object value = valueMatchMap.get(key); + else { + if(matchKeys.size() == 1 && V.notEmpty(splitBy) && getterFields.length == 1 && matchKey.contains(splitBy)) { + matchKeys = S.splitToList(matchKey, splitBy); + } + List matchedValues = new ArrayList(matchKeys.size()); + for(Object key : matchKeys){ + Object value = valueMatchMap.get(S.valueOf(key)); if(value != null){ if(value instanceof Collection){ Collection valueList = (Collection)value; @@ -88,7 +103,6 @@ public class ResultAssembler { beanWrapper.setPropertyValue(setterFieldName, matchedValues); } } - sb.setLength(0); } catch (Exception e){ log.warn("设置属性值异常, setterFieldName="+setterFieldName, e); @@ -154,25 +168,41 @@ public class ResultAssembler { if(V.isEmpty(fromList) || V.isEmpty(valueMatchMap)){ return; } - StringBuilder sb = new StringBuilder(); try{ for(E object : fromList){ - sb.setLength(0); + List matchKeys = null; for(int i=0; i0){ - sb.append(Cons.SEPARATOR_COMMA); + Object fieldValueObj = BeanUtils.getProperty(object, getterFields[i]); + if(fieldValueObj == null) { + continue; + } + if(fieldValueObj instanceof Collection) { + if(matchKeys == null) { + matchKeys = new ArrayList(); + } + matchKeys.addAll((Collection) fieldValueObj); + } + else { + if(matchKeys == null) { + matchKeys = new ArrayList(getterFields.length); + } + matchKeys.add(S.clearNonConst(S.valueOf(fieldValueObj))); } - sb.append(val); + } + // 无有效值,跳过 + if(matchKeys == null) { + continue; } // 查找匹配Key - String matchKey = sb.toString(); + String matchKey = S.join(matchKeys); List entityList = valueMatchMap.get(matchKey); - if(entityList == null && V.notEmpty(splitBy) && matchKey.contains(splitBy)){ - String[] keys = matchKey.split(splitBy); - List matchedValues = new ArrayList(keys.length); - for(String key : keys){ - Object value = valueMatchMap.get(key); + if(entityList == null){ + if (matchKeys.size() == 1 && V.notEmpty(splitBy) && matchKey.contains(splitBy)) { + matchKeys = S.splitToList(matchKey, splitBy); + } + List matchedValues = new ArrayList(matchKeys.size()); + for(Object key : matchKeys){ + Object value = valueMatchMap.get(S.valueOf(key)); if(value != null){ if(value instanceof Collection){ Collection valueList = (Collection)value; @@ -193,16 +223,13 @@ public class ResultAssembler { entityList = matchedValues; } } - if(entityList != null){ - // 赋值 - BeanWrapper beanWrapper = BeanUtils.getBeanWrapper(object); - for(int i = 0; i< annoObjSetterPropNameList.size(); i++){ - List valObjList = BeanUtils.collectToList(entityList, refGetterFieldNameList.get(i)); - beanWrapper.setPropertyValue(annoObjSetterPropNameList.get(i), valObjList); - } + // 赋值 + BeanWrapper beanWrapper = BeanUtils.getBeanWrapper(object); + for(int i = 0; i< annoObjSetterPropNameList.size(); i++){ + List valObjList = BeanUtils.collectToList(entityList, refGetterFieldNameList.get(i)); + beanWrapper.setPropertyValue(annoObjSetterPropNameList.get(i), valObjList); } } - sb.setLength(0); } catch (Exception e){ log.warn("设置属性值异常", e); @@ -323,16 +350,26 @@ public class ResultAssembler { List newValueList = new ArrayList(); valueList.forEach( value -> { if(value != null){ - String valueStr = S.valueOf(value); - if(valueStr.contains(splitBy)){ - for(String oneVal :valueStr.split(splitBy)){ + if(value instanceof Collection) { + for(Object key : (Collection)value){ + String oneVal = S.valueOf(key); if(!newValueList.contains(oneVal)){ newValueList.add(oneVal); } } } - else if(!newValueList.contains(valueStr)){ - newValueList.add(valueStr); + else { + String valueStr = S.clearNonConst(S.valueOf(value)); + if(V.notEmpty(splitBy) && valueStr.contains(splitBy)){ + for(String oneVal : valueStr.split(splitBy)){ + if(!newValueList.contains(oneVal)){ + newValueList.add(oneVal); + } + } + } + else if(!newValueList.contains(valueStr)){ + newValueList.add(valueStr); + } } } }); diff --git a/diboot-core/src/main/java/com/diboot/core/binding/helper/ServiceAdaptor.java b/diboot-core/src/main/java/com/diboot/core/binding/helper/ServiceAdaptor.java index f8a0809c6f8b7e89d7e86414567d6ae5486bbed1..c3379c2eea3e3e80655af0d374f4b9122dde8a20 100644 --- a/diboot-core/src/main/java/com/diboot/core/binding/helper/ServiceAdaptor.java +++ b/diboot-core/src/main/java/com/diboot/core/binding/helper/ServiceAdaptor.java @@ -84,6 +84,9 @@ public class ServiceAdaptor { return (List)baseService.getEntityList(queryWrapper, pagination); } else{ + if(queryWrapper.getEntityClass() == null) { + queryWrapper.setEntityClass(entityClass); + } if(pagination != null){ IPage page = convertToIPage(pagination, entityClass); page = iService.page(page, queryWrapper); diff --git a/diboot-core/src/main/java/com/diboot/core/binding/parser/EntityInfoCache.java b/diboot-core/src/main/java/com/diboot/core/binding/parser/EntityInfoCache.java index 3b11f0a1676154b8ddd27cd8fd86a300deeea180..05fe093662806c2a62736ca0687b09374b46ad59 100644 --- a/diboot-core/src/main/java/com/diboot/core/binding/parser/EntityInfoCache.java +++ b/diboot-core/src/main/java/com/diboot/core/binding/parser/EntityInfoCache.java @@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.extension.service.IService; import com.diboot.core.binding.cache.BindingCacheManager; import com.diboot.core.util.ContextHelper; import com.diboot.core.util.S; +import com.diboot.core.util.V; import lombok.Getter; import lombok.Setter; import org.springframework.core.annotation.AnnotationUtils; @@ -53,7 +54,7 @@ public class EntityInfoCache implements Serializable { this.propInfo = BindingCacheManager.getPropInfoByClass(entityClass); // 初始化tableName TableName tableNameAnno = AnnotationUtils.findAnnotation(entityClass, TableName.class); - if(tableNameAnno != null){ + if(tableNameAnno != null && V.notEmpty(tableNameAnno.value())){ this.tableName = tableNameAnno.value(); } else{ 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 f5575ac2250f9b8e14f2844cffcd0b3f9fd9a2fe..11d8ab23959f34c6278bedc9ae615d2da57d40f0 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 @@ -74,10 +74,9 @@ public class ParserCache { * @return */ public static BindAnnotationGroup getBindAnnotationGroup(Class voClass){ - BindAnnotationGroup group = allVoBindAnnotationCacheMap.get(voClass); - if(group == null){ + return allVoBindAnnotationCacheMap.computeIfAbsent(voClass, k -> { // 获取注解并缓存 - group = new BindAnnotationGroup(); + BindAnnotationGroup group = new BindAnnotationGroup(); // 获取当前VO的所有字段 List fields = BeanUtils.extractAllFields(voClass); if(V.notEmpty(fields)){ @@ -108,10 +107,9 @@ public class ParserCache { } } } - allVoBindAnnotationCacheMap.put(voClass, group); - } - // 返回归类后的注解对象 - return group; + // 返回归类后的注解对象 + return group; + }); } /** @@ -139,7 +137,7 @@ public class ParserCache { } else{ TableName tableNameAnno = AnnotationUtils.findAnnotation(entityClass, TableName.class); - if(tableNameAnno != null){ + if(tableNameAnno != null && V.notEmpty(tableNameAnno.value())){ return tableNameAnno.value(); } else{ diff --git a/diboot-core/src/main/java/com/diboot/core/binding/parser/PropInfo.java b/diboot-core/src/main/java/com/diboot/core/binding/parser/PropInfo.java index 85db8efcbe35398dcfd9533d7b8f462aa393b8af..4044e125c3ba9656d82e6c8f75a8f08ee24646b9 100644 --- a/diboot-core/src/main/java/com/diboot/core/binding/parser/PropInfo.java +++ b/diboot-core/src/main/java/com/diboot/core/binding/parser/PropInfo.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableLogic; +import com.diboot.core.config.BaseConfig; import com.diboot.core.util.BeanUtils; import com.diboot.core.util.S; import com.diboot.core.util.V; @@ -64,6 +65,15 @@ public class PropInfo implements Serializable { * @param beanClass */ public PropInfo(Class beanClass) { + this(beanClass, true); + } + + /** + * 初始化 + * @param beanClass + * @param isEntityClass 是否为entity实体类(数据库表对应实体) + */ + public PropInfo(Class beanClass, boolean isEntityClass) { List fields = BeanUtils.extractAllFields(beanClass); if(V.notEmpty(fields)){ for(Field fld : fields){ @@ -102,15 +112,19 @@ public class PropInfo implements Serializable { else{ TableLogic tableLogic = fld.getAnnotation(TableLogic.class); if(tableLogic != null){ - if (V.notEmpty(tableLogic.value())){ - columnName = tableLogic.value(); - } - else if(columnName == null){ + if(columnName == null){ columnName = S.toSnakeCase(fldName); } this.deletedColumn = columnName; + if (V.notEmpty(tableLogic.value())){ + BaseConfig.setActiveFlagValue(tableLogic.value()); + } } } + // 实体类基于默认规则提取列名 + if(columnName == null && isEntityClass) { + columnName = S.toSnakeCase(fldName); + } this.fieldToColumnMap.put(fldName, columnName); if(V.notEmpty(columnName)){ this.columnToFieldMap.put(columnName, fldName); diff --git a/diboot-core/src/main/java/com/diboot/core/binding/query/dynamic/DynamicJoinQueryWrapper.java b/diboot-core/src/main/java/com/diboot/core/binding/query/dynamic/DynamicJoinQueryWrapper.java index 7dcfe1bccd34ead5617b657f60e7af2aebc7d788..aa36adf3d1a8bfce7007c2684e9895aa37f94ae4 100644 --- a/diboot-core/src/main/java/com/diboot/core/binding/query/dynamic/DynamicJoinQueryWrapper.java +++ b/diboot-core/src/main/java/com/diboot/core/binding/query/dynamic/DynamicJoinQueryWrapper.java @@ -29,7 +29,7 @@ import java.util.List; * @version v2.0 * @date 2020/04/16 */ -public class DynamicJoinQueryWrapper extends ExtQueryWrapper { +public class DynamicJoinQueryWrapper extends ExtQueryWrapper { public DynamicJoinQueryWrapper(Class dtoClass, Collection fields){ this.dtoClass = dtoClass; this.fields = fields; @@ -58,7 +58,7 @@ public class DynamicJoinQueryWrapper extends ExtQueryWrapper { * @return */ @Override - public E queryOne(Class entityClazz){ + public T queryOne(Class entityClazz){ return JoinsBinder.queryOne(this, entityClazz); } @@ -68,7 +68,7 @@ public class DynamicJoinQueryWrapper extends ExtQueryWrapper { * @return */ @Override - public List queryList(Class entityClazz){ + public List queryList(Class entityClazz){ return JoinsBinder.queryList(this, entityClazz); } @@ -78,7 +78,7 @@ public class DynamicJoinQueryWrapper extends ExtQueryWrapper { * @return */ @Override - public List queryList(Class entityClazz, Pagination pagination){ + public List queryList(Class entityClazz, Pagination pagination){ return JoinsBinder.queryList(this, entityClazz, pagination); } diff --git a/diboot-core/src/main/java/com/diboot/core/binding/query/dynamic/DynamicSqlProvider.java b/diboot-core/src/main/java/com/diboot/core/binding/query/dynamic/DynamicSqlProvider.java index b3f396ada55410b0793d506d88d4c0ac2bad9417..1f84d0aabf1a2c8e56b78ade6ecdd525aed715dd 100644 --- a/diboot-core/src/main/java/com/diboot/core/binding/query/dynamic/DynamicSqlProvider.java +++ b/diboot-core/src/main/java/com/diboot/core/binding/query/dynamic/DynamicSqlProvider.java @@ -41,6 +41,11 @@ import java.util.Set; @Slf4j public class DynamicSqlProvider { + /** + * select中的占位列前缀标识 + */ + public static final String PLACEHOLDER_COLUMN_FLAG = "__"; + /** * 构建动态SQL * @param ew @@ -69,12 +74,7 @@ public class DynamicSqlProvider { private String buildDynamicSql(Page page, QueryWrapper ew){ DynamicJoinQueryWrapper wrapper = (DynamicJoinQueryWrapper)ew; return new SQL() {{ - if(V.isEmpty(ew.getSqlSelect())){ - SELECT_DISTINCT("self.*"); - } - else{ - SELECT_DISTINCT(formatSqlSelect(ew.getSqlSelect(), page)); - } + SELECT_DISTINCT(formatSqlSelect(ew.getSqlSelect(), page)); FROM(wrapper.getEntityTable()+" self"); //提取字段,根据查询条件中涉及的表,动态join List annoJoinerList = wrapper.getAnnoJoiners(); @@ -131,6 +131,15 @@ public class DynamicSqlProvider { } } } + // 存在联表且无where条件, + else if(V.notEmpty(annoJoinerList)){ + // 动态为主表添加is_deleted=0 + String isDeletedCol = ParserCache.getDeletedColumn(wrapper.getEntityTable()); + String isDeletedSection = "self."+ isDeletedCol; + if(isDeletedCol != null && QueryBuilder.checkHasColumn(segments.getNormal(), isDeletedSection) == false){ + WHERE(isDeletedSection+ " = " +BaseConfig.getActiveFlagValue()); + } + } } }}.toString(); } @@ -141,21 +150,28 @@ public class DynamicSqlProvider { * @return */ private String formatSqlSelect(String sqlSelect, Page page){ - String[] columns = S.split(sqlSelect); Set columnSets = new HashSet<>(); StringBuilder sb = new StringBuilder(); - for(int i=0; i0){ - sb.append(Cons.SEPARATOR_COMMA); + if(V.isEmpty(sqlSelect)){ + sb.append("self.*"); + } + else { + String[] columns = S.split(sqlSelect); + for(int i=0; i0){ + sb.append(Cons.SEPARATOR_COMMA); + } + sb.append("self.").append(column); + columnSets.add("self."+column); } - sb.append("self.").append(column); - columnSets.add("self."+column); } - if(page != null && page.getOrders() != null) { - for(OrderItem orderItem : page.getOrders()){ - if(!columnSets.contains(orderItem.getColumn())){ - sb.append(Cons.SEPARATOR_COMMA).append(orderItem.getColumn()).append(" AS _").append(S.replace(orderItem.getColumn(), ".", "_")); + if(page != null && page.orders() != null) { + for(OrderItem orderItem : page.orders()){ + if((V.isEmpty(sqlSelect) && !S.startsWith(orderItem.getColumn(), "self.")) + || !columnSets.contains(orderItem.getColumn()) + ){ + sb.append(Cons.SEPARATOR_COMMA).append(orderItem.getColumn()).append(" AS ").append(PLACEHOLDER_COLUMN_FLAG).append(S.replace(orderItem.getColumn(), ".", "_")); } } } diff --git a/diboot-core/src/main/java/com/diboot/core/binding/query/dynamic/ExtQueryWrapper.java b/diboot-core/src/main/java/com/diboot/core/binding/query/dynamic/ExtQueryWrapper.java index 3b9c64d6ce1e019adc2d3c96d606c68ba6b308b7..1b159632a6dec58f17bb188876cc68f7557fd158 100644 --- a/diboot-core/src/main/java/com/diboot/core/binding/query/dynamic/ExtQueryWrapper.java +++ b/diboot-core/src/main/java/com/diboot/core/binding/query/dynamic/ExtQueryWrapper.java @@ -33,19 +33,22 @@ import java.util.List; * @version v2.0 * @date 2020/04/16 */ -public class ExtQueryWrapper extends QueryWrapper { +public class ExtQueryWrapper extends QueryWrapper { /** * 主实体class */ @Getter @Setter - private Class mainEntityClass; + private Class mainEntityClass; /** * 获取entity表名 * @return */ public String getEntityTable(){ - return ParserCache.getEntityTableName(getMainEntityClass()); + if(this.mainEntityClass == null) { + this.mainEntityClass = getEntityClass(); + } + return ParserCache.getEntityTableName(this.mainEntityClass); } /** @@ -53,9 +56,9 @@ public class ExtQueryWrapper extends QueryWrapper { * @param entityClazz * @return */ - public E queryOne(Class entityClazz){ + public T queryOne(Class entityClazz){ this.mainEntityClass = entityClazz; - IService iService = ContextHelper.getIServiceByEntity(this.mainEntityClass); + IService iService = ContextHelper.getIServiceByEntity(this.mainEntityClass); if(iService != null){ return ServiceAdaptor.getSingleEntity(iService, this); } @@ -69,7 +72,7 @@ public class ExtQueryWrapper extends QueryWrapper { * @param entityClazz * @return */ - public List queryList(Class entityClazz){ + public List queryList(Class entityClazz){ this.mainEntityClass = entityClazz; IService iService = ContextHelper.getIServiceByEntity(entityClazz); if(iService != null){ @@ -85,7 +88,7 @@ public class ExtQueryWrapper extends QueryWrapper { * @param entityClazz * @return */ - public List queryList(Class entityClazz, Pagination pagination){ + public List queryList(Class entityClazz, Pagination pagination){ this.mainEntityClass = entityClazz; IService iService = ContextHelper.getIServiceByEntity(entityClazz); if(iService != null){ diff --git a/diboot-core/src/main/java/com/diboot/core/cache/BaseCacheManager.java b/diboot-core/src/main/java/com/diboot/core/cache/BaseCacheManager.java index d2aeecf42c6d413748bbe4e43f1365ad1d03036a..79529a7d58e4442aa8a68064a87d55a36e75b0d5 100644 --- a/diboot-core/src/main/java/com/diboot/core/cache/BaseCacheManager.java +++ b/diboot-core/src/main/java/com/diboot/core/cache/BaseCacheManager.java @@ -15,6 +15,8 @@ */ package com.diboot.core.cache; +import java.util.concurrent.Callable; + /** * 缓存manager父类 * @author JerryMa @@ -32,6 +34,17 @@ public interface BaseCacheManager { */ T getCacheObj(String cacheName, Object objKey, Class tClass); + /** + * 获取缓存对象, 如果找不到, 则生成初始值, 放入缓存, 并返回 + * + * @param cacheName cache名称 + * @param objKey 查找的key + * @param initSupplier 初始值提供者 + * @param 缓存对象类型 + * @return 缓存对象 + */ + T getCacheObj(String cacheName, Object objKey, Callable initSupplier); + /** * 获取缓存对象 * @param objKey diff --git a/diboot-core/src/main/java/com/diboot/core/cache/BaseMemoryCacheManager.java b/diboot-core/src/main/java/com/diboot/core/cache/BaseMemoryCacheManager.java index e0a544f09866c09bf40819fe448b40b2502c4e8e..e5e2ba45f11c2da24614dfb75114c636bde88f20 100644 --- a/diboot-core/src/main/java/com/diboot/core/cache/BaseMemoryCacheManager.java +++ b/diboot-core/src/main/java/com/diboot/core/cache/BaseMemoryCacheManager.java @@ -20,6 +20,8 @@ import org.springframework.cache.Cache; import org.springframework.cache.concurrent.ConcurrentMapCache; import org.springframework.cache.support.SimpleCacheManager; +import java.util.concurrent.Callable; + /** * 缓存manager父类 * @author JerryMa @@ -36,6 +38,7 @@ public abstract class BaseMemoryCacheManager extends SimpleCacheManager implemen * @param * @return */ + @Override public T getCacheObj(String cacheName, Object objKey, Class tClass){ Cache cache = getCache(cacheName); T value = cache != null? cache.get(objKey, tClass) : null; @@ -45,11 +48,31 @@ public abstract class BaseMemoryCacheManager extends SimpleCacheManager implemen return value; } + /** + * 获取缓存对象, 如果找不到, 则生成初始值, 放入缓存, 并返回 + * + * @param cacheName cache名称 + * @param objKey 查找的key + * @param initSupplier 初始值提供者 + * @param 缓存对象类型 + * @return 缓存对象 + */ + @Override + public T getCacheObj(String cacheName, Object objKey, Callable initSupplier) { + Cache cache = getCache(cacheName); + T value = cache != null ? cache.get(objKey, initSupplier) : null; + if (log.isTraceEnabled()) { + log.trace("从缓存读取: {}.{} = {}", cacheName, objKey, value); + } + return value; + } + /** * 获取缓存对象 * @param objKey * @return */ + @Override public String getCacheString(String cacheName, Object objKey){ return getCacheObj(cacheName, objKey, String.class); } @@ -60,6 +83,7 @@ public abstract class BaseMemoryCacheManager extends SimpleCacheManager implemen * @param objKey * @param obj */ + @Override public void putCacheObj(String cacheName, Object objKey, Object obj){ Cache cache = getCache(cacheName); cache.put(objKey, obj); @@ -74,6 +98,7 @@ public abstract class BaseMemoryCacheManager extends SimpleCacheManager implemen * @param cacheName * @param objKey */ + @Override public void removeCacheObj(String cacheName, Object objKey){ Cache cache = getCache(cacheName); cache.evict(objKey); @@ -88,6 +113,7 @@ public abstract class BaseMemoryCacheManager extends SimpleCacheManager implemen * @param cacheName * @return */ + @Override public boolean isUninitializedCache(String cacheName){ ConcurrentMapCache cache = (ConcurrentMapCache)getCache(cacheName); return cache.getNativeCache().isEmpty(); diff --git a/diboot-core/src/main/java/com/diboot/core/config/BaseConfig.java b/diboot-core/src/main/java/com/diboot/core/config/BaseConfig.java index 585fdda449675b5135c586411d61e897ee8d76d1..b0999b9aa7777c42a42a05778b63679797447a5e 100644 --- a/diboot-core/src/main/java/com/diboot/core/config/BaseConfig.java +++ b/diboot-core/src/main/java/com/diboot/core/config/BaseConfig.java @@ -142,4 +142,10 @@ public class BaseConfig { } return ACTIVE_FLAG_VALUE; } + + public static void setActiveFlagValue(String value) { + if(getActiveFlagValue() == null) { + ACTIVE_FLAG_VALUE = value; + } + } } \ No newline at end of file diff --git a/diboot-core/src/main/java/com/diboot/core/config/Cons.java b/diboot-core/src/main/java/com/diboot/core/config/Cons.java index b5071378941ebb1b583d625ebdd8178952cde3eb..9c8ccd3902a56246227c03986b63c4edb0f94e21 100644 --- a/diboot-core/src/main/java/com/diboot/core/config/Cons.java +++ b/diboot-core/src/main/java/com/diboot/core/config/Cons.java @@ -34,6 +34,10 @@ public class Cons { * 下划线分隔符_ */ public static final String SEPARATOR_UNDERSCORE = "_"; + /** + * 横杠分隔符 - + */ + public static final String SEPARATOR_CROSSBAR = "-"; /** * 冒号分隔符 */ @@ -50,6 +54,10 @@ public class Cons { * 分号分隔符 */ public final static String SEPARATOR_SEMICOLON = ";"; + /** + * 点分隔符 + */ + public static final String SEPARATOR_DOT = "."; /** * 排序 - 降序标记 */ @@ -63,7 +71,7 @@ public class Cons { */ public static final String COLUMN_CREATE_TIME = "create_time"; /*** - * 默认字段名定义 + * 常用字段名定义 */ public enum FieldName{ /** @@ -112,6 +120,85 @@ public class Cons { userId } + /*** + * 常用列名定义 + */ + public enum ColumnName{ + /** + * 主键属性名 + */ + id, + /** + * 租户ID + */ + tenant_id, + /** + * 默认的上级ID属性名 + */ + parent_id, + /** + * 子节点属性名 + */ + children, + /** + * 逻辑删除标记字段 + */ + is_deleted, + /** + * 创建时间字段 + */ + create_time, + /** + * 更新时间 + */ + update_time, + /** + * 创建人 + */ + create_by, + /** + * 更新人 + */ + update_by, + /** + * 组织id + */ + org_id, + /** + * 用户id + */ + user_id + } + + /** + * 分页相关参数 + */ + public enum PaginationParam { + /** + * 查询中排序参数名 + */ + orderBy, + /** + * 当前页数参数名 + */ + pageIndex, + /** + * 每页记录数参数名 + */ + pageSize, + /** + * 总数 + */ + totalCount; + + public static boolean isPaginationParam(String param) { + return orderBy.name().equals(param) + || pageIndex.name().equals(param) + || pageSize.name().equals(param) + || totalCount.name().equals(param); + } + } + /** * 字典Entity相关属性名定义 */ diff --git a/diboot-core/src/main/java/com/diboot/core/controller/BaseController.java b/diboot-core/src/main/java/com/diboot/core/controller/BaseController.java index 99c6d45e7fc4d9393052d879eeaf4c4e207ccb69..39745267453da6a0a4b29aa5ad71a27b97bf2e77 100644 --- a/diboot-core/src/main/java/com/diboot/core/controller/BaseController.java +++ b/diboot-core/src/main/java/com/diboot/core/controller/BaseController.java @@ -15,7 +15,6 @@ */ package com.diboot.core.controller; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.diboot.core.binding.Binder; @@ -35,6 +34,7 @@ import com.diboot.core.util.JSON; import com.diboot.core.util.S; import com.diboot.core.util.V; import com.diboot.core.vo.LabelValue; +import com.diboot.core.vo.Pagination; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -71,41 +71,32 @@ public class BaseController { } /*** - * 根据请求参数构建查询QueryWrapper (根据BindQuery注解构建相应的查询条件,url中的请求参数参与构建) - * @param entityOrDto Entity对象或者DTO对象 (属性若无BindQuery注解,默认构建为为EQ相等条件) - * @return - */ - protected QueryWrapper buildQueryWrapperByQueryParams(DTO entityOrDto) throws Exception{ - return QueryBuilder.toQueryWrapper(entityOrDto, extractQueryParams()); - } - - /*** - * 构建查询LambdaQueryWrapper (根据BindQuery注解构建相应的查询条件) + * 根据DTO构建查询QueryWrapper (根据BindQuery注解构建相应的查询条件,DTO中的非空属性均参与构建) * @param entityOrDto Entity对象或者DTO对象 (属性若无BindQuery注解,默认构建为为EQ相等条件) - * @see #buildLambdaQueryWrapperByDTO #buildLambdaQueryWrapperByQueryParams + * @param pagination 分页,如按关联表中的字段排序时需传入pagination * @return */ - @Deprecated - protected LambdaQueryWrapper buildLambdaQueryWrapper(DTO entityOrDto) throws Exception{ - return buildLambdaQueryWrapperByQueryParams(entityOrDto); + protected QueryWrapper buildQueryWrapperByDTO(DTO entityOrDto, Pagination pagination) throws Exception{ + return QueryBuilder.toQueryWrapper(entityOrDto, pagination); } /*** - * 根据DTO构建查询LambdaQueryWrapper (根据BindQuery注解构建相应的查询条件,DTO中的非空属性均参与构建) + * 根据请求参数构建查询QueryWrapper (根据BindQuery注解构建相应的查询条件,url中的请求参数参与构建) * @param entityOrDto Entity对象或者DTO对象 (属性若无BindQuery注解,默认构建为为EQ相等条件) * @return */ - protected LambdaQueryWrapper buildLambdaQueryWrapperByDTO(DTO entityOrDto) throws Exception{ - return QueryBuilder.toLambdaQueryWrapper(entityOrDto); + protected QueryWrapper buildQueryWrapperByQueryParams(DTO entityOrDto) throws Exception{ + return QueryBuilder.toQueryWrapper(entityOrDto, extractQueryParams()); } /*** - * 根据请求参数构建查询LambdaQueryWrapper (根据BindQuery注解构建相应的查询条件,url中的请求参数参与构建) + * 根据请求参数构建查询QueryWrapper (根据BindQuery注解构建相应的查询条件,url中的请求参数参与构建) * @param entityOrDto Entity对象或者DTO对象 (属性若无BindQuery注解,默认构建为为EQ相等条件) + * @param pagination 分页,如按关联表中的字段排序时需传入pagination * @return */ - protected LambdaQueryWrapper buildLambdaQueryWrapperByQueryParams(DTO entityOrDto) throws Exception{ - return QueryBuilder.toLambdaQueryWrapper(entityOrDto, extractQueryParams()); + protected QueryWrapper buildQueryWrapperByQueryParams(DTO entityOrDto, Pagination pagination) throws Exception{ + return QueryBuilder.toQueryWrapper(entityOrDto, extractQueryParams(), pagination); } /*** diff --git a/diboot-core/src/main/java/com/diboot/core/converter/EnhancedConversionService.java b/diboot-core/src/main/java/com/diboot/core/converter/EnhancedConversionService.java index 611197af9d2f7c773c806d753189e1402d726749..99397be27f19e630d8d91dce322ca8697f7db087 100644 --- a/diboot-core/src/main/java/com/diboot/core/converter/EnhancedConversionService.java +++ b/diboot-core/src/main/java/com/diboot/core/converter/EnhancedConversionService.java @@ -32,7 +32,13 @@ public class EnhancedConversionService extends DefaultConversionService { super(); addConverter(new Date2LocalDateConverter()); addConverter(new Date2LocalDateTimeConverter()); + addConverter(new LocalDate2DateConverter()); + addConverter(new LocalDateTime2DateConverter()); + addConverter(new SqlDate2LocalDateConverter()); + addConverter(new SqlDate2LocalDateTimeConverter()); addConverter(new String2DateConverter()); + addConverter(new String2LocalDateConverter()); + addConverter(new String2LocalDateTimeConverter()); addConverter(new String2BooleanConverter()); addConverter(new Timestamp2LocalDateTimeConverter()); } diff --git a/diboot-core/src/main/java/com/diboot/core/converter/LocalDate2DateConverter.java b/diboot-core/src/main/java/com/diboot/core/converter/LocalDate2DateConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..af5388cfb59f96f9d2caba506addeb43d682be56 --- /dev/null +++ b/diboot-core/src/main/java/com/diboot/core/converter/LocalDate2DateConverter.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015-2029, www.dibo.ltd (service@dibo.ltd). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.diboot.core.converter; + +import org.springframework.core.convert.converter.Converter; + +import java.time.Instant; +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.Date; + +/** + * LocalDate - Date 转换器 + * @author JerryMa + * @version v2.6.0 + * @date 2022/5/11 + * Copyright © diboot.com + */ +public class LocalDate2DateConverter implements Converter { + + @Override + public Date convert(LocalDate source) { + if (source == null) { + return null; + } + Instant instant = source.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant(); + return Date.from(instant); + } +} diff --git a/diboot-core/src/main/java/com/diboot/core/converter/LocalDateTime2DateConverter.java b/diboot-core/src/main/java/com/diboot/core/converter/LocalDateTime2DateConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..f476c8fb4d782467343e6d766ff4af5e515f9031 --- /dev/null +++ b/diboot-core/src/main/java/com/diboot/core/converter/LocalDateTime2DateConverter.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015-2029, www.dibo.ltd (service@dibo.ltd). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.diboot.core.converter; + +import org.springframework.core.convert.converter.Converter; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Date; + +/** + * LocalDateTime - Date 转换器 + * @author JerryMa + * @version v2.6.0 + * @date 2022/5/11 + * Copyright © diboot.com + */ +public class LocalDateTime2DateConverter implements Converter { + + @Override + public Date convert(LocalDateTime source) { + if (source == null) { + return null; + } + Instant instant = source.atZone(ZoneId.systemDefault()).toInstant(); + return Date.from(instant); + } +} diff --git a/diboot-core/src/main/java/com/diboot/core/converter/SqlDate2LocalDateConverter.java b/diboot-core/src/main/java/com/diboot/core/converter/SqlDate2LocalDateConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..345394a725bd1424f8e74041ccaed83d5b83aeaf --- /dev/null +++ b/diboot-core/src/main/java/com/diboot/core/converter/SqlDate2LocalDateConverter.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015-2029, www.dibo.ltd (service@dibo.ltd). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.diboot.core.converter; + +import org.springframework.core.convert.converter.Converter; +import java.sql.Date; +import java.time.LocalDate; + +/** + * java.sql.Date - LocalDate 转换器 + * @author JerryMa + * @version v2.6.0 + * @date 2022/5/11 + * Copyright © diboot.com + */ +public class SqlDate2LocalDateConverter implements Converter { + + @Override + public LocalDate convert(Date source) { + if (source == null) { + return null; + } + return source.toLocalDate(); + } + +} diff --git a/diboot-core/src/main/java/com/diboot/core/converter/SqlDate2LocalDateTimeConverter.java b/diboot-core/src/main/java/com/diboot/core/converter/SqlDate2LocalDateTimeConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..f96a9b1e0aaef7be4a8376b527365e2c5b0951ad --- /dev/null +++ b/diboot-core/src/main/java/com/diboot/core/converter/SqlDate2LocalDateTimeConverter.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015-2029, www.dibo.ltd (service@dibo.ltd). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.diboot.core.converter; + +import org.springframework.core.convert.converter.Converter; + +import java.sql.Date; +import java.sql.Timestamp; +import java.time.LocalDateTime; + +/** + * java.sql.Date - LocalDateTime 转换器 + * @author JerryMa + * @version v2.6.0 + * @date 2022/5/11 + * Copyright © diboot.com + */ +public class SqlDate2LocalDateTimeConverter implements Converter { + + @Override + public LocalDateTime convert(Date source) { + if (source == null) { + return null; + } + Timestamp timestamp = new Timestamp(source.getTime()); + return timestamp.toLocalDateTime(); + } + +} diff --git a/diboot-core/src/main/java/com/diboot/core/converter/String2DateConverter.java b/diboot-core/src/main/java/com/diboot/core/converter/String2DateConverter.java index 8400f037b42ac510b53295b8f51dc495b3a8f563..b316daa8d45dd3795df694f41ead1bdc5731f347 100644 --- a/diboot-core/src/main/java/com/diboot/core/converter/String2DateConverter.java +++ b/diboot-core/src/main/java/com/diboot/core/converter/String2DateConverter.java @@ -17,7 +17,6 @@ package com.diboot.core.converter; import com.diboot.core.util.D; import org.springframework.core.convert.converter.Converter; -import org.springframework.stereotype.Component; import java.util.Date; diff --git a/diboot-core/src/main/java/com/diboot/core/converter/String2LocalDateConverter.java b/diboot-core/src/main/java/com/diboot/core/converter/String2LocalDateConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..c979c06960910686449417cc7276c7e879ea829a --- /dev/null +++ b/diboot-core/src/main/java/com/diboot/core/converter/String2LocalDateConverter.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015-2029, www.dibo.ltd (service@dibo.ltd). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.diboot.core.converter; + +import com.diboot.core.util.D; +import org.springframework.core.convert.converter.Converter; + +import java.time.LocalDate; + +/** + * String - LocalDate 转换器 + * @author JerryMa + * @version v2.7.0 + * @date 2022/7/26 + * Copyright © diboot.com + */ +public class String2LocalDateConverter implements Converter { + + @Override + public LocalDate convert(String dateString) { + dateString = D.formatDateString(dateString); + return LocalDate.parse(dateString); + } + +} diff --git a/diboot-core/src/main/java/com/diboot/core/util/DateConverter.java b/diboot-core/src/main/java/com/diboot/core/converter/String2LocalDateTimeConverter.java similarity index 54% rename from diboot-core/src/main/java/com/diboot/core/util/DateConverter.java rename to diboot-core/src/main/java/com/diboot/core/converter/String2LocalDateTimeConverter.java index 972746681625ce3c9a16bf17f5c7ed1faba310ab..14ba9bda2f81aac011236b7823eb051b76d6e951 100644 --- a/diboot-core/src/main/java/com/diboot/core/util/DateConverter.java +++ b/diboot-core/src/main/java/com/diboot/core/converter/String2LocalDateTimeConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2020, www.dibo.ltd (service@dibo.ltd). + * Copyright (c) 2015-2029, www.dibo.ltd (service@dibo.ltd). *

* Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of @@ -13,27 +13,28 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.diboot.core.util; +package com.diboot.core.converter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.diboot.core.util.D; import org.springframework.core.convert.converter.Converter; +import java.time.LocalDate; +import java.time.LocalDateTime; import java.util.Date; /** - * Spring表单自动绑定到Java属性时的日期格式转换
- * @see com.diboot.core.converter.String2DateConverter - * @author mazc@dibo.ltd - * @version v2.0 - * @date 2019/01/01 + * String - LocalDateTime 转换器 + * @author JerryMa + * @version v2.7.0 + * @date 2022/7/26 + * Copyright © diboot.com */ -@Deprecated -public class DateConverter implements Converter { - private static final Logger log = LoggerFactory.getLogger(DateConverter.class); +public class String2LocalDateTimeConverter implements Converter { @Override - public Date convert(String dateString) { - return D.fuzzyConvert(dateString); + public LocalDateTime convert(String dateString) { + dateString = D.formatDateString(dateString); + return LocalDateTime.parse(dateString); } -} \ No newline at end of file + +} diff --git a/diboot-core/src/main/java/com/diboot/core/handler/DefaultExceptionHandler.java b/diboot-core/src/main/java/com/diboot/core/handler/DefaultExceptionHandler.java index 662461c70b63cf0b9481e8a5b945833f3e4e91b4..b9a3d3b536ae4a5daf75fc0490fc076c5d45a39f 100644 --- a/diboot-core/src/main/java/com/diboot/core/handler/DefaultExceptionHandler.java +++ b/diboot-core/src/main/java/com/diboot/core/handler/DefaultExceptionHandler.java @@ -60,6 +60,7 @@ public class DefaultExceptionHandler { map.put("code", Status.FAIL_VALIDATION.code()); String validateErrorMsg = V.getBindingError(br); map.put("msg", validateErrorMsg); + map.put("ok", false); log.warn("数据校验失败, {}: {}", br.getObjectName(), validateErrorMsg); } return new ResponseEntity<>(map, HttpStatus.OK); @@ -92,6 +93,7 @@ public class DefaultExceptionHandler { map.put("code", status.value()); String msg = buildMsg(status, e); map.put("msg", msg); + map.put("ok", false); } log.warn("请求处理异常", e); return new ResponseEntity<>(map, HttpStatus.OK); diff --git a/diboot-core/src/main/java/com/diboot/core/holder/AnnotationRestApiHolder.java b/diboot-core/src/main/java/com/diboot/core/holder/AnnotationRestApiHolder.java index d4afb43771af5f9decd748c528d4a07cda0ce0b6..403239bc52374d4cb4a8bdfc067befcb8343a56d 100644 --- a/diboot-core/src/main/java/com/diboot/core/holder/AnnotationRestApiHolder.java +++ b/diboot-core/src/main/java/com/diboot/core/holder/AnnotationRestApiHolder.java @@ -59,7 +59,7 @@ public class AnnotationRestApiHolder { */ private static final String CACHE_NAME_CATEGORY_TO_APILIST = "CATEGORY_TO_API_LIST"; - private static StaticMemoryCacheManager getCacheManager(){ + private synchronized static StaticMemoryCacheManager getCacheManager(){ if(cacheManager == null){ cacheManager = new StaticMemoryCacheManager( CACHE_NAME_CLASS_TO_WRAPPER, 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 560585ef348aec0bc42f441d7d9d4d10d365e144..ecaccfb00f912efc77024511cf360173641f0f31 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 @@ -521,6 +521,18 @@ public class BaseServiceImpl, T> extends ServiceImpl if(queryWrapper instanceof DynamicJoinQueryWrapper){ return Binder.joinQueryList((DynamicJoinQueryWrapper)queryWrapper, entityClass, pagination); } + else if(queryWrapper instanceof QueryWrapper) { + QueryWrapper mpQueryWrapper = ((QueryWrapper)queryWrapper); + if(mpQueryWrapper.getEntityClass() == null) { + mpQueryWrapper.setEntityClass(entityClass); + } + } + else if(queryWrapper instanceof LambdaQueryWrapper) { + LambdaQueryWrapper mpQueryWrapper = ((LambdaQueryWrapper)queryWrapper); + if(mpQueryWrapper.getEntityClass() == null) { + mpQueryWrapper.setEntityClass(entityClass); + } + } // 否则,调用MP默认实现 if(pagination != null){ IPage page = convertToIPage(queryWrapper, pagination); @@ -553,17 +565,25 @@ public class BaseServiceImpl, T> extends ServiceImpl @Override public List getValuesOfField(Wrapper queryWrapper, SFunction getterFn){ LambdaQueryWrapper query = null; + List entityList = null; // 优化SQL,只查询当前字段 if(queryWrapper instanceof QueryWrapper){ - query = ((QueryWrapper)queryWrapper).lambda(); + query = ((QueryWrapper)queryWrapper).lambda(); } else if(queryWrapper instanceof LambdaQueryWrapper){ - query = ((LambdaQueryWrapper) queryWrapper); + query = ((LambdaQueryWrapper) queryWrapper); } else { throw new InvalidUsageException("不支持的Wrapper类型:" + (queryWrapper == null ? "null" : queryWrapper.getClass())); } - List entityList = getEntityList(query.select(getterFn)); + // 如果是动态join,则调用JoinsBinder + query.select(getterFn); + if(queryWrapper instanceof DynamicJoinQueryWrapper){ + entityList = Binder.joinQueryList( (DynamicJoinQueryWrapper)queryWrapper, entityClass, null); + } + else{ + entityList = getEntityList(query); + } if(V.isEmpty(entityList)){ return Collections.emptyList(); } @@ -572,6 +592,12 @@ public class BaseServiceImpl, T> extends ServiceImpl @Override public List getEntityListLimit(Wrapper queryWrapper, int limitCount) { + // 如果是动态join,则调用JoinsBinder + if(queryWrapper instanceof DynamicJoinQueryWrapper){ + Pagination pagination = new Pagination(); + pagination.setPageIndex(1).setPageSize(limitCount); + return Binder.joinQueryList((DynamicJoinQueryWrapper)queryWrapper, entityClass, pagination); + } Page page = new Page<>(1, limitCount); page.setSearchCount(false); page = super.page(page, queryWrapper); @@ -580,6 +606,10 @@ public class BaseServiceImpl, T> extends ServiceImpl @Override public T getSingleEntity(Wrapper queryWrapper) { + // 如果是动态join,则调用JoinsBinder + if(queryWrapper instanceof DynamicJoinQueryWrapper){ + return (T)Binder.joinQueryOne((DynamicJoinQueryWrapper)queryWrapper, entityClass); + } List entityList = getEntityListLimit(queryWrapper, 1); if(V.notEmpty(entityList)){ return entityList.get(0); diff --git a/diboot-core/src/main/java/com/diboot/core/util/BeanUtils.java b/diboot-core/src/main/java/com/diboot/core/util/BeanUtils.java index 94587945bf2a2fd44c528b5265440fe9823a2815..4185e72767b6fca0b1eb37ae5909db725634ad8b 100644 --- a/diboot-core/src/main/java/com/diboot/core/util/BeanUtils.java +++ b/diboot-core/src/main/java/com/diboot/core/util/BeanUtils.java @@ -16,6 +16,7 @@ package com.diboot.core.util; import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; import com.diboot.core.config.Cons; import com.diboot.core.converter.*; import com.diboot.core.data.copy.AcceptAnnoCopier; @@ -149,7 +150,7 @@ public class BeanUtils { if (V.isAnyEmpty(model, propMap)) { return; } - BeanWrapper beanWrapper = BeanUtils.getBeanWrapper(model); + BeanWrapper beanWrapper = getBeanWrapper(model); for(Map.Entry entry : propMap.entrySet()){ try{ beanWrapper.setPropertyValue(entry.getKey(), entry.getValue()); @@ -188,10 +189,6 @@ public class BeanUtils { * @return */ public static String getStringProperty(Object obj, String field){ - if(obj instanceof Map){ - Map objMap = (Map)obj; - return objMap.containsKey(field)? S.valueOf(objMap.get(field)) : null; - } Object property = getProperty(obj, field); if(property == null){ return null; @@ -621,7 +618,11 @@ public class BeanUtils { Object fieldValue = getProperty(object, getterPropName); // E类型中的提取的字段值不需要进行重复判断,如果一定要查重,那应该使用Set代替List if (fieldValue != null) { - fieldValueList.add(fieldValue); + if (fieldValue instanceof Collection) { + fieldValueList.addAll((Collection) fieldValue); + } else { + fieldValueList.add(fieldValue); + } } } } @@ -796,6 +797,9 @@ public class BeanUtils { if (field.isAnnotationPresent(TableField.class)) { columnName = field.getAnnotation(TableField.class).value(); } + else if(field.isAnnotationPresent(TableId.class)) { + columnName = field.getAnnotation(TableId.class).value(); + } return S.getIfEmpty(columnName, () -> S.toSnakeCase(field.getName())); } 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 e5fb6dda5ec350f69d355e73e418411f8df2ffda..4f5191c562d09eb0bee3ce5b6778a232e674f96f 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 @@ -52,6 +52,7 @@ public class D extends DateUtils{ public static final String FORMAT_DATE_SLASH_Y4MD = "yyyy/MM/dd"; public static final String FORMAT_DATETIME_SLASH_Y4MDHM = "yyyy/MM/dd HH:mm"; public static final String FORMAT_DATETIME_SLASH_Y4MDHMS = "yyyy/MM/dd HH:mm:ss"; + public static final String FORMAT_DATETIME_Y4MD_T_HMS = "yyyy-MM-ddTHH:mm:ss"; /** * 星期(中文) */ @@ -443,6 +444,20 @@ public class D extends DateUtils{ * 模糊转换日期 */ public static Date fuzzyConvert(String dateString){ + if(V.isEmpty(dateString)){ + return null; + } + dateString = formatDateString(dateString); + if(!dateString.contains(" ")) { + return convert2FormatDate(dateString, FORMAT_DATE_Y4MD); + } + return convert2FormatDate(dateString, FORMAT_DATETIME_Y4MDHMS); + } + + /** + * 格式化日期字符串 + */ + public static String formatDateString(String dateString){ if(V.isEmpty(dateString)){ return null; } @@ -453,7 +468,7 @@ public class D extends DateUtils{ else{ dateString = dateString.replaceAll("/", "-").replaceAll("\\.", "-"); } - String[] parts = dateString.split(" "); + String[] parts = (dateString.contains("T") && !dateString.contains(" "))? dateString.split("T") : dateString.split(" "); String[] ymd = parts[0].split("-"); if(ymd.length >= 3){ if(ymd[0].length() == 2){ @@ -468,7 +483,7 @@ public class D extends DateUtils{ } parts[0] = S.join(ymd, "-"); if(parts.length == 1){ - return D.convert2FormatDate(parts[0], D.FORMAT_DATE_Y4MD); + return parts[0]; } // 18:20:30:103 String[] hmsArray = new String[3]; @@ -496,7 +511,7 @@ public class D extends DateUtils{ hmsArray[2] = "00"; } parts[1] = S.join(hmsArray, ":"); - return convert2FormatDate(S.join(parts, " "), FORMAT_DATETIME_Y4MDHMS); + return S.join(parts, " "); } } diff --git a/diboot-core/src/main/java/com/diboot/core/util/Encryptor.java b/diboot-core/src/main/java/com/diboot/core/util/Encryptor.java index add90b943007955b31fceb013656bdb5f3c377f5..e8c69d585ecda7a2b1bbed6614eb97e1d4f618b5 100644 --- a/diboot-core/src/main/java/com/diboot/core/util/Encryptor.java +++ b/diboot-core/src/main/java/com/diboot/core/util/Encryptor.java @@ -46,7 +46,7 @@ public class Encryptor { * 加密Cipher缓存 */ private static Map encryptorMap = null; - private static Map getEncryptorMap(){ + private synchronized static Map getEncryptorMap(){ if(encryptorMap == null){ encryptorMap = new ConcurrentHashMap<>(); } @@ -57,7 +57,7 @@ public class Encryptor { * 解密Cipher缓存 */ private static Map decryptorMap = null; - private static Map getDecryptorMap(){ + private synchronized static Map getDecryptorMap(){ if(decryptorMap == null){ decryptorMap = new ConcurrentHashMap<>(); } diff --git a/diboot-core/src/main/java/com/diboot/core/util/S.java b/diboot-core/src/main/java/com/diboot/core/util/S.java index 1c261f79521ab47da31b471750275dc19dd7cf9f..0512f33d358dff7d0f873cc9ee864d46017e9c75 100644 --- a/diboot-core/src/main/java/com/diboot/core/util/S.java +++ b/diboot-core/src/main/java/com/diboot/core/util/S.java @@ -87,6 +87,18 @@ public class S extends StringUtils{ return joinedStr.split(SEPARATOR); } + private static final String[] SEARCH_LIST = {"[", "]", "\"", "\'"}; + private static final String[] REPLACE_LIST = {"", "", "", ""}; + + /** + * 清除非常量标识符: json标识 []"'等 + * @param inputJsonStr + * @return + */ + public static String clearNonConst(String inputJsonStr) { + return S.replaceEach(inputJsonStr, SEARCH_LIST, REPLACE_LIST); + } + /*** * 转换为String数组(避免转型异常) * @param stringList @@ -102,10 +114,20 @@ public class S extends StringUtils{ * @return */ public static List splitToList(String joinedStr){ + return splitToList(joinedStr, SEPARATOR); + } + + + /*** + * 按,拆分字符串并转换为 List + * @param joinedStr + * @return + */ + public static List splitToList(String joinedStr, String separator){ if(joinedStr == null){ return null; } - return Arrays.asList(joinedStr.split(SEPARATOR)); + return Arrays.asList(joinedStr.split(separator)); } /*** @@ -306,6 +328,9 @@ public class S extends StringUtils{ if (o == null){ return null; } + if(o instanceof String) { + return (String)o; + } return String.valueOf(o); } diff --git a/diboot-core/src/main/java/com/diboot/core/util/SqlFileInitializer.java b/diboot-core/src/main/java/com/diboot/core/util/SqlFileInitializer.java index 772d6c6d7d1545c8ffa1bd7a9fe70a97d7995dc6..6acae317b3f72acdb70c83f0214a384ae3800dc3 100644 --- a/diboot-core/src/main/java/com/diboot/core/util/SqlFileInitializer.java +++ b/diboot-core/src/main/java/com/diboot/core/util/SqlFileInitializer.java @@ -345,7 +345,7 @@ public class SqlFileInitializer { return inputSql; } if(inputSql.contains("/*") && inputSql.contains("*/")){ - inputSql = inputSql.substring(0, inputSql.lastIndexOf("/*")) + inputSql.substring(inputSql.indexOf("*/")+2, inputSql.length()); + inputSql = inputSql.substring(0, inputSql.indexOf("/*")) + inputSql.substring(inputSql.indexOf("*/")+2); } if(inputSql.contains("/*") && inputSql.contains("*/")){ return removeMultipleLineComments(inputSql); diff --git a/diboot-core/src/main/java/com/diboot/core/util/V.java b/diboot-core/src/main/java/com/diboot/core/util/V.java index b14a196b3d1d7ce8465fd04a52e77d9119aaacb4..575a1b6d2e133046a28b8a66ec33d175c6f1a59b 100644 --- a/diboot-core/src/main/java/com/diboot/core/util/V.java +++ b/diboot-core/src/main/java/com/diboot/core/util/V.java @@ -593,8 +593,9 @@ public class V { return true; } else if (source == null || target == null) { return false; - } else if (source.getClass() != target.getClass()) { - // 根据equals设计原则,类型不一致,直接false + } + else if (source.getClass() != target.getClass() && !(source instanceof Map && target instanceof Map)) { + // 根据equals设计原则,类型不一致,直接false(仅允许HashMap、LinkedHashMap的差异) // 避免子类与父类、子类与子类比较时可能出现的问题 log.warn("source和target类型不匹配:" + source.getClass() + " 和 " + target.getClass()); return false; @@ -693,7 +694,7 @@ public class V { } else if (target instanceof Date && source instanceof String) { return D.getDateTime((Date) target).equals(source) || D.getDate((Date) target).equals(source); } else { - return String.valueOf(source).equals(String.valueOf(target)); + return S.valueOf(source).equals(S.valueOf(target)); } } diff --git a/diboot-core/src/main/java/com/diboot/core/util/init/BeanInitUtils.java b/diboot-core/src/main/java/com/diboot/core/util/init/BeanInitUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..54feab2bd142116cb795632e364561b73a479afc --- /dev/null +++ b/diboot-core/src/main/java/com/diboot/core/util/init/BeanInitUtils.java @@ -0,0 +1,108 @@ + +package com.diboot.core.util.init; + +import com.diboot.core.util.ContextHelper; +import lombok.SneakyThrows; + +import java.util.Objects; +import java.util.function.Supplier; + +/** + * 初始化器 工具类 + *

封装了 {@link BeanInitializer} , 提供一些简单的使用方法

+ * + * @author Zjp + * @date 2022/7/14 + */ +public class BeanInitUtils { + protected BeanInitUtils() { + } + + /** + * 获取 线程安全的 懒加载的 初始器 + * + * @param supplier 提供真正的对象 + * @param 真正的对象类型 + * @return 懒加载初始器 + */ + public static BeanInitializer lazyInit(Supplier supplier) { + return new LazyBeanInitializer() { + @Override + protected T initialize() { + return supplier.get(); + } + }; + } + + /** + * 获取 线程安全的 懒加载的 初始化器 + *

默认根据类型查找bean

+ * + * @param beanClass bean的class + * @param bean类型 + * @return 懒加载初始器 + */ + public static BeanInitializer lazyInit(Class beanClass) { + return new LazyBeanInitializer() { + @Override + protected T initialize() { + return Objects.requireNonNull(ContextHelper.getBean(beanClass), () -> "找不到class对应的bean: " + beanClass.getName()); + } + }; + } + + /** + * 使用 双重校验 实现 懒加载 + *

实现参照 {@link org.apache.commons.lang3.concurrent.LazyInitializer}

+ * + * @param 封装的数据对象类型 + */ + private static abstract class LazyBeanInitializer implements BeanInitializer { + /** + * 标记未初始化的 默认值 + */ + private static final Object NO_INIT = new Object(); + + @SuppressWarnings("unchecked") + // Stores the managed object. + private volatile T object = (T) NO_INIT; + + /** + * Returns the object wrapped by this instance. On first access the object + * is created. After that it is cached and can be accessed pretty fast. + * + * @return the object initialized by this {@code LazyInitializer} + */ + @SneakyThrows + @Override + public T get() { + // use a temporary variable to reduce the number of reads of the + // volatile field + T result = object; + + if (result == NO_INIT) { + synchronized (this) { + result = object; + if (result == NO_INIT) { + object = result = initialize(); + } + } + } + + return result; + } + + /** + * Creates and initializes the object managed by this {@code + * LazyInitializer}. This method is called by {@link #get()} when the object + * is accessed for the first time. An implementation can focus on the + * creation of the object. No synchronization is needed, as this is already + * handled by {@code get()}. + * + * @return the managed data object + * @throws Exception if an error occurs during object creation + */ + protected abstract T initialize() throws Exception; + } + +} diff --git a/diboot-core/src/main/java/com/diboot/core/util/init/BeanInitializer.java b/diboot-core/src/main/java/com/diboot/core/util/init/BeanInitializer.java new file mode 100644 index 0000000000000000000000000000000000000000..140470397d3ca62f8a71cebf8220534bc9a0e2a0 --- /dev/null +++ b/diboot-core/src/main/java/com/diboot/core/util/init/BeanInitializer.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015-2022, www.dibo.ltd (service@dibo.ltd). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.diboot.core.util.init; + +/** + * 对象 初始化器 接口 + *

仿照 {@link org.apache.commons.lang3.concurrent.ConcurrentInitializer} 的初始化器接口, + * 优点是 {@link #get()} 不会抛出受检异常 + *

+ * + * @author Zjp + * @date 2022/7/15 + * @see org.apache.commons.lang3.concurrent.ConcurrentInitializer + */ +public interface BeanInitializer { + /** + * 返回创建好的对象实例, 该方法可能会阻塞, 保证多次调用该方法获取的都是同一实例 + * + * @return 创建好的对象实例 + * @implSpec 子类 必须保证返回的是同一对象实例 + */ + T get(); +} diff --git a/diboot-core/src/main/java/com/diboot/core/vo/JsonResult.java b/diboot-core/src/main/java/com/diboot/core/vo/JsonResult.java index bb35735d7ccd5a9f3939dbebba6bccf239b20cb9..f70ca00dfa5668a354834207dd2e46414184d6a5 100644 --- a/diboot-core/src/main/java/com/diboot/core/vo/JsonResult.java +++ b/diboot-core/src/main/java/com/diboot/core/vo/JsonResult.java @@ -183,7 +183,7 @@ public class JsonResult implements Serializable { * @param pagination */ @SuppressWarnings("unchecked") - public JsonResult bindPagination(Pagination pagination){ + public PagingJsonResult bindPagination(Pagination pagination){ return new PagingJsonResult(this, pagination); } diff --git a/diboot-core/src/main/java/com/diboot/core/vo/Pagination.java b/diboot-core/src/main/java/com/diboot/core/vo/Pagination.java index 604df46999d6abeded39104d7cbfe8720e2bbde9..4f39af867e783c1381e6c07fe817b33180cdf37a 100644 --- a/diboot-core/src/main/java/com/diboot/core/vo/Pagination.java +++ b/diboot-core/src/main/java/com/diboot/core/vo/Pagination.java @@ -71,6 +71,7 @@ public class Pagination implements Serializable { */ private String orderBy = DEFAULT_ORDER_BY; + @JsonIgnore private Class entityClass; public Pagination() { @@ -192,10 +193,7 @@ public class Pagination implements Serializable { * @return */ public static boolean isPaginationParam(String paramName){ - return "pageIndex".equals(paramName) - || "pageSize".equals(paramName) - || "orderBy".equals(paramName) - || "totalCount".equals(paramName); + return Cons.PaginationParam.isPaginationParam(paramName); } private PropInfo getEntityPropInfo(){ diff --git a/diboot-core/src/main/java/com/diboot/core/vo/PagingJsonResult.java b/diboot-core/src/main/java/com/diboot/core/vo/PagingJsonResult.java index 8cb97f0134d60c39c5d161a2fcf11f2b9f868623..60190f1e35988e5a550019af873336d8e58739ce 100644 --- a/diboot-core/src/main/java/com/diboot/core/vo/PagingJsonResult.java +++ b/diboot-core/src/main/java/com/diboot/core/vo/PagingJsonResult.java @@ -29,7 +29,7 @@ import java.util.List; * @version v2.0 * @date 2019/01/01 */ -public class PagingJsonResult extends JsonResult{ +public class PagingJsonResult extends JsonResult { private static final long serialVersionUID = 1002L; /*** @@ -40,10 +40,14 @@ public class PagingJsonResult extends JsonResult{ public PagingJsonResult(){ } + public PagingJsonResult(T data){ + this.data(data); + } + /** * 默认成功,无返回数据 */ - public PagingJsonResult(JsonResult jsonResult, Pagination pagination){ + public PagingJsonResult(JsonResult jsonResult, Pagination pagination){ super(jsonResult.getCode(), jsonResult.getMsg(), jsonResult.getData()); this.page = pagination; } @@ -51,9 +55,9 @@ public class PagingJsonResult extends JsonResult{ /** * 基于IPage转换为PagingJsonResult * @param iPage - * @param + * @param */ - public PagingJsonResult(IPage iPage){ + public PagingJsonResult(IPage iPage){ Pagination pagination = new Pagination(); pagination.setPageIndex((int)iPage.getCurrent()); pagination.setPageSize((int)iPage.getSize()); @@ -71,7 +75,8 @@ public class PagingJsonResult extends JsonResult{ pagination.setOrderBy(S.join(orderByList)); } this.page = pagination; - this.data(iPage.getRecords()); + T data = (T)iPage.getRecords(); + this.data(data); } public PagingJsonResult setPage(Pagination pagination){ diff --git a/diboot-core/src/main/java/com/diboot/core/vo/Status.java b/diboot-core/src/main/java/com/diboot/core/vo/Status.java index e32a020a05fc9961ee1ba445807242afb19cb4c4..c79ee5da5f4a643ac85569fcb6f132bc52c980fb 100644 --- a/diboot-core/src/main/java/com/diboot/core/vo/Status.java +++ b/diboot-core/src/main/java/com/diboot/core/vo/Status.java @@ -76,6 +76,14 @@ public enum Status { * 认证不通过(用户名密码错误等认证失败场景) */ FAIL_AUTHENTICATION(4009, "认证不通过"), + /** + * 租户无效 + */ + FAIL_INVALID_TENANT(4011,"无效的租户"), + /** + * 账号无效 + */ + FAIL_INVALID_ACCOUNT(4012,"无效的账号"), /*** * 系统异常 diff --git a/diboot-file-starter/pom.xml b/diboot-file-starter/pom.xml index 085d524f6affb6d4e5c4240d5a418a63d99b4a08..78baf45d9acdbee6f94d51fadef8e311190f93c6 100644 --- a/diboot-file-starter/pom.xml +++ b/diboot-file-starter/pom.xml @@ -7,11 +7,11 @@ diboot-root com.diboot - 2.6.0 + 2.7.0 diboot-file-spring-boot-starter - 2.6.0 + 2.7.0 jar diboot file component project diff --git a/diboot-file-starter/src/main/java/com/diboot/file/controller/BaseFileController.java b/diboot-file-starter/src/main/java/com/diboot/file/controller/BaseFileController.java index 242f0cf44501deef429e346cb5b496dff886ea2b..7e62690501721c3644b739bfcc6b921c7e3dde60 100644 --- a/diboot-file-starter/src/main/java/com/diboot/file/controller/BaseFileController.java +++ b/diboot-file-starter/src/main/java/com/diboot/file/controller/BaseFileController.java @@ -57,7 +57,7 @@ public abstract class BaseFileController extends BaseController { /** * 合法的文件后缀 */ - protected static List VALID_FILE_EXTS = Arrays.asList( + protected static final List VALID_FILE_EXTS = Arrays.asList( "gif","ico","jpeg","jpg","png","tif","bmp","gif","webp", "csv", "xls","xlsx","xlsm","doc","docx","dot","ppt","pptx","pdf","css","dtd","txt","md", "mp3","mp4","wav","avi","wma","wsdl","xml","xsd","xsl","rar","zip","7z"); diff --git a/diboot-file-starter/src/main/java/com/diboot/file/excel/cache/ExcelBindAnnoHandler.java b/diboot-file-starter/src/main/java/com/diboot/file/excel/cache/ExcelBindAnnoHandler.java index b557a420097b63bb9322076568bae3378e671ce3..d092629b4f9fab1f8a7003c1ec30b9f449e3774a 100644 --- a/diboot-file-starter/src/main/java/com/diboot/file/excel/cache/ExcelBindAnnoHandler.java +++ b/diboot-file-starter/src/main/java/com/diboot/file/excel/cache/ExcelBindAnnoHandler.java @@ -63,20 +63,20 @@ public class ExcelBindAnnoHandler { BindDict bindDict = field.getAnnotation(BindDict.class); if(excelBindDict != null){ if(field2AnnoMap == null){ - field2AnnoMap = new HashMap<>(8); + field2AnnoMap = new LinkedHashMap<>(8); } field2AnnoMap.put(field.getName(), excelBindDict); } else if(bindDict != null) { if(field2AnnoMap == null){ - field2AnnoMap = new HashMap<>(8); + field2AnnoMap = new LinkedHashMap<>(8); } field2AnnoMap.put(field.getName(), bindDict); } ExcelBindField bindField = field.getAnnotation(ExcelBindField.class); if(bindField != null){ if(field2AnnoMap == null){ - field2AnnoMap = new HashMap<>(8); + field2AnnoMap = new LinkedHashMap<>(8); } field2AnnoMap.put(field.getName(), bindField); } diff --git a/diboot-file-starter/src/main/java/com/diboot/file/util/ImageHelper.java b/diboot-file-starter/src/main/java/com/diboot/file/util/ImageHelper.java index 04c2001123d5a7bce87151afa3e40fa6f6e13646..a1dec9addb1f4c1ccde95327425eba195fb67e61 100644 --- a/diboot-file-starter/src/main/java/com/diboot/file/util/ImageHelper.java +++ b/diboot-file-starter/src/main/java/com/diboot/file/util/ImageHelper.java @@ -19,8 +19,6 @@ import com.diboot.core.util.D; import com.diboot.core.util.S; import com.diboot.file.config.Cons; import lombok.extern.slf4j.Slf4j; -import net.coobird.thumbnailator.Thumbnails; -import net.coobird.thumbnailator.geometry.Positions; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.web.multipart.MultipartFile; @@ -129,26 +127,6 @@ public class ImageHelper { return sb.toString(); } - /** - * 压缩图片 - * @param imgUrl - * @return - */ - public static String generateThumbnail(String imgUrl, int width, int height){ - String file = imgUrl.substring(imgUrl.indexOf("/img/")); - String imageFileDirectory = FileHelper.getFileStorageDirectory() + file; - try { - // 压缩图片 - String targetFile = imgUrl.replace(".", "_tn."); - Thumbnails.of(imageFileDirectory).size(width, height).outputQuality(0.7f).toFile(FileHelper.getFileStorageDirectory() + targetFile); - return targetFile; - } - catch (IOException e1) { - log.error("压缩图片异常(image=" + imageFileDirectory + "): ", e1); - } - return imgUrl; - } - /** * 将Base64转换为图片 * @param base64Str @@ -156,7 +134,7 @@ public class ImageHelper { * @return * @throws IOException */ - private static boolean convertBase64ToImage(String base64Str, String fullFilePath){ + public static boolean convertBase64ToImage(String base64Str, String fullFilePath){ if(base64Str == null){ return false; } @@ -177,32 +155,5 @@ public class ImageHelper { return false; } } - - /** - * 生成缩略图 - * @return - * @throws Exception - */ - public static String generateThumbnail(String sourcePath, String targetPath, int width, int height) throws Exception{ - // 创建文件 - File file = new File(sourcePath); - if(!file.exists()){ - boolean result = file.mkdir(); - if(!result){ - log.warn("创建文件夹 {} 失败", sourcePath); - } - } - // 生成缩略图 - Thumbnails.of(sourcePath).size(width, height).toFile(targetPath); - return targetPath; - } - - /** - * 给图片添加水印 - * @param filePath - */ - private static void addWatermark(String filePath, String watermark) throws Exception{ - Thumbnails.of(filePath).watermark(Positions.BOTTOM_RIGHT, ImageIO.read(new File(watermark)), 0.8f).toFile(filePath); - } } diff --git a/diboot-file-starter/src/main/java/com/diboot/file/util/ImageThumbnailHelper.java b/diboot-file-starter/src/main/java/com/diboot/file/util/ImageThumbnailHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..5e1006a99d0524dd33a5cd5daa1f305b7b4c9e39 --- /dev/null +++ b/diboot-file-starter/src/main/java/com/diboot/file/util/ImageThumbnailHelper.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2015-2029, www.dibo.ltd (service@dibo.ltd). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.diboot.file.util; + +import lombok.extern.slf4j.Slf4j; +import net.coobird.thumbnailator.Thumbnails; +import net.coobird.thumbnailator.geometry.Positions; + +import javax.imageio.ImageIO; +import java.io.File; +import java.io.IOException; + +/** + * 图片缩略图相关工具类 + * @author JerryMa + * @version v2.7.0 + * @copyright dibo.ltd + */ +@Slf4j +public class ImageThumbnailHelper extends ImageHelper { + + /** + * 压缩图片 + * @param imgUrl + * @return + */ + public static String generateThumbnail(String imgUrl, int width, int height){ + String file = imgUrl.substring(imgUrl.indexOf("/img/")); + String imageFileDirectory = FileHelper.getFileStorageDirectory() + file; + try { + // 压缩图片 + String targetFile = imgUrl.replace(".", "_tn."); + Thumbnails.of(imageFileDirectory).size(width, height).outputQuality(0.7f).toFile(FileHelper.getFileStorageDirectory() + targetFile); + return targetFile; + } + catch (IOException e1) { + log.error("压缩图片异常(image=" + imageFileDirectory + "): ", e1); + } + return imgUrl; + } + + /** + * 生成缩略图 + * @return + * @throws Exception + */ + public static String generateThumbnail(String sourcePath, String targetPath, int width, int height) throws Exception{ + // 创建文件 + File file = new File(sourcePath); + if(!file.exists()){ + boolean result = file.mkdir(); + if(!result){ + log.warn("创建文件夹 {} 失败", sourcePath); + } + } + // 生成缩略图 + Thumbnails.of(sourcePath).size(width, height).toFile(targetPath); + return targetPath; + } + + /** + * 给图片添加水印 + * @param filePath + */ + public static void addWatermark(String filePath, String watermark) throws Exception{ + Thumbnails.of(filePath).watermark(Positions.BOTTOM_RIGHT, ImageIO.read(new File(watermark)), 0.8f).toFile(filePath); + } + +} diff --git a/diboot-iam-starter/pom.xml b/diboot-iam-starter/pom.xml index 73b94a5d1396a329caf3f2f2ac775b24da8920f9..432fcdbf6767d32c2c456d085bb283f23b50182b 100644 --- a/diboot-iam-starter/pom.xml +++ b/diboot-iam-starter/pom.xml @@ -7,11 +7,11 @@ com.diboot diboot-root - 2.6.0 + 2.7.0 diboot-iam-spring-boot-starter - 2.6.0 + 2.7.0 jar diboot IAM project @@ -26,7 +26,7 @@ org.apache.shiro shiro-spring-boot-web-starter - 1.9.0 + 1.9.1 com.squareup.okhttp3 diff --git a/diboot-iam-starter/src/main/java/com/diboot/iam/annotation/process/ApiPermissionExtractor.java b/diboot-iam-starter/src/main/java/com/diboot/iam/annotation/process/ApiPermissionExtractor.java index 82e058c2e39da732c1e07b2044010071c838de4d..139528eefe436e52809273caad34a145118edd46 100644 --- a/diboot-iam-starter/src/main/java/com/diboot/iam/annotation/process/ApiPermissionExtractor.java +++ b/diboot-iam-starter/src/main/java/com/diboot/iam/annotation/process/ApiPermissionExtractor.java @@ -124,23 +124,21 @@ public class ApiPermissionExtractor { if(apiUriCombo.isEmpty()){ continue; } - if(bindPermission != null){ - if(V.isEmpty(bindPermission.code())){ - log.warn("忽略无效的权限配置(未指定code): {}.{}", controllerClass.getSimpleName(), method.getName()); - continue; - } - String name = bindPermission.name(); - String code = (wrapper.getCode() != null)? wrapper.getCode()+":"+bindPermission.code() : bindPermission.code(); - ApiPermission apiPermission = tempCode2ObjMap.get(code); - if(apiPermission == null){ - apiPermission = new ApiPermission(code); - tempCode2ObjMap.put(code, apiPermission); - apiPermissions.add(apiPermission); - } - apiUriCombo.setLabel(name); - // 提取请求url-permission code的关系 - buildApiPermission(apiPermission, urlPrefix, apiUriCombo); + if(V.isEmpty(bindPermission.code())){ + log.warn("忽略无效的权限配置(未指定code): {}.{}", controllerClass.getSimpleName(), method.getName()); + continue; + } + String name = bindPermission.name(); + String code = (wrapper.getCode() != null)? wrapper.getCode()+":"+bindPermission.code() : bindPermission.code(); + ApiPermission apiPermission = tempCode2ObjMap.get(code); + if(apiPermission == null){ + apiPermission = new ApiPermission(code); + tempCode2ObjMap.put(code, apiPermission); + apiPermissions.add(apiPermission); } + apiUriCombo.setLabel(name); + // 提取请求url-permission code的关系 + buildApiPermission(apiPermission, urlPrefix, apiUriCombo); } // 添加至wrapper if(apiPermissions.size() > 0){ diff --git a/diboot-iam-starter/src/main/java/com/diboot/iam/auth/AuthService.java b/diboot-iam-starter/src/main/java/com/diboot/iam/auth/AuthService.java index 310654372bd0687e8f5c91eb3e3ac679910119ec..26c22ae58f597574518bcdd72df6c8e4af5fd02a 100644 --- a/diboot-iam-starter/src/main/java/com/diboot/iam/auth/AuthService.java +++ b/diboot-iam-starter/src/main/java/com/diboot/iam/auth/AuthService.java @@ -54,7 +54,7 @@ public interface AuthService { /** * 申请Token * @param credential 登录凭证 - * @return token JWT Token + * @return token Token */ String applyToken(AuthCredential credential); diff --git a/diboot-iam-starter/src/main/java/com/diboot/iam/auth/impl/BaseAuthServiceImpl.java b/diboot-iam-starter/src/main/java/com/diboot/iam/auth/impl/BaseAuthServiceImpl.java index d531aad155dc122aa5442c927d819062be41c196..c707dcd793cb21b904116bc06d806dd881701fe4 100644 --- a/diboot-iam-starter/src/main/java/com/diboot/iam/auth/impl/BaseAuthServiceImpl.java +++ b/diboot-iam-starter/src/main/java/com/diboot/iam/auth/impl/BaseAuthServiceImpl.java @@ -107,7 +107,7 @@ public abstract class BaseAuthServiceImpl implements AuthService { } /** - * 初始化JwtAuthToken实例 + * 初始化AuthToken实例 * @param credential * @return */ diff --git a/diboot-iam-starter/src/main/java/com/diboot/iam/auth/impl/IamExtensibleImpl.java b/diboot-iam-starter/src/main/java/com/diboot/iam/auth/impl/IamExtensibleImpl.java index a69907e633682e5a8cbb5c6881461817f5f7a418..2e380b80b3b9792a39f44e7a01c6d017933e7f8d 100644 --- a/diboot-iam-starter/src/main/java/com/diboot/iam/auth/impl/IamExtensibleImpl.java +++ b/diboot-iam-starter/src/main/java/com/diboot/iam/auth/impl/IamExtensibleImpl.java @@ -56,7 +56,7 @@ public class IamExtensibleImpl implements IamExtensible { if(userPosition != null){ Long orgId = userPosition.getOrgId(); IamPosition position = iamPositionService.getEntity(userPosition.getPositionId()); - PositionDataScope positionDataScope = new PositionDataScope(userId, position.getDataPermissionType(), userId, orgId); + PositionDataScope positionDataScope = new PositionDataScope(position.getId(), position.getDataPermissionType(), userId, orgId); List accessibleUserIds = new ArrayList<>(), accessibleOrgIds = new ArrayList<>(); // 本人及下属的用户ids accessibleUserIds.add(userId); diff --git a/diboot-iam-starter/src/main/java/com/diboot/iam/auth/impl/OAuth2SSOServiceImpl.java b/diboot-iam-starter/src/main/java/com/diboot/iam/auth/impl/OAuth2SSOServiceImpl.java index 34e05512eed61ccd29ff77d67cc57dd752791439..022a55f3b504fedf5df947ae3785b5fc53104099 100644 --- a/diboot-iam-starter/src/main/java/com/diboot/iam/auth/impl/OAuth2SSOServiceImpl.java +++ b/diboot-iam-starter/src/main/java/com/diboot/iam/auth/impl/OAuth2SSOServiceImpl.java @@ -77,7 +77,6 @@ public class OAuth2SSOServiceImpl extends BaseAuthServiceImpl { .select(IamAccount::getAuthAccount, IamAccount::getUserType, IamAccount::getUserId, IamAccount::getStatus) .eq(IamAccount::getUserType, iamAuthToken.getUserType()) .eq(IamAccount::getTenantId, iamAuthToken.getTenantId()) - //.eq(IamAccount::getAuthType, jwtToken.getAuthType()) SSO只检查用户名,支持任意类型账号 .eq(IamAccount::getAuthAccount, iamAuthToken.getAuthAccount()) .orderByDesc(IamAccount::getId); return queryWrapper; @@ -95,7 +94,7 @@ public class OAuth2SSOServiceImpl extends BaseAuthServiceImpl { } /** - * 初始化JwtAuthToken实例 + * 初始化AuthToken实例 * * @param credential * @return @@ -107,6 +106,7 @@ public class OAuth2SSOServiceImpl extends BaseAuthServiceImpl { token.setAuthAccount(credential.getAuthAccount()); token.setTenantId(credential.getTenantId()); token.setRememberMe(credential.isRememberMe()); + token.setExpiresInMinutes(getExpiresInMinutes()); // 生成token return token.generateAuthtoken(); } diff --git a/diboot-iam-starter/src/main/java/com/diboot/iam/auth/impl/PwdAuthServiceImpl.java b/diboot-iam-starter/src/main/java/com/diboot/iam/auth/impl/PwdAuthServiceImpl.java index 4c7f31b7ab54c5b9d111c725c6c6777d225becde..ec3a2ea88e23cc0c5a7a10987dff54411765b0cb 100644 --- a/diboot-iam-starter/src/main/java/com/diboot/iam/auth/impl/PwdAuthServiceImpl.java +++ b/diboot-iam-starter/src/main/java/com/diboot/iam/auth/impl/PwdAuthServiceImpl.java @@ -62,7 +62,8 @@ public class PwdAuthServiceImpl extends BaseAuthServiceImpl { public IamAccount getAccount(IamAuthToken iamAuthToken) throws AuthenticationException { IamAccount latestAccount = super.getAccount(iamAuthToken); // 如果需要密码校验,那么无状态的时候不需要验证 - if (iamAuthToken.isValidPassword() && isPasswordMatched(latestAccount, iamAuthToken) == false){ + if (latestAccount == null || + (iamAuthToken.isValidPassword() && isPasswordMatched(latestAccount, iamAuthToken) == false)){ throw new AuthenticationException("用户名或密码错误! account="+iamAuthToken.getAuthAccount()); } return latestAccount; @@ -71,14 +72,14 @@ public class PwdAuthServiceImpl extends BaseAuthServiceImpl { /** * 用户名密码是否一致 * @param account - * @param jwtToken + * @param authToken * @return */ - private static boolean isPasswordMatched(IamAccount account, IamAuthToken jwtToken){ + private static boolean isPasswordMatched(IamAccount account, IamAuthToken authToken){ //加密后比较 - String encryptedStr = IamSecurityUtils.encryptPwd(jwtToken.getAuthSecret(), account.getSecretSalt()); + String encryptedStr = IamSecurityUtils.encryptPwd(authToken.getAuthSecret(), account.getSecretSalt()); // 暂时兼容RC2版本,后期移除 - String oldEncryptedStr = Encryptor.encrypt(jwtToken.getAuthSecret(), account.getSecretSalt()); + String oldEncryptedStr = Encryptor.encrypt(authToken.getAuthSecret(), account.getSecretSalt()); return encryptedStr.equals(account.getAuthSecret()) || oldEncryptedStr.equals(account.getAuthSecret()); } diff --git a/diboot-iam-starter/src/main/java/com/diboot/iam/entity/BaseLoginUser.java b/diboot-iam-starter/src/main/java/com/diboot/iam/entity/BaseLoginUser.java index 2c45e2c97c2385562ae43fd5c95cc8c3f00828b7..d957dbf1d171ca642e52841cfadea41e303c14a9 100644 --- a/diboot-iam-starter/src/main/java/com/diboot/iam/entity/BaseLoginUser.java +++ b/diboot-iam-starter/src/main/java/com/diboot/iam/entity/BaseLoginUser.java @@ -19,7 +19,6 @@ import com.baomidou.mybatisplus.annotation.TableField; import com.diboot.core.entity.BaseEntity; import com.diboot.core.util.S; import com.diboot.core.vo.LabelValue; -import com.fasterxml.jackson.annotation.JsonIgnore; /** * 可登录用户Base类定义 @@ -44,7 +43,6 @@ public abstract class BaseLoginUser extends BaseEntity { /** * 附加对象,当前auth-token */ - @JsonIgnore @TableField(exist = false) private String authToken; diff --git a/diboot-iam-starter/src/main/java/com/diboot/iam/service/IamUserService.java b/diboot-iam-starter/src/main/java/com/diboot/iam/service/IamUserService.java index 3d466eb585532aa70deb3f9db3e3943e386dbe79..4e41f136ceb5846512cbabee9961c392a94aaaf0 100644 --- a/diboot-iam-starter/src/main/java/com/diboot/iam/service/IamUserService.java +++ b/diboot-iam-starter/src/main/java/com/diboot/iam/service/IamUserService.java @@ -16,6 +16,7 @@ package com.diboot.iam.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.diboot.core.vo.Pagination; import com.diboot.iam.dto.IamUserAccountDTO; import com.diboot.iam.entity.IamUser; @@ -83,6 +84,6 @@ public interface IamUserService extends BaseIamService { * @param orgId * @return */ - List getUserViewList(LambdaQueryWrapper queryWrapper, Pagination pagination, Long orgId); + List getUserViewList(QueryWrapper queryWrapper, Pagination pagination, Long orgId); } diff --git a/diboot-iam-starter/src/main/java/com/diboot/iam/service/impl/IamUserServiceImpl.java b/diboot-iam-starter/src/main/java/com/diboot/iam/service/impl/IamUserServiceImpl.java index 435cb1e80102a8371d5638a8ed15f9e6eb9496ae..829d28a4f826b39e97624405bf760b11b29003df 100644 --- a/diboot-iam-starter/src/main/java/com/diboot/iam/service/impl/IamUserServiceImpl.java +++ b/diboot-iam-starter/src/main/java/com/diboot/iam/service/impl/IamUserServiceImpl.java @@ -16,8 +16,10 @@ package com.diboot.iam.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.diboot.core.config.BaseConfig; +import com.diboot.core.config.Cons; import com.diboot.core.exception.BusinessException; import com.diboot.core.util.V; import com.diboot.core.vo.Pagination; @@ -186,20 +188,20 @@ public class IamUserServiceImpl extends BaseIamServiceImpl getUserViewList(LambdaQueryWrapper queryWrapper, Pagination pagination, Long orgId) { + public List getUserViewList(QueryWrapper queryWrapper, Pagination pagination, Long orgId) { List orgIds = new ArrayList<>(); // 获取当前部门及所有下属部门的人员列表 if (V.notEmpty(orgId) && V.notEquals(orgId, 0L)) { orgIds.add(orgId); // 获取所有下级部门列表 orgIds.addAll(iamOrgService.getChildOrgIds(orgId)); - queryWrapper.in(IamUser::getOrgId, orgIds); + queryWrapper.in(Cons.ColumnName.org_id.name(), orgIds); // 相应部门下岗位相关用户 LambdaQueryWrapper queryUserIds = Wrappers.lambdaQuery() .eq(IamUserPosition::getUserType, IamUser.class.getSimpleName()) .in(IamUserPosition::getOrgId, orgIds); List userIds = iamUserPositionService.getValuesOfField(queryUserIds, IamUserPosition::getUserId); - queryWrapper.or().in(V.notEmpty(userIds), IamUser::getId, userIds); + queryWrapper.or().in(V.notEmpty(userIds), Cons.FieldName.id.name(), userIds); } // 查询指定页的数据 List voList = getViewObjectList(queryWrapper, pagination, IamUserVO.class); diff --git a/diboot-iam-starter/src/main/java/com/diboot/iam/starter/IamAutoConfig.java b/diboot-iam-starter/src/main/java/com/diboot/iam/starter/IamAutoConfig.java index 28e48f13ffaf014df3468235f8c74af05217cc79..dcd038018b5c2c2fa5e5199393f742e35ebb84f4 100644 --- a/diboot-iam-starter/src/main/java/com/diboot/iam/starter/IamAutoConfig.java +++ b/diboot-iam-starter/src/main/java/com/diboot/iam/starter/IamAutoConfig.java @@ -160,7 +160,7 @@ public class IamAutoConfig { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 设置过滤器 Map filters = new LinkedHashMap<>(); - filters.put("jwt", shiroFilter()); + filters.put("accessControlFilter", shiroFilter()); shiroFilterFactoryBean.setFilters(filters); //Shiro securityManager shiroFilterFactoryBean.setSecurityManager(securityManager); @@ -192,9 +192,10 @@ public class IamAutoConfig { } filterChainMap.put("/login", "authc"); if (V.notEmpty(anonUrls) && anonUrls.contains("/**") && !iamProperties.isEnablePermissionCheck()) { + log.info("权限检查已停用,该配置仅用于开发环境 !"); filterChainMap.put("/**", "anon"); } else { - filterChainMap.put("/**", "jwt"); + filterChainMap.put("/**", "accessControlFilter"); } DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition(); chainDefinition.addPathDefinitions(filterChainMap); diff --git a/diboot-iam-starter/src/main/java/com/diboot/iam/starter/IamProperties.java b/diboot-iam-starter/src/main/java/com/diboot/iam/starter/IamProperties.java index d24dc50b4efa5c720cef7fe0243894ca70508322..71eff45183dfc85a724ba1dc0c9c06150ca1644a 100644 --- a/diboot-iam-starter/src/main/java/com/diboot/iam/starter/IamProperties.java +++ b/diboot-iam-starter/src/main/java/com/diboot/iam/starter/IamProperties.java @@ -38,16 +38,10 @@ public class IamProperties { private String application; /** - * jwt header key + * token header key */ private String tokenHeaderKey = "authtoken"; - /** - * jwt token过期分钟数 - */ - @Deprecated - private int jwtTokenExpiresMinutes = 60; - /** * token过期分钟数 */ diff --git a/diboot-iam-starter/src/main/java/com/diboot/iam/starter/IamRedisAutoConfig.java b/diboot-iam-starter/src/main/java/com/diboot/iam/starter/IamRedisAutoConfig.java index 2351fb0b399846c0c84e2755110d753a9a388752..05b71f429e948c60efba0f18be958135aac651ba 100644 --- a/diboot-iam-starter/src/main/java/com/diboot/iam/starter/IamRedisAutoConfig.java +++ b/diboot-iam-starter/src/main/java/com/diboot/iam/starter/IamRedisAutoConfig.java @@ -71,7 +71,7 @@ public class IamRedisAutoConfig { @ConditionalOnMissingBean(CacheManager.class) public CacheManager shiroCacheManager(RedisTemplate redisTemplate) { log.info("初始化shiro缓存: ShiroRedisCacheManager"); - return new ShiroRedisCacheManager(redisTemplate, iamProperties.getJwtTokenExpiresMinutes()); + return new ShiroRedisCacheManager(redisTemplate, iamProperties.getTokenExpiresMinutes()); } /** diff --git a/diboot-iam-starter/src/main/java/com/diboot/iam/util/IamSecurityUtils.java b/diboot-iam-starter/src/main/java/com/diboot/iam/util/IamSecurityUtils.java index 2a8d0aef7885f1043e6d2a1d54274366f33c9fec..2d28e23e38c87168a09d7f873c16bdcfef303e84 100644 --- a/diboot-iam-starter/src/main/java/com/diboot/iam/util/IamSecurityUtils.java +++ b/diboot-iam-starter/src/main/java/com/diboot/iam/util/IamSecurityUtils.java @@ -91,6 +91,7 @@ public class IamSecurityUtils extends SecurityUtils { BaseLoginUser user = (BaseLoginUser) principalCollection.getPrimaryPrincipal(); if (userTypeAndId.equals(user.getUserTypeAndId())) { cacheManager.getCache(Cons.AUTHENTICATION_CAHCE_NAME).remove(authInfo.getCredentials()); + TokenUtils.removeAccessTokens(principalCollection.toString()); log.info("强制退出用户: {}", userTypeAndId); } } diff --git a/diboot-iam-starter/src/main/resources/META-INF/sql/init-iam-mysql.sql b/diboot-iam-starter/src/main/resources/META-INF/sql/init-iam-mysql.sql index c720caa148e548dcfb93b48e86b2ffcf010900c4..10f80894d66c29d901604c3e82d34c30ad8bc494 100644 --- a/diboot-iam-starter/src/main/resources/META-INF/sql/init-iam-mysql.sql +++ b/diboot-iam-starter/src/main/resources/META-INF/sql/init-iam-mysql.sql @@ -197,7 +197,7 @@ create index idx_iam_position_tenant on iam_position (tenant_id); -- 用户岗位 create table iam_user_position ( - id int auto_increment comment 'ID' primary key, + id bigint auto_increment comment 'ID' primary key, tenant_id bigint NOT NULL DEFAULT 0 COMMENT '租户ID', user_type varchar(100) default 'IamUser' not null comment '用户类型', user_id bigint not null comment '用户ID', @@ -215,8 +215,8 @@ create index idx_iam_user_position_2 on iam_user_position (org_id, position_id); -- 系统配置表 CREATE TABLE `system_config` ( - `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID', - `tenant_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '租户ID', + `id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID', + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户ID', `type` varchar(50) CHARACTER SET utf8 NOT NULL COMMENT '类型', `prop` varchar(50) CHARACTER SET utf8 NOT NULL COMMENT '属性', `value` varchar(255) CHARACTER SET utf8 NULL DEFAULT NULL COMMENT '属性值', diff --git a/diboot-message-starter/pom.xml b/diboot-message-starter/pom.xml index b871c52c99d959ca78f04751efd31adbbc66d459..ea75436d09bb4653df82400422b1e9328be5d2a3 100644 --- a/diboot-message-starter/pom.xml +++ b/diboot-message-starter/pom.xml @@ -5,12 +5,12 @@ diboot-root com.diboot - 2.6.0 + 2.7.0 4.0.0 diboot-message-spring-boot-starter - 2.6.0 + 2.7.0 jar diboot消息组件 diff --git a/diboot-message-starter/src/main/java/com/diboot/message/channel/SystemMessageChannel.java b/diboot-message-starter/src/main/java/com/diboot/message/channel/SystemMessageChannel.java new file mode 100644 index 0000000000000000000000000000000000000000..403c286146fa26366e9466be60602714bb0d2027 --- /dev/null +++ b/diboot-message-starter/src/main/java/com/diboot/message/channel/SystemMessageChannel.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015-2021, www.dibo.ltd (service@dibo.ltd). + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.diboot.message.channel; + +import com.diboot.message.config.Cons; +import com.diboot.message.entity.Message; + +/** + * 系统消息通道 + * + * @author : wind + * @version : v2.7.0 + * @Date 2022/08/16 15:55 + */ +public class SystemMessageChannel implements MessageChannel { + + @Override + public String type() { + return Cons.MESSAGE_CHANNEL.SYS_MSG.name(); + } + + @Override + public void send(Message message) { + + } + +} diff --git a/diboot-message-starter/src/main/java/com/diboot/message/entity/BaseUserVariables.java b/diboot-message-starter/src/main/java/com/diboot/message/entity/BaseUserVariables.java index cfdd6300db1e42e6854d50c39193a03197a63fc5..89846b45dcd35b793b22f36756c4bba17a782a49 100644 --- a/diboot-message-starter/src/main/java/com/diboot/message/entity/BaseUserVariables.java +++ b/diboot-message-starter/src/main/java/com/diboot/message/entity/BaseUserVariables.java @@ -43,9 +43,9 @@ public class BaseUserVariables implements Serializable { private String realName; /** - * 称呼 + * 标题 */ - @BindVariable(name = "${称呼}") + @BindVariable(name = "${标题}") private String title; /** diff --git a/diboot-message-starter/src/main/java/com/diboot/message/service/impl/MessageServiceImpl.java b/diboot-message-starter/src/main/java/com/diboot/message/service/impl/MessageServiceImpl.java index 4bebc67eac839effae4891e88a400282751f1c0d..6e9661c1f07ff50f5e739208b5c97ba1221758be 100644 --- a/diboot-message-starter/src/main/java/com/diboot/message/service/impl/MessageServiceImpl.java +++ b/diboot-message-starter/src/main/java/com/diboot/message/service/impl/MessageServiceImpl.java @@ -28,6 +28,7 @@ import com.diboot.message.entity.Message; import com.diboot.message.entity.MessageTemplate; import com.diboot.message.mapper.MessageMapper; import com.diboot.message.service.MessageService; +import com.diboot.message.service.MessageTemplateService; import com.diboot.message.utils.TemplateUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -50,7 +51,7 @@ public class MessageServiceImpl extends BaseServiceImpl @Lazy @Autowired - private MessageTemplateServiceImpl messageTemplateService; + private MessageTemplateService messageTemplateService; /** * 发送通道 diff --git a/diboot-message-starter/src/main/java/com/diboot/message/starter/MessageAutoConfig.java b/diboot-message-starter/src/main/java/com/diboot/message/starter/MessageAutoConfig.java index 112ae2060ae73d4836a569ed338c970c460feb62..c5798142ed15bef4f31969595096223205b2d24d 100644 --- a/diboot-message-starter/src/main/java/com/diboot/message/starter/MessageAutoConfig.java +++ b/diboot-message-starter/src/main/java/com/diboot/message/starter/MessageAutoConfig.java @@ -16,6 +16,7 @@ package com.diboot.message.starter; import com.diboot.message.channel.SimpleEmailChannel; +import com.diboot.message.channel.SystemMessageChannel; import com.diboot.message.entity.BaseUserVariables; import com.diboot.message.service.MessageService; import com.diboot.message.service.impl.MessageServiceImpl; @@ -50,7 +51,7 @@ public class MessageAutoConfig { @ConditionalOnMissingBean public MessageService messageService() { return new MessageServiceImpl( - Arrays.asList(new SimpleEmailChannel()), + Arrays.asList(new SimpleEmailChannel(), new SystemMessageChannel()), Arrays.asList(BaseUserVariables.class) ); } diff --git a/diboot-mobile-starter/pom.xml b/diboot-mobile-starter/pom.xml index d5c2d3557388833e655bfadbe0855af0e9c643d9..82e837eafa93f1794a7e21782b659c2dc6ac2f44 100644 --- a/diboot-mobile-starter/pom.xml +++ b/diboot-mobile-starter/pom.xml @@ -6,7 +6,7 @@ diboot-root com.diboot - 2.6.0 + 2.7.0 com.diboot @@ -15,7 +15,7 @@ diboot mobile starter project - 4.3.0 + 4.4.0 diff --git a/diboot-mobile-starter/src/main/java/com/diboot/mobile/auth/impl/WxAuthServiceImpl.java b/diboot-mobile-starter/src/main/java/com/diboot/mobile/auth/impl/WxAuthServiceImpl.java index 11ddd32ea944f54977f5b42a1d9db6978b507741..ea23c71539b2654e5e60b7f9ce95e39afe48b2e3 100644 --- a/diboot-mobile-starter/src/main/java/com/diboot/mobile/auth/impl/WxAuthServiceImpl.java +++ b/diboot-mobile-starter/src/main/java/com/diboot/mobile/auth/impl/WxAuthServiceImpl.java @@ -56,7 +56,7 @@ public class WxAuthServiceImpl extends BaseAuthServiceImpl { } /** - * 初始化JwtAuthToken实例 + * 初始化AuthToken实例 * @param credential * @return */ @@ -66,6 +66,7 @@ public class WxAuthServiceImpl extends BaseAuthServiceImpl { // 设置登陆的 token.setAuthAccount(wxMpCredential.getAuthAccount()); token.setRememberMe(wxMpCredential.isRememberMe()); + token.setExpiresInMinutes(getExpiresInMinutes()); // 生成token return token.generateAuthtoken(); } diff --git a/diboot-mobile-ui/uview-ui/components/u-action-sheet/u-action-sheet.vue b/diboot-mobile-ui/uview-ui/components/u-action-sheet/u-action-sheet.vue index 722b668b1254c24452603e73d6ce596e97054bb7..c938c9b3772dd876db7add0a89b10480170e3cac 100644 --- a/diboot-mobile-ui/uview-ui/components/u-action-sheet/u-action-sheet.vue +++ b/diboot-mobile-ui/uview-ui/components/u-action-sheet/u-action-sheet.vue @@ -153,7 +153,7 @@ \ No newline at end of file + diff --git a/diboot-mobile-ui/uview-ui/components/u-car-keyboard/u-car-keyboard.vue b/diboot-mobile-ui/uview-ui/components/u-car-keyboard/u-car-keyboard.vue index 84b14678e2e82fd200ef6c15930f415a8d4df1df..338be7b3b5098062c2f849cd2c625e16921168d3 100644 --- a/diboot-mobile-ui/uview-ui/components/u-car-keyboard/u-car-keyboard.vue +++ b/diboot-mobile-ui/uview-ui/components/u-car-keyboard/u-car-keyboard.vue @@ -167,7 +167,7 @@ diff --git a/diboot-mobile-ui/uview-ui/components/u-column-notice/u-column-notice.vue b/diboot-mobile-ui/uview-ui/components/u-column-notice/u-column-notice.vue index dd8bd3182d5dc207dd116b6c306c9ee59b3622d3..59d90073c21815b1ee9b04b04ca6701698d8dcc9 100644 --- a/diboot-mobile-ui/uview-ui/components/u-column-notice/u-column-notice.vue +++ b/diboot-mobile-ui/uview-ui/components/u-column-notice/u-column-notice.vue @@ -189,7 +189,7 @@ export default { diff --git a/diboot-mobile-ui/uview-ui/components/u-dropdown/u-dropdown.vue b/diboot-mobile-ui/uview-ui/components/u-dropdown/u-dropdown.vue index a62e469aee7574d8b9666b37b869a0acdd8bedd7..b468108aeb18947f47230ebeb595b1f354dc7dad 100644 --- a/diboot-mobile-ui/uview-ui/components/u-dropdown/u-dropdown.vue +++ b/diboot-mobile-ui/uview-ui/components/u-dropdown/u-dropdown.vue @@ -229,7 +229,7 @@ diff --git a/diboot-mobile-ui/uview-ui/components/u-full-screen/u-full-screen.vue b/diboot-mobile-ui/uview-ui/components/u-full-screen/u-full-screen.vue index 4f7e7d95b1ed390301de5a5f9cebd9a1b1076380..c7d6b31d02f1afe05eba74b26b7cbcca853b73df 100644 --- a/diboot-mobile-ui/uview-ui/components/u-full-screen/u-full-screen.vue +++ b/diboot-mobile-ui/uview-ui/components/u-full-screen/u-full-screen.vue @@ -37,7 +37,7 @@ diff --git a/diboot-mobile-ui/uview-ui/components/u-grid-item/u-grid-item.vue b/diboot-mobile-ui/uview-ui/components/u-grid-item/u-grid-item.vue index 0773307c26c0d38cccb27da1cf0319908303f498..e1723438683527e6e73aa9df53f829d9005667b5 100644 --- a/diboot-mobile-ui/uview-ui/components/u-grid-item/u-grid-item.vue +++ b/diboot-mobile-ui/uview-ui/components/u-grid-item/u-grid-item.vue @@ -80,7 +80,7 @@