This commit is contained in:
2025-11-25 14:27:10 +08:00
parent d3931a9ddd
commit 7d8aeedcf2
23 changed files with 414 additions and 166 deletions

View File

@ -61,7 +61,7 @@ public class AuthController {
Files.write(path, authContent.getBytes(StandardCharsets.UTF_8));
return ApiResponse.success(null);
} catch (Exception e) {
return ApiResponse.failure("导入授权文件失败" + e.getMessage());
return ApiResponse.failure("导入授权文件失败: " + e.getMessage());
}
}
@ -80,7 +80,7 @@ public class AuthController {
AuthInfo authInfo = AuthValidator.getAuthInfo(authContent);
return ApiResponse.success(authInfo);
} catch (Exception e) {
return ApiResponse.failure("获取授权信息失败" + e.getMessage());
return ApiResponse.failure("获取授权信息失败: " + e.getMessage());
}
}
}

View File

@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yj.earth.business.domain.Device;
import com.yj.earth.business.service.DeviceService;
import com.yj.earth.common.util.ApiResponse;
import com.yj.earth.common.util.NetUtils;
import com.yj.earth.vo.AddDeviceDto;
import com.yj.earth.dto.device.ImportDeviceDto;
import com.yj.earth.dto.device.UpdateDeviceDto;
@ -27,6 +28,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
@Tag(name = "设备信息管理")
@ -73,14 +75,57 @@ public class DeviceController {
}
@GetMapping("/list")
@Operation(summary = "查询设备信息")
public ApiResponse listDevice(@Parameter(description = "分页数量") Integer pageNum, @Parameter(description = "分页大小") Integer pageSize,@Parameter(description = "设备名称") String cameraName) {
@Operation(summary = "查询设备信息(含在线状态)")
public ApiResponse listDevice(
@Parameter(description = "分页数量") Integer pageNum,
@Parameter(description = "分页大小") Integer pageSize,
@Parameter(description = "设备名称") String cameraName
) {
LambdaQueryWrapper<Device> queryWrapper = new LambdaQueryWrapper<>();
if (StringUtils.isNotBlank(cameraName)) {
queryWrapper.like(Device::getCameraName, cameraName);
}
// 执行标准的分页查询
Page<Device> devicePage = deviceService.page(new Page<>(pageNum, pageSize), queryWrapper);
return ApiResponse.success(devicePage);
List<Device> deviceList = devicePage.getRecords();
if (CollectionUtils.isEmpty(deviceList)) {
// 如果没有数据,直接返回空分页
return ApiResponse.success(devicePage);
}
try {
// 提取所有设备的 IP 地址、用于批量检测
List<String> ipAddresses = deviceList.stream()
.map(Device::getIp)
.filter(Objects::nonNull)
.collect(Collectors.toList());
// 异步并发检测所有 IP 的在线状态
Map<String, Boolean> reachabilityMap = NetUtils.checkReachabilityAsync(ipAddresses);
// 更新设备状态:遍历设备列表,根据 IP 设置 status 字段
deviceList.forEach(device -> {
String ip = device.getIp();
if (ip != null) {
Boolean isOnline = reachabilityMap.get(ip);
// 根据 Ping 结果设置 status: 1 为在线0 为离线
device.setStatus(isOnline != null && isOnline ? 1 : 0);
} else {
// 如果 IP 地址为空,直接设置为离线
device.setStatus(0);
}
});
// 直接返回更新后的分页对象
return ApiResponse.success(devicePage);
} catch (ExecutionException | InterruptedException e) {
// 恢复线程中断状态
Thread.currentThread().interrupt();
return ApiResponse.success(devicePage);
}
}
@GetMapping("/delete")
@ -270,7 +315,7 @@ public class DeviceController {
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode("设备信息导入模板", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
response.setHeader("Content-disposition", "attachment;filename*=" + fileName + ".xlsx");
// 写入模板表头(通过空数据列表触发表头生成)
EasyExcel.write(response.getOutputStream(), ImportDeviceDto.class)
.sheet("设备信息")

View File

@ -193,7 +193,7 @@ public class FileInfoController {
// 标准化路径
targetFilePath = Paths.get(fileAbsolutePath).toRealPath();
// 校验文件合法性是否存在、是否为普通文件
// 校验文件合法性: 是否存在、是否为普通文件
BasicFileAttributes fileAttr = Files.readAttributes(targetFilePath, BasicFileAttributes.class);
if (!fileAttr.isRegularFile()) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
@ -214,7 +214,7 @@ public class FileInfoController {
}
response.setContentLengthLong(fileAttr.size());
// 关键修改将attachment改为inline实现预览
// 关键修改: 将attachment改为inline实现预览
response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
"inline; filename=\"" + encodedFileName + "\"; filename*=UTF-8''" + encodedFileName);
@ -231,13 +231,13 @@ public class FileInfoController {
} catch (NoSuchFileException e) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
fileInfoService.writeResponseMessage(response, "文件不存在" + fileAbsolutePath);
fileInfoService.writeResponseMessage(response, "文件不存在: " + fileAbsolutePath);
} catch (SecurityException e) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
fileInfoService.writeResponseMessage(response, "访问拒绝无权限读取该文件");
fileInfoService.writeResponseMessage(response, "访问拒绝: 无权限读取该文件");
} catch (Exception e) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
fileInfoService.writeResponseMessage(response, "预览失败" + e.getMessage());
fileInfoService.writeResponseMessage(response, "预览失败: " + e.getMessage());
}
}
}

