add: 新增通用attachMore接口

This commit is contained in:
wuy 2020-06-12 13:23:09 +08:00
parent 993cb2e527
commit 1a4d50a25e
7 changed files with 260 additions and 21 deletions

View File

@ -31,6 +31,11 @@ public class CoreProperties {
*/ */
private boolean initSql = true; private boolean initSql = true;
/**
* kv查询的长度
*/
private Integer kvLimitCount = 100;
public boolean isInitSql() { public boolean isInitSql() {
return initSql; return initSql;
} }
@ -38,4 +43,12 @@ public class CoreProperties {
public void setInitSql(boolean initSql) { public void setInitSql(boolean initSql) {
this.initSql = initSql; this.initSql = initSql;
} }
public Integer getKvLimitCount() {
return kvLimitCount;
}
public void setKvLimitCount(Integer kvLimitCount) {
this.kvLimitCount = kvLimitCount;
}
} }

View File

@ -53,6 +53,10 @@ public class ParserCache {
* entity类-表名的缓存 * entity类-表名的缓存
*/ */
private static Map<String, String> entityClassTableCacheMap = new ConcurrentHashMap<>(); private static Map<String, String> entityClassTableCacheMap = new ConcurrentHashMap<>();
/**
* entity类小驼峰-entity类
*/
private static Map<String, Class<?>> entityLowerCaseCamelEntityClassCacheMap = new ConcurrentHashMap<>();
/** /**
* dto类-BindQuery注解的缓存 * dto类-BindQuery注解的缓存
*/ */
@ -117,6 +121,7 @@ public class ParserCache {
Class<?> entityClass = Class.forName(entityClassName); Class<?> entityClass = Class.forName(entityClassName);
TableLinkage linkage = new TableLinkage(entityClass, m); TableLinkage linkage = new TableLinkage(entityClass, m);
tableToLinkageCacheMap.put(linkage.getTable(), linkage); tableToLinkageCacheMap.put(linkage.getTable(), linkage);
entityLowerCaseCamelEntityClassCacheMap.put(entityClass.getSimpleName(), entityClass);
} }
} }
} }
@ -169,6 +174,16 @@ public class ParserCache {
return tableName; return tableName;
} }
/**
* 根据类的entity小驼峰获取EntityClass
* @return
*/
public static Class<?> getEntityClassByEntityLowerCaseCamel(String table){
initTableToLinkageCacheMap();
return entityLowerCaseCamelEntityClassCacheMap.get(table);
}
/** /**
* 当前DTO是否有Join绑定 * 当前DTO是否有Join绑定
* @param dto dto对象 * @param dto dto对象

View File

@ -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<AttachMoreDTO> attachMoreDTOList) {
Map<String, Object> 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<KeyValue> 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<KeyValue> 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);
}
}

View File

@ -0,0 +1,90 @@
package com.diboot.core.dto;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* attachMore 根据传递的格式自动加载相关的kvList
* <p>
* [{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
* <p>
* {@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;
}
}

View File

@ -447,6 +447,10 @@ public class BaseServiceImpl<M extends BaseCrudMapper<T>, T> extends ServiceImpl
String[] keyValueArray = sqlSelect.split(Cons.SEPARATOR_COMMA); String[] keyValueArray = sqlSelect.split(Cons.SEPARATOR_COMMA);
List<KeyValue> keyValueList = new ArrayList<>(mapList.size()); List<KeyValue> keyValueList = new ArrayList<>(mapList.size());
for(Map<String, Object> map : mapList){ for(Map<String, Object> map : mapList){
// 如果key和value的的值都为null的时候map也为空则不处理此项
if (V.isEmpty(map)) {
continue;
}
String key = keyValueArray[0], value = keyValueArray[1], ext = null; String key = keyValueArray[0], value = keyValueArray[1], ext = null;
// 兼容oracle大写 // 兼容oracle大写
if(map.containsKey(key) == false && map.containsKey(key.toUpperCase())){ if(map.containsKey(key) == false && map.containsKey(key.toUpperCase())){

View File

@ -23,13 +23,16 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.cache.CacheManager; import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.mgt.SessionsSecurityManager; import org.apache.shiro.mgt.SessionsSecurityManager;
import org.apache.shiro.realm.Realm; import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.mybatis.spring.annotation.MapperScan; import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties; 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 org.springframework.core.annotation.Order;
import javax.servlet.Filter; import javax.servlet.Filter;
@ -38,7 +41,8 @@ import java.util.Map;
/** /**
* IAM自动配置类 * IAM自动配置类
* @author : wee *
* @author : uu
* @version : v2.0 * @version : v2.0
* @Date 2019-10-11 10:54 * @Date 2019-10-11 10:54
*/ */
@ -46,7 +50,7 @@ import java.util.Map;
@Configuration @Configuration
@EnableConfigurationProperties({IamBaseProperties.class}) @EnableConfigurationProperties({IamBaseProperties.class})
@ComponentScan(basePackages = {"com.diboot.iam"}) @ComponentScan(basePackages = {"com.diboot.iam"})
@MapperScan(basePackages={"com.diboot.iam.mapper"}) @MapperScan(basePackages = {"com.diboot.iam.mapper"})
@Order(10) @Order(10)
public class IamBaseAutoConfig { public class IamBaseAutoConfig {
@ -55,7 +59,7 @@ public class IamBaseAutoConfig {
@Bean @Bean
@ConditionalOnMissingBean(IamBasePluginManager.class) @ConditionalOnMissingBean(IamBasePluginManager.class)
public IamBasePluginManager iamBasePluginManager(){ public IamBasePluginManager iamBasePluginManager() {
IamBasePluginManager pluginManager = new IamBasePluginManager(); IamBasePluginManager pluginManager = new IamBasePluginManager();
pluginManager.initPlugin(iamBaseProperties); pluginManager.initPlugin(iamBaseProperties);
System.out.println(iamBaseProperties); System.out.println(iamBaseProperties);
@ -64,19 +68,19 @@ public class IamBaseAutoConfig {
/** /**
* 根据用户配置的缓存类初始化CacheManager默认为Shiro内存缓存MemoryConstrainedCacheManager * 根据用户配置的缓存类初始化CacheManager默认为Shiro内存缓存MemoryConstrainedCacheManager
*
* @return * @return
*/ */
@Bean @Bean
@ConditionalOnMissingBean(CacheManager.class) @ConditionalOnMissingBean(CacheManager.class)
public CacheManager cacheManager() { public CacheManager cacheManager() {
String className = iamBaseProperties.getCacheManagerClass(); String className = iamBaseProperties.getCacheManagerClass();
if(V.isEmpty(className)){ if (V.isEmpty(className)) {
return null; return null;
} }
try{ try {
return (CacheManager) Class.forName(className).newInstance(); return (CacheManager) Class.forName(className).newInstance();
} } catch (Exception e) {
catch (Exception e){
log.warn("无法初始化CacheManager请检查配置: diboot.iam.cacheManagerClass"); log.warn("无法初始化CacheManager请检查配置: diboot.iam.cacheManagerClass");
return null; return null;
} }
@ -84,21 +88,26 @@ public class IamBaseAutoConfig {
@Bean @Bean
@DependsOn({"cacheManager"}) @DependsOn({"cacheManager"})
public Realm realm(){ public Realm realm() {
BaseJwtRealm realm = new BaseJwtRealm(); BaseJwtRealm realm = new BaseJwtRealm();
CacheManager cacheManager = cacheManager(); CacheManager cacheManager = cacheManager();
if(cacheManager != null){ if (cacheManager != null) {
realm.setCachingEnabled(true); realm.setCachingEnabled(true);
realm.setCacheManager(cacheManager); realm.setCacheManager(cacheManager);
} }
return realm; return realm;
} }
//TODO 支持无状态 @Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SessionsSecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
protected ShiroFilterFactoryBean shiroFilterFactoryBean(SessionsSecurityManager securityManager){ protected ShiroFilterFactoryBean shiroFilterFactoryBean(SessionsSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 设置过滤器 // 设置过滤器
Map<String, Filter> filters = new LinkedHashMap<>(); Map<String, Filter> filters = new LinkedHashMap<>();
@ -120,20 +129,19 @@ public class IamBaseAutoConfig {
boolean allAnon = false; boolean allAnon = false;
String anonUrls = iamBaseProperties.getAnonUrls(); String anonUrls = iamBaseProperties.getAnonUrls();
if(V.notEmpty(anonUrls)){ if (V.notEmpty(anonUrls)) {
for(String url : anonUrls.split(Cons.SEPARATOR_COMMA)){ for (String url : anonUrls.split(Cons.SEPARATOR_COMMA)) {
filterChainDefinitionMap.put(url, "anon"); filterChainDefinitionMap.put(url, "anon");
if(url.equals("/**")){ if (url.equals("/**")) {
allAnon = true; allAnon = true;
} }
} }
} }
filterChainDefinitionMap.put("/login", "authc"); filterChainDefinitionMap.put("/login", "authc");
filterChainDefinitionMap.put("/logout", "logout"); filterChainDefinitionMap.put("/logout", "logout");
if(allAnon && iamBaseProperties.isEnablePermissionCheck() == false){ if (allAnon && iamBaseProperties.isEnablePermissionCheck() == false) {
filterChainDefinitionMap.put("/**", "anon"); filterChainDefinitionMap.put("/**", "anon");
} } else {
else{
filterChainDefinitionMap.put("/**", "jwt"); filterChainDefinitionMap.put("/**", "jwt");
} }
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

View File

@ -18,11 +18,15 @@ package com.diboot.iam.starter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 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无法注入的问题 * Shiro代理相关配置类单独定义以避免Properties无法注入的问题
* @author : wee *
* @author : uu
* @version : v2.0 * @version : v2.0
* @Date 2019-10-11 10:54 * @Date 2019-10-11 10:54
*/ */