Spring JdbcTemplate实现自定义动态sql拼接功能

需求描述:

        sql 需要能满足支持动态拼接,包含 查询字段、查询表、关联表、查询条件、关联表的查询条件、排序、分组、去重等

实现步骤:

        1,创建表及导入测试数据

CREATE TABLE YES_DEV.T11 (ID BINARY_BIGINT NOT NULL,NAME VARCHAR(10),XX BINARY_BIGINT,CONSTRAINT _PK_SYS_25_63 PRIMARY KEY (ID)
);CREATE TABLE YES_DEV.T111 (ID BINARY_INTEGER NOT NULL,NAME NUMBER
);INSERT INTO YES_DEV.T11 (ID,NAME,XX) VALUES(11,'123',11),(9,'9',9),(8,'8',8),(7,'7',7),(6,'6',6),(5,'5',5),(4,'4',4),(3,'3',3),(2,'2',2),(1,'1',1);INSERT INTO YES_DEV.T111 (ID,NAME) VALUES(1,123);

        2,创建项目并引入 pom依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>testMybatis</artifactId><version>1.0-SNAPSHOT</version><!-- 父项目信息 --><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.8</version><relativePath/></parent><properties><maven.compiler.source>15</maven.compiler.source><maven.compiler.target>15</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.4</version></dependency><!-- 高斯DB驱动 --><dependency><groupId>com.huawei.gauss</groupId><artifactId>com.huawei.gauss.jdbc.ZenithDriver</artifactId><version>1.2.1</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><scope>test</scope></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.2</version></dependency><dependency><groupId>commons-lang</groupId><artifactId>commons-lang</artifactId><version>2.6</version></dependency><dependency><groupId>commons-collections</groupId><artifactId>commons-collections</artifactId><version>3.2.2</version></dependency><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>30.1-jre</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build></project>

        3,编写 application.properties文件

