feat(uapbd): 新增仓库的查询&实现查询接口的 SQL 动态条件生成
- 新增 QuerySyncSqlUtils 工具类,用于构建通用 SQL 条件 - 在 QuerySync 类中实现查询逻辑,使用新工具类生成 SQL 条件 - 添加分页功能,处理大量数据查询 - 优化 SQL 查询性能,通过 IN 子句批量查询主键
This commit is contained in:
parent
a4631eacee
commit
f4b5957a7b
|
@ -1,12 +1,19 @@
|
|||
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.JsonFactoryForAPI;
|
||||
import nccloud.api.rest.utils.OpenApiPageInfo;
|
||||
import nccloud.api.rest.utils.ResultMessageUtil;
|
||||
import nccloud.api.rest.utils.vo.ApiDataVO;
|
||||
import nccloud.api.rest.utils.vo.ApiQueryParam;
|
||||
import nccloud.api.rest.utils.vo.ApiUfinterface;
|
||||
import nccloud.api.uapbd.common.utils.OpenApiPagenationUtils;
|
||||
import nccloud.ws.rest.resource.AbstractNCCRestResource;
|
||||
import org.json.JSONString;
|
||||
|
||||
|
@ -14,10 +21,15 @@ import javax.ws.rs.Consumes;
|
|||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
|
||||
@Path("/uapbd/querySync")
|
||||
public class QuerySync extends AbstractNCCRestResource {
|
||||
|
||||
public static final BaseDAO BASE_DAO = new BaseDAO();
|
||||
@Override
|
||||
public String getModule() {
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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()) + "'";
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue