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.mzph.cn/pingmian/9826.shtml

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

相关文章

非模块化 Vue 开发的 bus 总线通信

个人感觉&#xff0c;JavaScript 非模块开发更适合新人上手&#xff0c;不需要安装配置一大堆软件环境&#xff0c;不需要编译&#xff0c;适合于中小项目开发&#xff0c;只需要一个代码编辑器即可开发&#xff0c;例如 vsCode。网页 html 文件通过 script 标签引入 JavaScrip…

使用Matplotlib绘制正弦和余弦函数曲线

前言 在数据可视化领域&#xff0c;Matplotlib是一个功能强大的Python库&#xff0c;它允许用户创建各种静态、交互式和动画图形。本文将引导您通过一个简单的示例&#xff0c;学习如何使用Matplotlib绘制正弦和余弦函数曲线。 第一步&#xff1a;导入必要的库&#xff1a; …

【漫画版】指挥官的排序战术:快速排序算法解密

作者介绍&#xff1a;10年大厂数据\经营分析经验&#xff0c;现任字节跳动数据部门负责人。 会一些的技术&#xff1a;数据分析、算法、SQL、大数据相关、python&#xff0c;欢迎探讨交流 欢迎加入社区&#xff1a;码上找工作 作者专栏每日更新&#xff1a; LeetCode解锁1000题…

基于自我对弈框架的偏好优化算法SPPO

传统的从人类反馈中进行强化学习&#xff08;RLHF&#xff09;的方法仰赖如Bradley-Terry模型等参数模型,但这样的模型难以充分捕捉人类偏好中的非递移性和非理性。最新的研究进展显示,直接使用偏好机率可以更准确地反映人类偏好,从而实现更灵活、更精确的语言模型对齐。本文提…

教你解决PUBG绝地求生登不进去 无法进入游戏 启动很慢的问题

尽管《绝地求生》&#xff08;PUBG&#xff09;以它那扣人心弦的战术竞技和逼真模拟的战场氛围风靡全球&#xff0c;揽获无数玩家的喜爱&#xff0c;但一些玩家在经历了一场血脉喷张的生存较量后&#xff0c;却不得不面对一个不那么愉悦的后续&#xff1a;游戏在结算阶段后出现…

YOLOv5改进 | 注意力机制 | 理解全局和局部信息的SE注意力机制

在深度学习目标检测领域&#xff0c;YOLOv5成为了备受关注的模型之一。本文给大家带来的是能够理解全局和局部信息的SE注意力机制。文章在介绍主要的原理后&#xff0c;将手把手教学如何进行模块的代码添加和修改&#xff0c;并将修改后的完整代码放在文章的最后&#xff0c;方…

C语言/数据结构——每日一题(分割链表)

一.前言 今天在LeetCode觉得很不错&#xff0c;想和大家们一起分享这道链表题——分割链表&#xff1a;https://leetcode.cn/problems/partition-list-lcci废话不多说&#xff0c;让我们直接进入正题吧。 二.正文 1.1题目描述 1.2题目分析 大致思路&#xff1a;我们可以通过…

从头开始的建材类电商小程序开发指南

在当今数字化时代&#xff0c;小程序已经成为了许多企业推广和销售的重要渠道。对于建筑材料行业来说&#xff0c;开发一个属于自己的小程序商城不仅可以提升产品曝光度&#xff0c;还可以提供更好的用户购物体验。下面&#xff0c;我们将逐步教你如何开发建筑材料行业小程序。…

文章分享:《肿瘤DNA甲基化标志物检测及临床应用专家共识(2024版)》

本文摘自于《肿瘤DNA甲基化标志物检测及临床应用专家共识&#xff08;2024版&#xff09;》 目录 1. DNA甲基化标志物概述 2 DNA甲基化标志物的临床检测 2.1 临床样本前处理注意事项 2.2 DNA甲基化标志物检测技术方法 2.2.1 DNA提取与纯化 2.2.2 DNA转化 2.2.3 DNA 甲基…

翻工第二次 Ant Design Pro 下载,发现问题,电脑网络配置有误,魔法了

