From 1a4d50a25e2e8fb81dec92671ed1ac34ddd66638 Mon Sep 17 00:00:00 2001 From: wuy <1311695042@qq.com> Date: Fri, 12 Jun 2020 13:23:09 +0800 Subject: [PATCH] =?UTF-8?q?add:=20=E6=96=B0=E5=A2=9E=E9=80=9A=E7=94=A8atta?= =?UTF-8?q?chMore=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../diboot/core/starter/CoreProperties.java | 13 +++ .../core/binding/parser/ParserCache.java | 15 +++ .../core/controller/AttachMoreController.java | 105 ++++++++++++++++++ .../com/diboot/core/dto/AttachMoreDTO.java | 90 +++++++++++++++ .../core/service/impl/BaseServiceImpl.java | 4 + .../diboot/iam/starter/IamBaseAutoConfig.java | 46 ++++---- .../diboot/iam/starter/ShiroProxyConfig.java | 8 +- 7 files changed, 260 insertions(+), 21 deletions(-) create mode 100644 diboot-core/src/main/java/com/diboot/core/controller/AttachMoreController.java create mode 100644 diboot-core/src/main/java/com/diboot/core/dto/AttachMoreDTO.java diff --git a/diboot-core-starter/src/main/java/com/diboot/core/starter/CoreProperties.java b/diboot-core-starter/src/main/java/com/diboot/core/starter/CoreProperties.java index 9a26243..29210f0 100644 --- a/diboot-core-starter/src/main/java/com/diboot/core/starter/CoreProperties.java +++ b/diboot-core-starter/src/main/java/com/diboot/core/starter/CoreProperties.java @@ -31,6 +31,11 @@ public class CoreProperties { */ private boolean initSql = true; + /** + * kv查询的长度 + */ + private Integer kvLimitCount = 100; + public boolean isInitSql() { return initSql; } @@ -38,4 +43,12 @@ public class CoreProperties { public void setInitSql(boolean initSql) { this.initSql = initSql; } + + public Integer getKvLimitCount() { + return kvLimitCount; + } + + public void setKvLimitCount(Integer kvLimitCount) { + this.kvLimitCount = kvLimitCount; + } } 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 e9f2738..ad9d317 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 @@ -53,6 +53,10 @@ public class ParserCache { * entity类-表名的缓存 */ private static Map entityClassTableCacheMap = new ConcurrentHashMap<>(); + /** + * entity类小驼峰-entity类 + */ + private static Map> entityLowerCaseCamelEntityClassCacheMap = new ConcurrentHashMap<>(); /** * dto类-BindQuery注解的缓存 */ @@ -117,6 +121,7 @@ public class ParserCache { Class entityClass = Class.forName(entityClassName); TableLinkage linkage = new TableLinkage(entityClass, m); tableToLinkageCacheMap.put(linkage.getTable(), linkage); + entityLowerCaseCamelEntityClassCacheMap.put(entityClass.getSimpleName(), entityClass); } } } @@ -169,6 +174,16 @@ public class ParserCache { return tableName; } + + /** + * 根据类的entity小驼峰获取EntityClass + * @return + */ + public static Class getEntityClassByEntityLowerCaseCamel(String table){ + initTableToLinkageCacheMap(); + return entityLowerCaseCamelEntityClassCacheMap.get(table); + } + /** * 当前DTO是否有Join绑定 * @param dto dto对象 diff --git a/diboot-core/src/main/java/com/diboot/core/controller/AttachMoreController.java b/diboot-core/src/main/java/com/diboot/core/controller/AttachMoreController.java new file mode 100644 index 0000000..3d347f1 --- /dev/null +++ b/diboot-core/src/main/java/com/diboot/core/controller/AttachMoreController.java @@ -0,0 +1,105 @@ +package com.diboot.core.controller; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.diboot.core.binding.parser.ParserCache; +import com.diboot.core.config.BaseConfig; +import com.diboot.core.dto.AttachMoreDTO; +import com.diboot.core.entity.Dictionary; +import com.diboot.core.entity.ValidList; +import com.diboot.core.service.BaseService; +import com.diboot.core.service.DictionaryService; +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.JsonResult; +import com.diboot.core.vo.KeyValue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 获取附加属性的通用接口 + * + * @author : uu + * @version : v2.0 + * @Date 2020/6/11 16:02 + */ +@RestController +@RequestMapping("/attachMore") +public class AttachMoreController { + + @Autowired + private DictionaryService dictionaryService; + + private final static Logger log = LoggerFactory.getLogger(AttachMoreController.class); + + /** + * 获取kvList的通用接口 + * + * @param attachMoreDTOList + * @return + */ + @PostMapping + public JsonResult attachMore(@Valid @RequestBody ValidList attachMoreDTOList) { + Map result = new HashMap<>(16); + String kvLimitCountStr = BaseConfig.getProperty("diboot.core.kv-limit-count", "100"); + Integer kvLimitCount = 100; + try { + kvLimitCount = Integer.valueOf(kvLimitCountStr); + } catch (Exception e) { + log.warn("diboot.core.kvLimitCount配置只能为整数,当前使用默认配置长度【100】", e); + } + for (AttachMoreDTO attachMoreDTO : attachMoreDTOList) { + AttachMoreDTO.REF_TYPE type = attachMoreDTO.getType(); + if (type.equals(AttachMoreDTO.REF_TYPE.D)) { + List keyValueList = dictionaryService.getKeyValueList( + Wrappers.query() + .select(S.toSnakeCase(BeanUtils.convertToFieldName(Dictionary::getItemName)), S.toSnakeCase(BeanUtils.convertToFieldName(Dictionary::getItemValue))) + .eq(S.toSnakeCase(BeanUtils.convertToFieldName(Dictionary::getType)), attachMoreDTO.getTarget()) + .gt(S.toSnakeCase(BeanUtils.convertToFieldName(Dictionary::getParentId)), 0) + .last("limit " + kvLimitCount) + ); + result.put(S.toLowerCaseCamel(attachMoreDTO.getTarget()) + "KvList", keyValueList); + } else if (type.equals(AttachMoreDTO.REF_TYPE.T)) { + String lowerCaseCamelEntityName = attachMoreDTO.getTarget(); + String entityClassName = S.capFirst(lowerCaseCamelEntityName); + Class entityClass = ParserCache.getEntityClassByEntityLowerCaseCamel(entityClassName); + if (V.isEmpty(entityClass)) { + log.warn("传递错误的实体类型:{}", attachMoreDTO.getTarget()); + continue; + } + String value = V.isEmpty(attachMoreDTO.getValue()) ? ContextHelper.getPrimaryKey(entityClass) : attachMoreDTO.getValue(); + String key = attachMoreDTO.getKey(); + if (V.isEmpty(key)) { + for (Field field : entityClass.getDeclaredFields()) { + if (V.equals(field.getType().getName(), String.class.getName())) { + key = field.getName(); + break; + } + } + } + BaseService baseService = ContextHelper.getBaseServiceByEntity(entityClass); + List keyValueList = baseService.getKeyValueList( + Wrappers.query() + .select(key, value) + .last("limit " + kvLimitCount) + ); + result.put(lowerCaseCamelEntityName + "KvList", keyValueList); + } else { + log.error("错误的加载绑定类型:{}", attachMoreDTO.getType()); + } + } + return JsonResult.OK(result); + } +} diff --git a/diboot-core/src/main/java/com/diboot/core/dto/AttachMoreDTO.java b/diboot-core/src/main/java/com/diboot/core/dto/AttachMoreDTO.java new file mode 100644 index 0000000..65fe6fc --- /dev/null +++ b/diboot-core/src/main/java/com/diboot/core/dto/AttachMoreDTO.java @@ -0,0 +1,90 @@ +package com.diboot.core.dto; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** + * attachMore 根据传递的格式,自动加载相关的kvList + *

