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

@ -106,7 +106,7 @@
<i class="fa fa-road text-primary mr-2"></i>路径参数
</h2>
<!-- 起点移除默认value、默认无数据 -->
<!-- 起点: 移除默认value、默认无数据 -->
<div class="space-y-1">
<label class="block text-sm font-medium text-gray-700">起点 <span
class="text-danger">*</span></label>
@ -514,7 +514,7 @@
document.getElementById('resultContainer').classList.add('hidden');
}
// 清空所有起点重置为空(而非默认坐标)
// 清空所有: 起点重置为空(而非默认坐标)
function clearAll() {
clearRoute();
@ -578,7 +578,7 @@
});
if (response.data.code !== 200 || !response.data.data || !response.data.data[0]) {
throw new Error(`上传失败${response.data.message || '未知错误'}`);
throw new Error(`上传失败: ${response.data.message || '未知错误'}`);
}
const fileId = response.data.data[0].id;
@ -587,7 +587,7 @@
} catch (error) {
const errorMsg = error.response?.data?.message || error.message || '上传异常';
updateLoadProgress(false);
alert(`⚠️ 上传失败${errorMsg}`);
alert(`⚠️ 上传失败: ${errorMsg}`);
throw error;
}
}
@ -600,7 +600,7 @@
const response = await axios.post(`${API_BASE_URL}/graphhopper/loadMap`, formData);
if (response.data.code !== 200) {
throw new Error(`加载失败${response.data.message || '接口返回异常'}`);
throw new Error(`加载失败: ${response.data.message || '接口返回异常'}`);
}
updateLoadProgress(false);
@ -612,7 +612,7 @@
} catch (error) {
const errorMsg = error.response?.data?.message || error.message || '加载异常';
updateLoadProgress(false);
alert(`⚠️ 地图加载失败${errorMsg}`);
alert(`⚠️ 地图加载失败: ${errorMsg}`);
throw error;
}
}
@ -662,13 +662,13 @@
);
if (response.data.code !== 200 || !response.data.data) {
throw new Error(`计算失败${response.data.message || '接口返回异常'}`);
throw new Error(`计算失败: ${response.data.message || '接口返回异常'}`);
}
handleRouteResponse(response.data.data);
} catch (error) {
const errorMsg = error.response?.data?.message || error.message || '计算异常';
alert(`⚠️ 路径计算失败${errorMsg}`);
alert(`⚠️ 路径计算失败: ${errorMsg}`);
} finally {
calcBtn.disabled = false;
calcBtn.innerHTML = '<i class="fa fa-calculator mr-2"></i>计算路径';
@ -691,12 +691,12 @@
routeLine = L.polyline(latLngs, lineStyles[document.getElementById('profile').value])
.addTo(map)
.bindPopup(`<div class="text-sm"><p>距离${routeData.distanceKm.toFixed(2)} 公里</p><p>时间${routeData.timeMinutes} 分钟</p></div>`);
.bindPopup(`<div class="text-sm"><p>距离: ${routeData.distanceKm.toFixed(2)} 公里</p><p>时间: ${routeData.timeMinutes} 分钟</p></div>`);
map.fitBounds(routeLine.getBounds(), {padding: [50, 50], maxZoom: 14});
}
// 事件绑定移除起点按钮弹窗
// 事件绑定: 移除起点按钮弹窗
function bindEvents() {
// 文件选择相关
document.getElementById('selectFileBtn').addEventListener('click', () => {
@ -713,7 +713,7 @@
const file = e.target.files[0];
if (file.name.toLowerCase().endsWith('.pbf')) {
const fileSizeMB = (file.size / (1024 * 1024)).toFixed(2);
fileInfoEl.textContent = `已选择${file.name}${fileSizeMB} MB`;
fileInfoEl.textContent = `已选择: ${file.name}${fileSizeMB} MB`;
fileInfoEl.className = 'mt-1 text-sm text-gray-600';
} else {
fileInfoEl.textContent = '❌ 请选择PBF格式的地图文件';
@ -736,11 +736,11 @@
fileInput.value = '';
document.getElementById('fileInfo').classList.add('hidden');
} catch (error) {
console.error('地图加载失败', error);
console.error('地图加载失败: ', error);
}
});
// 起点按钮移除弹窗、仅保留地图选点逻辑
// 起点按钮: 移除弹窗、仅保留地图选点逻辑
document.getElementById('setStartBtn').addEventListener('click', () => {
map.once('click', (e) => setStartPoint(e.latlng.lat, e.latlng.lng));
});

View File

@ -85,9 +85,9 @@ public class AuthGenerator {
// 将授权字符串写入文件
Files.write(licPath, authContent.getBytes(StandardCharsets.UTF_8));
System.out.println("授权文件生成成功" + licPath.toAbsolutePath());
System.out.println("授权文件生成成功: " + licPath.toAbsolutePath());
} catch (Exception e) {
System.err.println("生成授权文件失败" + e.getMessage());
System.err.println("生成授权文件失败: " + e.getMessage());
e.printStackTrace();
}
}