一、相关网址链接 鱼皮的用户中心项目 &#xff08;前端Ant Design Pro构建&#xff09; 语雀 ## 没有选择umi版本这一步 Issue #11144 ant-design/ant-design-pro GitHub 关于umi ui图标未显示问题_umi ui不出现-CSDN博客 二、存在问题 导致下载速度慢 本人镜像代码写…

AI实景模型无人自动直播助手.减少商家在短视频线上卖货的成本,开启无人直播新时代!

在互联网时代&#xff0c;直播已经成为信息传播的主流方式&#xff0c;尤其是在年轻人中&#xff0c;直播更是备受追捧。然而&#xff0c;对于许多想要尝试直播的人来说&#xff0c;缺乏合适的主播可能成为一大障碍。那么&#xff0c;面对这一难题&#xff0c;如何实现手机无人…

C++ 常量

常量是指在程序运行过程中&#xff0c;其值不能被改变的量。 如&#xff1a;i255;arearr3.14; 在程序中直接使用数值有两个问题&#xff1a; 可读性差&#xff1b; 可维护差&#xff1b; 一 符号常量 C语言符号常量的顶用形式如下&#xff1a; 二 C99的const常量 C 语言co…

【C++】学习笔记——优先级队列

文章目录 十、优先级队列1. priority_queue的介绍2. 优先级队列如何使小的数据优先级高3. 仿函数介绍4. priority_queue的模拟实现 补&#xff1a; 反向迭代器未完待续 十、优先级队列 1. priority_queue的介绍 优先级队列 其实也不属于队列&#xff0c;它跟 stack 和 queue …

NSS刷题

1、[SWPUCTF 2021 新生赛]gift_f12 打开题目后查看源码无发现&#xff0c;用f12发现flag 2、[GDOUCTF 2023]hate eat snake 打开链接是一个贪吃蛇小游戏&#xff0c;f12找到js文件中有一个speed的语句&#xff0c;该语句的作用是使速度增加&#xff0c;因此&#xff0c;将该语…

引用数据类型 栈内存 堆内存

let m { a: 10, b: 20 }; let n m; n.a 15; console.log(m.a) // 15 原因&#xff1a;基本数据类型存储在栈内存中&#xff0c;引用数据类型存储在堆内存中 &#xff0c;引用数据类型存储在堆内存中会在栈内存中创建一个指针&#xff0c;栈内存中的这个指针指向堆内存中的地…

SpringCloud生态体系介绍

Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发&#xff0c;如服务发现注册、配置中心、智能路由、消息总线、负载均衡、断路器、数据监控等&#xff0c;都可以用Spring Boot的开发风格做到一键启动和部署。 SpringC…

linux上安装Jmeter环境

以前都是在Windows本机上使用界面版Jmeter&#xff0c;今天试一下安装到linux上在linux中使用&#xff0c;Jmeter的使用需要先安装jdk环境然后再配置jmeter。 1.配置环境 linux环境&#xff1a;Centos 8.2 64位 JDK版本&#xff1a;jdk-8u221-linux-x64.tar.gz &#xff08;…

数据中心法

数据中心法是实现词法分析器的结构化方法。通过设计主表和子表分开存储状态转移信息&#xff0c;实现词法分析器的控制逻辑和数据结构分离。 主要解决了状态爆炸、难以维护和复杂性的问题。 状态爆炸是指当状态和转移较多时&#xff0c;单一使用一个表来存储所有的信息的话会导…

YOLO数据集制作(一)|Labelme标注的矩形框json文件转txt

以下教程用于将使用Labelme软件标注生成的json格式文件转成YOLO使用的txt格式&#xff0c;适用场景&#xff1a;矩形框 使用方法&#xff1a;将json文件夹路径填到json_dir后&#xff0c; 将保存转化后txt的路径填入txt_dir后&#xff0c;运行即可转化。 运行完成后会生成label…

OpenAI 正在开发一种可以防止版权诉讼的工具

OpenAI 正在开发一种名为 Media Manager 的工具&#xff0c;该工具将使内容创建者和所有者能够确定他们是否愿意将自己的内容用于 ML 研究和 AI 模型训练。 Media Manager 将做什么&#xff1f; 明年推出的 Media Manager 将使内容创作者和所有者能够更好地控制他们的工作是否…