This commit is contained in:
2025-11-20 15:10:08 +08:00
parent 5a77756c33
commit ca13d078a3
12 changed files with 216 additions and 203 deletions

View File

@ -4,11 +4,12 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title>路径规划系统</title>
<!-- 仅保留必要CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
<script src="https://cdn.jsdelivr.net/npm/axios@1.6.8/dist/axios.min.js"></script>
<!-- Tailwind配置 -->
@ -38,25 +39,32 @@
.content-auto {
content-visibility: auto;
}
.map-height {
height: 100vh; /* 调整为占满视口高度 */
}
.sidebar-height {
height: 100vh; /* 调整为占满视口高度 */
}
.scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;
}
.scrollbar-hide::-webkit-scrollbar {
display: none;
}
.custom-marker .fa {
font-size: 14px;
}
.input-error {
@apply border-danger focus:ring-danger/50 focus:border-danger;
}
.btn-disabled {
@apply bg-gray-300 text-gray-500 cursor-not-allowed hover:bg-gray-300;
}
@ -100,7 +108,8 @@
<!-- 起点移除默认value、默认无数据 -->
<div class="space-y-1">
<label class="block text-sm font-medium text-gray-700">起点 <span class="text-danger">*</span></label>
<label class="block text-sm font-medium text-gray-700">起点 <span
class="text-danger">*</span></label>
<div class="flex space-x-2">
<div class="flex-1 space-y-0.5">
<input type="text" id="startLat" placeholder="纬度"
@ -114,7 +123,8 @@
maxlength="10">
<span id="startLngError" class="text-danger text-xs hidden">请输入有效经度</span>
</div>
<button id="setStartBtn" class="p-2 bg-gray-100 hover:bg-gray-200 rounded transition-colors duration-200"
<button id="setStartBtn"
class="p-2 bg-gray-100 hover:bg-gray-200 rounded transition-colors duration-200"
title="在地图上选择起点">
<i class="fa fa-map-marker text-danger"></i>
</button>
@ -123,7 +133,8 @@
<!-- 终点 -->
<div class="space-y-1">
<label class="block text-sm font-medium text-gray-700">终点 <span class="text-danger">*</span></label>
<label class="block text-sm font-medium text-gray-700">终点 <span
class="text-danger">*</span></label>
<div class="flex space-x-2">
<div class="flex-1 space-y-0.5">
<input type="text" id="endLat" placeholder="纬度"
@ -137,7 +148,8 @@
maxlength="10">
<span id="endLngError" class="text-danger text-xs hidden">请输入有效经度</span>
</div>
<button id="setEndBtn" class="p-2 bg-gray-100 hover:bg-gray-200 rounded transition-colors duration-200"
<button id="setEndBtn"
class="p-2 bg-gray-100 hover:bg-gray-200 rounded transition-colors duration-200"
title="在地图上选择终点">
<i class="fa fa-flag text-success"></i>
</button>
@ -160,7 +172,8 @@
<!-- 交通方式 -->
<div class="space-y-1">
<label class="block text-sm font-medium text-gray-700">交通方式 <span class="text-danger">*</span></label>
<label class="block text-sm font-medium text-gray-700">交通方式 <span
class="text-danger">*</span></label>
<select id="profile"
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary/50 focus:border-primary text-sm transition-all bg-white">
<option value="car">驾车</option>
@ -241,14 +254,14 @@
<script>
// 大整数转字符串处理(保留原逻辑)
axios.defaults.transformResponse = [
function(data) {
function (data) {
if (typeof data !== 'string') return data;
const bigIntRegex = /(\s*"[^"]*"\s*:\s*)(\d{16,})(\s*)/g;
return data.replace(bigIntRegex, (match, keyPart, bigInt, endPart) => {
return `${keyPart}"${bigInt}"${endPart}`;
});
},
function(parsedData) {
function (parsedData) {
try {
return JSON.parse(parsedData);
} catch (e) {
@ -265,7 +278,7 @@
let routeLine = null;
let waypointCount = 0;
const API_BASE_URL = "http://127.0.0.1:8848";
const DEFAULT_CENTER = { lat: 30.6570, lng: 104.0650 }; // 成都默认坐标
const DEFAULT_CENTER = {lat: 30.6570, lng: 104.0650}; // 成都默认坐标
// 地图初始化
function initMap() {
@ -353,7 +366,7 @@
}).addTo(map);
startMarker.on('dragend', (e) => {
const { lat, lng } = e.target.getLatLng();
const {lat, lng} = e.target.getLatLng();
setStartPoint(lat, lng);
});
}
@ -383,7 +396,7 @@
}).addTo(map);
endMarker.on('dragend', (e) => {
const { lat, lng } = e.target.getLatLng();
const {lat, lng} = e.target.getLatLng();
setEndPoint(lat, lng);
});
}
@ -436,7 +449,7 @@
waypointDiv.querySelector('.set-waypoint-btn').addEventListener('click', () => {
const id = parseInt(waypointDiv.dataset.id);
map.once('click', (e) => {
const { lat, lng } = e.latlng;
const {lat, lng} = e.latlng;
latInput.value = lat.toFixed(6);
lngInput.value = lng.toFixed(6);
latInput.dispatchEvent(new Event('input'));
@ -457,7 +470,7 @@
}).addTo(map);
waypointMarkers[id].on('dragend', (e) => {
const { lat, lng } = e.target.getLatLng();
const {lat, lng} = e.target.getLatLng();
latInput.value = lat.toFixed(6);
lngInput.value = lng.toFixed(6);
latInput.dispatchEvent(new Event('input'));
@ -480,7 +493,7 @@
// 地图点击处理
function handleMapClick(e) {
const { lat, lng } = e.latlng;
const {lat, lng} = e.latlng;
const startLat = document.getElementById('startLat').value;
const endLat = document.getElementById('endLat').value;
@ -632,7 +645,7 @@
const lat = parseFloat(item.querySelector('.waypoint-lat').value);
const lng = parseFloat(item.querySelector('.waypoint-lng').value);
if (!isNaN(lat) && !isNaN(lng) && validateCoord(lat, 'lat') && validateCoord(lng, 'lng')) {
waypoints.push({ lat, lng });
waypoints.push({lat, lng});
}
});
@ -644,8 +657,8 @@
try {
const response = await axios.post(
`${API_BASE_URL}/graphhopper/route`,
{ startLat, startLng, endLat, endLng, profile, waypoints },
{ headers: { 'Content-Type': 'application/json' } }
{startLat, startLng, endLat, endLng, profile, waypoints},
{headers: {'Content-Type': 'application/json'}}
);
if (response.data.code !== 200 || !response.data.data) {
@ -671,16 +684,16 @@
if (routeLine) map.removeLayer(routeLine);
const latLngs = routeData.pathPoints.map(point => [point.lat, point.lng]);
const lineStyles = {
car: { color: '#165DFF', weight: 5, opacity: 0.8, dashArray: '' },
bike: { color: '#00B42A', weight: 4, opacity: 0.8, dashArray: '5,5' },
foot: { color: '#4b0c35', weight: 3, opacity: 0.8, dashArray: '2,2' }
car: {color: '#165DFF', weight: 5, opacity: 0.8, dashArray: ''},
bike: {color: '#00B42A', weight: 4, opacity: 0.8, dashArray: '5,5'},
foot: {color: '#4b0c35', weight: 3, opacity: 0.8, dashArray: '2,2'}
};
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>`);
map.fitBounds(routeLine.getBounds(), { padding: [50, 50], maxZoom: 14 });
map.fitBounds(routeLine.getBounds(), {padding: [50, 50], maxZoom: 14});
}
// 事件绑定:移除起点按钮弹窗

View File

@ -150,10 +150,10 @@ public class GraphHopperController {
public ApiResponse calculateRoute(@RequestBody RouteRequest request) {
// 区分未加载地图和加载中两种状态
if (isLoading.get()) {
return ApiResponse.failure("地图正在加载中请稍后再试");
return ApiResponse.failure("地图正在加载中请稍后再试");
}
if (!isLoaded.get() || currentHopper == null) {
return ApiResponse.failure("地图未加载请先加载地图");
return ApiResponse.failure("地图未加载请先加载地图");
}
try {
// 构建路径点列表

View File

@ -33,6 +33,7 @@ import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.util.ArrayList;
@ -200,29 +201,16 @@ public class IconLibraryController {
@Operation(summary = "添加图标文件")
@PostMapping("/addIconFile")
public ApiResponse addIconFile(@RequestParam("files") MultipartFile[] files, @RequestParam("iconTypeId") @Parameter(description = "图标类型ID") String typeId) throws IOException, SQLException, IllegalAccessException, InstantiationException {
// 获取当前启用的图标库
public ApiResponse addIconFile(@RequestParam("filePaths") List<String> filePaths, @RequestParam("iconTypeId") String typeId) throws Exception {
// 获取当前启用的图标库路径
String iconPath = getIconLibrary();
if (iconPath == null) {
return ApiResponse.failure("请先创建或导入图标库");
}
// 校验类型是否存在
if (!isIconTypeExist(iconPath, typeId)) {
return ApiResponse.failure("图标类型不存在:" + typeId);
}
// 循环处理每个文件
for (MultipartFile file : files) {
if (file.isEmpty()) {
continue; // 跳过空文件
}
// 循环处理每个绝对路径对应的文件
for (String filePath : filePaths) {
File file = new File(filePath);
// 解析文件名与后缀
String originalFileName = file.getOriginalFilename();
if (originalFileName == null) {
continue;
}
String originalFileName = file.getName();
String fileSuffix = FileUtil.extName(originalFileName);
String fileNameWithoutSuffix = FileUtil.mainName(originalFileName);
@ -235,10 +223,10 @@ public class IconLibraryController {
params.add(typeId);
params.add(fileNameWithoutSuffix);
params.add(fileSuffix);
params.add(file.getBytes());
params.add(Files.readAllBytes(file.toPath()));
params.add(LocalDateTime.now().toString());
System.out.println(insertSql);
// 执行数据库插入
SQLiteUtil.executeUpdate(iconPath, insertSql, params);
}
@ -391,7 +379,7 @@ public class IconLibraryController {
private String getIconLibrary() {
LambdaQueryWrapper<IconLibrary> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(IconLibrary::getIsEnable, 1); // 1=启用、0=未启用
queryWrapper.eq(IconLibrary::getIsEnable, 1);
IconLibrary library = iconLibraryService.getOne(queryWrapper);
return library == null ? null : library.getPath();
}

View File

@ -1,21 +1,32 @@
package com.yj.earth.business.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yj.earth.business.domain.Matter;
import com.yj.earth.business.domain.Source;
import com.yj.earth.business.service.MatterService;
import com.yj.earth.business.service.SourceService;
import com.yj.earth.common.util.ApiResponse;
import com.yj.earth.common.util.JsonUtil;
import com.yj.earth.dto.matter.AddMatterDto;
import com.yj.earth.dto.matter.UpdateMatterDto;
import com.yj.earth.params.Point;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@Tag(name = "物资数据管理")
@ -24,6 +35,8 @@ import java.util.List;
public class MatterController {
@Resource
private MatterService matterService;
@Resource
private SourceService sourceService;
@PostMapping("/add")
@Operation(summary = "添加物资")
@ -71,10 +84,122 @@ public class MatterController {
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) {
LambdaQueryWrapper<Matter> queryWrapper = new LambdaQueryWrapper<>();
Map<String, Integer> goodsTotalMap = getGoodCountMap();
// 分页查询物资表的数据
LambdaQueryWrapper<Matter> matterWrapper = new LambdaQueryWrapper<>();
if (StringUtils.isNotBlank(name)) {
queryWrapper.like(Matter::getName, name);
matterWrapper.like(Matter::getName, name);
}
return ApiResponse.success(matterService.page(new Page<>(pageNum, pageSize), queryWrapper));
Page<Matter> matterPage = matterService.page(new Page<>(pageNum, pageSize), matterWrapper);
// 用统计出的数量替换分页结果中的数量
if (!CollectionUtils.isEmpty(matterPage.getRecords())) {
matterPage.getRecords().forEach(matter -> {
String matterName = matter.getName();
Integer count = goodsTotalMap.get(matterName);
if (count != null) {
matter.setNum(count);
}
});
}
return ApiResponse.success(matterPage);
}
@Operation(summary = "物资统计")
@PostMapping("/statistics")
public ApiResponse statistics(@Parameter(description = "点ID列表") @RequestBody List<String> pointIdList) {
// 构建Source表的查询条件
LambdaQueryWrapper<Source> sourceWrapper = new LambdaQueryWrapper<>();
// 根据ID列表查询
sourceWrapper.in(Source::getId, pointIdList);
// 执行查询、获取所有符合条件的Source列表
List<Source> sourceList = sourceService.list(sourceWrapper);
// 初始化物资统计Map用于存储 "物资名称 -> 总数量" 的映射关系
Map<String, Integer> goodsTotalMap = new HashMap<>();
if (!CollectionUtils.isEmpty(sourceList)) {
for (Source source : sourceList) {
try {
Point point = JsonUtil.jsonToObject(source.getParams(), Point.class);
if (point == null) continue;
Optional.ofNullable(point.getAttribute())
.map(Point.Attribute::getGoods)
.map(Point.Attribute.Goods::getContent)
.ifPresent(contentList -> {
// 遍历物资列表中的每个物资项
for (Point.Attribute.Goods.GoodsContent goodsContent : contentList) {
if (goodsContent == null) continue;
// 处理物资名称
String goodsName = Optional.ofNullable(goodsContent.getName())
.orElse("未知物资");
// 处理物资数量
int count = Optional.ofNullable(goodsContent.getCnt())
.map(Integer::valueOf)
.orElse(0);
// 累加物资总数量
goodsTotalMap.merge(goodsName, count, Integer::sum);
}
});
} catch (Exception e) {
}
}
}
// 返回最终的物资统计Map
return ApiResponse.success(goodsTotalMap);
}
private Map<String, Integer> getGoodCountMap() {
// 构建Source表的查询条件
LambdaQueryWrapper<Source> sourceWrapper = new LambdaQueryWrapper<>();
sourceWrapper.eq(Source::getSourceType, "point");
// 执行查询、获取所有符合条件的Source列表
List<Source> sourceList = sourceService.list(sourceWrapper);
// 初始化物资统计Map用于存储 "物资名称 -> 总数量" 的映射关系
Map<String, Integer> goodsTotalMap = new HashMap<>();
if (!CollectionUtils.isEmpty(sourceList)) {
for (Source source : sourceList) {
try {
Point point = JsonUtil.jsonToObject(source.getParams(), Point.class);
if (point == null) continue;
Optional.ofNullable(point.getAttribute())
.map(Point.Attribute::getGoods)
.map(Point.Attribute.Goods::getContent)
.ifPresent(contentList -> {
// 遍历物资列表中的每个物资项
for (Point.Attribute.Goods.GoodsContent goodsContent : contentList) {
if (goodsContent == null) continue;
// 处理物资名称
String goodsName = Optional.ofNullable(goodsContent.getName())
.orElse("未知物资");
// 处理物资数量
int count = Optional.ofNullable(goodsContent.getCnt())
.map(Integer::valueOf)
.orElse(0);
// 累加物资总数量
goodsTotalMap.merge(goodsName, count, Integer::sum);
}
});
} catch (Exception e) {
}
}
}
// 返回最终的物资统计Map
return goodsTotalMap;
}
}

View File

@ -33,6 +33,7 @@ import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.util.ArrayList;
@ -200,29 +201,16 @@ public class MilitaryLibraryController {
@Operation(summary = "添加军标文件")
@PostMapping("/addMilitaryFile")
public ApiResponse addMilitaryFile(@RequestParam("files") MultipartFile[] files, @RequestParam("militaryTypeId") @Parameter(description = "军标类型ID") String typeId) throws IOException, SQLException, IllegalAccessException, InstantiationException {
// 获取当前启用的军标库
public ApiResponse addMilitaryFile(@RequestParam("filePaths") List<String> filePaths,
@RequestParam("militaryTypeId") @Parameter(description = "军标类型ID") String typeId) throws IOException, SQLException {
String militaryPath = getMilitaryLibrary();
if (militaryPath == null) {
return ApiResponse.failure("请先创建或导入军标库");
}
// 校验类型是否存在
if (!isMilitaryTypeExist(militaryPath, typeId)) {
return ApiResponse.failure("军标类型不存在:" + typeId);
}
// 循环处理每个文件
for (MultipartFile file : files) {
if (file.isEmpty()) {
continue; // 跳过空文件
}
// 循环处理每个绝对路径对应的文件
for (String filePath : filePaths) {
File file = new File(filePath);
// 解析文件名与后缀
String originalFileName = file.getOriginalFilename();
if (originalFileName == null) {
continue;
}
String originalFileName = file.getName();
String fileSuffix = FileUtil.extName(originalFileName);
String fileNameWithoutSuffix = FileUtil.mainName(originalFileName);
@ -235,7 +223,7 @@ public class MilitaryLibraryController {
params.add(typeId);
params.add(fileNameWithoutSuffix);
params.add(fileSuffix);
params.add(file.getBytes());
params.add(Files.readAllBytes(file.toPath()));
params.add(LocalDateTime.now().toString());
SQLiteUtil.executeUpdate(militaryPath, insertSql, params);
@ -243,7 +231,6 @@ public class MilitaryLibraryController {
return ApiResponse.success(null);
}
@Operation(summary = "获取军标文件数据")
@GetMapping("/data/military/{militaryId}/{fileSuffix}")
public ResponseEntity<byte[]> getMilitaryData(@PathVariable("militaryId") @Parameter(description = "军标ID") String militaryId, @PathVariable("fileSuffix") @Parameter(description = "军标文件后缀") String fileSuffix) {

View File

@ -16,6 +16,7 @@ import com.yj.earth.dto.modelLibrary.AddModelTypeDto;
import com.yj.earth.dto.modelLibrary.CreateModelLibraryDto;
import com.yj.earth.dto.modelLibrary.DragModelTypeDto;
import com.yj.earth.dto.modelLibrary.UpdateModelTypeNameDto;
import com.yj.earth.vo.IconDataVo;
import com.yj.earth.vo.ModelDataVo;
import com.yj.earth.vo.ModelTypeVo;
import com.yj.earth.vo.ModelVo;
@ -36,6 +37,7 @@ import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.util.*;
@ -165,25 +167,24 @@ public class ModelLibraryController {
@Operation(summary = "添加模型文件")
@PostMapping("/addModelFile")
public ApiResponse addModelFile(@RequestParam("files") MultipartFile[] files, @Parameter(description = "模型类型ID") @RequestParam("modelTypeId") String modelTypeId) throws IOException, SQLException {
public ApiResponse addModelFile(
@Parameter(description = "绝对文件路径列表") @RequestParam("filePaths") List<String> filePaths,
@Parameter(description = "模型类型ID") @RequestParam("modelTypeId") String modelTypeId) throws IOException, SQLException {
// 获取最新的模型库路径
String modelPath = getModelLibrary();
if (modelPath == null) {
return ApiResponse.failure("请先创建或导入模型库");
}
// 循环处理每个上传的文件
for (MultipartFile file : files) {
// 跳过空文件
if (file.isEmpty()) {
continue;
}
// 获取文件信息
String fileName = file.getOriginalFilename();
if (fileName == null) {
continue;
}
String fileSuffix = FileUtil.extName(fileName);
String fileNameWithoutSuffix = FileUtil.mainName(fileName);
// 简化校验:仅判断列表是否为空
if (filePaths == null || filePaths.isEmpty()) {
return ApiResponse.failure("文件路径列表不能为空");
}
// 循环处理每个文件路径
for (String filePath : filePaths) {
File file = new File(filePath);
// 构建插入SQL
String sql = "INSERT INTO model " +
@ -194,9 +195,9 @@ public class ModelLibraryController {
String modelId = UUID.fastUUID().toString(true);
params.add(modelId);
params.add(modelTypeId);
params.add(fileNameWithoutSuffix);
params.add(fileSuffix);
params.add(file.getBytes());
params.add(file.getName().split("\\.")[0]);
params.add(file.getName().substring(file.getName().lastIndexOf(".") + 1));
params.add(Files.readAllBytes(file.toPath()));
params.add(LocalDateTime.now());
// 执行插入操作

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

View File

@ -50,6 +50,7 @@ public class TsSourceController {
public ApiResponse update(@RequestBody UpdateTsSourceDto updateTsSourceDto) {
TsSource tsSource = new TsSource();
BeanUtils.copyProperties(updateTsSourceDto, tsSource);
tsSourceService.updateById(tsSource);
return ApiResponse.success(null);
}

View File

@ -49,14 +49,16 @@ public class JsonUtil {
}
}
/**
* 将 JSON 字符串转换为指定类型的对象
*/
public static <T> T jsonToObject(String json, Class<T> clazz) {
if (json == null || json.trim().isEmpty()) {
return null;
}
return objectMapper.convertValue(json, clazz);
try {
return objectMapper.readValue(json, clazz);
} catch (Exception e) {
return null;
}
}
/**

View File

@ -90,7 +90,7 @@ public class SQLiteUtil {
stmt.execute("PRAGMA busy_timeout=2000;"); // 忙等待超时2秒避免瞬时并发锁等待
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("初始化SQLite数据源失败路径" + dbFilePath + "+ 原因是:" + e.getMessage());
throw new RuntimeException("请检查路径是否存在");
}
return dataSource;

View File

@ -141,11 +141,11 @@ public class DatabaseManager {
public static String getSqliteDbFilePath() {
if (!isPathInitialized || FOLDER_NAME == null) {
throw new IllegalStateException("数据库路径尚未初始化请先调用 initializePath 方法或等待 @PostConstruct 完成");
throw new IllegalStateException("数据库路径尚未初始化请先调用 initializePath 方法或等待 @PostConstruct 完成");
}
if (sqliteDbFilePath == null) {
// 如果没有预先创建则动态构建路径
// 如果没有预先创建则动态构建路径
Path appDir = Paths.get(FOLDER_NAME);
Path dbFile = appDir.resolve(DB_FILE_NAME);
sqliteDbFilePath = dbFile.toAbsolutePath().toString();
@ -208,7 +208,7 @@ public class DatabaseManager {
// 直接使用配置的绝对路径
if (FOLDER_NAME == null || FOLDER_NAME.trim().isEmpty()) {
throw new IOException("server.path 配置为空无法创建SQLite数据库文件");
throw new IOException("server.path 配置为空无法创建SQLite数据库文件");
}
Path appDir = Paths.get(FOLDER_NAME);
@ -484,10 +484,10 @@ public class DatabaseManager {
DatabaseManager.initializePath(serverPath);
log.info("已提前初始化数据库路径: {}", serverPath);
} else {
log.warn("未找到 server.path 配置将等待 @PostConstruct 初始化");
log.warn("未找到 server.path 配置将等待 @PostConstruct 初始化");
}
} catch (Exception e) {
log.warn("提前初始化数据库路径失败将等待 @PostConstruct 初始化: {}", e.getMessage());
log.warn("提前初始化数据库路径失败将等待 @PostConstruct 初始化: {}", e.getMessage());
}
}
}

View File

@ -1,104 +0,0 @@
package com.yj.earth.word;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTShd;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STShd;
import java.io.FileOutputStream;
import java.io.IOException;
public class GenerateDocx {
public static void main(String[] args) {
// 创建文档对象
XWPFDocument document = new XWPFDocument();
try {
// 添加标题段落
XWPFParagraph titlePara = document.createParagraph();
titlePara.setAlignment(ParagraphAlignment.CENTER);
XWPFRun titleRun = titlePara.createRun();
titleRun.setText("POI 生成 Docx 示例");
// 字体大小
titleRun.setFontSize(20);
// 加粗
titleRun.setBold(true);
// 字体
titleRun.setFontFamily("宋体");
// 添加正文段落
XWPFParagraph contentPara1 = document.createParagraph();
contentPara1.setAlignment(ParagraphAlignment.LEFT);
XWPFRun run1 = contentPara1.createRun();
run1.setText("这是使用 Apache POI 生成的 docx 文档。");
run1.setFontSize(12);
run1.setFontFamily("微软雅黑");
// 换行
XWPFParagraph contentPara2 = document.createParagraph();
XWPFRun run2 = contentPara2.createRun();
run2.setText("支持设置文本样式,如:");
run2.setFontSize(12);
// 文本样式示例(同一行不同样式)
XWPFRun run3 = contentPara2.createRun();
run3.setText(" 加粗 ");
run3.setBold(true);
XWPFRun run4 = contentPara2.createRun();
run4.setText(" 斜体 ");
run4.setItalic(true);
XWPFRun run5 = contentPara2.createRun();
run5.setText(" 下划线 ");
run5.setUnderline(UnderlinePatterns.SINGLE); // 单下划线
XWPFRun run6 = contentPara2.createRun();
run6.setText(" 红色 ");
run6.setColor("FF0000"); // 红色
// 添加表格
int rows = 3; // 3行
int cols = 3; // 3列
XWPFTable table = document.createTable(rows, cols);
table.setWidth("100%"); // 表格宽度
// 设置表头
XWPFTableRow headerRow = table.getRow(0);
headerRow.getCell(0).setText("ID");
headerRow.getCell(1).setText("名称");
headerRow.getCell(2).setText("描述");
// 表头背景色(浅灰色)
for (XWPFTableCell cell : headerRow.getTableCells()) {
CTShd cTShd = cell.getCTTc().addNewTcPr().addNewShd();
cTShd.setVal(STShd.CLEAR);
cTShd.setFill("D9D9D9"); // 浅灰色
}
// 设置表格内容
XWPFTableRow row1 = table.getRow(1);
row1.getCell(0).setText("1");
row1.getCell(1).setText("POI");
row1.getCell(2).setText("处理 Office 文档的 Java 库");
XWPFTableRow row2 = table.getRow(2);
row2.getCell(0).setText("2");
row2.getCell(1).setText("Docx");
row2.getCell(2).setText("Word 2007+ 格式");
// 保存文档到本地
FileOutputStream out = new FileOutputStream("poi-demo.docx");
document.write(out);
out.close();
System.out.println("docx 生成成功!");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
document.close(); // 关闭文档,释放资源
} catch (IOException e) {
e.printStackTrace();
}
}
}
}