| | |
| | | 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.*; |
| | |
| | | /** |
| | | * Created by vincent on 2/13/2024 |
| | | */ |
| | | @Slf4j |
| | | public class PageParam<T, U extends BaseParam> extends Page<T> { |
| | | |
| | | 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<T> cls; |
| | | |
| | | /** |
| | | * 额外的字段验证类列表(用于支持 DTO、VO 等类的字段验证) |
| | | */ |
| | | private List<Class<?>> additionalFieldClasses; |
| | | |
| | | public PageParam() { |
| | | this(null); |
| | |
| | | } |
| | | |
| | | public QueryWrapper<T> buildWrapper(boolean like, List<String> fields) { |
| | | return this.buildWrapper(like, null,"create_time", fields); |
| | | return this.buildWrapper(like, null, "create_time", fields); |
| | | } |
| | | |
| | | @SuppressWarnings("all") |
| | |
| | | Map<String, Object> map = where.getMap(); |
| | | for (String key : map.keySet()) { |
| | | Object val = map.get(key); |
| | | |
| | | if (Cools.isEmpty(val)){ |
| | | continue; |
| | | } |
| | | if (key.contains("Range")) { |
| | | ArrayList<String> list = null; |
| | | if (val instanceof ArrayList) { |
| | |
| | | |
| | | if (!Cools.isEmpty(where.getOrderBy())) { |
| | | if (sortIsSQL(where.getOrderBy())) { |
| | | setOrders(parseOrderSQL(where.getOrderBy())); |
| | | List<OrderItem> 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<String> columns = new ArrayList<>(); |
| | | for (Field field : Cools.getAllFields(cls)){ |
| | | for (Field field : Cools.getAllFields(cls)) { |
| | | if (Modifier.isFinal(field.getModifiers()) |
| | | || Modifier.isStatic(field.getModifiers()) |
| | | || Modifier.isTransient(field.getModifiers())){ |
| | | || Modifier.isTransient(field.getModifiers())) { |
| | | continue; |
| | | } |
| | | |
| | | if (field.isAnnotationPresent(TableField.class)){ |
| | | if (field.isAnnotationPresent(TableField.class)) { |
| | | TableField annotation = field.getAnnotation(TableField.class); |
| | | if (!annotation.exist()) { |
| | | continue; |
| | | } |
| | | } |
| | | |
| | | String column = Utils.toSymbolCase(field.getName(), '_'); |
| | | String column = Utils.toSymbolCase(field.getName(), '_'); |
| | | columns.add(column); |
| | | } |
| | | if (!columns.isEmpty()) { |
| | | queryWrapper.and(wrapper -> { |
| | | for (int i=0;i<columns.size();i++){ |
| | | for (int i = 0; i < columns.size(); i++) { |
| | | String column = columns.get(i); |
| | | String condition = where.getCondition(); |
| | | if (i == 0) { |
| | |
| | | } |
| | | |
| | | @SuppressWarnings("all") |
| | | public QueryWrapper<T> buildWrapper(boolean like, Consumer<QueryWrapper<T>> consumer,String timeField, List<String> fields) { |
| | | public QueryWrapper<T> buildWrapper(boolean like, Consumer<QueryWrapper<T>> consumer, String timeField, List<String> fields) { |
| | | QueryWrapper<T> queryWrapper = new QueryWrapper<>(); |
| | | Map<String, Object> map = where.getMap(); |
| | | for (String key : map.keySet()) { |
| | | Object val = map.get(key); |
| | | |
| | | if (Cools.isEmpty(val)){ |
| | | continue; |
| | | } |
| | | if (key.contains("Range")) { |
| | | ArrayList<String> list = null; |
| | | if (val instanceof ArrayList) { |
| | |
| | | key = Utils.toSymbolCase(key, '_'); |
| | | } |
| | | if (like && !fields.contains(key)) { |
| | | queryWrapper.like("`" + key + "`", val); |
| | | queryWrapper.like("`" + key + "`", val); |
| | | } else { |
| | | queryWrapper.eq("`" + key + "`", val); |
| | | queryWrapper.eq("`" + key + "`", val); |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | if (!Cools.isEmpty(where.getOrderBy())) { |
| | | if (sortIsSQL(where.getOrderBy())) { |
| | | setOrders(parseOrderSQL(where.getOrderBy())); |
| | | List<OrderItem> 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<String> columns = new ArrayList<>(); |
| | | for (Field field : Cools.getAllFields(cls)){ |
| | | for (Field field : Cools.getAllFields(cls)) { |
| | | if (Modifier.isFinal(field.getModifiers()) |
| | | || Modifier.isStatic(field.getModifiers()) |
| | | || Modifier.isTransient(field.getModifiers())){ |
| | | || Modifier.isTransient(field.getModifiers())) { |
| | | continue; |
| | | } |
| | | |
| | | if (field.isAnnotationPresent(TableField.class)){ |
| | | if (field.isAnnotationPresent(TableField.class)) { |
| | | TableField annotation = field.getAnnotation(TableField.class); |
| | | if (!annotation.exist()) { |
| | | continue; |
| | | } |
| | | } |
| | | |
| | | String column = Utils.toSymbolCase(field.getName(), '_'); |
| | | String column = Utils.toSymbolCase(field.getName(), '_'); |
| | | columns.add(column); |
| | | } |
| | | // if (!columns.isEmpty()) { |
| | | // for (int i=0;i<columns.size();i++){ |
| | | // String column = columns.get(i); |
| | | // String condition = where.getCondition(); |
| | | // |
| | | // if (i == 0) { |
| | | // queryWrapper.and(wrapper -> wrapper.like("`" + column + "`", condition)); |
| | | // } else { |
| | | // queryWrapper.or().like("`" + column + "`", condition); |
| | | // } |
| | | // } |
| | | // } |
| | | if (!columns.isEmpty()) { |
| | | for (int i=0;i<columns.size();i++){ |
| | | String column = columns.get(i); |
| | | String condition = where.getCondition(); |
| | | |
| | | if (i == 0) { |
| | | queryWrapper.and(wrapper -> wrapper.like("`" + column + "`", condition)); |
| | | } else { |
| | | queryWrapper.or().like("`" + column + "`", condition); |
| | | 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 List<OrderItem> parseOrderSQL(String orderSQL) { |
| | | List<OrderItem> orders = new ArrayList<>(); |
| | | if (!Cools.isEmpty(orderSQL)) { |
| | | // 获取实体类的有效字段列表 |
| | | Set<String> 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<String> getValidColumns() { |
| | | Set<String> 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<String> 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<T, U> setAdditionalFieldClasses(Class<?>... classes) { |
| | | if (classes != null && classes.length > 0) { |
| | | this.additionalFieldClasses = Arrays.asList(classes); |
| | | } |
| | | return this; |
| | | } |
| | | |
| | | /** |
| | | * 设置额外的字段验证类列表(用于支持 DTO、VO 等类的字段验证) |
| | | * @param classes 额外的类列表 |
| | | * @return 当前实例,支持链式调用 |
| | | */ |
| | | public PageParam<T, U> setAdditionalFieldClasses(List<Class<?>> classes) { |
| | | this.additionalFieldClasses = classes; |
| | | return this; |
| | | } |
| | | |
| | | public Map<String, Object> checkoutMap() { |
| | | Map<String, Object> map = where.getMap(); |
| | | if (!Cools.isEmpty(where.getOrderBy())) { |