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

10 KiB
Raw Blame History

实现要点分析:

  1. 动态地图加载: 算法从数据库动态加载地图数据,包括障碍物信息和地图尺寸,使得路径规划能够适应地图的变化。
  2. 优先队列优化: 使用优先队列PriorityQueue存储开放列表确保每次都能高效地选择F值最小的节点大大提高了算法效率。
  3. 曼哈顿距离启发函数: 选择曼哈顿距离作为启发函数,适合网格化的移动模式,能够准确估计网格间的距离。
  4. 路径重建: 通过记录每个节点的父节点,实现了从终点回溯到起点的路径重建,返回完整的路径点列表。

程序流程图:

flowchart TD
    A[开始] --> B[加载地图数据]
    B --> C[初始化开放列表和关闭列表]
    C --> D[将起点加入开放列表]
    D --> E{开放列表为空?}
    E -->|是| F[返回空路径]
    E -->|否| G[从开放列表取出F值最小的节点]
    G --> H{是终点?}
    H -->|是| I[重建并返回路径]
    H -->|否| J[处理相邻节点]
    J --> E

API接口:

@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. 反馈管理模块

反馈管理模块是系统的核心业务模块之一,负责处理用户提交的环境问题反馈。我实现了完整的反馈提交、审核和处理流程,包括多条件查询、状态流转和文件上传等功能。

关键代码展示:

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

服务层实现:

@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. 多条件动态查询: 实现了灵活的多条件组合查询,支持按状态、类型、严重程度、地理位置和时间范围等进行过滤。