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;
/**
* 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;
}
}

View File

@ -53,6 +53,10 @@ public class ParserCache {
* entity类-表名的缓存
*/
private static Map<String, String> entityClassTableCacheMap = new ConcurrentHashMap<>();
/**
* entity类小驼峰-entity类
*/
private static Map<String, Class<?>> 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对象

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);
List<KeyValue> keyValueList = new ArrayList<>(mapList.size());
for(Map<String, Object> 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())){

View File

@ -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<String, Filter> 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);

View File

@ -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
*/