View File

@ -100,15 +100,15 @@ public class AuthValidator {
String serverUniqueId = ServerUniqueIdUtil.getServerUniqueId();
// 生成授权
String authString = AuthGenerator.generateAuth("标准版", 1000, 30, "35A0DF1D05AEAE77E1E2715CC36A7368");
System.out.println("授权字符串" + authString);
System.out.println("授权字符串: " + authString);
// 验证授权
boolean isValid = AuthValidator.validateAuth(authString, serverUniqueId);
System.out.println("授权是否有效" + isValid);
System.out.println("授权是否有效: " + isValid);
int remainingDays = AuthValidator.getRemainingDays(authString);
System.out.println("剩余天数" + remainingDays);
System.out.println("剩余天数: " + remainingDays);
AuthInfo authInfo = AuthValidator.getAuthInfo(authString);
System.out.println("授权信息" + authInfo);
System.out.println("授权信息: " + authInfo);
}
}

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);

View File

@ -172,7 +172,7 @@ public class MilitaryConverter {
}
}
System.out.println("\n成功转换 jun_biao_types 表数据" + count + "条记录");
System.out.println("\n成功转换 jun_biao_types 表数据: " + count + "条记录");
rs.close();
sourceStmt.close();
targetStmt.close();
@ -225,7 +225,7 @@ public class MilitaryConverter {
}
}
System.out.println("\n成功转换 jun_biaos 表数据" + count + "条记录");
System.out.println("\n成功转换 jun_biaos 表数据: " + count + "条记录");
rs.close();
sourceStmt.close();
targetStmt.close();

View File

@ -155,7 +155,7 @@ public class ModelConverter {
}
}
System.out.println("\n成功转换 mode_types 表数据" + count + "条记录");
System.out.println("\n成功转换 mode_types 表数据: " + count + "条记录");
rs.close();
sourceStmt.close();
targetStmt.close();
@ -209,7 +209,7 @@ public class ModelConverter {
}
}
System.out.println("\n成功转换 models 表数据" + count + "条记录");
System.out.println("\n成功转换 models 表数据: " + count + "条记录");
rs.close();
sourceStmt.close();
targetStmt.close();

View File

