242 lines
10 KiB
Markdown
242 lines
10 KiB
Markdown
**实现要点分析**:
|
||
|
||
1. **动态地图加载**: 算法从数据库动态加载地图数据,包括障碍物信息和地图尺寸,使得路径规划能够适应地图的变化。
|
||
2. **优先队列优化**: 使用优先队列(PriorityQueue)存储开放列表,确保每次都能高效地选择F值最小的节点,大大提高了算法效率。
|
||
3. **曼哈顿距离启发函数**: 选择曼哈顿距离作为启发函数,适合网格化的移动模式,能够准确估计网格间的距离。
|
||
4. **路径重建**: 通过记录每个节点的父节点,实现了从终点回溯到起点的路径重建,返回完整的路径点列表。
|
||
|
||
**程序流程图**:
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
A[开始] --> B[加载地图数据]
|
||
B --> C[初始化开放列表和关闭列表]
|
||
C --> D[将起点加入开放列表]
|
||
D --> E{开放列表为空?}
|
||
E -->|是| F[返回空路径]
|
||
E -->|否| G[从开放列表取出F值最小的节点]
|
||
G --> H{是终点?}
|
||
H -->|是| I[重建并返回路径]
|
||
H -->|否| J[处理相邻节点]
|
||
J --> E
|
||
```
|
||
|
||
**API接口**:
|
||
|
||
```java
|
||
@RestController
|
||
@RequestMapping("/api/pathfinding")
|
||
@RequiredArgsConstructor
|
||
public class PathfindingController {
|
||
|
||
private final AStarService aStarService;
|
||
|
||
@GetMapping("/find")
|
||
@PreAuthorize("hasRole('GRID_WORKER')")
|
||
public ResponseEntity<List<Point>> findPath(
|
||
@RequestParam int startX, @RequestParam int startY,
|
||
@RequestParam int endX, @RequestParam int endY) {
|
||
|
||
Point start = new Point(startX, startY);
|
||
Point end = new Point(endX, endY);
|
||
|
||
List<Point> path = aStarService.findPath(start, end);
|
||
return ResponseEntity.ok(path);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3. 反馈管理模块
|
||
|
||
反馈管理模块是系统的核心业务模块之一,负责处理用户提交的环境问题反馈。我实现了完整的反馈提交、审核和处理流程,包括多条件查询、状态流转和文件上传等功能。
|
||
|
||
**关键代码展示**:
|
||
|
||
```java
|
||
@RestController
|
||
@RequestMapping("/api/feedback")
|
||
@RequiredArgsConstructor
|
||
public class FeedbackController {
|
||
|
||
private final FeedbackService feedbackService;
|
||
|
||
/**
|
||
* 提交反馈(正式接口)
|
||
* 使用multipart/form-data格式提交反馈,支持附件上传
|
||
*/
|
||
@PostMapping(value = "/submit", consumes = {"multipart/form-data"})
|
||
@PreAuthorize("isAuthenticated()")
|
||
public ResponseEntity<Feedback> submitFeedback(
|
||
@Valid @RequestPart("feedback") FeedbackSubmissionRequest request,
|
||
@RequestPart(value = "files", required = false) MultipartFile[] files,
|
||
@AuthenticationPrincipal CustomUserDetails userDetails) {
|
||
|
||
Feedback createdFeedback = feedbackService.submitFeedback(request, files);
|
||
return new ResponseEntity<>(createdFeedback, HttpStatus.CREATED);
|
||
}
|
||
|
||
/**
|
||
* 获取所有反馈(分页+多条件过滤)
|
||
* 支持按状态、污染类型、严重程度、地理位置、时间范围和关键词进行组合查询
|
||
*/
|
||
@GetMapping
|
||
@PreAuthorize("isAuthenticated()")
|
||
public ResponseEntity<Page<FeedbackResponseDTO>> getAllFeedback(
|
||
@AuthenticationPrincipal CustomUserDetails userDetails,
|
||
@RequestParam(required = false) FeedbackStatus status,
|
||
@RequestParam(required = false) PollutionType pollutionType,
|
||
@RequestParam(required = false) SeverityLevel severityLevel,
|
||
@RequestParam(required = false) String cityName,
|
||
@RequestParam(required = false) String districtName,
|
||
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
|
||
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate,
|
||
@RequestParam(required = false) String keyword,
|
||
Pageable pageable) {
|
||
|
||
Page<FeedbackResponseDTO> feedbackPage = feedbackService.getFeedback(
|
||
userDetails, status, pollutionType, severityLevel, cityName, districtName,
|
||
startDate, endDate, keyword, pageable);
|
||
|
||
return ResponseEntity.ok(feedbackPage);
|
||
}
|
||
|
||
/**
|
||
* 处理反馈 (例如, 批准)
|
||
*/
|
||
@PostMapping("/{id}/process")
|
||
@PreAuthorize("hasAnyRole('ADMIN', 'SUPERVISOR')")
|
||
public ResponseEntity<FeedbackResponseDTO> processFeedback(
|
||
@PathVariable Long id,
|
||
@Valid @RequestBody ProcessFeedbackRequest request) {
|
||
FeedbackResponseDTO updatedFeedback = feedbackService.processFeedback(id, request);
|
||
return ResponseEntity.ok(updatedFeedback);
|
||
}
|
||
}
|
||
```
|
||
|
||
**服务层实现**:
|
||
|
||
```java
|
||
@Service
|
||
@RequiredArgsConstructor
|
||
public class FeedbackServiceImpl implements FeedbackService {
|
||
|
||
private final FeedbackRepository feedbackRepository;
|
||
private final UserAccountRepository userAccountRepository;
|
||
private final FileStorageService fileStorageService;
|
||
private final ApplicationEventPublisher eventPublisher;
|
||
|
||
@Override
|
||
public Feedback submitFeedback(FeedbackSubmissionRequest request, MultipartFile[] files) {
|
||
// 1. 获取当前用户
|
||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||
String email = authentication.getName();
|
||
UserAccount user = userAccountRepository.findByEmail(email)
|
||
.orElseThrow(() -> new ResourceNotFoundException("User", "email", email));
|
||
|
||
// 2. 创建反馈实体
|
||
Feedback feedback = new Feedback();
|
||
feedback.setTitle(request.getTitle());
|
||
feedback.setDescription(request.getDescription());
|
||
feedback.setPollutionType(request.getPollutionType());
|
||
feedback.setSeverityLevel(request.getSeverityLevel());
|
||
feedback.setLatitude(request.getLatitude());
|
||
feedback.setLongitude(request.getLongitude());
|
||
feedback.setTextAddress(request.getTextAddress());
|
||
feedback.setGridX(request.getGridX());
|
||
feedback.setGridY(request.getGridY());
|
||
feedback.setStatus(FeedbackStatus.SUBMITTED);
|
||
feedback.setSubmitter(user);
|
||
feedback.setEventId(generateEventId());
|
||
|
||
// 3. 保存反馈
|
||
Feedback savedFeedback = feedbackRepository.save(feedback);
|
||
|
||
// 4. 处理附件
|
||
if (files != null && files.length > 0) {
|
||
List<Attachment> attachments = new ArrayList<>();
|
||
for (MultipartFile file : files) {
|
||
String fileName = fileStorageService.storeFile(file);
|
||
Attachment attachment = new Attachment();
|
||
attachment.setFileName(fileName);
|
||
attachment.setFilePath("/uploads/" + fileName);
|
||
attachment.setFileType(file.getContentType());
|
||
attachment.setFileSize(file.getSize());
|
||
attachments.add(attachment);
|
||
}
|
||
savedFeedback.setAttachments(attachments);
|
||
feedbackRepository.save(savedFeedback);
|
||
}
|
||
|
||
// 5. 发布事件,触发AI审核
|
||
eventPublisher.publishEvent(new FeedbackSubmittedEvent(savedFeedback));
|
||
|
||
return savedFeedback;
|
||
}
|
||
|
||
@Override
|
||
public FeedbackResponseDTO processFeedback(Long id, ProcessFeedbackRequest request) {
|
||
Feedback feedback = feedbackRepository.findById(id)
|
||
.orElseThrow(() -> new ResourceNotFoundException("Feedback", "id", id));
|
||
|
||
// 验证状态转换是否有效
|
||
if (!isValidStatusTransition(feedback.getStatus(), request.getStatus())) {
|
||
throw new IllegalStateException("Invalid status transition from " +
|
||
feedback.getStatus() + " to " + request.getStatus());
|
||
}
|
||
|
||
// 更新反馈状态
|
||
feedback.setStatus(request.getStatus());
|
||
|
||
// 如果批准反馈,则更新为PENDING_ASSIGNMENT状态
|
||
if (request.getStatus() == FeedbackStatus.APPROVED) {
|
||
feedback.setStatus(FeedbackStatus.PENDING_ASSIGNMENT);
|
||
}
|
||
|
||
Feedback updatedFeedback = feedbackRepository.save(feedback);
|
||
|
||
// 如果反馈被批准,发布事件通知任务管理模块
|
||
if (request.getStatus() == FeedbackStatus.APPROVED) {
|
||
eventPublisher.publishEvent(new FeedbackApprovedEvent(updatedFeedback));
|
||
}
|
||
|
||
return mapToDTO(updatedFeedback);
|
||
}
|
||
|
||
// 生成唯一的事件ID
|
||
private String generateEventId() {
|
||
return "EMS-" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + "-"
|
||
+ UUID.randomUUID().toString().substring(0, 8).toUpperCase();
|
||
}
|
||
|
||
// 验证状态转换是否有效
|
||
private boolean isValidStatusTransition(FeedbackStatus current, FeedbackStatus next) {
|
||
// 实现状态机逻辑
|
||
switch (current) {
|
||
case SUBMITTED:
|
||
return next == FeedbackStatus.AI_REVIEWED;
|
||
case AI_REVIEWED:
|
||
return next == FeedbackStatus.PENDING_REVIEW;
|
||
case PENDING_REVIEW:
|
||
return next == FeedbackStatus.APPROVED || next == FeedbackStatus.REJECTED;
|
||
case APPROVED:
|
||
return next == FeedbackStatus.PENDING_ASSIGNMENT;
|
||
case PENDING_ASSIGNMENT:
|
||
return next == FeedbackStatus.ASSIGNED;
|
||
case ASSIGNED:
|
||
return next == FeedbackStatus.PROCESSED;
|
||
case PROCESSED:
|
||
return next == FeedbackStatus.CLOSED;
|
||
default:
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
**实现要点分析**:
|
||
|
||
1. **多部分表单处理**: 使用`@RequestPart`注解同时处理JSON数据和文件上传,实现了富媒体反馈提交。
|
||
2. **事件驱动架构**: 通过Spring的事件机制,实现了反馈提交后的异步处理,如AI审核和任务创建,提高了系统响应速度。
|
||
3. **状态机模式**: 使用状态机模式管理反馈的生命周期,确保状态转换的合法性,防止非法操作。
|
||
4. **多条件动态查询**: 实现了灵活的多条件组合查询,支持按状态、类型、严重程度、地理位置和时间范围等进行过滤。 |