+ * [{type: 'T', target: 'category', value: 'id', key: 'name’}, {type: 'D', target: 'GENDER'}] + * + * @author : uu + * @version : v2.0 + * @Date 2020/6/11 15:42 + */ +public class AttachMoreDTO implements Serializable { + /** + * 关联类型 + */ + public enum REF_TYPE { + /** + * 绑定的是对象 + */ + T, + /** + * 绑定的是字典 + */ + D + } + + /** + * 关联的类型 + */ + @NotNull(message = "绑定类型不能为空,且只能为:T或D类型!") + private REF_TYPE type; + + /** + * 指向的实体类 或者 字典的type + *

+ * 当{@link REF_TYPE#T} target指向实体的小驼峰命名 + * 当{@link REF_TYPE#D} target指向{@link com.diboot.core.entity.Dictionary#type} + */ + @NotNull(message = "查询类型不能为空!") + private String target; + + /** + * 需要的key字段 + * 当{@link REF_TYPE#T} key为表中字段名称 + * 当{@link REF_TYPE#D} key为表中{@link com.diboot.core.entity.Dictionary#itemName} + */ + private String key; + + /** + * 需要查询的value字段 + * 当{@link REF_TYPE#T} key为表中字段名称 + * 当{@link REF_TYPE#D} key为表中{@link com.diboot.core.entity.Dictionary#itemValue} + */ + private String value; + + public REF_TYPE getType() { + return type; + } + + public void setType(REF_TYPE type) { + this.type = type; + } + + public String getTarget() { + return target; + } + + public void setTarget(String target) { + this.target = target; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} 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 c7da2a6..120cbbe 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 @@ -447,6 +447,10 @@ public class BaseServiceImpl, T> extends ServiceImpl String[] keyValueArray = sqlSelect.split(Cons.SEPARATOR_COMMA); List keyValueList = new ArrayList<>(mapList.size()); for(Map map : mapList){ + // 如果key和value的的值都为null的时候map也为空,则不处理此项 + if (V.isEmpty(map)) { + continue; + } String key = keyValueArray[0], value = keyValueArray[1], ext = null; // 兼容oracle大写 if(map.containsKey(key) == false && map.containsKey(key.toUpperCase())){ diff --git a/iam-base-starter/src/main/java/com/diboot/iam/starter/IamBaseAutoConfig.java b/iam-base-starter/src/main/java/com/diboot/iam/starter/IamBaseAutoConfig.java index 1057633..3553c38 100644 --- a/iam-base-starter/src/main/java/com/diboot/iam/starter/IamBaseAutoConfig.java +++ b/iam-base-starter/src/main/java/com/diboot/iam/starter/IamBaseAutoConfig.java @@ -23,13 +23,16 @@ import lombok.extern.slf4j.Slf4j; import org.apache.shiro.cache.CacheManager; import org.apache.shiro.mgt.SessionsSecurityManager; import org.apache.shiro.realm.Realm; +import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.*; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; import org.springframework.core.annotation.Order; import javax.servlet.Filter; @@ -38,7 +41,8 @@ import java.util.Map; /** * IAM自动配置类 - * @author : wee + * + * @author : uu * @version : v2.0 * @Date 2019-10-11 10:54 */ @@ -46,7 +50,7 @@ import java.util.Map; @Configuration @EnableConfigurationProperties({IamBaseProperties.class}) @ComponentScan(basePackages = {"com.diboot.iam"}) -@MapperScan(basePackages={"com.diboot.iam.mapper"}) +@MapperScan(basePackages = {"com.diboot.iam.mapper"}) @Order(10) public class IamBaseAutoConfig { @@ -55,7 +59,7 @@ public class IamBaseAutoConfig { @Bean @ConditionalOnMissingBean(IamBasePluginManager.class) - public IamBasePluginManager iamBasePluginManager(){ + public IamBasePluginManager iamBasePluginManager() { IamBasePluginManager pluginManager = new IamBasePluginManager(); pluginManager.initPlugin(iamBaseProperties); System.out.println(iamBaseProperties); @@ -64,19 +68,19 @@ public class IamBaseAutoConfig { /** * 根据用户配置的缓存类初始化CacheManager,默认为Shiro内存缓存MemoryConstrainedCacheManager + * * @return */ @Bean @ConditionalOnMissingBean(CacheManager.class) public CacheManager cacheManager() { String className = iamBaseProperties.getCacheManagerClass(); - if(V.isEmpty(className)){ + if (V.isEmpty(className)) { return null; } - try{ + try { return (CacheManager) Class.forName(className).newInstance(); - } - catch (Exception e){ + } catch (Exception e) { log.warn("无法初始化CacheManager,请检查配置: diboot.iam.cacheManagerClass"); return null; } @@ -84,21 +88,26 @@ public class IamBaseAutoConfig { @Bean @DependsOn({"cacheManager"}) - public Realm realm(){ + public Realm realm() { BaseJwtRealm realm = new BaseJwtRealm(); CacheManager cacheManager = cacheManager(); - if(cacheManager != null){ + if (cacheManager != null) { realm.setCachingEnabled(true); realm.setCacheManager(cacheManager); } return realm; } - //TODO 支持无状态 + @Bean + public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SessionsSecurityManager securityManager) { + AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); + advisor.setSecurityManager(securityManager); + return advisor; + } @Bean @ConditionalOnMissingBean - protected ShiroFilterFactoryBean shiroFilterFactoryBean(SessionsSecurityManager securityManager){ + protected ShiroFilterFactoryBean shiroFilterFactoryBean(SessionsSecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 设置过滤器 Map filters = new LinkedHashMap<>(); @@ -120,20 +129,19 @@ public class IamBaseAutoConfig { boolean allAnon = false; String anonUrls = iamBaseProperties.getAnonUrls(); - if(V.notEmpty(anonUrls)){ - for(String url : anonUrls.split(Cons.SEPARATOR_COMMA)){ + if (V.notEmpty(anonUrls)) { + for (String url : anonUrls.split(Cons.SEPARATOR_COMMA)) { filterChainDefinitionMap.put(url, "anon"); - if(url.equals("/**")){ + if (url.equals("/**")) { allAnon = true; } } } filterChainDefinitionMap.put("/login", "authc"); filterChainDefinitionMap.put("/logout", "logout"); - if(allAnon && iamBaseProperties.isEnablePermissionCheck() == false){ + if (allAnon && iamBaseProperties.isEnablePermissionCheck() == false) { filterChainDefinitionMap.put("/**", "anon"); - } - else{ + } else { filterChainDefinitionMap.put("/**", "jwt"); } shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); diff --git a/iam-base-starter/src/main/java/com/diboot/iam/starter/ShiroProxyConfig.java b/iam-base-starter/src/main/java/com/diboot/iam/starter/ShiroProxyConfig.java index 20163e1..d29fefe 100644 --- a/iam-base-starter/src/main/java/com/diboot/iam/starter/ShiroProxyConfig.java +++ b/iam-base-starter/src/main/java/com/diboot/iam/starter/ShiroProxyConfig.java @@ -18,11 +18,15 @@ package com.diboot.iam.starter; import lombok.extern.slf4j.Slf4j; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.annotation.*; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; +import org.springframework.context.annotation.EnableAspectJAutoProxy; /** * Shiro代理相关配置类(单独定义以避免Properties无法注入的问题) - * @author : wee + * + * @author : uu * @version : v2.0 * @Date 2019-10-11 10:54 */