Skip to content

Commit

Permalink
update spring boot 3.2.1
Browse files Browse the repository at this point in the history
  • Loading branch information
vnobo committed Jan 10, 2024
1 parent da609c4 commit d031c13
Show file tree
Hide file tree
Showing 12 changed files with 151 additions and 105 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.platform.boot.commons.query;

import com.google.common.collect.Maps;

import java.io.Serializable;
import java.util.Map;
import java.util.StringJoiner;
Expand All @@ -10,8 +8,6 @@
* @author <a href="https://github.com/vnobo">Alex bob</a>
*/
public record ParamSql(StringJoiner sql, Map<String, Object> params) implements Serializable {
public final static ParamSql EMPTY = ParamSql.of(new StringJoiner(" AND "), Maps.newHashMap());

/**
* Creates a new ParamSql instance with the given SQL string and parameters.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
package com.platform.boot.commons.query;

import com.google.common.base.CaseFormat;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.springframework.data.domain.Sort;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.StringJoiner;
import java.util.*;
import java.util.stream.Collectors;

/**
Expand All @@ -32,75 +31,100 @@ public class QueryJson {
KEYWORDS.put("LTE", "<=");
KEYWORDS.put("LessThan", "<");
KEYWORDS.put("LT", "<");
KEYWORDS.put("Between", "BETWEEN");
KEYWORDS.put("NotBetween", "NOT BETWEEN");
KEYWORDS.put("NotIn", "NOT IN");
KEYWORDS.put("In", "IN");
KEYWORDS.put("IsNotNull", "IS NOT NULL");
KEYWORDS.put("NotNull", "IS NOT NULL");
KEYWORDS.put("IsNull", "IS NULL");
KEYWORDS.put("Null", "IS NULL");
KEYWORDS.put("NotLike", "NOT LIKE");
KEYWORDS.put("Like", "LIKE");
KEYWORDS.put("StartingWith", "LIKE");
KEYWORDS.put("EndingWith", "LIKE");
KEYWORDS.put("IsNotLike", "NOT LIKE");
KEYWORDS.put("Containing", "LIKE");
KEYWORDS.put("NotContaining", "NOT LIKE");
KEYWORDS.put("Between", "between");
KEYWORDS.put("NotBetween", "not between");
KEYWORDS.put("NotIn", "not in");
KEYWORDS.put("In", "in");
KEYWORDS.put("IsNotNull", "is not null");
KEYWORDS.put("NotNull", "is not null");
KEYWORDS.put("IsNull", "is null");
KEYWORDS.put("Null", "is null");
KEYWORDS.put("NotLike", "not like");
KEYWORDS.put("Like", "like");
KEYWORDS.put("StartingWith", "like");
KEYWORDS.put("EndingWith", "like");
KEYWORDS.put("IsNotLike", "not like");
KEYWORDS.put("Containing", "like");
KEYWORDS.put("NotContaining", "not like");
KEYWORDS.put("Not", "!=");
KEYWORDS.put("IsTrue", "IS TRUE");
KEYWORDS.put("True", "IS TRUE");
KEYWORDS.put("IsFalse", "IS FALSE");
KEYWORDS.put("False", "IS FALSE");
KEYWORDS.put("IsTrue", "is true");
KEYWORDS.put("True", "is true");
KEYWORDS.put("IsFalse", "is false");
KEYWORDS.put("False", "is false");
}

/**
* Generates a JSON query based on the provided parameters and returns a map
* of the generated SQL query and its corresponding parameters.
*
* @param params a map of key-value pairs representing the parameters for the query
* @return a map containing the generated SQL query and its parameters
*/
public static ParamSql queryJson(Map<String, Object> params) {
public static Sort sortJson(Sort sort, String prefix) {
if (sort == null || sort.isEmpty()) {
return Sort.unsorted();
}
List<Sort.Order> orders = Lists.newArrayList();
for (Sort.Order order : sort) {
String[] keys = StringUtils.delimitedListToStringArray(order.getProperty(), ".");
if (keys.length > 1) {
int lastIndex = keys.length - 1;
var sortReplaceArray = Arrays.copyOfRange(keys, 1, lastIndex);
String sortedProperty = keys[0];
if (StringUtils.hasLength(prefix)) {
sortedProperty = prefix + "." + sortedProperty;
}
String sortReplace = sortedProperty + jsonPathKey(sortReplaceArray).append("->>'")
.append(keys[lastIndex]).append("'");
orders.add(Sort.Order.by(sortReplace).with(order.getDirection()));
} else {
orders.add(order);
}
}
return Sort.by(orders);
}

public static ParamSql queryJson(Map<String, Object> params, String prefix) {
if (ObjectUtils.isEmpty(params)) {
return ParamSql.EMPTY;
return ParamSql.of(new StringJoiner(" AND "), Maps.newHashMap());
}
Map<String, Object> bindParams = Maps.newHashMap();
StringJoiner whereSql = new StringJoiner(" and ");
for (Map.Entry<String, Object> entry : params.entrySet()) {
String[] keys = StringUtils.delimitedListToStringArray(entry.getKey(), ".");
Map.Entry<String, String> exps = jsonPathKeyAndParamName(keys);
Map.Entry<String, String> exps = jsonPathKeyAndParamName(keys, prefix);
whereSql.add(exps.getValue());
bindParams.put(exps.getKey(), entry.getValue());
}
return ParamSql.of(whereSql, bindParams);
}

private static Map.Entry<String, String> jsonPathKeyAndParamName(String[] keys) {
String lastKey = keys[keys.length - 1];
String colum = keys[0];

Map.Entry<String, String> exps = exitsKeyWords(lastKey);

StringBuilder jsonPath = new StringBuilder(colum);

String[] joinKeys = Arrays.copyOfRange(keys, 1, keys.length - 1);
for (String path : joinKeys) {
var capath = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, path);
jsonPath.append("->'").append(capath).append("'");
private static Map.Entry<String, String> jsonPathKeyAndParamName(String[] keys, String prefix) {
int lastIndex = keys.length - 1;
String column = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, keys[0]);
if (StringUtils.hasLength(prefix)) {
column = prefix + "." + keys[0];
}
StringBuilder jsonPath = new StringBuilder(column);
String[] joinKeys = Arrays.copyOfRange(keys, 1, lastIndex);
jsonPath.append(jsonPathKey(joinKeys));

String lastKey = keys[lastIndex];
Map.Entry<String, String> exps = exitsKeyWords(lastKey);
String key = lastKey.substring(0, lastKey.length() - exps.getKey().length());
jsonPath.append("->>'").append(key).append("' ");

String paramName = StringUtils.arrayToDelimitedString(keys, "_");
if (!ObjectUtils.isEmpty(exps)) {
jsonPath.append(exps.getValue()).append(" :").append(paramName);
} else {
jsonPath.append("=").append(" :").append(paramName);
}

return Map.entry(paramName, jsonPath.toString());
}

private static StringBuilder jsonPathKey(String[] joinKeys) {
StringBuilder jsonPath = new StringBuilder();
for (String path : joinKeys) {
jsonPath.append("->'").append(path).append("'");
}
return jsonPath;
}

private static Map.Entry<String, String> exitsKeyWords(String inputStr) {
Set<Map.Entry<String, String>> entries = KEYWORDS.entrySet().stream()
.filter(entry -> StringUtils.endsWithIgnoreCase(inputStr, entry.getKey()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.google.common.base.CaseFormat;
import com.google.common.collect.Maps;
import com.platform.boot.commons.query.ParamSql;
import com.platform.boot.commons.query.QueryJson;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.relational.core.query.Criteria;
Expand Down Expand Up @@ -54,15 +55,17 @@ public static String applySort(Sort sort, String prefix) {
if (sort == null || sort.isUnsorted()) {
return "";
}
sort = QueryJson.sortJson(sort, prefix);
StringJoiner sortSql = new StringJoiner(", ");
sort.iterator().forEachRemaining((o) -> {
String sortedPropertyName = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, o.getProperty());
String sortedProperty = o.isIgnoreCase() ? "lower(" + sortedPropertyName + ")" : sortedPropertyName;
for (Sort.Order order : sort) {
String sortedPropertyName = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, order.getProperty());
String sortedProperty = order.isIgnoreCase() ? "lower(" + sortedPropertyName + ")" : sortedPropertyName;
if (StringUtils.hasLength(prefix)) {
sortedProperty = prefix + "." + sortedProperty;
}
sortSql.add(sortedProperty + (o.isAscending() ? " asc" : " desc"));
});
sortSql.add(sortedProperty + (order.isAscending() ? " asc" : " desc"));
}

return " order by " + sortSql;
}

Expand All @@ -74,20 +77,38 @@ public static String applySort(Sort sort, String prefix) {
* @param prefix the prefix for the SQL clause
* @return the generated WHERE SQL clause
*/
@SuppressWarnings("unchecked")
public static ParamSql buildParamSql(Object object, Collection<String> skipKeys, String prefix) {

Map<String, Object> objectMap = BeanUtils.beanToMap(object, false, true);
if (ObjectUtils.isEmpty(objectMap)) {
return ParamSql.EMPTY;
return ParamSql.of(new StringJoiner(" AND "), Maps.newHashMap());
}
ParamSql jsonParamSql = QueryJson.queryJson((Map<String, Object>) objectMap.get("query"), prefix);
Map<String, Object> params = jsonParamSql.params();
StringJoiner sql = jsonParamSql.sql();

if (!ObjectUtils.isEmpty(objectMap.get("securityCode"))) {
String key = "tenant_code";
if (StringUtils.hasLength(prefix)) {
key = prefix + "." + key;
}
sql.add(key + " like :securityCode");
params.put("securityCode", objectMap.get("securityCode"));
}

Set<String> removeKeys = new HashSet<>(SKIP_CRITERIA_KEYS);
removeKeys.add("query");
removeKeys.add("securityCode");
if (!ObjectUtils.isEmpty(skipKeys)) {
removeKeys.addAll(skipKeys);
}

objectMap = Maps.filterKeys(objectMap, key -> !removeKeys.contains(key));
return buildParamSql(objectMap, prefix);
ParamSql entityParamSql = buildParamSql(objectMap, prefix);
params.putAll(entityParamSql.params());
sql.merge(entityParamSql.sql());
return ParamSql.of(sql, params);
}

/**
Expand All @@ -100,20 +121,20 @@ public static ParamSql buildParamSql(Object object, Collection<String> skipKeys,
public static ParamSql buildParamSql(Map<String, Object> objectMap, String prefix) {
StringJoiner whereSql = new StringJoiner(" and ");
for (Map.Entry<String, Object> entry : objectMap.entrySet()) {
String key = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, entry.getKey());
String column = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, entry.getKey());
if (StringUtils.hasLength(prefix)) {
key = prefix + "." + key;
column = prefix + "." + column;
}

Object value = entry.getValue();
String paramName = ":" + entry.getKey();

if (value instanceof String) {
whereSql.add(key + " like " + paramName);
whereSql.add(column + " like " + paramName);
} else if (value instanceof Collection<?>) {
whereSql.add(key + " in :" + paramName);
whereSql.add(column + " in :" + paramName);
} else {
whereSql.add(key + " = " + paramName);
whereSql.add(column + " = " + paramName);
}
}
return ParamSql.of(whereSql, objectMap);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
public class SecurityController {

private final SecurityManager securityManager;

private final PasswordEncoder passwordEncoder;
private final ServerOAuth2AuthorizedClientRepository clientRepository;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
package com.platform.boot.security.core.tenant;

import com.platform.boot.commons.query.ParamSql;
import com.platform.boot.commons.utils.BeanUtils;
import com.platform.boot.commons.utils.CriteriaUtils;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.data.relational.core.query.Criteria;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.util.Set;
import java.util.List;
import java.util.Map;

/**
* @author <a href="https://github.com/vnobo">Alex bob</a>
Expand All @@ -19,6 +19,8 @@
@ToString(callSuper = true)
public class TenantRequest extends Tenant implements Serializable {

private Map<String, Object> query;

private String securityCode;

public TenantRequest securityCode(String securityCode) {
Expand All @@ -30,14 +32,7 @@ public Tenant toTenant() {
return BeanUtils.copyProperties(this, Tenant.class);
}

public Criteria toCriteria() {

Criteria criteria = CriteriaUtils.build(this, Set.of("securityCode"));

if (StringUtils.hasLength(this.securityCode)) {
criteria = criteria.and("code").like(this.securityCode + "%");
}

return criteria;
public ParamSql bindParamSql() {
return CriteriaUtils.buildParamSql(this, List.of(), null);
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package com.platform.boot.security.core.tenant;

import com.platform.boot.commons.base.AbstractDatabase;
import com.platform.boot.commons.query.ParamSql;
import com.platform.boot.commons.utils.BeanUtils;
import com.platform.boot.commons.utils.ContextUtils;
import com.platform.boot.commons.utils.CriteriaUtils;
import com.platform.boot.security.core.tenant.member.TenantMembersRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.relational.core.query.Query;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
Expand All @@ -25,17 +26,19 @@ public class TenantsService extends AbstractDatabase {

public Flux<Tenant> search(TenantRequest request, Pageable pageable) {
var cacheKey = ContextUtils.cacheKey(request, pageable);
var query = Query.query(request.toCriteria()).with(pageable);
return super.queryWithCache(cacheKey, query, Tenant.class)
ParamSql paramSql = request.bindParamSql();
String query = "select * from se_tenants" + paramSql.whereSql() + CriteriaUtils.applyPage(pageable);
return super.queryWithCache(cacheKey, query, paramSql.params(), Tenant.class)
.flatMap(ContextUtils::serializeUserAuditor);
}

public Mono<Page<Tenant>> page(TenantRequest request, Pageable pageable) {
var tenantsMono = this.search(request, pageable).collectList();

var cacheKey = ContextUtils.cacheKey(request);
Query query = Query.query(request.toCriteria());
var countMono = this.countWithCache(cacheKey, query, Tenant.class);
ParamSql paramSql = request.bindParamSql();
String query = "select count(*) from se_tenants" + paramSql.whereSql() + CriteriaUtils.applyPage(pageable);
var countMono = this.countWithCache(cacheKey, query, paramSql.params());

return Mono.zip(tenantsMono, countMono)
.map(tuple2 -> new PageImpl<>(tuple2.getT1(), pageable, tuple2.getT2()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ public class User implements BaseEntity<Long> {
@NotBlank(message = "user code [code] cannot be empty!", groups = Update.class)
private String code;

@NotBlank(message = "Tenant [tenantCode] not be empty!")
private String tenantCode;

@NotBlank(message = "Login username [username] cannot be empty!")
@Pattern(regexp = "^[a-zA-Z0-9_-]{6,16}$", message = "Login username [username] must be " +
"6 to 16 characters (letters, numbers, _, -)!")
Expand Down
Loading

0 comments on commit d031c13

Please sign in to comment.