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<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 PageParam(U where) {
|
this(where, true);
|
}
|
|
public PageParam(U where, Class<T> cls) {
|
this(where, true, cls);
|
}
|
|
public PageParam(U where, boolean isToUnderlineCase) {
|
this(where, isToUnderlineCase, null);
|
}
|
|
public PageParam(U where, boolean isToUnderlineCase, Class<T> 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<T> buildWrapper(boolean like) {
|
return this.buildWrapper(like, null, "create_time");
|
}
|
|
public QueryWrapper<T> buildWrapper(boolean like, String timeField) {
|
return this.buildWrapper(like, null, timeField);
|
}
|
|
public QueryWrapper<T> buildWrapper(boolean like, List<String> fields) {
|
return this.buildWrapper(like, null, "create_time", fields);
|
}
|
|
@SuppressWarnings("all")
|
public QueryWrapper<T> buildWrapper(boolean like, Consumer<QueryWrapper<T>> consumer, String timeField) {
|
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) {
|
list = (ArrayList<String>) 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<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)) {
|
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<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) {
|
list = (ArrayList<String>) 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<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)) {
|
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<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()) {
|
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<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())) {
|
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;
|
}
|
|
|
}
|