spring.datasource.url=jdbc:zenith:@xxxx:xxx
spring.datasource.username=xxx
spring.datasource.password=xxxx
spring.datasource.driver-class-name=com.huawei.gauss.jdbc.inner.GaussDriver
mybatis.mapper-locations=classpath:mapper/*.xmlorg.apache.springframework.jdbc.core.JdbcTemplate = debug

        4,核心类之 Column

package com.example.dao.sql;import com.example.utils.SqlUtils;
import lombok.Getter;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;@Getter
public class Column {private final String name;private final List<String> tableAliases = new ArrayList<>();private Column(String name, List<String> tableAliases) {this.name = name;if (CollectionUtils.isNotEmpty(tableAliases)) {this.tableAliases.addAll(tableAliases);}}public static Column of(String name, String... tableAliases) {if (ArrayUtils.isNotEmpty(tableAliases)) {tableAliases = Arrays.stream(tableAliases).filter(Objects::nonNull).toArray(String[]::new);}if (ArrayUtils.isEmpty(tableAliases)) {String tableAlias = StringUtils.substringBefore(name, ".").trim();if (SqlUtils.isValidAlias(tableAlias)) {tableAliases = new String[] {tableAlias};}}return new Column(name, ArrayUtils.isEmpty(tableAliases) ? null : Arrays.asList(tableAliases));}public String getTableAlias() {return tableAliases.isEmpty() ? null : tableAliases.get(0);}}

        5,核心类之 Table

package com.example.dao.sql;import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.example.utils.SqlUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;public class Table {private String joinType;private boolean weak;private boolean optimizable = true;private Map<String, List<?>> parameterTempData;private final String name;private final String alias;private final String physicalName;private final List<Condition> joinConditions = new ArrayList<>();private final List<PredicateCondition<?>> joinPredicateConditions = new ArrayList<>();private final List<Condition> filterConditions = new ArrayList<>();private final List<PredicateCondition<?>> filterPredicateConditions = new ArrayList<>();private final List<PropertyCondition> filterPropertyConditions = new ArrayList<>();private Table(String name, String alias, String physicalName) {this.name = name;this.alias = alias;this.physicalName = physicalName;}public static Table of(String name, String physicalName) {String separator = " ";String normalName = name.trim();String alias = StringUtils.substringAfterLast(normalName, separator).trim();SqlUtils.assertValidAlias(alias);if (StringUtils.isEmpty(physicalName)) {physicalName = StringUtils.substringBefore(normalName, separator).trim();}return new Table(name, alias, physicalName);}public static Table of(String name) {return of(name, (String) null);}public static Table of(String name, Map<String, List<?>> parameterTempData) {return of(name, null, parameterTempData);}public static Table of(String name, String physicalName, Map<String, List<?>> parameterTempData) {Table table = Table.of(name, physicalName);table.setParameterTempData(parameterTempData);return table;}public String getJoinType() {return joinType;}public void setJoinType(String joinType) {this.joinType = joinType;}public String getName() {return name;}public String getAlias() {return alias;}public String getPhysicalName() {return physicalName;}public List<Condition> getJoinConditions() {return joinConditions;}public List<PredicateCondition<?>> getJoinPredicateConditions() {return joinPredicateConditions;}public List<Condition> getFilterConditions() {return filterConditions;}public List<PredicateCondition<?>> getFilterPredicateConditions() {return filterPredicateConditions;}public List<PropertyCondition> getFilterPropertyConditions() {return filterPropertyConditions;}public Table on(String condition, String... associationTableAliases) {joinConditions.add(Condition.of(condition, associationTableAliases == null ? null : Arrays.asList(associationTableAliases)));return this;}public <T> Table on(PredicateCondition<T> predicateCondition) {joinPredicateConditions.add(predicateCondition);return this;}public <T> Table on(Predicate<T> predicate, String condition) {return filter(PredicateCondition.of(predicate, condition));}public <T> Table on(Predicate<T> predicate, Function<T, String> conditionSupplier) {return filter(PredicateCondition.of(predicate, conditionSupplier));}@SafeVarargspublic final <T> Table on(Predicate<T> predicate, PredicateCondition<T>... predicateConditions) {if (ArrayUtils.isEmpty(predicateConditions)) {return this;}for (PredicateCondition<T> predicateCondition : predicateConditions) {predicateCondition.setPredicate(predicate.and(predicateCondition.getPredicate()));joinPredicateConditions.add(predicateCondition);}return this;}public Table filter(String... conditions) {if (ArrayUtils.isNotEmpty(conditions)) {filterConditions.addAll(Stream.of(conditions).map(Condition::of).collect(Collectors.toList()));}return this;}public <T> Table filter(PredicateCondition<T> predicateCondition) {filterPredicateConditions.add(predicateCondition);return this;}public <T> Table filter(SFunction<T, Object> fieldGetter, String columnName) {return filter(fieldGetter, columnName, true);}public <T> Table filter(SFunction<T, Object> fieldGetter, String columnName, boolean optimizable) {filterPropertyConditions.add(PropertyCondition.of(fieldGetter, columnName, optimizable));return this;}public <T> Table filter(Predicate<T> predicate, String condition) {return filter(PredicateCondition.of(predicate, condition));}public <T> Table filter(Predicate<T> predicate, Function<T, String> conditionSupplier) {return filter(PredicateCondition.of(predicate, conditionSupplier));}@SafeVarargspublic final <T> Table filter(Predicate<T> predicate, PredicateCondition<T>... predicateConditions) {if (ArrayUtils.isEmpty(predicateConditions)) {return this;}for (PredicateCondition<T> predicateCondition : predicateConditions) {predicateCondition.setPredicate(predicate.and(predicateCondition.getPredicate()));filter(predicateCondition);}return this;}public Table weak() {return weak(true);}public Table weak(boolean weak) {this.weak = weak;return this;}public boolean isWeak() {return weak;}public Table optimize(boolean optimizable) {this.optimizable = optimizable;return this;}public boolean isOptimizable() {return optimizable;}public Map<String, List<?>> getParameterTempData() {return parameterTempData;}public void setParameterTempData(Map<String, List<?>> parameterTempData) {this.parameterTempData = parameterTempData;}}

        6,核心类之 Condition

package com.example.dao.sql;import java.util.Collections;
import java.util.List;class Condition {private final String sql;private final List<String> associationTableAliases;public static Condition of(String sql) {return new Condition(sql, null);}public static Condition of(String sql, List<String> associationTableAliases) {return new Condition(sql, associationTableAliases);}private Condition(String sql, List<String> associationTableAliases) {this.sql = sql;this.associationTableAliases = associationTableAliases == null ? Collections.emptyList() : associationTableAliases;}public String getSql() {return sql;}public List<String> getAssociationTableAliases() {return associationTableAliases;}}

        7,核心类之 PredicateCondition

package com.example.dao.sql;import java.util.function.Function;
import java.util.function.Predicate;public class PredicateCondition<T> {private Predicate<T> predicate;private Condition condition;private Function<T, Condition> conditionSupplier;public static <T> PredicateCondition<T> of(Predicate<T> predicate, String condition) {return new PredicateCondition<>(predicate, Condition.of(condition));}public static <T> PredicateCondition<T> of(Predicate<T> predicate, Function<T, String> conditionSupplier) {return new PredicateCondition<>(predicate, parameter -> Condition.of(conditionSupplier.apply(parameter)));}private PredicateCondition(Predicate<T> predicate, Condition condition) {this.predicate = predicate;this.condition = condition;}private PredicateCondition(Predicate<T> predicate, Function<T, Condition> conditionSupplier) {this.predicate = predicate;this.conditionSupplier = conditionSupplier;}public Predicate<T> getPredicate() {return predicate;}public void setPredicate(Predicate<T> predicate) {this.predicate = predicate;}public Condition getCondition() {return condition;}public void setCondition(Condition condition) {this.condition = condition;}public Function<T, Condition> getConditionSupplier() {return conditionSupplier;}public void setConditionSupplier(Function<T, Condition> conditionSupplier) {this.conditionSupplier = conditionSupplier;}}

        8,核心类之 PropertyCondition

package com.example.dao.sql;import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import lombok.Data;@Data
public class PropertyCondition {private SFunction<?, Object> fieldGetter;private String columnName;private boolean optimizable;private PropertyCondition(SFunction<?, Object> fieldGetter, String columnName, boolean optimizable) {this.fieldGetter = fieldGetter;this.columnName = columnName;this.optimizable = optimizable;}public static PropertyCondition of(SFunction<?, Object> fieldGetter, String columnName, boolean optimizable) {return new PropertyCondition(fieldGetter, columnName, optimizable);}}

        9,核心类之 SqlBuilder

package com.example.dao.sql;import com.baomidou.mybatisplus.core.toolkit.LambdaUtils;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.example.utils.ObjectUtils;
import com.example.utils.SqlUtils;
import com.google.common.base.CaseFormat;
import lombok.Getter;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.reflection.property.PropertyNamer;import java.util.*;
import java.util.stream.Collectors;//TODO 优化join排序,无依赖的inner join排在前面,有依赖的排在依赖表后面
public class SqlBuilder {private static final int PARAM_VALUE_NUM = 1000;private static final String NA = "NA";private static final String FROM = "FROM";private static final String INNER = "INNER";private static final String LEFT = "LEFT";private static final String RIGHT = "RIGHT";private static final String FULL = "FULL";@Getterprivate final List<Table> fromTables = new ArrayList<>();@Getterprivate final List<Table> queryTables = new ArrayList<>();@Getterprivate final List<Column> selectColumns = new ArrayList<>();private final List<Condition> filterConditions = new ArrayList<>();private final List<String> orderByConditions = new ArrayList<>();private final List<String> appendSqlSnippets = new ArrayList<>();private final Map<Table, TableQueryCondition> tableQueryConditions = new HashMap<>();//private final Map<Table, List<Table>> associationTables = new HashMap<>();/*   private final List<PredicateCondition<?>> predicateConditions = new ArrayList<>();*/private boolean enablePlaceholder = true;private boolean enableOrderBy = true;/*** 增加字段去重*/private boolean enableDistinct;public boolean isEnablePlaceholder() {return enablePlaceholder;}public SqlBuilder setEnablePlaceholder(boolean enablePlaceholder) {this.enablePlaceholder = enablePlaceholder;return this;}public SqlBuilder enableOrderBy() {this.enableOrderBy = true;return this;}public SqlBuilder disableOrderBy() {this.enableOrderBy = false;return this;}public boolean isEnableDistinct() {return enableDistinct;}public void setEnableDistinct(boolean enableDistinct) {this.enableDistinct = enableDistinct;}private static class TableQueryCondition {private final Table table;private String joinCondition;private String filterCondition;private boolean referenced;public TableQueryCondition(Table table) {this.table = table;}public Table getTable() {return table;}public String getJoinCondition() {return joinCondition;}public void setJoinCondition(String joinCondition) {this.joinCondition = joinCondition;}public String getFilterCondition() {return filterCondition;}public void setFilterCondition(String filterCondition) {this.filterCondition = filterCondition;}public boolean isReferenced() {return referenced;}public void setReferenced(boolean referenced) {this.referenced = referenced;}}private Map<String, List<?>> supplementPropertyFilters(Table table, Object queryCriteria) {Map<String, List<?>> parameterTempData = new HashMap<>();if(queryCriteria == null){return parameterTempData;}for (PropertyCondition propertyCondition : table.getFilterPropertyConditions()) {SFunction<?, Object> fieldGetter = propertyCondition.getFieldGetter();String fieldName = PropertyNamer.methodToProperty(LambdaUtils.resolve(fieldGetter).getImplMethodName());Object fieldValue = fieldGetter.apply(ObjectUtils.cast(queryCriteria));if (!(fieldValue instanceof List) || ((List<?>) fieldValue).isEmpty()) {continue;}String columnName = propertyCondition.getColumnName();if (!propertyCondition.isOptimizable()) {table.optimize(false);}List<?> collectionValue = ((List<?>) fieldValue);if (collectionValue.size() <= PARAM_VALUE_NUM) {StringBuilder condition = new StringBuilder(columnName).append(SqlUtils.buildColumnInCondition(fieldName, collectionValue, enablePlaceholder));if (collectionValue.contains(NA) || collectionValue.contains(null)) {condition.append(" OR ").append(columnName).append(" is null");table.optimize(false);}table.filter(condition.toString());} else {// 当参数值过多采用临时表关联时,将表设置为强关联// todo referencedtable.weak(false);String tempTableAlias = "_" + CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, fieldName);String tempDataType = tempTableAlias.toUpperCase();StringBuilder joinCondition = new StringBuilder();joinCondition.append(tempTableAlias).append(".value").append(" = ");if (collectionValue.contains(NA)) {joinCondition.append("nvl(").append(columnName).append(", '").append(NA).append("')");} else {joinCondition.append(columnName);}Object sampleValue = collectionValue.get(0);String queryField = sampleValue instanceof Number ? "to_number(string_value)" : "string_value";Table tempTable = Table.of("(SELECT " + queryField + " value FROM t_comm_data_temp WHERE data_type = '" + tempDataType + "') " + tempTableAlias).on(joinCondition.toString(), table.getAlias());tempTable.setJoinType(INNER);associationTable(tempTable, table);parameterTempData.put(tempDataType, collectionValue);}}return parameterTempData;}public ExecutionSql builder(Object queryCriteria) {ExecutionSql executionSql = new ExecutionSql();analyzeTables(queryCriteria, executionSql);StringBuilder sql = new StringBuilder();appendSelectColumns(sql);appendFromTables(sql, executionSql);appendJoinTables(sql, executionSql);appendWhereConditions(sql);appendOrderByConditions(sql);appendSqlSnippets(sql);executionSql.setSql(sql.toString());return executionSql;}private void analyzeTables(Object queryCriteria, ExecutionSql executionSql) {supplementTablePropertyFilters(queryCriteria, executionSql);analyzeTableDependences(queryCriteria);}private void supplementTablePropertyFilters(Object queryCriteria, ExecutionSql executionSql) {Map<String, List<?>> parameterTempData = new HashMap<>();// Query Table列表需进行拷贝,便于逻辑中动态增加临时表for (Table table : new ArrayList<>(queryTables)) {parameterTempData.putAll(supplementPropertyFilters(table, queryCriteria));}executionSql.setParameterTempData(parameterTempData);}private void analyzeTableDependences(Object queryCriteria) {Set<String> referencedTableAliases = filterConditions.stream().flatMap(record -> record.getAssociationTableAliases().stream()).collect(Collectors.toSet());referencedTableAliases.addAll(selectColumns.stream().flatMap(column -> column.getTableAliases().stream()).collect(Collectors.toSet()));Map<String, Table> tableAliasMap = new HashMap<>();List<Table> referencedTables = new ArrayList<>();for (Table table : queryTables) {TableQueryCondition tableAnalysisResult = new TableQueryCondition(table);tableAnalysisResult.setJoinCondition(buildConditionSql(table.getJoinConditions(), table.getJoinPredicateConditions(), queryCriteria));tableAnalysisResult.setFilterCondition(buildConditionSql(table.getFilterConditions(), table.getFilterPredicateConditions(), queryCriteria));// 是否自带过滤条件或被其他其他地方使用if (StringUtils.isNotEmpty(tableAnalysisResult.getFilterCondition()) || referencedTableAliases.contains(table.getAlias())) {tableAnalysisResult.setReferenced(true);referencedTables.add(table);}// 是否开启优化, 有过滤条件的情况下将Left/Right Join优化成Inner Join,提升查询速度if (table.isOptimizable() && Arrays.asList(LEFT, RIGHT).contains(table.getJoinType()) && StringUtils.isNotEmpty(tableAnalysisResult.getFilterCondition())) {table.setJoinType(INNER);}tableQueryConditions.put(table, tableAnalysisResult);tableAliasMap.put(StringUtils.defaultString(table.getAlias(), table.getName()), table);}//TODO tale and table 引用依赖/*for (Table table : referencedTables) {markReferenceTable(table, queryCriteria, tableAliasMap);}*/}/*private void markReferenceTable(Table referencedTable, Object queryCriteria, Map<String, Table> tableAliasMap) {List<Condition> effectiveConditions = findEffectiveConditions(referencedTable.getJoinConditions(), referencedTable.getJoinPredicateConditions(),queryCriteria);effectiveConditions.addAll(findEffectiveConditions(referencedTable.getFilterConditions(), referencedTable.getFilterPredicateConditions(), queryCriteria));List<String> associationTableAliases = effectiveConditions.stream().flatMap(condition -> condition.getAssociationTableAliases().stream()).collect(Collectors.toList());for (String associationTableAlias : associationTableAliases) {Table associationTable = tableAliasMap.get(associationTableAlias);Assert.notNull(associationTable, "Can't find association table for alias [" + associationTableAlias + "]");TableQueryCondition tableQueryCondition = tableQueryConditions.get(associationTable);if (!tableQueryCondition.isReferenced()) {//todo table.setReferenced(true);tableQueryCondition.setReferenced(true);markReferenceTable(associationTable, queryCriteria, tableAliasMap);}}}*/private List<Condition> findEffectiveConditions(List<Condition> conditions, List<PredicateCondition<?>> predicateConditions, Object queryCriteria) {List<Condition> effectiveConditions = new ArrayList<>();conditions.stream().filter(record -> StringUtils.isNotEmpty(record.getSql())).forEach(effectiveConditions::add);if (predicateConditions != null) {for (PredicateCondition<?> predicateCondition : predicateConditions) {if (predicateCondition.getPredicate().test(ObjectUtils.cast(queryCriteria))) {Condition condition = predicateCondition.getCondition();if (condition != null && StringUtils.isNotEmpty(condition.getSql())) {effectiveConditions.add(condition);}if (predicateCondition.getConditionSupplier() != null) {condition = predicateCondition.getConditionSupplier().apply(ObjectUtils.cast(queryCriteria));if (condition != null && StringUtils.isNotEmpty(condition.getSql())) {effectiveConditions.add(condition);}}}}}return effectiveConditions;}private String buildConditionSql(List<Condition> conditions, List<PredicateCondition<?>> predicateConditions, Object queryCriteria) {StringBuilder conditionSql = new StringBuilder();List<Condition> effectiveConditions = findEffectiveConditions(conditions, predicateConditions, queryCriteria);for (Condition condition : effectiveConditions) {appendChildCondition(conditionSql, condition.getSql(), true);}return conditionSql.toString();}private void appendSelectColumns(StringBuilder sql) {sql.append("SELECT ");if(enableDistinct){sql.append("DISTINCT ");}for (int i = 0; i < selectColumns.size(); i++) {Column currentColumn = selectColumns.get(i);sql.append(currentColumn.getName());if (i < selectColumns.size() - 1) {sql.append(", ");}}}private void appendFromTables(StringBuilder sql, ExecutionSql executionSql) {List<Table> fromTables = queryTables.stream().filter(table -> FROM.equals(table.getJoinType())).collect(Collectors.toList());sql.append(" FROM ");for (int i = 0; i < fromTables.size(); i++) {Table table = fromTables.get(i);sql.append(table.getName());if (i < fromTables.size() - 1) {sql.append(", ");}if (table.getParameterTempData() != null) {executionSql.getParameterTempData().putAll(table.getParameterTempData());}}}private void appendJoinTables(StringBuilder sql, ExecutionSql executionSql) {List<Table> joinTables = queryTables.stream().filter(table -> !FROM.equals(table.getJoinType())).collect(Collectors.toList());for (Table table : joinTables) {if (!judgeJoinTable(table)) {continue;}sql.append(" ").append(table.getJoinType()).append(" JOIN ").append(table.getName());sql.append(" ON ").append(tableQueryConditions.get(table).getJoinCondition());if (table.getParameterTempData() != null) {executionSql.getParameterTempData().putAll(table.getParameterTempData());}}}private boolean judgeJoinTable(Table table) {// 非弱表(即强表)则必须Joinif (!table.isWeak()) {return true;}// 是否有被引用return tableQueryConditions.get(table).isReferenced();}private void appendWhereConditions(StringBuilder sql) {StringBuilder whereConditionSql = new StringBuilder();for (Table table : queryTables) {String conditionSql = tableQueryConditions.get(table).getFilterCondition();appendChildCondition(whereConditionSql, conditionSql);}String conditionSql = buildConditionSql(filterConditions, null, null);appendChildCondition(whereConditionSql, conditionSql);if (whereConditionSql.length() > 0) {sql.append(" WHERE ").append(whereConditionSql);}}private void appendChildCondition(StringBuilder parentSql, String condition) {appendChildCondition(parentSql, condition, false);}private void appendChildCondition(StringBuilder parentSql, String condition, boolean bracketWrap) {if (StringUtils.isNotEmpty(condition)) {if (parentSql.length() > 0) {parentSql.append(" AND ");}if (bracketWrap) {condition = "(" + condition + ")";}parentSql.append(condition);}}private void appendOrderByConditions(StringBuilder sql) {if (enableOrderBy && CollectionUtils.isNotEmpty(orderByConditions)) {sql.append(" ORDER BY ").append(String.join(", ", orderByConditions));}}private void appendSqlSnippets(StringBuilder sql) {if (CollectionUtils.isNotEmpty(appendSqlSnippets)) {sql.append(" ").append(String.join(" ", appendSqlSnippets));}}public SqlBuilder select(String... columnNames) {if (ArrayUtils.isNotEmpty(columnNames)) {for (String columnName : columnNames) {select(columnName, null);}}return this;}public SqlBuilder select(String columnName, String tableAlias) {selectColumns.add(Column.of(columnName, tableAlias));return this;}public SqlBuilder select(Column... columns) {if (ArrayUtils.isEmpty(columns)) {return this;}return select(Arrays.asList(columns));}public SqlBuilder select(List<Column> columns) {selectColumns.addAll(columns);return this;}public SqlBuilder fromTable(Table table) {table.setJoinType(FROM);fromTables.add(table);associationTable(table, null);return this;}public SqlBuilder innerJoin(Table table) {table.setJoinType(INNER);associationTable(table, null);return this;}public SqlBuilder leftJoin(Table table) {table.weak().setJoinType(LEFT);associationTable(table, null);return this;}public SqlBuilder rightJoin(Table table) {table.weak().setJoinType(RIGHT);associationTable(table, null);return this;}public SqlBuilder fullJoin(Table table) {table.setJoinType(FULL);associationTable(table, null);return this;}private void associationTable(Table table, Table previousTable) {int index = previousTable == null ? queryTables.size() : queryTables.indexOf(previousTable) + 1;queryTables.add(index, table);}public SqlBuilder filter(String condition, String... associationTableAliases) {filterConditions.add(Condition.of(condition, ArrayUtils.isEmpty(associationTableAliases) ? Collections.emptyList() : Arrays.asList(associationTableAliases)));return this;}public SqlBuilder orderBy(String condition) {orderByConditions.add(condition);return this;}public SqlBuilder append(String sqlSnippet) {appendSqlSnippets.add(sqlSnippet);return this;}}

