动态join支持通过中间表的关联
This commit is contained in:
parent
a980b290bb
commit
7327a356fe
|
@ -127,8 +127,10 @@ public class QueryBuilder {
|
|||
return new QueryWrapper<>();
|
||||
}
|
||||
QueryWrapper wrapper;
|
||||
// 只解析有值的
|
||||
fields = fieldValuesMap.keySet();
|
||||
// 是否有join联表查询
|
||||
boolean hasJoinTable = ParserCache.hasJoinTable(dto, fieldValuesMap.keySet());
|
||||
boolean hasJoinTable = ParserCache.hasJoinTable(dto, fields);
|
||||
if(hasJoinTable){
|
||||
wrapper = new DynamicJoinQueryWrapper<>(dto.getClass(), fields);
|
||||
}
|
||||
|
@ -337,7 +339,7 @@ public class QueryBuilder {
|
|||
try {
|
||||
value = field.get(dto);
|
||||
} catch (IllegalAccessException e) {
|
||||
log.error("通过反射获取属性值出错:" + e);
|
||||
log.error("通过反射获取属性值出错:{}", e.getMessage());
|
||||
}
|
||||
// 忽略逻辑删除字段
|
||||
if(Cons.FieldName.deleted.name().equals(field.getName())
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
package com.diboot.core.binding.binder;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.diboot.core.util.BeanUtils;
|
||||
import com.diboot.core.util.S;
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
package com.diboot.core.binding.binder;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.diboot.core.util.*;
|
||||
import org.slf4j.Logger;
|
||||
|
|
|
@ -16,11 +16,16 @@
|
|||
package com.diboot.core.binding.binder;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.diboot.core.util.*;
|
||||
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.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 关联字段绑定
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2020, www.dibo.ltd (service@dibo.ltd).
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* 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.binding.parser;
|
||||
|
||||
import com.diboot.core.util.S;
|
||||
import com.diboot.core.util.V;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
|
||||
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
|
||||
import net.sf.jsqlparser.schema.Column;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 条件管理器base类
|
||||
* @author mazc@dibo.ltd
|
||||
* @version v2.0
|
||||
* @date 2020/06/02
|
||||
*/
|
||||
@Slf4j
|
||||
public class BaseConditionManager {
|
||||
/**
|
||||
* 表达式缓存Map
|
||||
*/
|
||||
private static Map<String, List<Expression>> expressionParseResultMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 获取解析后的Expression列表
|
||||
* @param condition
|
||||
* @return
|
||||
*/
|
||||
protected static List<Expression> getExpressionList(String condition){
|
||||
if(V.isEmpty(condition)){
|
||||
return null;
|
||||
}
|
||||
List<Expression> expressionList = expressionParseResultMap.get(condition);
|
||||
if(expressionList == null){
|
||||
ConditionParser visitor = new ConditionParser();
|
||||
try{
|
||||
Expression expression = CCJSqlParserUtil.parseCondExpression(condition);
|
||||
expression.accept(visitor);
|
||||
expressionList = visitor.getExpressList();
|
||||
expressionParseResultMap.put(condition, expressionList);
|
||||
}
|
||||
catch (Exception e){
|
||||
log.error("关联条件解析异常", e);
|
||||
}
|
||||
}
|
||||
return expressionList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取中间表表对象名
|
||||
* @param expressionList
|
||||
* @return
|
||||
*/
|
||||
protected static String extractMiddleTableName(List<Expression> expressionList){
|
||||
Set<String> tableNameSet = new HashSet<>();
|
||||
for(Expression operator : expressionList){
|
||||
if(operator instanceof EqualsTo){
|
||||
EqualsTo express = (EqualsTo)operator;
|
||||
// 均为列
|
||||
if(express.getLeftExpression() instanceof Column && express.getRightExpression() instanceof Column){
|
||||
// 统计左侧列中出现的表名
|
||||
String leftColumn = express.getLeftExpression().toString();
|
||||
collectTableName(tableNameSet, leftColumn);
|
||||
// 统计右侧列中出现的表名
|
||||
String rightColumn = express.getRightExpression().toString();
|
||||
collectTableName(tableNameSet, rightColumn);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(tableNameSet.isEmpty()){
|
||||
return null;
|
||||
}
|
||||
if(tableNameSet.size() > 1){
|
||||
log.warn("中间表关联条件暂只支持1张中间表!");
|
||||
}
|
||||
return tableNameSet.iterator().next();
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计表名出现的次数
|
||||
* @param tableNameSet
|
||||
* @param columnStr
|
||||
*/
|
||||
private static void collectTableName(Set<String> tableNameSet, String columnStr) {
|
||||
if(!columnStr.contains(".")){
|
||||
return;
|
||||
}
|
||||
// 如果是中间表(非this,self标识的当前表)
|
||||
if(!isCurrentObjColumn(columnStr)){
|
||||
String tempTableName = S.substringBefore(columnStr, ".");
|
||||
tableNameSet.add(tempTableName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为VO自身属性(以this开头的)
|
||||
* @param expression
|
||||
* @return
|
||||
*/
|
||||
protected static boolean isCurrentObjColumn(String expression){
|
||||
String tempTableName = S.substringBefore(expression, ".");
|
||||
// 如果是中间表(非this,self标识的当前表)
|
||||
return "this".equals(tempTableName) || "self".equals(tempTableName);
|
||||
}
|
||||
}
|
|
@ -18,18 +18,13 @@ package com.diboot.core.binding.parser;
|
|||
import com.diboot.core.binding.binder.BaseBinder;
|
||||
import com.diboot.core.util.S;
|
||||
import com.diboot.core.util.V;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.*;
|
||||
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
|
||||
import net.sf.jsqlparser.schema.Column;
|
||||
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.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 条件表达式的管理器
|
||||
|
@ -37,38 +32,8 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
* @version v2.0
|
||||
* @date 2019/4/1
|
||||
*/
|
||||
public class ConditionManager {
|
||||
private static final Logger log = LoggerFactory.getLogger(ConditionManager.class);
|
||||
|
||||
/**
|
||||
* 表达式缓存Map
|
||||
*/
|
||||
private static Map<String, List<Expression>> expressionParseResultMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 获取解析后的Expression列表
|
||||
* @param condition
|
||||
* @return
|
||||
*/
|
||||
public static List<Expression> getExpressionList(String condition){
|
||||
if(V.isEmpty(condition)){
|
||||
return null;
|
||||
}
|
||||
List<Expression> expressionList = expressionParseResultMap.get(condition);
|
||||
if(expressionList == null){
|
||||
ConditionParser visitor = new ConditionParser();
|
||||
try{
|
||||
Expression expression = CCJSqlParserUtil.parseCondExpression(condition);
|
||||
expression.accept(visitor);
|
||||
expressionList = visitor.getExpressList();
|
||||
expressionParseResultMap.put(condition, expressionList);
|
||||
}
|
||||
catch (Exception e){
|
||||
log.error("关联条件解析异常", e);
|
||||
}
|
||||
}
|
||||
return expressionList;
|
||||
}
|
||||
@Slf4j
|
||||
public class ConditionManager extends BaseConditionManager{
|
||||
|
||||
/**
|
||||
* 附加条件到binder
|
||||
|
@ -241,7 +206,7 @@ public class ConditionManager {
|
|||
// 绑定左手边连接列
|
||||
String leftHandColumn = removeLeftAlias(leftColumn);
|
||||
// this. 开头的vo对象字段
|
||||
if(isVoColumn(leftColumn)){
|
||||
if(isCurrentObjColumn(leftColumn)){
|
||||
// 识别到vo对象的属性 departmentId
|
||||
annoObjectForeignKey = leftHandColumn;
|
||||
// 对应中间表的关联字段
|
||||
|
@ -259,7 +224,7 @@ public class ConditionManager {
|
|||
if(leftColumn.startsWith(tableName+".")){
|
||||
// 绑定右手边连接列
|
||||
String rightHandColumn = removeLeftAlias(rightColumn);
|
||||
if(isVoColumn(rightColumn)){
|
||||
if(isCurrentObjColumn(rightColumn)){
|
||||
// 识别到vo对象的属性 departmentId
|
||||
annoObjectForeignKey = rightHandColumn;
|
||||
// 对应中间表的关联字段
|
||||
|
@ -337,61 +302,6 @@ public class ConditionManager {
|
|||
return additionalExpressions;
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取中间表表对象名
|
||||
* @param expressionList
|
||||
* @return
|
||||
*/
|
||||
private static String extractMiddleTableName(List<Expression> expressionList){
|
||||
Map<String, Integer> tableNameCountMap = new HashMap<>();
|
||||
for(Expression operator : expressionList){
|
||||
if(operator instanceof EqualsTo){
|
||||
EqualsTo express = (EqualsTo)operator;
|
||||
// 均为列
|
||||
if(express.getLeftExpression() instanceof Column && express.getRightExpression() instanceof Column){
|
||||
// 统计左侧列中出现的表名
|
||||
String leftColumn = express.getLeftExpression().toString();
|
||||
countTableName(tableNameCountMap, leftColumn);
|
||||
// 统计右侧列中出现的表名
|
||||
String rightColumn = express.getRightExpression().toString();
|
||||
countTableName(tableNameCountMap, rightColumn);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(tableNameCountMap.isEmpty()){
|
||||
return null;
|
||||
}
|
||||
String tableName = null;
|
||||
int count = 1;
|
||||
for(Map.Entry<String, Integer> entry : tableNameCountMap.entrySet()){
|
||||
if(entry.getValue() > count){
|
||||
count = entry.getValue();
|
||||
tableName = entry.getKey();
|
||||
}
|
||||
}
|
||||
return tableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计表名出现的次数
|
||||
* @param tableNameCountMap
|
||||
* @param columnStr
|
||||
*/
|
||||
private static void countTableName(Map<String, Integer> tableNameCountMap, String columnStr) {
|
||||
if(columnStr.contains(".")){
|
||||
// 如果是中间表(非this,self标识的当前表)
|
||||
if(!isVoColumn(columnStr)){
|
||||
String tempTableName = S.substringBefore(columnStr, ".");
|
||||
Integer count = tableNameCountMap.get(tempTableName);
|
||||
if(count == null){
|
||||
count = 0;
|
||||
}
|
||||
count++;
|
||||
tableNameCountMap.put(tempTableName, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注解列
|
||||
* @return
|
||||
|
@ -403,15 +313,4 @@ public class ConditionManager {
|
|||
return annoColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为VO自身属性(以this开头的)
|
||||
* @param expression
|
||||
* @return
|
||||
*/
|
||||
private static boolean isVoColumn(String expression){
|
||||
String tempTableName = S.substringBefore(expression, ".");
|
||||
// 如果是中间表(非this,self标识的当前表)
|
||||
return "this".equals(tempTableName) || "self".equals(tempTableName);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,8 +15,11 @@
|
|||
*/
|
||||
package com.diboot.core.binding.parser;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.diboot.core.config.BaseConfig;
|
||||
import com.diboot.core.config.Cons;
|
||||
import com.diboot.core.util.ContextHelper;
|
||||
import com.diboot.core.util.S;
|
||||
import com.diboot.core.util.SqlExecutor;
|
||||
import com.diboot.core.util.V;
|
||||
|
@ -101,15 +104,21 @@ public class MiddleTable {
|
|||
* @return
|
||||
*/
|
||||
public Map<String, Object> executeOneToOneQuery(List annoObjectForeignKeyList){
|
||||
// 提取中间表查询SQL: SELECT id, org_id FROM department WHERE id IN(?)
|
||||
String sql = toSQL(annoObjectForeignKeyList);
|
||||
// 执行查询并合并结果
|
||||
//id
|
||||
String keyName = getEqualsToAnnoObjectFKColumn(),
|
||||
//org_id
|
||||
valueName = getEqualsToRefEntityPkColumn();
|
||||
Map<String, Object> middleTableResultMap = SqlExecutor.executeQueryAndMergeOneToOneResult(sql, annoObjectForeignKeyList, keyName, valueName);
|
||||
return middleTableResultMap;
|
||||
//id //org_id
|
||||
String keyName = getEqualsToAnnoObjectFKColumn(), valueName = getEqualsToRefEntityPkColumn();
|
||||
TableLinkage linkage = ParserCache.getTableLinkage(table);
|
||||
// 有定义mapper,首选mapper
|
||||
if(linkage != null){
|
||||
List<Map<String, Object>> resultSetMapList = queryByMapper(linkage, annoObjectForeignKeyList);
|
||||
return SqlExecutor.convertToOneToOneResult(resultSetMapList, keyName, valueName);
|
||||
}
|
||||
else{
|
||||
// 提取中间表查询SQL: SELECT id, org_id FROM department WHERE id IN(?)
|
||||
String sql = toSQL(annoObjectForeignKeyList);
|
||||
// 执行查询并合并结果
|
||||
Map<String, Object> middleTableResultMap = SqlExecutor.executeQueryAndMergeOneToOneResult(sql, annoObjectForeignKeyList, keyName, valueName);
|
||||
return middleTableResultMap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -118,15 +127,42 @@ public class MiddleTable {
|
|||
* @return
|
||||
*/
|
||||
public Map<String, List> executeOneToManyQuery(List annoObjectForeignKeyList){
|
||||
// 提取中间表查询SQL: SELECT user_id, role_id FROM user_role WHERE user_id IN(?)
|
||||
String sql = toSQL(annoObjectForeignKeyList);
|
||||
// 执行查询并合并结果
|
||||
//user_id
|
||||
String keyName = getEqualsToAnnoObjectFKColumn(),
|
||||
//role_id
|
||||
valueName = getEqualsToRefEntityPkColumn();
|
||||
Map<String, List> middleTableResultMap = SqlExecutor.executeQueryAndMergeOneToManyResult(sql, annoObjectForeignKeyList, keyName, valueName);
|
||||
return middleTableResultMap;
|
||||
//user_id //role_id
|
||||
String keyName = getEqualsToAnnoObjectFKColumn(), valueName = getEqualsToRefEntityPkColumn();
|
||||
TableLinkage linkage = ParserCache.getTableLinkage(table);
|
||||
// 有定义mapper,首选mapper
|
||||
if(linkage != null){
|
||||
List<Map<String, Object>> resultSetMapList = queryByMapper(linkage, annoObjectForeignKeyList);
|
||||
return SqlExecutor.convertToOneToManyResult(resultSetMapList, keyName, valueName);
|
||||
}
|
||||
else{
|
||||
// 提取中间表查询SQL: SELECT user_id, role_id FROM user_role WHERE user_id IN(?)
|
||||
String sql = toSQL(annoObjectForeignKeyList);
|
||||
// 执行查询并合并结果
|
||||
Map<String, List> middleTableResultMap = SqlExecutor.executeQueryAndMergeOneToManyResult(sql, annoObjectForeignKeyList, keyName, valueName);
|
||||
return middleTableResultMap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过定义的Mapper查询结果
|
||||
* @param linkage
|
||||
* @param annoObjectForeignKeyList
|
||||
* @return
|
||||
*/
|
||||
private List<Map<String, Object>> queryByMapper(TableLinkage linkage, List annoObjectForeignKeyList){
|
||||
BaseMapper mapper = (BaseMapper) ContextHelper.getBean(linkage.getMapperClass());
|
||||
QueryWrapper queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.setEntityClass(linkage.getEntityClass());
|
||||
queryWrapper.select(equalsToAnnoObjectFKColumn, equalsToRefEntityPkColumn);
|
||||
queryWrapper.in(equalsToAnnoObjectFKColumn, annoObjectForeignKeyList);
|
||||
if(additionalConditions != null){
|
||||
for(String condition : additionalConditions){
|
||||
queryWrapper.apply(condition);
|
||||
}
|
||||
}
|
||||
List<Map<String, Object>> resultSetMapList = mapper.selectMaps(queryWrapper);
|
||||
return resultSetMapList;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -134,7 +170,7 @@ public class MiddleTable {
|
|||
* @param annoObjectForeignKeyList 注解外键值的列表,用于拼接SQL查询
|
||||
* @return
|
||||
*/
|
||||
public String toSQL(List annoObjectForeignKeyList){
|
||||
private String toSQL(List annoObjectForeignKeyList){
|
||||
if(V.isEmpty(annoObjectForeignKeyList)){
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -18,12 +18,12 @@ package com.diboot.core.binding.parser;
|
|||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.diboot.core.binding.query.BindQuery;
|
||||
import com.diboot.core.binding.query.dynamic.AnnoJoiner;
|
||||
import com.diboot.core.config.Cons;
|
||||
import com.diboot.core.util.BeanUtils;
|
||||
import com.diboot.core.util.ContextHelper;
|
||||
import com.diboot.core.util.S;
|
||||
import com.diboot.core.util.SqlExecutor;
|
||||
import com.diboot.core.util.V;
|
||||
import org.apache.ibatis.jdbc.SQL;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
@ -39,15 +39,16 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
* @version 2.0<br>
|
||||
* @date 2019/04/03 <br>
|
||||
*/
|
||||
@Slf4j
|
||||
public class ParserCache {
|
||||
/**
|
||||
* VO类-绑定注解缓存
|
||||
*/
|
||||
private static Map<Class, BindAnnotationGroup> allVoBindAnnotationCacheMap = new ConcurrentHashMap<>();
|
||||
/**
|
||||
* 中间表是否包含is_deleted列 缓存
|
||||
* 表及相关信息的缓存
|
||||
*/
|
||||
private static Map<String, Boolean> middleTableHasDeletedCacheMap = new ConcurrentHashMap<>();
|
||||
private static Map<String, TableLinkage> tableToLinkageCacheMap = new ConcurrentHashMap<>();
|
||||
/**
|
||||
* entity类-表名的缓存
|
||||
*/
|
||||
|
@ -97,29 +98,54 @@ public class ParserCache {
|
|||
}
|
||||
|
||||
/**
|
||||
* 是否有is_deleted列
|
||||
* @return
|
||||
* 初始化Table的相关对象信息
|
||||
*/
|
||||
public static boolean hasDeletedColumn(String middleTable){
|
||||
if(middleTableHasDeletedCacheMap.containsKey(middleTable)){
|
||||
return middleTableHasDeletedCacheMap.get(middleTable);
|
||||
private static void initTableToLinkageCacheMap(){
|
||||
if(tableToLinkageCacheMap.isEmpty()){
|
||||
SqlSessionFactory sqlSessionFactory = ContextHelper.getBean(SqlSessionFactory.class);
|
||||
Collection<Class<?>> mappers = sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers();
|
||||
if(V.notEmpty(mappers)){
|
||||
mappers.forEach(m->{
|
||||
Type[] types = m.getGenericInterfaces();
|
||||
try{
|
||||
if(types != null && types.length > 0 && types[0] != null){
|
||||
ParameterizedType genericType = (ParameterizedType) types[0];
|
||||
Type[] superTypes = genericType.getActualTypeArguments();
|
||||
if(superTypes != null && superTypes.length > 0 && superTypes[0] != null){
|
||||
String entityClassName = superTypes[0].getTypeName();
|
||||
if(entityClassName.length() > 1){
|
||||
Class<?> entityClass = Class.forName(entityClassName);
|
||||
TableLinkage linkage = new TableLinkage(entityClass, m);
|
||||
tableToLinkageCacheMap.put(linkage.getTable(), linkage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e){
|
||||
log.warn("解析mapper异常", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
boolean hasColumn = SqlExecutor.validateQuery(buildCheckDeletedColSql(middleTable));
|
||||
middleTableHasDeletedCacheMap.put(middleTable, hasColumn);
|
||||
return hasColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建检测是否有删除字段的sql
|
||||
* @param table
|
||||
* 是否有is_deleted列
|
||||
* @return
|
||||
*/
|
||||
private static String buildCheckDeletedColSql(String table){
|
||||
return new SQL(){{
|
||||
SELECT(Cons.COLUMN_IS_DELETED);
|
||||
FROM(table);
|
||||
LIMIT(1);
|
||||
}}.toString();
|
||||
public static boolean hasDeletedColumn(String table){
|
||||
TableLinkage linkage = getTableLinkage(table);
|
||||
return linkage != null && linkage.isHasDeleted();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取table相关信息
|
||||
* @return
|
||||
*/
|
||||
public static TableLinkage getTableLinkage(String table){
|
||||
initTableToLinkageCacheMap();
|
||||
TableLinkage linkage = tableToLinkageCacheMap.get(table);
|
||||
return linkage;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -150,7 +176,7 @@ public class ParserCache {
|
|||
* @param <DTO>
|
||||
* @return
|
||||
*/
|
||||
public static <DTO> boolean hasJoinTable(DTO dto, Set<String> fieldNameSet){
|
||||
public static <DTO> boolean hasJoinTable(DTO dto, Collection<String> fieldNameSet){
|
||||
List<AnnoJoiner> annoList = getBindQueryAnnos(dto.getClass());
|
||||
if(V.notEmpty(annoList)){
|
||||
for(AnnoJoiner anno : annoList){
|
||||
|
@ -199,6 +225,7 @@ public class ParserCache {
|
|||
else{
|
||||
annoJoiner.setAlias(alias);
|
||||
}
|
||||
annoJoiner.parse();
|
||||
}
|
||||
annos.add(annoJoiner);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2020, www.dibo.ltd (service@dibo.ltd).
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* 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.binding.parser;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.diboot.core.config.Cons;
|
||||
import com.diboot.core.util.BeanUtils;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* table的相关线索信息
|
||||
* @author mazc
|
||||
* @version v1.0
|
||||
* @date 2020/06/02
|
||||
*/
|
||||
@Getter @Setter
|
||||
public class TableLinkage implements Serializable {
|
||||
private static final long serialVersionUID = 4416187849283913895L;
|
||||
|
||||
public TableLinkage(Class<?> entityClass, Class<?> mapperClass){
|
||||
this.entityClass = entityClass;
|
||||
this.mapperClass = mapperClass;
|
||||
this.table = ParserCache.getEntityTableName(entityClass);
|
||||
// 初始化是否有is_deleted
|
||||
Field field = BeanUtils.extractField(entityClass, Cons.FieldName.deleted.name());
|
||||
if(field != null){
|
||||
TableField tableField = field.getAnnotation(TableField.class);
|
||||
if(tableField != null && tableField.exist() == true){
|
||||
this.hasDeleted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String table;
|
||||
/**
|
||||
* 表对应的entity类
|
||||
*/
|
||||
private Class<?> entityClass;
|
||||
|
||||
/**
|
||||
* 表对应的mapper类
|
||||
*/
|
||||
private Class<?> mapperClass;
|
||||
|
||||
/**
|
||||
* 是否有逻辑删除字段
|
||||
*/
|
||||
private boolean hasDeleted = false;
|
||||
|
||||
}
|
|
@ -67,23 +67,42 @@ public class AnnoJoiner implements Serializable {
|
|||
|
||||
private String columnName;
|
||||
|
||||
private String join;
|
||||
private String condition;
|
||||
|
||||
private String join;
|
||||
/**
|
||||
* 别名
|
||||
*/
|
||||
private String alias;
|
||||
|
||||
private String condition;
|
||||
/**
|
||||
* on条件
|
||||
*/
|
||||
private String onSegment;
|
||||
|
||||
/**
|
||||
* 获取On条件
|
||||
* @return
|
||||
* 中间表
|
||||
*/
|
||||
public String getOnSegment(){
|
||||
if(V.notEmpty(condition)){
|
||||
return JoinConditionParser.parseJoinCondition(this.condition, this.alias);
|
||||
private String middleTable;
|
||||
|
||||
/**
|
||||
* 中间表别名
|
||||
*/
|
||||
public String getMiddleTableAlias(){
|
||||
if(middleTable != null && alias != null){
|
||||
return alias+"m";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* 中间表on
|
||||
*/
|
||||
private String middleTableOnSegment;
|
||||
|
||||
/**
|
||||
* 解析
|
||||
*/
|
||||
public void parse(){
|
||||
// 解析查询
|
||||
JoinConditionManager.parseJoinCondition(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,6 +89,18 @@ public class DynamicSqlProvider {
|
|||
StringBuilder sb = new StringBuilder();
|
||||
for(AnnoJoiner joiner : annoJoinerList){
|
||||
if(V.notEmpty(joiner.getJoin()) && V.notEmpty(joiner.getOnSegment())){
|
||||
if(joiner.getMiddleTable() != null){
|
||||
sb.setLength(0);
|
||||
sb.append(joiner.getMiddleTable()).append(" ").append(joiner.getMiddleTableAlias()).append(" ON ").append(joiner.getMiddleTableOnSegment());
|
||||
if(S.containsIgnoreCase(joiner.getMiddleTable(), " "+Cons.COLUMN_IS_DELETED) == false && ParserCache.hasDeletedColumn(joiner.getMiddleTable())){
|
||||
sb.append(" AND ").append(joiner.getMiddleTableAlias()).append(".").append(Cons.COLUMN_IS_DELETED).append(" = ").append(BaseConfig.getActiveFlagValue());
|
||||
}
|
||||
String joinSegment = sb.toString();
|
||||
if(!tempSet.contains(joinSegment)){
|
||||
LEFT_OUTER_JOIN(joinSegment);
|
||||
tempSet.add(joinSegment);
|
||||
}
|
||||
}
|
||||
sb.setLength(0);
|
||||
sb.append(joiner.getJoin()).append(" ").append(joiner.getAlias()).append(" ON ").append(joiner.getOnSegment());
|
||||
if(S.containsIgnoreCase(joiner.getOnSegment(), " "+Cons.COLUMN_IS_DELETED) == false && ParserCache.hasDeletedColumn(joiner.getJoin())){
|
||||
|
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2020, www.dibo.ltd (service@dibo.ltd).
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* 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.binding.query.dynamic;
|
||||
|
||||
import com.diboot.core.binding.parser.BaseConditionManager;
|
||||
import com.diboot.core.exception.BusinessException;
|
||||
import com.diboot.core.util.S;
|
||||
import com.diboot.core.util.V;
|
||||
import com.diboot.core.vo.Status;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.expression.BinaryExpression;
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.*;
|
||||
import net.sf.jsqlparser.schema.Column;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Join条件表达式的管理器
|
||||
* @author mazc@dibo.ltd
|
||||
* @version v2.0
|
||||
* @date 2019/4/1
|
||||
*/
|
||||
@Slf4j
|
||||
public class JoinConditionManager extends BaseConditionManager {
|
||||
|
||||
/**
|
||||
* 解析condition条件
|
||||
* @param joiner
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void parseJoinCondition(AnnoJoiner joiner) {
|
||||
List<Expression> expressionList = getExpressionList(joiner.getCondition());
|
||||
if(V.isEmpty(expressionList)){
|
||||
log.warn("无法解析注解条件: {} ", joiner.getCondition());
|
||||
throw new BusinessException(Status.FAIL_VALIDATION);
|
||||
}
|
||||
// 解析中间表关联
|
||||
String tableName = extractMiddleTableName(expressionList);
|
||||
if(tableName != null){
|
||||
joiner.setMiddleTable(tableName);
|
||||
}
|
||||
// 解析join
|
||||
parseJoinOn(joiner, expressionList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析直接关联
|
||||
* @param joiner
|
||||
* @param expressionList
|
||||
*/
|
||||
private static void parseJoinOn(AnnoJoiner joiner, List<Expression> expressionList) {
|
||||
List<String> segments = new ArrayList<>(), middleTableOnSegments = new ArrayList<>();
|
||||
// 解析直接关联
|
||||
for(Expression operator : expressionList){
|
||||
// 默认当前表条件
|
||||
List<String> currentSegments = segments;
|
||||
if(operator instanceof BinaryExpression){
|
||||
BinaryExpression expression = (BinaryExpression)operator;
|
||||
String left = formatColumn(expression.getLeftExpression(), joiner);
|
||||
String right = formatColumn(expression.getRightExpression(), joiner);
|
||||
// 中间表条件
|
||||
if(joiner.getMiddleTable() != null &&
|
||||
(left.startsWith(joiner.getMiddleTableAlias() + ".") || right.startsWith(joiner.getMiddleTableAlias() + "."))){
|
||||
if(left.startsWith(joiner.getAlias()+".") || right.startsWith(joiner.getAlias()+".")){
|
||||
}
|
||||
else{
|
||||
currentSegments = middleTableOnSegments;
|
||||
}
|
||||
}
|
||||
if(operator instanceof EqualsTo){
|
||||
currentSegments.add(left + " = " + right);
|
||||
}
|
||||
else if(operator instanceof NotEqualsTo){
|
||||
currentSegments.add(left + " != " + right);
|
||||
}
|
||||
else if(operator instanceof GreaterThan){
|
||||
currentSegments.add(left + " > " + right);
|
||||
}
|
||||
else if(operator instanceof GreaterThanEquals){
|
||||
currentSegments.add(left + " >= " + right);
|
||||
}
|
||||
else if(operator instanceof MinorThan){
|
||||
currentSegments.add(left + " < " + right);
|
||||
}
|
||||
else if(operator instanceof MinorThanEquals){
|
||||
currentSegments.add(left + " <= " + right);
|
||||
}
|
||||
else{
|
||||
log.warn("暂不支持的条件: "+ expression.toString());
|
||||
}
|
||||
}
|
||||
else if(operator instanceof IsNullExpression){
|
||||
IsNullExpression expression = (IsNullExpression)operator;
|
||||
String left = formatColumn(expression.getLeftExpression(), joiner);
|
||||
// 中间表条件
|
||||
if(joiner.getMiddleTable() != null && left.startsWith(joiner.getMiddleTableAlias() + ".")){
|
||||
currentSegments = middleTableOnSegments;
|
||||
}
|
||||
if(expression.isNot() == false){
|
||||
currentSegments.add(left + " IS NULL");
|
||||
}
|
||||
else{
|
||||
currentSegments.add(left + " IS NOT NULL");
|
||||
}
|
||||
}
|
||||
else if(operator instanceof InExpression){
|
||||
InExpression expression = (InExpression)operator;
|
||||
String left = formatColumn(expression.getLeftExpression(), joiner);
|
||||
// 中间表条件
|
||||
if(joiner.getMiddleTable() != null && left.startsWith(joiner.getMiddleTableAlias() + ".")){
|
||||
currentSegments = middleTableOnSegments;
|
||||
}
|
||||
if(expression.isNot() == false){
|
||||
currentSegments.add(left + " IN " + expression.getRightItemsList().toString());
|
||||
}
|
||||
else{
|
||||
currentSegments.add(left + " NOT IN " + expression.getRightItemsList().toString());
|
||||
}
|
||||
}
|
||||
else if(operator instanceof Between){
|
||||
Between expression = (Between)operator;
|
||||
String left = formatColumn(expression.getLeftExpression(), joiner);
|
||||
// 中间表条件
|
||||
if(joiner.getMiddleTable() != null && left.startsWith(joiner.getMiddleTableAlias() + ".")){
|
||||
currentSegments = middleTableOnSegments;
|
||||
}
|
||||
if(expression.isNot() == false){
|
||||
currentSegments.add(left + " BETWEEN " + expression.getBetweenExpressionStart().toString() + " AND " + expression.getBetweenExpressionEnd().toString());
|
||||
}
|
||||
else{
|
||||
currentSegments.add(left + " NOT BETWEEN " + expression.getBetweenExpressionStart().toString() + " AND " + expression.getBetweenExpressionEnd().toString());
|
||||
}
|
||||
}
|
||||
else if(operator instanceof LikeExpression){
|
||||
LikeExpression expression = (LikeExpression)operator;
|
||||
String left = formatColumn(expression.getLeftExpression(), joiner);
|
||||
// 中间表条件
|
||||
if(joiner.getMiddleTable() != null && left.startsWith(joiner.getMiddleTableAlias() + ".")){
|
||||
currentSegments = middleTableOnSegments;
|
||||
}
|
||||
if(expression.isNot() == false){
|
||||
currentSegments.add(left + " LIKE " + expression.getStringExpression());
|
||||
}
|
||||
else{
|
||||
currentSegments.add(left + " NOT LIKE " + expression.getStringExpression());
|
||||
}
|
||||
}
|
||||
else{
|
||||
log.warn("不支持的条件: "+operator.toString());
|
||||
}
|
||||
}
|
||||
if(segments.isEmpty() && middleTableOnSegments.isEmpty()){
|
||||
return;
|
||||
}
|
||||
joiner.setOnSegment(S.join(segments, " AND "));
|
||||
if(V.notEmpty(middleTableOnSegments)){
|
||||
joiner.setMiddleTableOnSegment(S.join(middleTableOnSegments, " AND "));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化左侧
|
||||
* @return
|
||||
*/
|
||||
private static String formatColumn(Expression expression, AnnoJoiner joiner){
|
||||
String annoColumn = S.toSnakeCase(expression.toString());
|
||||
if(expression instanceof Column){
|
||||
// 其他表列
|
||||
if(annoColumn.contains(".")){
|
||||
String tableName = S.substringBefore(annoColumn, ".");
|
||||
// 当前表替换别名
|
||||
if(tableName.equals("this")){
|
||||
annoColumn = "self." + S.substringAfter(annoColumn, "this.");
|
||||
}
|
||||
else if(tableName.equals("self")){
|
||||
}
|
||||
else if(tableName.equals(joiner.getMiddleTable())){
|
||||
annoColumn = joiner.getMiddleTableAlias() + "." + S.substringAfter(annoColumn, ".");
|
||||
}
|
||||
else{
|
||||
log.warn("无法识别的条件: {}", annoColumn);
|
||||
}
|
||||
}
|
||||
// 当前表列
|
||||
else{
|
||||
annoColumn = joiner.getAlias() + "." + annoColumn;
|
||||
}
|
||||
}
|
||||
return annoColumn;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,166 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2020, www.dibo.ltd (service@dibo.ltd).
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* 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.binding.query.dynamic;
|
||||
|
||||
import com.diboot.core.binding.parser.ConditionManager;
|
||||
import com.diboot.core.util.S;
|
||||
import com.diboot.core.util.V;
|
||||
import net.sf.jsqlparser.expression.BinaryExpression;
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.*;
|
||||
import net.sf.jsqlparser.schema.Column;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Join条件表达式的管理器
|
||||
* @author mazc@dibo.ltd
|
||||
* @version v2.0
|
||||
* @date 2019/4/1
|
||||
*/
|
||||
public class JoinConditionParser {
|
||||
private static final Logger log = LoggerFactory.getLogger(JoinConditionParser.class);
|
||||
|
||||
/**
|
||||
* 解析condition条件
|
||||
* @param condition
|
||||
* @param alias
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String parseJoinCondition(String condition, String alias) {
|
||||
List<Expression> expressionList = ConditionManager.getExpressionList(condition);
|
||||
if(V.isEmpty(expressionList)){
|
||||
log.warn("无法解析注解条件: {} ", condition);
|
||||
return null;
|
||||
}
|
||||
// 解析join
|
||||
return parseJoinOn(alias, expressionList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析直接关联
|
||||
* @param alias
|
||||
* @param expressionList
|
||||
*/
|
||||
private static String parseJoinOn(String alias, List<Expression> expressionList) {
|
||||
List<String> segments = new ArrayList<>();
|
||||
// 解析直接关联
|
||||
for(Expression operator : expressionList){
|
||||
if(operator instanceof BinaryExpression){
|
||||
BinaryExpression expression = (BinaryExpression)operator;
|
||||
String left = formatLeft(expression.getLeftExpression().toString());
|
||||
String right = formatRight(expression.getRightExpression().toString());
|
||||
if(expression.getRightExpression() instanceof Column){
|
||||
right = alias + "." + right;
|
||||
}
|
||||
else if(expression.getLeftExpression() instanceof Column){
|
||||
left = alias + "." + left;
|
||||
}
|
||||
if(operator instanceof EqualsTo){
|
||||
segments.add(left + " = " + right);
|
||||
}
|
||||
else if(operator instanceof NotEqualsTo){
|
||||
segments.add(left + " != " + right);
|
||||
}
|
||||
else if(operator instanceof GreaterThan){
|
||||
segments.add(left + " > " + right);
|
||||
}
|
||||
else if(operator instanceof GreaterThanEquals){
|
||||
segments.add(left + " >= " + right);
|
||||
}
|
||||
else if(operator instanceof MinorThan){
|
||||
segments.add(left + " < " + right);
|
||||
}
|
||||
else if(operator instanceof MinorThanEquals){
|
||||
segments.add(left + " <= " + right);
|
||||
}
|
||||
else{
|
||||
log.warn("暂不支持的条件: "+ expression.toString());
|
||||
}
|
||||
}
|
||||
else if(operator instanceof IsNullExpression){
|
||||
IsNullExpression expression = (IsNullExpression)operator;
|
||||
String left = formatLeft(expression.getLeftExpression().toString());
|
||||
if(expression.isNot() == false){
|
||||
segments.add(left + " IS NULL");
|
||||
}
|
||||
else{
|
||||
segments.add(left + " IS NOT NULL");
|
||||
}
|
||||
}
|
||||
else if(operator instanceof InExpression){
|
||||
InExpression expression = (InExpression)operator;
|
||||
String left = formatLeft(expression.getLeftExpression().toString());
|
||||
if(expression.isNot() == false){
|
||||
segments.add(left + " IN " + expression.getRightItemsList().toString());
|
||||
}
|
||||
else{
|
||||
segments.add(left + " NOT IN " + expression.getRightItemsList().toString());
|
||||
}
|
||||
}
|
||||
else if(operator instanceof Between){
|
||||
Between expression = (Between)operator;
|
||||
String left = formatLeft(expression.getLeftExpression().toString());
|
||||
if(expression.isNot() == false){
|
||||
segments.add(left + " BETWEEN " + expression.getBetweenExpressionStart().toString() + " AND " + expression.getBetweenExpressionEnd().toString());
|
||||
}
|
||||
else{
|
||||
segments.add(left + " NOT BETWEEN " + expression.getBetweenExpressionStart().toString() + " AND " + expression.getBetweenExpressionEnd().toString());
|
||||
}
|
||||
}
|
||||
else if(operator instanceof LikeExpression){
|
||||
LikeExpression expression = (LikeExpression)operator;
|
||||
String left = formatLeft(expression.getLeftExpression().toString());
|
||||
if(expression.isNot() == false){
|
||||
segments.add(left + " LIKE " + expression.getStringExpression());
|
||||
}
|
||||
else{
|
||||
segments.add(left + " NOT LIKE " + expression.getStringExpression());
|
||||
}
|
||||
}
|
||||
else{
|
||||
log.warn("不支持的条件: "+operator.toString());
|
||||
}
|
||||
}
|
||||
if(segments.isEmpty()){
|
||||
return null;
|
||||
}
|
||||
return S.join(segments, " AND ");
|
||||
}
|
||||
|
||||
/**
|
||||
* 注解列
|
||||
* @return
|
||||
*/
|
||||
private static String formatLeft(String annoColumn){
|
||||
if(annoColumn.contains("this.")){
|
||||
annoColumn = S.replace(annoColumn, "this.", "self.");
|
||||
}
|
||||
return S.toSnakeCase(annoColumn);
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化右侧列
|
||||
* @return
|
||||
*/
|
||||
private static String formatRight(String annoColumn){
|
||||
return S.toSnakeCase(annoColumn);
|
||||
}
|
||||
|
||||
}
|
|
@ -16,10 +16,6 @@
|
|||
package com.diboot.core.util;
|
||||
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Assert;
|
||||
import com.baomidou.mybatisplus.core.toolkit.LambdaUtils;
|
||||
import com.baomidou.mybatisplus.core.toolkit.support.ColumnCache;
|
||||
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
|
||||
import com.diboot.core.config.Cons;
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import com.diboot.core.exception.BusinessException;
|
||||
|
|
|
@ -116,13 +116,12 @@ public class ContextHelper implements ApplicationContextAware {
|
|||
}
|
||||
|
||||
/***
|
||||
* 获取指定类型的全部实例
|
||||
* 获取指定类型的全部实现类
|
||||
* @param type
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public static <T> List<T> getBeans(Class<T> type){
|
||||
// 获取所有的定时任务实现类
|
||||
Map<String, T> map = getApplicationContext().getBeansOfType(type);
|
||||
if(V.isEmpty(map)){
|
||||
return null;
|
||||
|
|
|
@ -115,7 +115,6 @@ public class SqlExecutor {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 执行1-1关联查询和合并结果并将结果Map的key类型转成String
|
||||
*
|
||||
|
@ -130,6 +129,18 @@ public class SqlExecutor {
|
|||
} catch (Exception e) {
|
||||
log.warn("执行查询异常", e);
|
||||
}
|
||||
return convertToOneToOneResult(resultSetMapList, keyName, valueName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并为1-1的map结果
|
||||
* @param resultSetMapList
|
||||
* @param keyName
|
||||
* @param valueName
|
||||
* @param <E>
|
||||
* @return
|
||||
*/
|
||||
public static <E> Map<String, Object> convertToOneToOneResult(List<Map<String, E>> resultSetMapList, String keyName, String valueName) {
|
||||
// 合并list为map
|
||||
Map<String, Object> resultMap = new HashMap<>();
|
||||
if(V.notEmpty(resultSetMapList)){
|
||||
|
@ -162,6 +173,18 @@ public class SqlExecutor {
|
|||
catch (Exception e) {
|
||||
log.warn("执行查询异常", e);
|
||||
}
|
||||
return convertToOneToManyResult(resultSetMapList, keyName, valueName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并为1-n的map结果
|
||||
* @param resultSetMapList
|
||||
* @param keyName
|
||||
* @param valueName
|
||||
* @param <E>
|
||||
* @return
|
||||
*/
|
||||
public static <E> Map<String, List> convertToOneToManyResult(List<Map<String, E>> resultSetMapList, String keyName, String valueName){
|
||||
// 合并list为map
|
||||
Map<String, List> resultMap = new HashMap<>();
|
||||
if(V.notEmpty(resultSetMapList)){
|
||||
|
|
|
@ -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.EntityListComplexBinderVO;
|
||||
import diboot.core.test.binder.vo.EntityListSimpleBinderVO;
|
||||
import diboot.core.test.config.SpringMvcConfig;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
|
|
@ -23,7 +23,9 @@ 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.User;
|
||||
import diboot.core.test.binder.service.DepartmentService;
|
||||
import diboot.core.test.binder.vo.DepartmentVO;
|
||||
import diboot.core.test.config.SpringMvcConfig;
|
||||
|
@ -146,6 +148,29 @@ public class TestJoinQuery {
|
|||
Assert.assertTrue(list.size() == 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试有中间表的动态sql join
|
||||
*/
|
||||
@Test
|
||||
public void testDynamicSqlQueryWithMiddleTable() {
|
||||
// 初始化DTO,测试不涉及关联的情况
|
||||
UserDTO dto = new UserDTO();
|
||||
dto.setDeptName("研发组");
|
||||
dto.setDeptId(10002L);
|
||||
|
||||
// builder直接查询,不分页 3条结果
|
||||
List<User> builderResultList = QueryBuilder.toDynamicJoinQueryWrapper(dto).queryList(User.class);
|
||||
Assert.assertTrue(builderResultList.size() == 2);
|
||||
|
||||
dto.setOrgName("苏州帝博");
|
||||
builderResultList = QueryBuilder.toDynamicJoinQueryWrapper(dto).queryList(User.class);
|
||||
Assert.assertTrue(builderResultList.size() == 2);
|
||||
|
||||
dto.setRoleCode("ADMIN");
|
||||
builderResultList = QueryBuilder.toDynamicJoinQueryWrapper(dto).queryList(User.class);
|
||||
Assert.assertTrue(builderResultList.size() == 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test(){
|
||||
String sql = buildCheckDeletedColSql("test");
|
||||
|
|
|
@ -26,7 +26,7 @@ import lombok.Setter;
|
|||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 定时任务
|
||||
* Department DTO
|
||||
* @author mazc@dibo.ltd
|
||||
* @version v2.0
|
||||
* @date 2018/12/27
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2020, www.dibo.ltd (service@dibo.ltd).
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* 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.dto;
|
||||
|
||||
import com.diboot.core.binding.query.BindQuery;
|
||||
import com.diboot.core.binding.query.Comparison;
|
||||
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.Data;
|
||||
|
||||
/**
|
||||
* User DTO
|
||||
* @author mazc@dibo.ltd
|
||||
* @version v2.0
|
||||
* @date 2018/12/27
|
||||
*/
|
||||
@Data
|
||||
public class UserDTO extends User {
|
||||
|
||||
// 字段关联
|
||||
@BindQuery(entity= Department.class, field = "name", condition="this.department_id=id") // AND parent_id >= 0
|
||||
private String deptName;
|
||||
|
||||
// 字段关联
|
||||
@BindQuery(entity= Department.class, field = "id", condition="this.department_id=id") // AND parent_id >= 0
|
||||
private Long deptId;
|
||||
|
||||
// 通过中间表关联Entity
|
||||
@BindQuery(comparison = Comparison.CONTAINS, entity = Organization.class, field = "name",
|
||||
condition = "this.department_id=department.id AND department.org_id=id AND parent_id=0")
|
||||
private String orgName;
|
||||
// LEFT JOIN department r2m ON self.department_id = r2m.id
|
||||
// LEFT JOIN organization r1 ON r2m.org_id=r2.id
|
||||
|
||||
@BindQuery(entity = Role.class, field = "code", condition = "this.id=user_role.user_id AND user_role.role_id=id")
|
||||
private String roleCode;
|
||||
// LEFT JOIN user_role r3m ON self.id = r3m.user_id
|
||||
// LEFT JOIN role r3 ON r3m.role_id = r3.id
|
||||
|
||||
}
|
|
@ -24,7 +24,7 @@ import lombok.Setter;
|
|||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 定时任务
|
||||
* Department
|
||||
* @author mazc@dibo.ltd
|
||||
* @version v2.0
|
||||
* @date 2018/12/27
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2020, www.dibo.ltd (service@dibo.ltd).
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* 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.diboot.core.entity.BaseEntity;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 用户角色
|
||||
* @author mazc@dibo.ltd
|
||||
* @version v2.0
|
||||
* @date 2019/1/30
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Accessors(chain = true)
|
||||
public class UserRole extends BaseEntity {
|
||||
private static final long serialVersionUID = 3030761344045195972L;
|
||||
|
||||
@TableField
|
||||
private Long userId;
|
||||
|
||||
@TableField
|
||||
private Long roleId;
|
||||
|
||||
@TableField(exist = false)
|
||||
private boolean deleted;
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2020, www.dibo.ltd (service@dibo.ltd).
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* 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.UserRole;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 用户角色Mapper
|
||||
* @author mazc@dibo.ltd
|
||||
* @version 2018/12/22
|
||||
*/
|
||||
@Mapper
|
||||
public interface UserRoleMapper extends BaseCrudMapper<UserRole> {
|
||||
|
||||
}
|
||||
|
|
@ -24,7 +24,7 @@ import lombok.Setter;
|
|||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 定时任务
|
||||
* Department VO
|
||||
* @author mazc@dibo.ltd
|
||||
* @version v2.0
|
||||
* @date 2018/12/27
|
||||
|
|
|
@ -40,7 +40,7 @@ public class EntityListComplexBinderVO extends User {
|
|||
private String userType = "OrgUser";
|
||||
|
||||
// 支持通过中间表的多-多Entity实体关联
|
||||
@BindEntityList(entity = Role.class, condition="this.id=user_role.user_id AND user_role.role_id=id")
|
||||
@BindEntityList(entity = Role.class, condition="this.id=user_role.user_id AND user_role.role_id=id AND user_role.user_id>1")
|
||||
private List<Role> roleList;
|
||||
|
||||
// 支持通过中间表的多-多Entity的单个属性集
|
||||
|
|
Loading…
Reference in New Issue