@ -92,7 +92,7 @@ public class SourceDataGenerator {
continue;
}
// 基本类型、包装类、字符串直接设默认值
// 基本类型、包装类、字符串: 直接设默认值
if (isPrimitiveOrWrapper(fieldType) || fieldType.equals(String.class)) {
field.set(instance, getDefaultValue(fieldType));
continue;
@ -238,13 +238,13 @@ public class SourceDataGenerator {
}
/**
* 获取类型默认值字符串返回空字符串、其他类型按原有逻辑
* 获取类型默认值: 字符串返回空字符串、其他类型按原有逻辑
*/
private static Object getDefaultValue(Class<?> type) {
if (type.equals(String.class)) {
return "";
}
// 原有逻辑基本类型返回对应默认值boolean=false/数值=0/char='\0'
// 原有逻辑: 基本类型返回对应默认值boolean=false/数值=0/char='\0'
if (type.isPrimitive()) {
if (type == boolean.class) return false;
if (type == char.class) return '\0';

View File

@ -0,0 +1,120 @@
package com.yj.earth.common.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.*;
import java.util.concurrent.*;
/**
* 网络工具类
*/
public class NetUtils {
private static final Logger logger = LoggerFactory.getLogger(NetUtils.class);
// Ping 超时时间(毫秒)
private static final int PING_TIMEOUT = 500;
// TCP Ping 端口
private static final int TCP_PING_PORT = 80;
// TCP Ping 超时时间(毫秒)
private static final int TCP_TIMEOUT = 1500;
private static final ExecutorService PING_EXECUTOR = Executors.newFixedThreadPool(
Math.min(Runtime.getRuntime().availableProcessors() * 2, 50),
new ThreadFactory() {
private int count = 0;
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName("ping-executor-" + (count++));
thread.setDaemon(true);
return thread;
}
}
);
/**
* 使用 ICMP Echo Request (标准 Ping) 检测主机是否可达
* @param ipAddress IP地址或主机名
* @return true if reachable, false otherwise
*/
public static boolean isReachableByIcmp(String ipAddress) {
if (ipAddress == null || ipAddress.trim().isEmpty()) {
return false;
}
try {
InetAddress address = InetAddress.getByName(ipAddress);
// isReachable 会尝试 ICMP Echo 和 TCP Echo (端口 7)
return address.isReachable(PING_TIMEOUT);
} catch (UnknownHostException e) {
logger.warn("未知的主机: {}", ipAddress);
return false;
} catch (IOException e) {
// 发生 IO 异常、视为不可达
return false;
}
}
/**
* 使用 TCP 连接检测主机端口是否开放(模拟 Ping
* 当 ICMP 被防火墙禁止时、此方法更有效
* @param ipAddress IP地址
* @param port 端口号
* @return true if port is open, false otherwise
*/
public static boolean isReachableByTcp(String ipAddress, int port) {
if (ipAddress == null || ipAddress.trim().isEmpty() || port < 1 || port > 65535) {
return false;
}
Socket socket = null;
try {
socket = new Socket();
socket.connect(new java.net.InetSocketAddress(ipAddress, port), TCP_TIMEOUT);
return true;
} catch (IOException e) {
// 连接失败、端口未开放或主机不可达
return false;
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
// ignore
}
}
}
}
/**
* 异步并发检测多个IP的可达性
* @param ips 需要检测的IP列表
* @return 一个 Map、key 是 IP、value 是 Boolean (是否在线)
* @throws ExecutionException 执行异常
* @throws InterruptedException 线程中断异常
*/
public static Map<String, Boolean> checkReachabilityAsync(Collection<String> ips) throws ExecutionException, InterruptedException {
if (ips == null || ips.isEmpty()) {
return Collections.emptyMap();
}
List<Callable<Map.Entry<String, Boolean>>> tasks = new ArrayList<>();
for (String ip : ips) {
tasks.add(() -> {
boolean isOnline = isReachableByTcp(ip, TCP_PING_PORT) || isReachableByIcmp(ip);
return new AbstractMap.SimpleEntry<>(ip, isOnline);
});
}
List<Future<Map.Entry<String, Boolean>>> futures = PING_EXECUTOR.invokeAll(tasks);
Map<String, Boolean> results = new ConcurrentHashMap<>();
for (Future<Map.Entry<String, Boolean>> future : futures) {
Map.Entry<String, Boolean> entry = future.get();
results.put(entry.getKey(), entry.getValue());
}
return results;
}
}

View File

@ -35,12 +35,12 @@ public class PoiExporter {
}
log.info("查询完成、共获取到[{}]个地区码(含子区域)", adcodeList.size());
log.info("开始导出数据到新文件{}", newDbPath);
log.info("开始导出数据到新文件: {}", newDbPath);
exportDataToNewDb(originalDbPath, newDbUrl, adcodeList);
log.info("=== [{}]的POI数据导出成功文件路径{} ===", areaName, newDbPath);
log.info("=== [{}]的POI数据导出成功文件路径: {} ===", areaName, newDbPath);
} catch (SQLException e) {
log.error("=== [{}]的POI数据导出失败原因{} ===", areaName, e.getMessage(), e);
log.error("=== [{}]的POI数据导出失败原因: {} ===", areaName, e.getMessage(), e);
throw e;
}
}
@ -57,7 +57,7 @@ public class PoiExporter {
log.warn("未查询到[{}]对应的根地区码", areaName);
return adcodeList;
}
log.info("查询到[{}]的根地区码{}", areaName, rootAdcode);
log.info("查询到[{}]的根地区码: {}", areaName, rootAdcode);
// 递归查询所有子adcode
String recursiveSql = "WITH RECURSIVE sub_areas(adcode) AS (" +
@ -75,7 +75,7 @@ public class PoiExporter {
}
}
} catch (SQLException e) {
log.error("查询地区码列表失败!原因{}", e.getMessage(), e);
log.error("查询地区码列表失败!原因: {}", e.getMessage(), e);
throw e;
}
return adcodeList;
@ -94,7 +94,7 @@ public class PoiExporter {
}
}
} catch (SQLException e) {
log.error("查询[{}]的根地区码失败!原因{}", areaName, e.getMessage(), e);
log.error("查询[{}]的根地区码失败!原因: {}", areaName, e.getMessage(), e);
throw e;
}
return null;
@ -146,7 +146,7 @@ public class PoiExporter {
// 每10000条打印一次进度
if (totalCount % batchSize == 0) {
insertPs.executeBatch();
log.info("已处理数据{}条", totalCount);
log.info("已处理数据: {}条", totalCount);
}
}
// 处理剩余数据
@ -158,7 +158,7 @@ public class PoiExporter {
}
}
} catch (SQLException e) {
log.error("新数据库操作失败!原因{}", e.getMessage(), e);
log.error("新数据库操作失败!原因: {}", e.getMessage(), e);
throw e;
}
}

