Files
Environment-Monitoring-System/Report/系统实现_第一部分.md
ChuXun 02a830145e 1
2025-10-25 19:18:43 +08:00

217 lines
7.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 3.3 系统实现
## 3.3.1 开发环境与技术栈
在本项目的开发过程中,我采用了现代化、高效且广泛应用于企业级开发的技术栈组合,确保系统的稳定性、可扩展性和维护性。
### 后端技术栈
- **编程语言**: Java 17
- **框架**: Spring Boot 3.1.5
- **API文档**: Springdoc OpenAPI (Swagger)
- **安全框架**: Spring Security + JWT
- **构建工具**: Maven 3.9
- **数据存储**: 自定义JSON文件存储模拟数据库
- **异步处理**: Spring Events
- **日志框架**: SLF4J + Logback
- **单元测试**: JUnit 5 + Mockito
### 前端技术栈
- **框架**: Vue 3 (Composition API)
- **构建工具**: Vite
- **UI组件库**: Element Plus
- **状态管理**: Pinia
- **路由**: Vue Router
- **HTTP客户端**: Axios
- **CSS预处理器**: SCSS
- **图表库**: ECharts
### 开发工具
- **IDE**: IntelliJ IDEA / VS Code
- **版本控制**: Git
- **API测试**: Postman
- **代码质量**: SonarLint
- **调试工具**: Chrome DevTools
## 3.3.2 核心功能模块实现
在系统设计阶段,我们已经详细规划了各个功能模块。在实现阶段,我负责了多个核心模块的编码工作,下面将详细介绍这些模块的实现细节。
### 1. 泛型JSON存储服务
在本项目中我设计并实现了一个创新的数据持久化解决方案使用JSON文件代替传统数据库进行数据存储。这种方案简化了系统部署同时提供了类似于JPA的操作接口使得业务层代码无需关心底层存储细节。
**关键代码展示**:
```java
@Service
public class JsonStorageService {
private static final Path STORAGE_DIRECTORY = Paths.get("json-db");
private final ObjectMapper objectMapper;
public JsonStorageService(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
try {
if (!Files.exists(STORAGE_DIRECTORY)) {
Files.createDirectories(STORAGE_DIRECTORY);
}
} catch (IOException e) {
throw new UncheckedIOException("无法创建存储目录", e);
}
}
// 同步写数据方法,保证线程安全
public synchronized <T> void writeData(String fileName, List<T> data) {
try {
Path filePath = STORAGE_DIRECTORY.resolve(fileName);
// 使用writeValueAsString先转为格式化的JSON字符串再写入文件提高可读性
String jsonContent = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(data);
Files.write(filePath, jsonContent.getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
throw new UncheckedIOException("写入数据到 " + fileName + " 时出错", e);
}
}
// 读数据方法
public <T> List<T> readData(String fileName, TypeReference<List<T>> typeReference) {
Path filePath = STORAGE_DIRECTORY.resolve(fileName);
if (!Files.exists(filePath)) {
return new ArrayList<>(); // 文件不存在是正常情况,返回空列表
}
try {
// 使用TypeReference来处理泛型擦除问题确保JSON能被正确反序列化为List<T>
return objectMapper.readValue(filePath.toFile(), typeReference);
} catch (IOException e) {
log.warn("无法读取或解析文件: {}. 返回空列表。", fileName, e);
return new ArrayList<>();
}
}
}
```
**实现要点分析**:
1. **泛型设计**: 通过Java泛型和TypeReference实现了类型安全的数据读写支持任意模型类。
2. **线程安全**: 使用synchronized关键字确保写操作的线程安全防止并发写入导致的数据损坏。
3. **容错处理**: 对文件不存在、IO异常等情况进行了妥善处理增强了系统的健壮性。
4. **格式化输出**: 使用Jackson的prettyPrinter功能使生成的JSON文件具有良好的可读性便于调试。
**程序流程图**:
```mermaid
flowchart TD
A[开始] --> B{文件存在?}
B -->|是| C[读取文件内容]
B -->|否| D[返回空列表]
C --> E{解析JSON成功?}
E -->|是| F[返回对象列表]
E -->|否| G[记录警告日志]
G --> D
```
### 2. A*寻路算法实现
在网格与地图模块中我实现了A*寻路算法,为网格员提供从当前位置到任务地点的最优路径规划。该算法考虑了地图障碍物,能够高效地找到最短路径。
**关键代码展示**:
```java
@Service
@RequiredArgsConstructor
public class AStarService {
private final MapGridRepository mapGridRepository;
// 内部Node类用于A*算法的节点表示
private static class Node {
Point point;
int g; // 从起点到当前节点的实际代价
int h; // 启发式:从当前节点到终点的估计代价
int f; // g + h
Node parent;
public Node(Point point, Node parent, int g, int h) {
this.point = point;
this.parent = parent;
this.g = g;
this.h = h;
this.f = g + h;
}
}
/**
* 寻找两点间的最短路径,避开障碍物
* 地图数据(包括尺寸和障碍物)从数据库动态加载
*/
public List<Point> findPath(Point start, Point end) {
// 从数据库加载地图数据
List<MapGrid> mapGrids = mapGridRepository.findAll();
if (mapGrids.isEmpty()) {
return Collections.emptyList(); // 无地图数据
}
// 动态确定地图尺寸和障碍物
int maxX = 0, maxY = 0;
Set<Point> obstacles = new HashSet<>();
for (MapGrid gridCell : mapGrids) {
if (gridCell.isObstacle() || gridCell.getCityName() == null || gridCell.getCityName().trim().isEmpty()) {
obstacles.add(new Point(gridCell.getX(), gridCell.getY()));
}
if (gridCell.getX() > maxX) maxX = gridCell.getX();
if (gridCell.getY() > maxY) maxY = gridCell.getY();
}
final int mapWidth = maxX + 1;
final int mapHeight = maxY + 1;
// A*算法核心实现
PriorityQueue<Node> openSet = new PriorityQueue<>(Comparator.comparingInt(n -> n.f));
Map<Point, Node> allNodes = new HashMap<>();
Node startNode = new Node(start, null, 0, calculateHeuristic(start, end));
openSet.add(startNode);
allNodes.put(start, startNode);
while (!openSet.isEmpty()) {
Node currentNode = openSet.poll();
if (currentNode.point.equals(end)) {
return reconstructPath(currentNode);
}
for (Point neighborPoint : getNeighbors(currentNode.point, mapWidth, mapHeight)) {
if (obstacles.contains(neighborPoint)) {
continue;
}
int tentativeG = currentNode.g + 1; // 相邻节点间距离为1
Node neighborNode = allNodes.get(neighborPoint);
if (neighborNode == null) {
// 新节点
int h = calculateHeuristic(neighborPoint, end);
neighborNode = new Node(neighborPoint, currentNode, tentativeG, h);
allNodes.put(neighborPoint, neighborNode);
openSet.add(neighborNode);
} else if (tentativeG < neighborNode.g) {
// 找到更好的路径
neighborNode.parent = currentNode;
neighborNode.g = tentativeG;
neighborNode.f = tentativeG + neighborNode.h;
// 更新优先队列
openSet.remove(neighborNode);
openSet.add(neighborNode);
}
}
}
return Collections.emptyList(); // 未找到路径
}
// 计算启发式函数值(曼哈顿距离)
private int calculateHeuristic(Point a, Point b) {
return Math.abs(a.x() - b.x()) + Math.abs(a.y() - b.y());
}
}