feat(uapbd): 新增仓库的查询&实现查询接口的 SQL 动态条件生成

- 新增 QuerySyncSqlUtils 工具类,用于构建通用 SQL 条件
- 在 QuerySync 类中实现查询逻辑,使用新工具类生成 SQL 条件
- 添加分页功能,处理大量数据查询
- 优化 SQL 查询性能,通过 IN 子句批量查询主键
This commit is contained in:
maolei 2025-05-12 14:02:04 +08:00
parent a4631eacee
commit f4b5957a7b
2 changed files with 161 additions and 2 deletions

View File

@ -1,12 +1,19 @@
package nccloud.api.uapbd; package nccloud.api.uapbd;
import com.alibaba.fastjson.JSONObject;
import nc.bs.dao.BaseDAO;
import nc.bs.dao.DAOException;
import nc.jdbc.framework.processor.ColumnListProcessor;
import nc.jdbc.framework.processor.MapListProcessor;
import nccloud.api.rest.utils.IJsonForAPI; import nccloud.api.rest.utils.IJsonForAPI;
import nccloud.api.rest.utils.JsonFactoryForAPI; import nccloud.api.rest.utils.JsonFactoryForAPI;
import nccloud.api.rest.utils.OpenApiPageInfo;
import nccloud.api.rest.utils.ResultMessageUtil; import nccloud.api.rest.utils.ResultMessageUtil;
import nccloud.api.rest.utils.vo.ApiDataVO; import nccloud.api.rest.utils.vo.ApiDataVO;
import nccloud.api.rest.utils.vo.ApiQueryParam; import nccloud.api.rest.utils.vo.ApiQueryParam;
import nccloud.api.rest.utils.vo.ApiUfinterface; import nccloud.api.rest.utils.vo.ApiUfinterface;
import nccloud.api.uapbd.common.utils.OpenApiPagenationUtils;
import nccloud.ws.rest.resource.AbstractNCCRestResource; import nccloud.ws.rest.resource.AbstractNCCRestResource;
import org.json.JSONString; import org.json.JSONString;
@ -14,10 +21,15 @@ import javax.ws.rs.Consumes;
import javax.ws.rs.POST; import javax.ws.rs.POST;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
@Path("/uapbd/querySync") @Path("/uapbd/querySync")
public class QuerySync extends AbstractNCCRestResource { public class QuerySync extends AbstractNCCRestResource {
public static final BaseDAO BASE_DAO = new BaseDAO();
@Override @Override
public String getModule() { public String getModule() {
return "uapbd"; return "uapbd";
@ -51,9 +63,29 @@ public class QuerySync extends AbstractNCCRestResource {
} }
} }
private JSONString queryStordoc(ApiUfinterface apiUfinterface) { private JSONString queryStordoc(ApiUfinterface apiUfinterface) throws DAOException {
Map<String, Object> data = apiUfinterface.getData().getParamdata();
JSONObject pageInfo = (JSONObject) JSONObject.toJSON(apiUfinterface.getPageInfo());
data.remove("type");
String condition = QuerySyncSqlUtils.buildUniversalCondition(data);
return null; String sql = "SELECT pk_stordoc FROM V_UAPBD_QUERYSYNC_STORDOC WHERE " + condition;
List<String> allPks = (List<String>) BASE_DAO.executeQuery(sql, new ColumnListProcessor());
OpenApiPageInfo openApiPageInfo = new OpenApiPageInfo();
String[] currPks = OpenApiPagenationUtils.getCurrentPagePksAndPageInfo(allPks, pageInfo, openApiPageInfo);
if (currPks == null || currPks.length == 0) {
return ResultMessageUtil.toJSONByPage(new JSONObject[0], openApiPageInfo, false);
}
StringJoiner stringJoiner = new StringJoiner(",");
for (String pk : currPks) {
stringJoiner.add("'" + pk + "'");
}
String pks = "(" + stringJoiner + ")";
List<Map<String, Object>> rows = (List<Map<String, Object>>) BASE_DAO.executeQuery("select * from v_uapbd_querysync_stordoc where pk_stordoc in " + pks, new MapListProcessor());
return ResultMessageUtil.toJSONByPage(rows, openApiPageInfo, false);
} }
} }

View File