View File

@ -27,10 +27,10 @@ public class SQLiteUtil {
// 统一日期格式LocalDateTime
private static final DateTimeFormatter LOCAL_DATE_TIME_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
// 连接池缓存key=数据库文件路径、value=DBCP2数据源支持多连接复用
// 连接池缓存: key=数据库文件路径、value=DBCP2数据源支持多连接复用
private static final Map<String, BasicDataSource> DATA_SOURCE_POOL = new ConcurrentHashMap<>();
// 字段缓存缓存类的字段映射(避免反射重复开销)
// 字段缓存: 缓存类的字段映射(避免反射重复开销)
private static final Map<Class<?>, Map<String, Field>> FIELD_CACHE = new ConcurrentHashMap<>();
@ -64,17 +64,17 @@ public class SQLiteUtil {
dataSource.setUrl("jdbc:sqlite:" + dbFilePath);
// 2. 连接池核心参数根据并发量调整、SQLite不建议过多连接
dataSource.setMaxTotal(30); // 最大连接数20-50根据服务器CPU/内存调整)
dataSource.setMaxIdle(15); // 最大空闲连接保留部分连接避免频繁创建
dataSource.setMinIdle(5); // 最小空闲连接保证基础并发响应速度
dataSource.setTimeBetweenEvictionRunsMillis(60000); // 连接检测间隔1分钟
dataSource.setMinEvictableIdleTimeMillis(300000); // 连接空闲超时5分钟清理长期空闲连接
dataSource.setMaxTotal(30); // 最大连接数: 20-50根据服务器CPU/内存调整)
dataSource.setMaxIdle(15); // 最大空闲连接: 保留部分连接避免频繁创建
dataSource.setMinIdle(5); // 最小空闲连接: 保证基础并发响应速度
dataSource.setTimeBetweenEvictionRunsMillis(60000); // 连接检测间隔: 1分钟
dataSource.setMinEvictableIdleTimeMillis(300000); // 连接空闲超时: 5分钟清理长期空闲连接
// 3. 连接有效性验证(避免使用失效连接)
dataSource.setTestOnBorrow(true); // 借连接时验证
dataSource.setTestOnReturn(false); // 还连接时不验证(减少开销)
dataSource.setValidationQuery("SELECT 1"); // 轻量验证SQLSQLite支持
dataSource.setValidationQueryTimeout(2); // 验证超时2秒
dataSource.setValidationQueryTimeout(2); // 验证超时: 2秒
// 4. PreparedStatement缓存减少SQL解析开销
dataSource.setPoolPreparedStatements(true);
@ -83,11 +83,11 @@ public class SQLiteUtil {
// 5. SQLite底层性能优化关键提升并发能力
try (Connection conn = dataSource.getConnection();
Statement stmt = conn.createStatement()) {
stmt.execute("PRAGMA journal_mode=WAL;"); // 启用WAL模式支持多读者+单写者(核心优化)
stmt.execute("PRAGMA journal_mode=WAL;"); // 启用WAL模式: 支持多读者+单写者(核心优化)
stmt.execute("PRAGMA cache_size=-20000;"); // 页面缓存20MB负号表示KB单位、内存足可调大
stmt.execute("PRAGMA synchronous=NORMAL;"); // 同步级别平衡性能与安全崩溃最多丢WAL日志
stmt.execute("PRAGMA synchronous=NORMAL;"); // 同步级别: 平衡性能与安全崩溃最多丢WAL日志
stmt.execute("PRAGMA temp_store=MEMORY;"); // 临时表/索引存内存减少磁盘IO
stmt.execute("PRAGMA busy_timeout=2000;"); // 忙等待超时2秒避免瞬时并发锁等待
stmt.execute("PRAGMA busy_timeout=2000;"); // 忙等待超时: 2秒避免瞬时并发锁等待
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("请检查路径是否存在");
@ -108,7 +108,7 @@ public class SQLiteUtil {
try {
dataSource.close(); // DBCP2会自动关闭所有活跃/空闲连接
} catch (SQLException e) {
System.err.println("关闭SQLite数据源失败路径" + dbFilePath + "" + e.getMessage());
System.err.println("关闭SQLite数据源失败路径: " + dbFilePath + ": " + e.getMessage());
}
}
}
@ -121,7 +121,7 @@ public class SQLiteUtil {
try {
dataSource.close();
} catch (SQLException e) {
System.err.println("关闭SQLite数据源失败" + e.getMessage());
System.err.println("关闭SQLite数据源失败: " + e.getMessage());
}
}
// 清理缓存(避免内存泄漏)
@ -129,7 +129,7 @@ public class SQLiteUtil {
FIELD_CACHE.clear();
}
// JVM关闭钩子确保程序退出时释放所有数据源资源
// JVM关闭钩子: 确保程序退出时释放所有数据源资源
static {
Runtime.getRuntime().addShutdownHook(new Thread(SQLiteUtil::closeAllDataSources));
}
@ -138,7 +138,7 @@ public class SQLiteUtil {
// ========================== 数据查询核心方法 ==========================
/**
* 执行查询并返回单个对象(优化版连接池+字段缓存)
* 执行查询并返回单个对象(优化版: 连接池+字段缓存)
*
* @param dbFilePath 数据库路径
* @param sql 查询SQL
@ -152,7 +152,7 @@ public class SQLiteUtil {
}
/**
* 执行查询并返回对象列表(优化版预构建字段映射+资源自动回收)
* 执行查询并返回对象列表(优化版: 预构建字段映射+资源自动回收)
*
* @param dbFilePath 数据库路径
* @param sql 查询SQL
@ -169,7 +169,7 @@ public class SQLiteUtil {
// 预加载字段映射(缓存生效、避免重复反射)
Map<String, Field> fieldMap = getFieldMap(clazz);
// try-with-resources自动关闭Connection、PreparedStatement、ResultSet
// try-with-resources: 自动关闭Connection、PreparedStatement、ResultSet
try (Connection conn = getConnection(dbFilePath);
PreparedStatement pstmt = createPreparedStatement(conn, sql, params);
ResultSet rs = pstmt.executeQuery()) {
@ -193,20 +193,20 @@ public class SQLiteUtil {
resultList.add(obj);
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException |
InvocationTargetException e) {
throw new SQLException("创建对象实例失败(类型" + clazz.getName() + "", e);
throw new SQLException("创建对象实例失败(类型: " + clazz.getName() + "", e);
}
}
} catch (SQLException e) {
// 异常时关闭当前数据源(避免后续请求使用异常连接)
closeDataSource(dbFilePath);
throw new SQLException("执行查询失败SQL" + sql + "", e);
throw new SQLException("执行查询失败SQL: " + sql + "", e);
}
return resultList;
}
/**
* 执行增删改SQL优化版连接池+自动提交)
* 执行增删改SQL优化版: 连接池+自动提交)
*
* @param dbFilePath 数据库路径
* @param sql 增删改SQL
@ -223,12 +223,12 @@ public class SQLiteUtil {
return pstmt.executeUpdate();
} catch (SQLException e) {
closeDataSource(dbFilePath);
throw new SQLException("执行增删改失败SQL" + sql + "", e);
throw new SQLException("执行增删改失败SQL: " + sql + "", e);
}
}
/**
* 执行计数查询(优化版轻量结果处理)
* 执行计数查询(优化版: 轻量结果处理)
*
* @param dbFilePath 数据库路径
* @param sql 计数SQL如SELECT COUNT(*) ...
@ -246,7 +246,7 @@ public class SQLiteUtil {
return rs.next() ? rs.getInt(1) : 0;
} catch (SQLException e) {
closeDataSource(dbFilePath);
throw new SQLException("执行计数查询失败SQL" + sql + "", e);
throw new SQLException("执行计数查询失败SQL: " + sql + "", e);
}
}
@ -270,12 +270,12 @@ public class SQLiteUtil {
pstmt.execute();
} catch (SQLException e) {
closeDataSource(dbFilePath);
throw new SQLException("执行DDL失败SQL" + sql + "、路径" + dbFilePath + "", e);
throw new SQLException("执行DDL失败SQL: " + sql + "、路径: " + dbFilePath + "", e);
}
}
/**
* 重载无参数的DDL执行
* 重载: 无参数的DDL执行
*/
public static void executeDDL(String dbFilePath, String sql) throws SQLException {
executeDDL(dbFilePath, sql, null);
@ -408,7 +408,7 @@ public class SQLiteUtil {
field.set(obj, convertedValue);
}
} catch (IllegalAccessException e) {
System.err.println("警告字段赋值失败(字段" + field.getName() + "、值类型" + value.getClass().getName() + "" + e.getMessage());
System.err.println("警告: 字段赋值失败(字段: " + field.getName() + "、值类型: " + value.getClass().getName() + ": " + e.getMessage());
}
}
@ -452,7 +452,7 @@ public class SQLiteUtil {
}
// 不支持的类型转换(打印警告)
System.err.println("警告不支持的类型转换(目标类型" + targetType.getName() + "、原始值类型" + value.getClass().getName() + "");
System.err.println("警告: 不支持的类型转换(目标类型: " + targetType.getName() + "、原始值类型: " + value.getClass().getName() + "");
return null;
}
@ -461,7 +461,7 @@ public class SQLiteUtil {
try {
return Integer.parseInt(value.trim());
} catch (NumberFormatException e) {
System.err.println("警告字符串转Integer失败" + value + "");
System.err.println("警告: 字符串转Integer失败: " + value + "");
return null;
}
}
@ -470,7 +470,7 @@ public class SQLiteUtil {
try {
return Long.parseLong(value.trim());
} catch (NumberFormatException e) {
System.err.println("警告字符串转Long失败" + value + "");
System.err.println("警告: 字符串转Long失败: " + value + "");
return null;
}
}
@ -479,7 +479,7 @@ public class SQLiteUtil {
try {
return Double.parseDouble(value.trim());
} catch (NumberFormatException e) {
System.err.println("警告字符串转Double失败" + value + "");
System.err.println("警告: 字符串转Double失败: " + value + "");
return null;
}
}
@ -489,7 +489,7 @@ public class SQLiteUtil {
try {
return LocalDateTime.parse((String) value, LOCAL_DATE_TIME_FORMATTER);
} catch (DateTimeParseException e) {
System.err.println("警告字符串转LocalDateTime失败" + value + "");
System.err.println("警告: 字符串转LocalDateTime失败: " + value + "");
return null;
}
} else if (value instanceof Timestamp) {
@ -513,7 +513,7 @@ public class SQLiteUtil {
try {
return blob.getBytes(1, (int) blob.length());
} catch (SQLException e) {
System.err.println("警告Blob转byte[]失败" + e.getMessage());
System.err.println("警告: Blob转byte[]失败: " + e.getMessage());
}
}
return null;

View File

@ -139,7 +139,7 @@ public class SdkUtil {
// 判断操作系统类型
boolean isWindows = System.getProperty("os.name").toLowerCase().contains("win");
// 构建JDK路径根目录/jdk/bin/java(或java.exe)
// 构建JDK路径: 根目录/jdk/bin/java(或java.exe)
String javaRelativePath = "jdk" + File.separator + "bin" + File.separator +
(isWindows ? "java.exe" : "java");
return new File(rootDir, javaRelativePath).getAbsolutePath();

View File

@ -83,7 +83,7 @@ public class DatabaseManager {
ENTITY_CLASSES = Collections.unmodifiableList(classes);
}
// 新增方法提前初始化路径
// 新增方法: 提前初始化路径
public static void initializePath(String path) {
if (!isPathInitialized) {
FOLDER_NAME = path;