feat(REQ-2972): 支持传统分页和游标分页
This commit is contained in:
parent
170bec1b89
commit
769126b9f8
@ -26,7 +26,8 @@ public interface LogApi {
|
||||
/**
|
||||
* 通过筛查条件查询日志列表
|
||||
* <p>
|
||||
* 若所有条件为空,则返回按时间序倒排的1000条日志
|
||||
* 1. 若所有条件为空,则返回最近的1000条日志
|
||||
* 2. 支持分页(可通过开关控制),默认开启,最多返回1000条
|
||||
* </p>
|
||||
*
|
||||
* @param req 查询条件 {@link LogFindReq}
|
||||
|
||||
@ -41,28 +41,53 @@ public class LogFindReq {
|
||||
* 日志内容筛查
|
||||
* 具体使用可参考:https://alidocs.dingtalk.com/i/nodes/YndMj49yWj7q1dB9hQLNneo0V3pmz5aA
|
||||
* <p>
|
||||
* message中可嵌套json,当需要查询内部json中某个字段的相关情况时,key为message.xxx,例如:message.userId
|
||||
* "messageConditions": [
|
||||
* {
|
||||
* "key": "comments.commentId",
|
||||
* "operator": "like",
|
||||
* "value": "c"
|
||||
* },{
|
||||
* "key": "articleId",
|
||||
* "operator": "not exists"
|
||||
* }
|
||||
* ]
|
||||
* message中可嵌套json,当需要查询内部json中某个字段的相关情况时,key为message.xxx,例如:message.comments.commentId
|
||||
* "messageConditions": [
|
||||
* {
|
||||
* "key": "comments.commentId",
|
||||
* "operator": "like",
|
||||
* "value": "c"
|
||||
* },{
|
||||
* "key": "articleId",
|
||||
* "operator": "not exists"
|
||||
* }
|
||||
* ]
|
||||
* </p>
|
||||
*/
|
||||
private List<@Valid Condition> messageConditions;
|
||||
|
||||
/**
|
||||
* 开始时间,时间戳字符串
|
||||
* 开始时间,时间戳
|
||||
*/
|
||||
private Long start;
|
||||
|
||||
/**
|
||||
* 结束时间,时间戳字符串
|
||||
* 结束时间,时间戳
|
||||
*/
|
||||
private Long end;
|
||||
|
||||
/**
|
||||
* 分页页码,从1开始,与{@code pageSize}搭配使用
|
||||
* <p>
|
||||
* 1. 分页开关开启后生效,默认开启分页
|
||||
* 2. 若与{@code lastId}同时存在,则优先使用{@code lastId}参数
|
||||
* </p>
|
||||
*/
|
||||
private Long pageNum;
|
||||
|
||||
/**
|
||||
* 分页大小,与{@code pageNum}或{@code lastId}搭配使用
|
||||
* <p>最大限制为1000</p>
|
||||
*/
|
||||
private Integer pageSize;
|
||||
|
||||
/**
|
||||
* 游标:上次请求返回的最后一条日志的id,与{@code pageSize}搭配使用
|
||||
* <p>
|
||||
* 1. 分页开关开启后生效,默认开启分页
|
||||
* 2. 默认为空,首次请求时,不传此参数
|
||||
* 3. 若与{@code pageNum}同时存在,则优先使用本参数
|
||||
* </p>
|
||||
*/
|
||||
private String lastId;
|
||||
}
|
||||
|
||||
@ -33,7 +33,8 @@ public class WebLogController {
|
||||
/**
|
||||
* 通过筛查条件查询日志列表
|
||||
* <p>
|
||||
* 若所有条件为空,则返回按时间序倒排的1000条日志
|
||||
* 1. 若所有条件为空,则返回最近的1000条日志
|
||||
* 2. 支持分页(可通过开关控制),默认开启,最多返回1000条
|
||||
* </p>
|
||||
*
|
||||
* @param req 查询条件 {@link LogFindReq}
|
||||
|
||||
@ -17,8 +17,10 @@ import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.bson.Document;
|
||||
import org.bson.types.ObjectId;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.json.JSONArray;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
@ -38,6 +40,7 @@ import java.util.stream.Collectors;
|
||||
* @version 1.0
|
||||
* @date 2024/9/11 11:04
|
||||
*/
|
||||
@RefreshScope
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class LogServiceImpl implements LogService {
|
||||
@ -50,6 +53,12 @@ public class LogServiceImpl implements LogService {
|
||||
|
||||
public static String MESSAGE_FIELD_ARRAY_DEFAULT_KEY = "\"defaultItems\"";
|
||||
|
||||
/**
|
||||
* 是否开启分页查询
|
||||
*/
|
||||
@Value("${log.enable-page:true}")
|
||||
public boolean enablePage;
|
||||
|
||||
/**
|
||||
* 添加日志
|
||||
*
|
||||
@ -72,13 +81,13 @@ public class LogServiceImpl implements LogService {
|
||||
@Override
|
||||
public LogResp findLogById(String id) {
|
||||
return logMapper.findById(id)
|
||||
.map(logEntity -> {
|
||||
LogResp logResp = BeanUtil.copyProperties(logEntity, LogResp.class);
|
||||
logResp.setMessage(logEntity.getMessage()
|
||||
.toJson());
|
||||
return logResp;
|
||||
})
|
||||
.orElse(null);
|
||||
.map(logEntity -> {
|
||||
LogResp logResp = BeanUtil.copyProperties(logEntity, LogResp.class);
|
||||
logResp.setMessage(logEntity.getMessage()
|
||||
.toJson());
|
||||
return logResp;
|
||||
})
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -95,7 +104,7 @@ public class LogServiceImpl implements LogService {
|
||||
List<LogEntity> logs;
|
||||
if (Objects.isNull(req) || isAllFieldsNullOrBlankOrEmpty(req)) {
|
||||
// 按照时间倒序(即字段timestamp)查询1000条
|
||||
logs = findTopLimitOrderByTimestamp(1, 1000L);
|
||||
logs = findTopLimitOrderById(-1, 1000L);
|
||||
if (ObjectUtil.isEmpty(logs)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@ -108,13 +117,13 @@ public class LogServiceImpl implements LogService {
|
||||
}
|
||||
}
|
||||
return logs.stream()
|
||||
.map(logEntity -> {
|
||||
LogResp logResp = BeanUtil.copyProperties(logEntity, LogResp.class, "message");
|
||||
logResp.setMessage(logEntity.getMessage()
|
||||
.toJson());
|
||||
return logResp;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
.map(logEntity -> {
|
||||
LogResp logResp = BeanUtil.copyProperties(logEntity, LogResp.class, "message");
|
||||
logResp.setMessage(logEntity.getMessage()
|
||||
.toJson());
|
||||
return logResp;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -126,13 +135,13 @@ public class LogServiceImpl implements LogService {
|
||||
@Override
|
||||
public List<String> batchAddLogs(LogBatchAddReq req) {
|
||||
List<LogEntity> logEntities = req.getLogs()
|
||||
.stream()
|
||||
.map(this::buildToLogEntity)
|
||||
.collect(Collectors.toList());
|
||||
.stream()
|
||||
.map(this::buildToLogEntity)
|
||||
.collect(Collectors.toList());
|
||||
logMapper.saveAll(logEntities);
|
||||
return logEntities.stream()
|
||||
.map(LogEntity::getId)
|
||||
.collect(Collectors.toList());
|
||||
.map(LogEntity::getId)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -142,7 +151,7 @@ public class LogServiceImpl implements LogService {
|
||||
* @return Query对象
|
||||
*/
|
||||
@NotNull
|
||||
private static Query buildQueryCriteria(LogFindReq req) {
|
||||
private Query buildQueryCriteria(LogFindReq req) {
|
||||
Criteria criteria = new Criteria();
|
||||
if (CharSequenceUtil.isNotBlank(req.getScene())) {
|
||||
criteria.and("scene")
|
||||
@ -167,8 +176,21 @@ public class LogServiceImpl implements LogService {
|
||||
criteria.and("timestamp")
|
||||
.lte(req.getEnd());
|
||||
}
|
||||
Sort sort = Sort.by(Sort.Direction.DESC, "timestamp");
|
||||
Query query = new Query(criteria);
|
||||
// 构建分页条件
|
||||
if (enablePage) {
|
||||
if (CharSequenceUtil.isNotBlank(req.getLastId())) {
|
||||
criteria.and("_id").lt(new ObjectId(req.getLastId()));
|
||||
} else if (NumberUtil.isPositiveNumber(req.getPageNum())) {
|
||||
query.skip((req.getPageNum() - 1) * req.getPageSize());
|
||||
}
|
||||
|
||||
if (NumberUtil.isNotPositiveNumber(req.getPageSize()) || req.getPageSize() > 1000) {
|
||||
req.setPageSize(1000);
|
||||
}
|
||||
query.limit(req.getPageSize());
|
||||
}
|
||||
Sort sort = Sort.by(Sort.Direction.DESC, "_id");
|
||||
query.with(sort);
|
||||
return query;
|
||||
}
|
||||
@ -235,12 +257,12 @@ public class LogServiceImpl implements LogService {
|
||||
* @param size 查询条数
|
||||
* @return 日志列表
|
||||
*/
|
||||
List<LogEntity> findTopLimitOrderByTimestamp(Integer order, Long size) {
|
||||
List<LogEntity> findTopLimitOrderById(Integer order, Long size) {
|
||||
Criteria criteria = Criteria.where("timestamp")
|
||||
.exists(true);
|
||||
.exists(true);
|
||||
Query query = new Query(criteria);
|
||||
query.with(Sort.by(order > 0 ? Sort.Direction.ASC : Sort.Direction.DESC, "timestamp"))
|
||||
.limit(size.intValue());
|
||||
.limit(size.intValue());
|
||||
return mongoTemplate.find(query, LogEntity.class);
|
||||
}
|
||||
|
||||
@ -262,7 +284,7 @@ public class LogServiceImpl implements LogService {
|
||||
Object value = field.get(obj);
|
||||
if (value instanceof String) {
|
||||
if (!((String) value).trim()
|
||||
.isEmpty()) {
|
||||
.isEmpty()) {
|
||||
return false; // 字段不是空字符串
|
||||
}
|
||||
} else if (value instanceof Collection) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user