@ -0,0 +1,127 @@
package nccloud.api.uapbd;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class QuerySyncSqlUtils {
/**
* 构建SQL IN子句
* 例如fieldName IN ('value1', 123, NULL)
* 此方法假定传入的 `values` 列表是非空的由调用方 `buildUniversalCondition` 保证
*
* @param fieldName 字段名
* @param values 值的列表 (来自非空数组或List)
* @return 构建好的IN子句字符串
*/
private static String buildInClause(String fieldName, List<?> values) {
String inValues = values.stream()
.map(val -> {
if (val == null) {
return "NULL"; // SQL中的NULL字面量
}
if (val instanceof String) {
return "'" + escapeSql((String) val) + "'";
}
if (val instanceof Number || val instanceof Boolean) {
return val.toString(); // 数字和布尔值不需要单引号
}
// 对于其他类型例如日期自定义对象等默认按其toString()处理进行转义和加单引号
return "'" + escapeSql(val.toString()) + "'";
})
.collect(Collectors.joining(", ")); // 注意用逗号和空格分隔更美观
return fieldName + " IN (" + inValues + ")";
}
/**
* 通用构建SQL条件
* 根据参数Map动态生成SQL WHERE子句的条件部分
* - 对于简单值非null非空字符串使用相等匹配 (field = value)
* - 对于非空数组或List类型的值使用IN匹配 (field IN (value1, value2, ...))
* - 如果参数值为null空字符串空List或空数组则不处理该字段
* - 最终生成的条件会被圆括号包裹
* - 如果没有有效的条件生成例如map为空或所有值都无效则返回 "(1=1)" 以确保SQL语法正确
*
* @param paramMap 参数Map键为字段名值为字段值
* @return 构建好的SQL条件字符串例如 "(field1 = 'value1' AND field2 IN ('a', 'b'))" "(1=1)"
*/
public static String buildUniversalCondition(Map<String, Object> paramMap) {
if (paramMap == null || paramMap.isEmpty()) {
return "(1=1)"; // 如果参数map本身为null或空直接返回(1=1)
}
List<String> conditions = new ArrayList<>();
for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
String fieldName = entry.getKey();
Object value = entry.getValue();
// 1. 如果值本身为 null则不处理此条目
if (value == null) {
continue;
}
// 2. 根据值的类型进行处理
if (value instanceof String) {
String stringValue = (String) value;
if (stringValue.trim().isEmpty()) { // 如果是空字符串或仅含空格
continue; // 不处理
}
conditions.add(fieldName + " = " + formatSqlValue(stringValue));
} else if (value instanceof List) {
List<?> listValue = (List<?>) value;
if (listValue.isEmpty()) { // 如果列表为空
continue; // 不处理
}
conditions.add(buildInClause(fieldName, listValue));
} else if (value.getClass().isArray()) {
int length = Array.getLength(value);
if (length == 0) { // 如果数组为空
continue; // 不处理
}
List<Object> arrayAsList = new ArrayList<>(length);
for (int i = 0; i < length; i++) {
arrayAsList.add(Array.get(value, i));
}
conditions.add(buildInClause(fieldName, arrayAsList)); // 数组元素已转为List处理
} else {
// 其他非null非空字符串非空集合/数组的类型例如数字布尔值日期等
// formatSqlValue 会处理它们的格式化
conditions.add(fieldName + " = " + formatSqlValue(value));
}
}
if (conditions.isEmpty()) {
return "(1=1)"; // 如果没有收集到任何有效条件返回(1=1)
}
return "(" + String.join(" AND ", conditions) + ")"; // 用AND连接并用括号包裹
}
private static String escapeSql(String value) {
return value == null ? null : value.replace("'", "''");
}
/**
* 格式化SQL查询中的单个值用于相等条件
* 此方法假定传入的 `value` 非null且如果是字符串非空
*
* @param value 要格式化的值 (不为null)
* @return 格式化后的SQL值字符串
*/
private static String formatSqlValue(Object value) {
// value 在这里保证不为null
if (value instanceof String) {
// 空字符串的检查已在 buildUniversalCondition 中完成
return "'" + escapeSql((String) value) + "'";
} else if (value instanceof Number || value instanceof Boolean) {
return value.toString(); // 数字和布尔值直接使用其字符串表示不加单引号
}
return "'" + escapeSql(value.toString()) + "'";
}
}