View File

@ -71,22 +71,22 @@ public class IconLibraryController {
if (!parentDir.exists()) {
boolean mkdirsSuccess = parentDir.mkdirs();
if (!mkdirsSuccess) {
return ApiResponse.failure("创建父目录失败" + folderPath);
return ApiResponse.failure("创建父目录失败: " + folderPath);
}
}
// 校验图标库文件是否已存在
if (iconFile.exists()) {
if (iconFile.isDirectory()) {
return ApiResponse.failure("同名目录已存在、无法创建文件" + iconPath);
return ApiResponse.failure("同名目录已存在、无法创建文件: " + iconPath);
}
return ApiResponse.failure("图标库文件已存在" + iconPath);
return ApiResponse.failure("图标库文件已存在: " + iconPath);
}
// 创建SQLite文件
boolean createFileSuccess = iconFile.createNewFile();
if (!createFileSuccess) {
return ApiResponse.failure("创建图标库文件失败" + iconPath);
return ApiResponse.failure("创建图标库文件失败: " + iconPath);
}
// 初始化图标库表结构
@ -95,7 +95,7 @@ public class IconLibraryController {
addIconLibrary(iconPath);
return ApiResponse.success(null);
} catch (Exception e) {
return ApiResponse.failure("创建图标库失败" + e.getMessage());
return ApiResponse.failure("创建图标库失败: " + e.getMessage());
}
}
@ -107,13 +107,13 @@ public class IconLibraryController {
// 校验路径是否存在
File iconFile = new File(iconPath);
if (!iconFile.exists() || !iconFile.isFile()) {
return ApiResponse.failure("图标库文件不存在" + iconPath);
return ApiResponse.failure("图标库文件不存在: " + iconPath);
}
// 添加到配置表并启用
addIconLibrary(iconPath);
return ApiResponse.success(null);
} catch (Exception e) {
return ApiResponse.failure("导入图标库失败" + e.getMessage());
return ApiResponse.failure("导入图标库失败: " + e.getMessage());
}
}
@ -136,7 +136,7 @@ public class IconLibraryController {
iconPath, checkParentSql, parentParams, IconType.class
);
if (parentType == null) {
return ApiResponse.failure("父级图标类型不存在" + parentId);
return ApiResponse.failure("父级图标类型不存在: " + parentId);
}
}

View File

@ -81,22 +81,22 @@ public class MilitaryLibraryController {
if (!parentDir.exists()) {
boolean mkdirsSuccess = parentDir.mkdirs();
if (!mkdirsSuccess) {
return ApiResponse.failure("创建父目录失败" + folderPath);
return ApiResponse.failure("创建父目录失败: " + folderPath);
}
}
// 校验军标库文件是否已存在
if (militaryFile.exists()) {
if (militaryFile.isDirectory()) {
return ApiResponse.failure("同名目录已存在、无法创建文件" + militaryPath);
return ApiResponse.failure("同名目录已存在、无法创建文件: " + militaryPath);
}
return ApiResponse.failure("军标库文件已存在" + militaryPath);
return ApiResponse.failure("军标库文件已存在: " + militaryPath);
}
// 创建SQLite文件
boolean createFileSuccess = militaryFile.createNewFile();
if (!createFileSuccess) {
return ApiResponse.failure("创建军标库文件失败" + militaryPath);
return ApiResponse.failure("创建军标库文件失败: " + militaryPath);
}
// 初始化军标库表结构
@ -105,7 +105,7 @@ public class MilitaryLibraryController {
addMilitaryLibrary(militaryPath);
return ApiResponse.success(null);
} catch (Exception e) {
return ApiResponse.failure("创建军标库失败" + e.getMessage());
return ApiResponse.failure("创建军标库失败: " + e.getMessage());
}
}
@ -117,13 +117,13 @@ public class MilitaryLibraryController {
// 校验路径是否存在
File militaryFile = new File(militaryPath);
if (!militaryFile.exists() || !militaryFile.isFile()) {
return ApiResponse.failure("军标库文件不存在" + militaryPath);
return ApiResponse.failure("军标库文件不存在: " + militaryPath);
}
// 添加到配置表并启用
addMilitaryLibrary(militaryPath);
return ApiResponse.success(null);
} catch (Exception e) {
return ApiResponse.failure("导入军标库失败" + e.getMessage());
return ApiResponse.failure("导入军标库失败: " + e.getMessage());
}
}
@ -146,7 +146,7 @@ public class MilitaryLibraryController {
militaryPath, checkParentSql, parentParams, MilitaryType.class
);
if (parentType == null) {
return ApiResponse.failure("父级军标类型不存在" + parentId);
return ApiResponse.failure("父级军标类型不存在: " + parentId);
}
}

View File

