全部
This commit is contained in:
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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("设备信息")
|
||||
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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功能初始化失败: 驱动未找到");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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());
|
||||
|
||||
@ -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());
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user