package com.vincent.rsf.server.common.domain; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.OrderItem; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.vincent.rsf.common.utils.Utils; import com.vincent.rsf.framework.common.Cools; import com.vincent.rsf.framework.common.DateUtils; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.*; import java.util.function.Consumer; /** * Created by vincent on 2/13/2024 */ @Slf4j public class PageParam extends Page { private static final long serialVersionUID = 1L; public static final String ORDER_DESC_VALUE = "desc"; @Getter private final U where; /** * 是否把字段名称驼峰转下划线 */ private final boolean isToUnderlineCase; private final Class cls; /** * 额外的字段验证类列表(用于支持 DTO、VO 等类的字段验证) */ private List> additionalFieldClasses; public PageParam() { this(null); } public PageParam(U where) { this(where, true); } public PageParam(U where, Class cls) { this(where, true, cls); } public PageParam(U where, boolean isToUnderlineCase) { this(where, isToUnderlineCase, null); } public PageParam(U where, boolean isToUnderlineCase, Class cls) { super(); this.where = where; this.isToUnderlineCase = isToUnderlineCase; this.cls = cls; if (where != null) { if (where.getCurrent() != null) { setCurrent(where.getCurrent()); } if (where.getPageSize() != null) { setSize(where.getPageSize()); } } } public QueryWrapper buildWrapper(boolean like) { return this.buildWrapper(like, null, "create_time"); } public QueryWrapper buildWrapper(boolean like, String timeField) { return this.buildWrapper(like, null, timeField); } public QueryWrapper buildWrapper(boolean like, List fields) { return this.buildWrapper(like, null, "create_time", fields); } @SuppressWarnings("all") public QueryWrapper buildWrapper(boolean like, Consumer> consumer, String timeField) { QueryWrapper queryWrapper = new QueryWrapper<>(); Map map = where.getMap(); for (String key : map.keySet()) { Object val = map.get(key); if (Cools.isEmpty(val)){ continue; } if (key.contains("Range")) { ArrayList list = null; if (val instanceof ArrayList) { list = (ArrayList) val; } if (null != list) { key = key.replaceAll("Range", ""); if (this.isToUnderlineCase) { key = Utils.toSymbolCase(key, '_'); } queryWrapper.ge(key, DateUtils.convert(list.get(0))); queryWrapper.le(key, DateUtils.convert(list.get(1))); } } else { if (this.isToUnderlineCase) { key = Utils.toSymbolCase(key, '_'); } String finalKey = key; if (like && key.contains(timeField)) { queryWrapper.and(wrapper -> wrapper.like("`" + finalKey + "`", val)); // queryWrapper.like("`" + key + "`", val); } else { queryWrapper.and(wrapper -> wrapper.eq("`" + finalKey + "`", val)); // queryWrapper.eq("`" + key + "`", val); } } } if (null != consumer) { consumer.accept(queryWrapper); } if (!Cools.isEmpty(where.getTimeStart())) { Date timeStart = DateUtils.convert(String.valueOf(where.getTimeStart()), DateUtils.yyyyMMdd_F); queryWrapper.ge(timeField, timeStart); } if (!Cools.isEmpty(where.getTimeEnd())) { Date timeStart = DateUtils.convert(String.valueOf(where.getTimeEnd()), DateUtils.yyyyMMdd_F); queryWrapper.le(timeField, timeStart); } if (!Cools.isEmpty(where.getOrderBy())) { if (sortIsSQL(where.getOrderBy())) { List orders = parseOrderSQL(where.getOrderBy()); // 如果所有排序字段都无效,使用默认排序 if (orders.isEmpty()) { queryWrapper.orderByDesc("create_time"); } else { setOrders(orders); } } } else { // queryWrapper.orderByDesc("create_time"); } if (!Cools.isEmpty(where.getCondition()) && !Cools.isEmpty(cls)) { List columns = new ArrayList<>(); for (Field field : Cools.getAllFields(cls)) { if (Modifier.isFinal(field.getModifiers()) || Modifier.isStatic(field.getModifiers()) || Modifier.isTransient(field.getModifiers())) { continue; } if (field.isAnnotationPresent(TableField.class)) { TableField annotation = field.getAnnotation(TableField.class); if (!annotation.exist()) { continue; } } String column = Utils.toSymbolCase(field.getName(), '_'); columns.add(column); } if (!columns.isEmpty()) { queryWrapper.and(wrapper -> { for (int i = 0; i < columns.size(); i++) { String column = columns.get(i); String condition = where.getCondition(); if (i == 0) { wrapper.or().like("`" + column + "`", condition); } else { wrapper.or().like("`" + column + "`", condition); } } }); } } return queryWrapper; } @SuppressWarnings("all") public QueryWrapper buildWrapper(boolean like, Consumer> consumer, String timeField, List fields) { QueryWrapper queryWrapper = new QueryWrapper<>(); Map map = where.getMap(); for (String key : map.keySet()) { Object val = map.get(key); if (Cools.isEmpty(val)){ continue; } if (key.contains("Range")) { ArrayList list = null; if (val instanceof ArrayList) { list = (ArrayList) val; } if (null != list) { key = key.replaceAll("Range", ""); if (this.isToUnderlineCase) { key = Utils.toSymbolCase(key, '_'); } queryWrapper.ge(key, DateUtils.convert(list.get(0))); queryWrapper.le(key, DateUtils.convert(list.get(1))); } } else { if (this.isToUnderlineCase) { key = Utils.toSymbolCase(key, '_'); } if (like && !fields.contains(key)) { queryWrapper.like("`" + key + "`", val); } else { queryWrapper.eq("`" + key + "`", val); } } } if (null != consumer) { consumer.accept(queryWrapper); } if (!Cools.isEmpty(where.getTimeStart())) { Date timeStart = DateUtils.convert(String.valueOf(where.getTimeStart()), DateUtils.yyyyMMdd_F); queryWrapper.ge(timeField, timeStart); } if (!Cools.isEmpty(where.getTimeEnd())) { Date timeStart = DateUtils.convert(String.valueOf(where.getTimeEnd()), DateUtils.yyyyMMdd_F); queryWrapper.le(timeField, timeStart); } if (!Cools.isEmpty(where.getOrderBy())) { if (sortIsSQL(where.getOrderBy())) { List orders = parseOrderSQL(where.getOrderBy()); // 如果所有排序字段都无效,使用默认排序 if (orders.isEmpty()) { queryWrapper.orderByDesc("create_time"); } else { setOrders(orders); } } } else { // queryWrapper.orderByDesc("create_time"); } if (!Cools.isEmpty(where.getCondition()) && !Cools.isEmpty(cls)) { List columns = new ArrayList<>(); for (Field field : Cools.getAllFields(cls)) { if (Modifier.isFinal(field.getModifiers()) || Modifier.isStatic(field.getModifiers()) || Modifier.isTransient(field.getModifiers())) { continue; } if (field.isAnnotationPresent(TableField.class)) { TableField annotation = field.getAnnotation(TableField.class); if (!annotation.exist()) { continue; } } String column = Utils.toSymbolCase(field.getName(), '_'); columns.add(column); } // if (!columns.isEmpty()) { // for (int i=0;i wrapper.like("`" + column + "`", condition)); // } else { // queryWrapper.or().like("`" + column + "`", condition); // } // } // } if (!columns.isEmpty()) { queryWrapper.and(wrapper -> { for (int i = 0; i < columns.size(); i++) { String column = columns.get(i); String condition = where.getCondition(); if (i == 0) { wrapper.or().like("`" + column + "`", condition); } else { wrapper.or().like("`" + column + "`", condition); } } }); } } return queryWrapper; } private boolean sortIsSQL(String sort) { return sort != null && (sort.contains(",") || sort.trim().contains(" ")); } private List parseOrderSQL(String orderSQL) { List orders = new ArrayList<>(); if (!Cools.isEmpty(orderSQL)) { // 获取实体类的有效字段列表 Set validColumns = getValidColumns(); for (String item : orderSQL.split(",")) { String[] temp = item.trim().split(" "); if (!temp[0].isEmpty()) { String column = this.isToUnderlineCase ? Utils.toSymbolCase(temp[0], '_') : temp[0]; // 验证字段是否存在,如果不存在则跳过 if (validColumns != null && !validColumns.isEmpty() && !validColumns.contains(column)) { // 获取当前请求信息 String requestInfo = getRequestInfo(); // log.warn("跳过无效的排序字段: '{}' (原始值: '{}'),实体类: {},请求地址: {}", // column, temp[0], cls != null ? cls.getSimpleName() : "null", requestInfo); continue; } boolean asc = temp.length == 1 || !temp[temp.length - 1].toLowerCase().equals(ORDER_DESC_VALUE); orders.add(new OrderItem(column, asc)); } } } return orders; } /** * 获取当前请求信息(路径和方法) * @return 请求信息字符串,格式:HTTP方法 请求路径 */ private String getRequestInfo() { try { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (attributes != null) { HttpServletRequest request = attributes.getRequest(); if (request != null) { String method = request.getMethod(); String uri = request.getRequestURI(); return String.format("%s %s", method, uri); } } } catch (Exception e) { // 忽略异常,避免影响主流程 log.debug("获取请求信息失败: {}", e.getMessage()); } return "未知"; } /** * 获取实体类的有效字段列表(用于验证排序字段) * 包括:实体类字段、以及额外指定的DTO/VO类字段 * 注意:BaseParam 的字段是查询参数,不用于数据库字段验证 */ private Set getValidColumns() { Set columns = new HashSet<>(); // 1. 获取实体类(cls)的字段 if (cls != null) { addFieldsFromClass(cls, columns); } // 2. 获取额外指定的类(DTO/VO等)的字段 if (additionalFieldClasses != null && !additionalFieldClasses.isEmpty()) { for (Class clazz : additionalFieldClasses) { addFieldsFromClass(clazz, columns); } } return columns.isEmpty() ? null : columns; } /** * 从指定类中提取字段并添加到集合中 * @param clazz 要提取字段的类 * @param columns 字段集合 */ private void addFieldsFromClass(Class clazz, Set columns) { for (Field field : Cools.getAllFields(clazz)) { // 跳过 final、static、transient 字段 if (Modifier.isFinal(field.getModifiers()) || Modifier.isStatic(field.getModifiers()) || Modifier.isTransient(field.getModifiers())) { continue; } // 跳过标记为 exist=false 的字段(这些字段不存在于数据库中) if (field.isAnnotationPresent(TableField.class)) { TableField annotation = field.getAnnotation(TableField.class); if (!annotation.exist()) { continue; } } String column = Utils.toSymbolCase(field.getName(), '_'); columns.add(column); } } /** * 设置额外的字段验证类列表(用于支持 DTO、VO 等类的字段验证) * @param classes 额外的类列表 * @return 当前实例,支持链式调用 */ public PageParam setAdditionalFieldClasses(Class... classes) { if (classes != null && classes.length > 0) { this.additionalFieldClasses = Arrays.asList(classes); } return this; } /** * 设置额外的字段验证类列表(用于支持 DTO、VO 等类的字段验证) * @param classes 额外的类列表 * @return 当前实例,支持链式调用 */ public PageParam setAdditionalFieldClasses(List> classes) { this.additionalFieldClasses = classes; return this; } public Map checkoutMap() { Map map = where.getMap(); if (!Cools.isEmpty(where.getOrderBy())) { map.put("orderBy", where.getOrderBy()); } if (!Cools.isEmpty(where.getTimeStart())) { map.put("timeStart", DateUtils.convert(String.valueOf(where.getTimeStart()), DateUtils.yyyyMMdd_F)); } if (!Cools.isEmpty(where.getTimeEnd())) { map.put("timeEnd", DateUtils.convert(String.valueOf(where.getTimeEnd()), DateUtils.yyyyMMdd_F)); } if (!Cools.isEmpty(where.getCondition())) { map.put("condition", where.getCondition()); } return map; } }