@ -81,27 +81,27 @@ public class ModelLibraryController {
if (!parentDir.exists()) {
boolean mkdirsSuccess = parentDir.mkdirs();
if (!mkdirsSuccess) {
return ApiResponse.failure("创建父目录失败" + folderPath);
return ApiResponse.failure("创建父目录失败: " + folderPath);
}
}
// 检查模型库文件是否已存在
if (modelFile.exists()) {
if (modelFile.isDirectory()) {
return ApiResponse.failure("同名目录已存在、无法创建文件" + modelPath);
return ApiResponse.failure("同名目录已存在、无法创建文件: " + modelPath);
}
return ApiResponse.failure("模型库文件已存在" + modelPath);
return ApiResponse.failure("模型库文件已存在: " + modelPath);
}
// 创建模型库文件(
boolean createSuccess = modelFile.createNewFile();
if (!createSuccess) {
return ApiResponse.failure("创建模型库文件失败" + modelPath);
return ApiResponse.failure("创建模型库文件失败: " + modelPath);
}
// 添加模型库信息
addModelLibrary(modelPath);
SQLiteUtil.initializationModel(modelPath);
return ApiResponse.success(null);
} catch (Exception e) {
return ApiResponse.failure("创建模型库失败" + e.getMessage());
return ApiResponse.failure("创建模型库失败: " + e.getMessage());
}
}
@ -174,7 +174,7 @@ public class ModelLibraryController {
@Operation(summary = "模型类型列表")
@GetMapping("/modelTypeList")
public ApiResponse modelTypeTree(@Parameter(description = "模型名称") @RequestParam("modelName") String modelName) throws SQLException, IllegalAccessException, InstantiationException {
public ApiResponse modelTypeTree(@Parameter(description = "模型名称") @RequestParam(value = "modelName",required = false) String modelName) throws SQLException, IllegalAccessException, InstantiationException {
return ApiResponse.success(modelTypeList(modelName));
}
@ -190,7 +190,7 @@ public class ModelLibraryController {
return ApiResponse.failure("请先创建或导入模型库");
}
// 简化校验仅判断列表是否为空
// 简化校验: 仅判断列表是否为空
if (filePaths == null || filePaths.isEmpty()) {
return ApiResponse.failure("文件路径列表不能为空");
}
@ -286,9 +286,12 @@ public class ModelLibraryController {
}
@Operation(summary = "根据模型类型查看模型列表")
@Operation(summary = "根据模型类型和名称模糊查询模型列表")
@PostMapping("/modelList")
public ApiResponse modelList(@Parameter(description = "模型类型ID") @RequestParam("modelTypeId") String modelTypeId) throws SQLException, IllegalAccessException, InstantiationException {
public ApiResponse modelList(
@Parameter(description = "模型类型ID") @RequestParam("modelTypeId") String modelTypeId,
@Parameter(description = "模型名称模糊查询") @RequestParam(value = "name", required = false) String name
) throws SQLException, IllegalAccessException, InstantiationException {
// 获取最新的模型库
String modelPath = getModelLibrary();
if (modelPath == null) {
@ -298,15 +301,15 @@ public class ModelLibraryController {
// 获取分类ID及其所有子分类ID的列表
List<String> typeIdList = getModelTypeIdsWithChildren(modelTypeId);
if (typeIdList.isEmpty()) {
return ApiResponse.success(null);
return ApiResponse.success(Collections.emptyList());
}
String idsWithQuotes = typeIdList.stream()
.map(id -> "'" + id + "'")
.collect(Collectors.joining(","));
// 多表联查、查询所有指定分类及其子分类下的模型
String sql = """
// 构建SQL语句
StringBuilder sql = new StringBuilder("""
SELECT
model.id,
model.model_type_id as modelTypeId,
@ -318,12 +321,18 @@ public class ModelLibraryController {
model_type.name as modelTypeName
FROM model
JOIN model_type ON model.model_type_id = model_type.id
WHERE model.model_type_id IN (?)
""".replace("?", idsWithQuotes);
WHERE model.model_type_id IN (%s)
""".formatted(idsWithQuotes));
// 如果传入了名称、则增加模糊查询条件
if (name != null && !name.trim().isEmpty()) {
// 直接拼接SQL、注意SQL注入风险
sql.append(" AND model.model_name LIKE '%" + name.trim() + "%'");
}
// 执行查询
List<ModelVo> modelVos = SQLiteUtil.queryForList(modelPath, sql.toString(), null, ModelVo.class);
// 使用所有分类ID作为查询参数
List<Object> params = new ArrayList<>();
List<ModelVo> modelVos = SQLiteUtil.queryForList(modelPath, sql, null, ModelVo.class);
// 循环遍历数据
for (ModelVo modelVo : modelVos) {
if (modelVo.getModelType() != null) {
@ -443,27 +452,35 @@ public class ModelLibraryController {
return ApiResponse.success(modelTypeList(null));
}
/**
* 查询模型分类树形结构
*/
private List<ModelTypeVo> modelTypeList(String modelName) throws SQLException, IllegalAccessException, InstantiationException {
String modelPath = getModelLibrary();
if (modelPath == null) {
return null;
}
// 构建基础SQL语句
StringBuilder sqlBuilder = new StringBuilder("""
SELECT id, name, parent_id as parentId,
tree_index as treeIndex, created_at as createdAt,
updated_at as updatedAt
FROM model_type
SELECT DISTINCT model_type.id, model_type.name, model_type.parent_id,
model_type.tree_index, model_type.created_at,
model_type.updated_at
FROM model_type
""");
// 如果传入了模型名称、则拼接 JOIN 和 WHERE 条件
if (modelName != null && !modelName.trim().isEmpty()) {
sqlBuilder.append("WHERE name LIKE '%").append(modelName.trim()).append("%' ");
String trimmedName = modelName.trim();
// 直接拼接SQL、不做任何转义存在SQL注入风险
sqlBuilder.append(" INNER JOIN model ON model_type.id = model.model_type_id");
sqlBuilder.append(" WHERE model.model_name LIKE '%" + trimmedName + "%'");
}
// 为所有查询都加上统一的排序条件
sqlBuilder.append("ORDER BY tree_index ASC");
sqlBuilder.append(" ORDER BY model_type.tree_index ASC");
// 执行查询
// 执行查询、获取符合条件的模型分类列表
List<ModelType> modelTypes = SQLiteUtil.queryForList(
modelPath,
sqlBuilder.toString(),
@ -471,9 +488,10 @@ public class ModelLibraryController {
ModelType.class
);
// 转换为树形结构
// 将扁平的分类列表转换为树形结构
return buildModelTypeTree(modelTypes);
}
private List<ModelTypeVo> buildModelTypeTree(List<ModelType> modelTypes) {
List<ModelTypeVo> treeNodes = modelTypes.stream()
.map(modelType -> new ModelTypeVo(modelType))
@ -572,7 +590,7 @@ public class ModelLibraryController {
// 结果列表初始化
List<String> typeIdList = new ArrayList<>();
// 校验入参分类ID不能为空
// 校验入参: 分类ID不能为空
if (StringUtils.isEmpty(modelTypeId)) {
return null;
}

View File

@ -34,7 +34,7 @@ public class PoiController {
Class.forName("org.sqlite.JDBC");
String dbPath = System.getProperty("user.dir") + File.separator + "poi" + File.separator + "poi.db";
connection = DriverManager.getConnection("jdbc:sqlite:" + dbPath);
logger.info("POI数据库连接初始化成功、路径{}", dbPath);
logger.info("POI数据库连接初始化成功、路径: {}", dbPath);
}
}
@ -92,10 +92,10 @@ public class PoiController {
return ApiResponse.success(poiList);
} catch (SQLException e) {
logger.error("POI数据查询失败", e);
return ApiResponse.failure("POI数据查询失败" + e.getMessage());
return ApiResponse.failure("POI数据查询失败: " + e.getMessage());
} catch (ClassNotFoundException e) {
logger.error("POI数据库驱动加载失败", e);
return ApiResponse.failure("POI功能初始化失败驱动未找到");
return ApiResponse.failure("POI功能初始化失败: 驱动未找到");
}
}
}

View File

@ -130,7 +130,7 @@ public class PoiInfoController {
return ApiResponse.success(poiList);
} catch (Exception e) {
return ApiResponse.failure("POI数据查询失败" + e.getMessage());
return ApiResponse.failure("POI数据查询失败: " + e.getMessage());
}
}
@ -144,13 +144,13 @@ public class PoiInfoController {
}
File dbFile = new File(absolutePath.trim());
if (!dbFile.exists()) {
throw new SQLException("数据库文件不存在" + absolutePath);
throw new SQLException("数据库文件不存在: " + absolutePath);
}
if (!dbFile.isFile()) {
throw new SQLException("路径指向的不是文件" + absolutePath);
throw new SQLException("路径指向的不是文件: " + absolutePath);
}
if (!dbFile.canRead()) {
throw new SQLException("没有权限读取数据库文件" + absolutePath);
throw new SQLException("没有权限读取数据库文件: " + absolutePath);
}
try {
Class.forName(JDBC.class.getName());

View File

@ -93,9 +93,9 @@ public class SystemController {
return ApiResponse.success(null);
} catch (IOException e) {
return ApiResponse.failure("更新端口配置失败" + e.getMessage());
return ApiResponse.failure("更新端口配置失败: " + e.getMessage());
} catch (Exception e) {
return ApiResponse.failure("操作失败" + e.getMessage());
return ApiResponse.failure("操作失败: " + e.getMessage());
}
}
@ -141,10 +141,10 @@ public class SystemController {
String originalParentId = source.getParentId();
if (originalParentId != null && !originalParentId.trim().isEmpty() && originalIdToNewId.containsKey(originalParentId)) {
// 父节点在导入数据中用新ID关联
// 父节点在导入数据中: 用新ID关联
source.setParentId(originalIdToNewId.get(originalParentId));
} else {
// 父节点不在导入数据中挂到总根节点
// 父节点不在导入数据中: 挂到总根节点
source.setParentId(newParentId);
}
return source;
@ -177,7 +177,7 @@ public class SystemController {
source.setSourceType(resultSet.getString("source_type"));
source.setSourcePath(resultSet.getString("source_path"));
// 关键修改读取原始parent_id、而非覆盖为新父节点ID
// 关键修改: 读取原始parent_id、而非覆盖为新父节点ID
source.setParentId(resultSet.getString("parent_id"));
Integer treeIndex = resultSet.getObject("tree_index") != null
@ -318,13 +318,13 @@ public class SystemController {
}
File dbFile = new File(absolutePath.trim());
if (!dbFile.exists()) {
throw new SQLException("数据库文件不存在" + absolutePath);
throw new SQLException("数据库文件不存在: " + absolutePath);
}
if (!dbFile.isFile()) {
throw new SQLException("路径指向的不是文件" + absolutePath);
throw new SQLException("路径指向的不是文件: " + absolutePath);
}
if (!dbFile.canRead()) {
throw new SQLException("没有权限读取数据库文件" + absolutePath);
throw new SQLException("没有权限读取数据库文件: " + absolutePath);
}
try {
Class.forName(JDBC.class.getName());

View File

@ -18,8 +18,14 @@ import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.time.DateTimeException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
@Tag(name = "态势方案管理")
@ -67,41 +73,100 @@ public class TsPlanController {
@Operation(summary = "查询所有方案")
@PostMapping("/list")
public ApiResponse list(@Parameter(description = "分页数量") @RequestParam(value = "pageNum") Integer pageNum,
@Parameter(description = "分页大小") @RequestParam(value = "pageSize") Integer pageSize,
@Parameter(description = "方案名称") @RequestParam(value = "name", required = false) String name,
@Parameter(description = "用户名称") @RequestParam(value = "username", required = false) String username,
@Parameter(description = "开始时间") @RequestParam(value = "startTime", required = false) String startTime,
@Parameter(description = "结束时间") @RequestParam(value = "endTime", required = false) String endTime) {
public ApiResponse list(@Parameter(description = "分页数量") @RequestParam Integer pageNum,
@Parameter(description = "分页大小") @RequestParam Integer pageSize,
@Parameter(description = "方案名称") @RequestParam(required = false) String name,
@Parameter(description = "用户名称") @RequestParam(required = false) String username,
@Parameter(description = "开始时间") @RequestParam(required = false) String startTime,
@Parameter(description = "结束时间") @RequestParam(required = false) String endTime) {
LambdaQueryWrapper<TsPlan> queryWrapper = new LambdaQueryWrapper<>();
// 方案名称模糊查询
if (StringUtils.isNotBlank(name)) {
queryWrapper.like(TsPlan::getName, name);
}
// 用户名查询
if (StringUtils.isNotBlank(username)) {
// 根据用户名查询用户ID
LambdaQueryWrapper<User> userQueryWrapper = new LambdaQueryWrapper<>();
userQueryWrapper.like(User::getUsername, username);
User user = userService.getOne(userQueryWrapper);
if (user != null) {
queryWrapper.eq(TsPlan::getCreatedBy, user.getId());
List<User> userList = userService.list(userQueryWrapper);
// 判断列表是否为空
if (userList.isEmpty()) {
// 无匹配用户、直接返回空分页结果
Page<TsPlan> emptyPage = new Page<>(pageNum, pageSize);
emptyPage.setTotal(0);
emptyPage.setRecords(Collections.emptyList());
return ApiResponse.success(emptyPage);
}
// 提取用户 ID 列表(确保类型匹配)
List<String> userIdList = userList.stream()
.map(User::getId)
.filter(Objects::nonNull)
.toList();
// 若 ID 列表为空,也返回空结果
if (userIdList.isEmpty()) {
Page<TsPlan> emptyPage = new Page<>(pageNum, pageSize);
emptyPage.setTotal(0);
emptyPage.setRecords(Collections.emptyList());
return ApiResponse.success(emptyPage);
}
queryWrapper.in(TsPlan::getCreatedBy, userIdList);
}
// 时间条件优化
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
if (startTime != null && endTime != null) {
// 把字符串的时间字符串 转换成 LocalDateTime
LocalDateTime startTimeDate = LocalDateTime.parse(startTime, formatter);
LocalDateTime endTimeDate = LocalDateTime.parse(endTime, formatter);
queryWrapper.between(TsPlan::getCreatedAt, startTimeDate, endTimeDate);
}
Page<TsPlan> page = tsPlanService.page(new Page<>(pageNum, pageSize), queryWrapper);
// 需要设置创建人名称
page.getRecords().forEach(tsPlan -> {
// 根据用户ID查询用户名
User user = userService.getById(tsPlan.getCreatedBy());
if (user != null) {
tsPlan.setCreatedBy(user.getNickname());
if (StringUtils.isNotBlank(startTime)) {
try {
LocalDateTime start = LocalDateTime.parse(startTime, formatter);
queryWrapper.ge(TsPlan::getCreatedAt, start);
} catch (DateTimeException e) {
return ApiResponse.failure("开始时间格式错误,需为 yyyy-MM-dd HH:mm:ss");
}
});
}
if (StringUtils.isNotBlank(endTime)) {
try {
LocalDateTime end = LocalDateTime.parse(endTime, formatter);
queryWrapper.le(TsPlan::getCreatedAt, end);
} catch (DateTimeException e) {
return ApiResponse.failure("结束时间格式错误,需为 yyyy-MM-dd HH:mm:ss");
}
}
// 分页查询方案
Page<TsPlan> page = tsPlanService.page(new Page<>(pageNum, pageSize), queryWrapper);
// 优化用户名查询
if (!page.getRecords().isEmpty()) {
// 提取所有创建人 ID
List<String> creatorIds = page.getRecords().stream()
.map(TsPlan::getCreatedBy)
.filter(Objects::nonNull)
.distinct()
.toList();
// 批量查询用户
if (!creatorIds.isEmpty()) {
List<User> creators = userService.listByIds(creatorIds);
// 构建 ID -> 昵称映射
Map<String, String> creatorNicknameMap = creators.stream()
.collect(Collectors.toMap(
User::getId,
User::getNickname,
(k1, k2) -> k1));
// 填充昵称
page.getRecords().forEach(plan -> {
String nickname = creatorNicknameMap.getOrDefault(plan.getCreatedBy(), "未知用户");
plan.setCreatedBy(nickname);
});
}
}
return ApiResponse.success(page);
}
}

View File

@ -211,7 +211,7 @@ public class FileInfoServiceImpl extends ServiceImpl<FileInfoMapper, FileInfo> i
if (degreesMinutesSeconds == null || degreesMinutesSeconds.length != 3 || ref == null) {
return null;
}
// 度分秒转十进制度 + 分/60 + 秒/3600
// 度分秒转十进制: 度 + 分/60 + 秒/3600
double degrees = degreesMinutesSeconds[0].doubleValue();
double minutes = degreesMinutesSeconds[1].doubleValue();
double seconds = degreesMinutesSeconds[2].doubleValue();

View File

@ -218,15 +218,15 @@ public class SourceServiceImpl extends ServiceImpl<SourceMapper, Source> impleme
// 添加createdAt时间范围过滤如果时间不为空
if (startTime != null && endTime != null) {
// 同时存在开始和结束时间查询范围内的数据
// 同时存在开始和结束时间: 查询范围内的数据
sourceQueryWrapper.between(Source::getCreatedAt, startTime, endTime);
countQueryWrapper.between(Source::getCreatedAt, startTime, endTime);
} else if (startTime != null) {
// 仅存在开始时间查询大于等于开始时间的数据
// 仅存在开始时间: 查询大于等于开始时间的数据
sourceQueryWrapper.ge(Source::getCreatedAt, startTime);
countQueryWrapper.ge(Source::getCreatedAt, startTime);
} else if (endTime != null) {
// 仅存在结束时间查询小于等于结束时间的数据
// 仅存在结束时间: 查询小于等于结束时间的数据
sourceQueryWrapper.le(Source::getCreatedAt, endTime);
countQueryWrapper.le(Source::getCreatedAt, endTime);
}
@ -252,7 +252,7 @@ public class SourceServiceImpl extends ServiceImpl<SourceMapper, Source> impleme
if (pageNum != null && pageSize != null) {
// 分页时、查询条件排除directory类型
sourceQueryWrapper.ne(Source::getSourceType, "directory");
// 分页查询获取分页数据
// 分页查询: 获取分页数据
Page<Source> page = new Page<>(pageNum, pageSize);
IPage<Source> resultPage = sourceService.page(page, sourceQueryWrapper);
// 使用单独的count查询条件计算总数已排除directory
@ -260,7 +260,7 @@ public class SourceServiceImpl extends ServiceImpl<SourceMapper, Source> impleme
resultMap.put("list", resultPage.getRecords());
resultMap.put("total", total);
} else {
// 不分页获取全部数据包含所有类型和总数排除directory
// 不分页: 获取全部数据包含所有类型和总数排除directory
List<Source> sourceList = sourceService.list(sourceQueryWrapper);
long total = sourceService.count(countQueryWrapper);