        10,核心类之 ExecutionSql

package com.example.dao.sql;import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;public class ExecutionSql {private String id;private String sql;private Map<String, List<?>> parameterTempData = new HashMap<>();public ExecutionSql() {id = UUID.randomUUID().toString().replace("-", "");id = id.substring(id.length() - 10);}public String getId() {return id;}public String getSql() {return sql;}public void setSql(String sql) {this.sql = sql;}public Map<String, List<?>> getParameterTempData() {return parameterTempData;}public void setParameterTempData(Map<String, List<?>> parameterTempData) {this.parameterTempData = parameterTempData;}}

        11,核心类之 BasicConditionQueryCriteria(入参)

package com.example.dao.sql;import lombok.Data;import java.util.List;
import java.util.Set;@Data
public class BasicConditionQueryCriteria implements Cloneable {private List<String> name;private List<Long> xx;private List<Integer> newName;
}

        12,编写测试类

import com.example.DemoApplication;
import com.example.dao.sql.*;
import com.example.entity.DataTemp;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.junit4.SpringRunner;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class)
@Slf4j
public class SqlBuilderTest {@Autowiredprivate JdbcTemplate jdbcTemplate;@Testpublic void test1(){BasicConditionQueryCriteria queryCriteria = new BasicConditionQueryCriteria();queryCriteria.setName(Arrays.asList("1","2"));//拼接sqlList<Column> columns = Arrays.asList(Column.of("t11.id","t11"),Column.of("t11.name","t11"),Column.of("t11.xx","t11"),Column.of("T1111.name as newName","T1111"));SqlBuilder sqlBuilder = new SqlBuilder();sqlBuilder.select(columns);sqlBuilder.setEnablePlaceholder(false);sqlBuilder.fromTable(Table.of("t11 t11").filter(BasicConditionQueryCriteria::getName,"t11.name")).leftJoin(Table.of("T1111 T1111").on("t11.name = T1111.name"));ExecutionSql executionSql = sqlBuilder.builder(queryCriteria);executionSql.setSql(executionSql.getSql() + " order by t11.id");log.info("sql:{}",executionSql.getSql());List<Map<String, Object>> maps = jdbcTemplate.queryForList(executionSql.getSql());maps.stream().forEach(v->{v.entrySet().stream().forEach(w->{log.info("key:{},value:{}",w.getKey(),w.getValue());});});}}

        13,项目结构类图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/323266.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【管理咨询宝藏93】大型制造集团数字化转型设计方案

【管理咨询宝藏93】大型制造集团数字化转型设计方案 【格式】PDF版本 【关键词】国际咨询公司、制造型企业转型、数字化转型 【核心观点】 - 235页大型制造型集团数字化转型方案设计&#xff01;细节非常详尽&#xff0c;图表丰富&#xff01; - 系统架构必须采用成熟、具有国…

美食推荐网站设计

**中文摘要&#xff1a;**在当今信息化、网络化的时代背景下&#xff0c;美食文化正逐渐融入人们的日常生活&#xff0c;而网络平台成为人们获取美食信息、分享美食体验的重要途径。为了满足广大美食爱好者对美食信息的探索和推荐需求&#xff0c;本文提出了一种创新的美食推荐…

YOLOv8网络结构介绍

将按照YOLOv8目标检测任务、实例分割任务、关键点检测任务以及旋转目标检测任务的顺序来介绍&#xff0c;主要内容也是在目标检测任务中介绍&#xff0c;其他任务也只是Head层不相同。 1.YOLOv8_det网络结构 首先&#xff0c;YOLOv8网络分成了三部分&#xff0c;分别是主干网络…

Spark云计算平台Databricks使用,创建workspace和Compute计算集群(Spark集群)

Databricks&#xff0c;是属于 Spark 的商业化公司&#xff0c;由美国加州大学伯克利 AMP 实验室的 Spark 大数据处理系统多位创始人联合创立。Databricks 致力于提供基于 Spark 的云服务&#xff0c;可用于数据集成&#xff0c;数据管道等任务。 1 创建workspace 点击创建wor…

word 毕业论文格式调整

添加页眉页脚 页眉 首先在页面上端页眉区域双击&#xff0c;即可出现“页眉和页脚”设置页面&#xff1a; 页眉左右两端对齐 如果想要页眉页脚左右两端对齐&#xff0c;可以选择添加三栏页眉&#xff0c;然后将中间那一栏删除&#xff0c;即可自动实现左右两端对齐&#x…

Spring Boot集成Ldap快速入门Demo

1.Ldap介绍 LDAP&#xff0c;Lightweight Directory Access Protocol&#xff0c;轻量级目录访问协议. LDAP是一种特殊的服务器&#xff0c;可以存储数据数据的存储是目录形式的&#xff0c;或者可以理解为树状结构&#xff08;一层套一层&#xff09;一般存储关于用户、用户…

吴恩达机器学习笔记:第 9 周-17大规模机器学习(Large Scale Machine Learning)17.3-17.4

目录 第 9 周 17、 大规模机器学习(Large Scale Machine Learning)17.3 小批量梯度下降17.4 随机梯度下降收敛 第 9 周 17、 大规模机器学习(Large Scale Machine Learning) 17.3 小批量梯度下降 小批量梯度下降算法是介于批量梯度下降算法和随机梯度下降算法之间的算法&…

基于Springboot的线上教学平台

基于SpringbootVue的线上教学平台设计与实现 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringbootMybatis工具&#xff1a;IDEA、Maven、Navicat 系统展示 用户登录 首页 学习资料 交流论坛 试卷列表 公告信息 后台登录 后台首页 学员管理 资料类型…

Junit 测试中如何对异常进行断言

本文对在 Junit 测试中如何对异常进行断言的几种方法进行说明。 使用 Junit 5 如果你使用 Junit 5 的话&#xff0c;你可以直接使用 assertThrows 方法来对异常进行断言。 代码如下&#xff1a; Exception exception assertThrows(NumberFormatException.class, () -> {n…

Universal Thresholdizer:将多种密码学原语门限化

参考文献&#xff1a; [LS90] Lapidot D, Shamir A. Publicly verifiable non-interactive zero-knowledge proofs[C]//Advances in Cryptology-CRYPTO’90: Proceedings 10. Springer Berlin Heidelberg, 1991: 353-365.[Shoup00] Shoup V. Practical threshold signatures[C…

七、 数据出境安全评估申报需要多长时间?

《评估申报指南&#xff08;第二版&#xff09;》未区分数据处理者进行数据出境安全评估线上申报和线下申报整体所需时间。一般情况下&#xff0c;数据出境安全评估的申报时长周期如图所示&#xff1a; 根据《评估申报指南&#xff08;第二版&#xff09;》第二条的规定&#…

Spirng-IOC零碎知识点

Spirng IOC 依赖注入 根据名称注入 <?xml version"1.0" encoding"UTF-8"?> <beansxmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xmlns:util"http://w…

引入RabbitMQ

前置条件 docker 安装 mq docker run \-e RABBITMQ_DEFAULT_USERdudu \-e RABBITMQ_DEFAULT_PASS123456 \-v mq-plugins:/plugins \--name mq \--hostname mq \-p 15672:15672 \-p 5672:5672 \--network hmall \-d \rabbitmq:3.8-management可能会出现&#xff1a;docker: Er…

【深度学习】【Lora训练0】StabelDiffusion,Lora训练,kohya_ss训练

文章目录 环境数据自动标注kohya_ss BLIP2kohya_ss WD14 后续 资源&#xff1a; &#xff08;1&#xff09;训练ui kohya_ss&#xff1a; https://github.com/bmaltais/kohya_ss &#xff08;2&#xff09;kohya_ss 的docker 其他docker https://github.com/ashleykleynhans…

GraphGPT——图结构数据的新语言模型

在人工智能的浪潮中&#xff0c;图神经网络&#xff08;GNNs&#xff09;已经成为理解和分析图结构数据的强大工具。然而&#xff0c;GNNs在面对未标记数据时&#xff0c;其泛化能力往往受限。为了突破这一局限&#xff0c;研究者们提出了GraphGPT&#xff0c;这是一种为大语言…

AcWing 161:电话列表 ← 字典树(Trie 树)之前缀匹配

【题目来源】https://www.acwing.com/problem/content/163/【题目描述】 给出一个电话列表&#xff0c;如果列表中存在其中一个号码是另一个号码的前缀这一情况&#xff0c;那么就称这个电话列表是不兼容的。 假设电话列表如下&#xff1a;Emergency 911 Alice 97625999 Bob …

2022 亚马逊云科技中国峰会,对话开发者论坛

目录 前言 最近整理资料发现还有一些前 2 年的内容没发出来&#xff0c;故补发记录&#xff0c;每年都有新的感悟。 开发者论坛 1. 你认为什么是开发者社区&#xff0c;如何定义一个成功的开发者社区&#xff1f; 我认为可以把开发者社区看成一个 “产品” 来对待&#xff…

ESP8266-01s刷入固件报SP8266 Chip efuse check error esp_check_mac_and_efuse

一、遇到的问题 使用ESP8266 固件烧录工具flash_download_tools_v3.6.8 烧录固件报错&#xff1a; 二、解决方法 使用espressif推出发基于python的底层烧写工具&#xff1a;esptool 安装方法&#xff1a;详见https://docs.espressif.com/projects/esptool/en/latest/esp32/ …

电脑中的两个固态硬盘比一个好,想知道为什么吗

你当前的电脑很有可能有一个NVME SSD作为主驱动器&#xff0c;但可能至少还有一个插槽可以放另一个SSD&#xff0c;而且这样做可能是个好主意。 两个SSD可以提高性能 如果你有两个固态硬盘&#xff0c;你可以从中获得比有一个更好的性能。一种方法是使用RAID 0将两个驱动器组…

《ESP8266通信指南》14-连接WIFI(基于Lua)

往期 《ESP8266通信指南》13-Lua 简单入门&#xff08;打印数据&#xff09;-CSDN博客 《ESP8266通信指南》12-Lua 固件烧录-CSDN博客 《ESP8266通信指南》11-Lua开发环境配置-CSDN博客 《ESP8266通信指南》10-MQTT通信&#xff08;Arduino开发&#xff09;-CSDN博客 《ES…