From e92d7a63ce14e03228fb1be54e4e2bc2dafaecbc Mon Sep 17 00:00:00 2001 From: wanglei <3085637232@qq.com> Date: Sat, 27 Dec 2025 19:01:02 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=BB=88=E7=AB=AF=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/web/TerminalController.java | 104 +++++++++++ .../water/entity/vo/TerminalManageVO.java | 34 ++++ .../DeviceTerminalMappingRepository.java | 11 ++ .../campus/water/service/TerminalService.java | 25 +++ .../water/service/TerminalServiceImpl.java | 164 ++++++++++++++++++ 5 files changed, 338 insertions(+) create mode 100644 src/main/java/com/campus/water/controller/web/TerminalController.java create mode 100644 src/main/java/com/campus/water/entity/vo/TerminalManageVO.java create mode 100644 src/main/java/com/campus/water/service/TerminalService.java create mode 100644 src/main/java/com/campus/water/service/TerminalServiceImpl.java diff --git a/src/main/java/com/campus/water/controller/web/TerminalController.java b/src/main/java/com/campus/water/controller/web/TerminalController.java new file mode 100644 index 0000000..c8f9791 --- /dev/null +++ b/src/main/java/com/campus/water/controller/web/TerminalController.java @@ -0,0 +1,104 @@ +// java/com/campus/water/controller/web/TerminalController.java +package com.campus.water.controller.web; + +import com.campus.water.service.TerminalService; +import com.campus.water.entity.vo.TerminalManageVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("/api/web/terminal") +@RequiredArgsConstructor +@Tag(name = "终端管理接口", description = "管理员基于设备终端映射表/终端位置表的增删改查操作") +public class TerminalController { + + private final TerminalService terminalService; + + @PostMapping("/add") + @PreAuthorize("hasAnyRole('SUPER_ADMIN', 'AREA_ADMIN')") + @Operation(summary = "新增终端", description = "同时保存终端位置和基础映射信息") + // 泛型改为?,兼容TerminalManageVO和Map + public ResponseEntity addTerminal(@Valid @RequestBody TerminalManageVO terminalVO) { + try { + TerminalManageVO newTerminal = terminalService.addTerminal(terminalVO); + return new ResponseEntity<>(newTerminal, HttpStatus.CREATED); + } catch (Exception e) { + Map errorMap = new HashMap<>(); + errorMap.put("message", "终端新增失败: " + e.getMessage()); + return new ResponseEntity<>(errorMap, HttpStatus.BAD_REQUEST); + } + } + + @PutMapping("/update") + @PreAuthorize("hasAnyRole('SUPER_ADMIN', 'AREA_ADMIN')") + @Operation(summary = "更新终端", description = "支持更新终端名称、状态、经纬度等信息") + // 泛型改为?,兼容TerminalManageVO和Map + public ResponseEntity updateTerminal(@Valid @RequestBody TerminalManageVO terminalVO) { + try { + TerminalManageVO updated = terminalService.updateTerminal(terminalVO); + return ResponseEntity.ok(updated); + } catch (Exception e) { + Map errorMap = new HashMap<>(); + errorMap.put("message", "终端更新失败: " + e.getMessage()); + return new ResponseEntity<>(errorMap, HttpStatus.BAD_REQUEST); + } + } + + @DeleteMapping("/delete/{terminalId}") + @PreAuthorize("hasAnyRole('SUPER_ADMIN', 'AREA_ADMIN')") + @Operation(summary = "删除终端", description = "先校验设备绑定状态,再级联删除相关数据") + // 该方法成功/失败均返回Map,泛型可保留Map(无冲突) + public ResponseEntity> deleteTerminal(@PathVariable String terminalId) { + try { + terminalService.deleteTerminal(terminalId); + Map successMap = new HashMap<>(); + successMap.put("message", "终端删除成功"); + return ResponseEntity.ok(successMap); + } catch (Exception e) { + Map errorMap = new HashMap<>(); + errorMap.put("message", "终端删除失败: " + e.getMessage()); + return new ResponseEntity<>(errorMap, HttpStatus.BAD_REQUEST); + } + } + + @GetMapping("/{terminalId}") + @PreAuthorize("hasAnyRole('SUPER_ADMIN', 'AREA_ADMIN')") + @Operation(summary = "查询终端详情", description = "根据终端ID获取整合后的完整信息") + // 泛型改为?,兼容TerminalManageVO和Map + public ResponseEntity getTerminal(@PathVariable String terminalId) { + try { + TerminalManageVO terminal = terminalService.getTerminalById(terminalId); + return ResponseEntity.ok(terminal); + } catch (Exception e) { + Map errorMap = new HashMap<>(); + errorMap.put("message", "终端查询失败: " + e.getMessage()); + return new ResponseEntity<>(errorMap, HttpStatus.NOT_FOUND); + } + } + + @GetMapping("/list") + @PreAuthorize("hasAnyRole('SUPER_ADMIN', 'AREA_ADMIN')") + @Operation(summary = "查询终端列表", description = "支持按终端名称模糊筛选") + // 泛型改为?,兼容List和Map + public ResponseEntity getTerminalList( + @RequestParam(required = false) String terminalName) { + try { + List terminals = terminalService.getTerminalList(terminalName); + return ResponseEntity.ok(terminals); + } catch (Exception e) { + Map errorMap = new HashMap<>(); + errorMap.put("message", "终端列表查询失败: " + e.getMessage()); + return new ResponseEntity<>(errorMap, HttpStatus.BAD_REQUEST); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/campus/water/entity/vo/TerminalManageVO.java b/src/main/java/com/campus/water/entity/vo/TerminalManageVO.java new file mode 100644 index 0000000..96090ae --- /dev/null +++ b/src/main/java/com/campus/water/entity/vo/TerminalManageVO.java @@ -0,0 +1,34 @@ +// java/com/campus/water/vo/TerminalManageVO.java +package com.campus.water.entity.vo; + +import com.campus.water.entity.DeviceTerminalMapping; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; + +/** + * 终端管理VO(整合位置表和映射表的核心信息) + */ +@Data +public class TerminalManageVO { + // 终端核心标识(关联两张表的主键/外键) + private String terminalId; + + // 终端名称(来自映射表) + private String terminalName; + + // 终端经纬度(来自位置表) + private BigDecimal longitude; + private BigDecimal latitude; + + // 终端状态(来自映射表) + private DeviceTerminalMapping.TerminalStatus terminalStatus; + + // 安装日期(来自映射表) + private LocalDate installDate; + + // 设备ID(关联的设备,来自映射表) + private String deviceId; +} \ No newline at end of file diff --git a/src/main/java/com/campus/water/mapper/DeviceTerminalMappingRepository.java b/src/main/java/com/campus/water/mapper/DeviceTerminalMappingRepository.java index de016ce..69e7a36 100644 --- a/src/main/java/com/campus/water/mapper/DeviceTerminalMappingRepository.java +++ b/src/main/java/com/campus/water/mapper/DeviceTerminalMappingRepository.java @@ -19,4 +19,15 @@ public interface DeviceTerminalMappingRepository extends JpaRepository findByDeviceIdAndTerminalId(String deviceId, String terminalId); + + // ========== 新增必要方法(支撑终端增删改查业务) ========== + // 1. 判断终端是否已绑定设备(删除终端时的核心校验) + boolean existsByTerminalId(String terminalId); + + // 2. 按终端名称模糊查询(终端列表筛选) + List findByTerminalNameContaining(String terminalName); + + // 3. 按终端ID删除所有关联映射(删除终端时级联清理映射数据) + void deleteByTerminalId(String terminalId); + } \ No newline at end of file diff --git a/src/main/java/com/campus/water/service/TerminalService.java b/src/main/java/com/campus/water/service/TerminalService.java new file mode 100644 index 0000000..bfc1650 --- /dev/null +++ b/src/main/java/com/campus/water/service/TerminalService.java @@ -0,0 +1,25 @@ +// java/com/campus/water/service/TerminalService.java +package com.campus.water.service; + +import com.campus.water.entity.DeviceTerminalMapping; +import com.campus.water.entity.WaterTerminalLocation; +import com.campus.water.entity.vo.TerminalManageVO; + +import java.util.List; + +public interface TerminalService { + // 新增终端(同时保存位置信息和基础映射信息) + TerminalManageVO addTerminal(TerminalManageVO terminalVO); + + // 更新终端(支持更新名称、状态、经纬度等信息) + TerminalManageVO updateTerminal(TerminalManageVO terminalVO); + + // 删除终端(先校验是否绑定设备,再级联删除两张表的相关数据) + void deleteTerminal(String terminalId); + + // 按ID查询终端详情(整合两张表的数据) + TerminalManageVO getTerminalById(String terminalId); + + // 查询终端列表(支持按名称筛选,返回整合后的数据) + List getTerminalList(String terminalName); +} \ No newline at end of file diff --git a/src/main/java/com/campus/water/service/TerminalServiceImpl.java b/src/main/java/com/campus/water/service/TerminalServiceImpl.java new file mode 100644 index 0000000..c3f33c4 --- /dev/null +++ b/src/main/java/com/campus/water/service/TerminalServiceImpl.java @@ -0,0 +1,164 @@ +// java/com/campus/water/service/impl/TerminalServiceImpl.java +package com.campus.water.service; + +import com.campus.water.entity.DeviceTerminalMapping; +import com.campus.water.entity.WaterTerminalLocation; +import com.campus.water.mapper.DeviceTerminalMappingRepository; +import com.campus.water.mapper.WaterTerminalLocationRepository; +import com.campus.water.service.TerminalService; +import com.campus.water.entity.vo.TerminalManageVO; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +@Service +@RequiredArgsConstructor +public class TerminalServiceImpl implements TerminalService { + + private final WaterTerminalLocationRepository locationRepository; + private final DeviceTerminalMappingRepository mappingRepository; + + @Override + @Transactional + public TerminalManageVO addTerminal(TerminalManageVO terminalVO) { + // 1. 校验终端ID是否已存在(通过位置表主键判断,避免重复新增) + if (locationRepository.existsById(terminalVO.getTerminalId())) { + throw new RuntimeException("终端ID已存在,无法重复新增:" + terminalVO.getTerminalId()); + } + + // 2. 保存终端位置信息(经纬度为必填项,校验非空) + if (terminalVO.getLongitude() == null || terminalVO.getLatitude() == null) { + throw new RuntimeException("终端经度和纬度为必填项,不可为空"); + } + WaterTerminalLocation location = new WaterTerminalLocation(); + location.setTerminalId(terminalVO.getTerminalId()); + location.setLongitude(terminalVO.getLongitude()); + location.setLatitude(terminalVO.getLatitude()); + locationRepository.save(location); + + // 3. 保存终端映射信息(状态默认active,复用原有Repository的save方法) + DeviceTerminalMapping mapping = new DeviceTerminalMapping(); + mapping.setTerminalId(terminalVO.getTerminalId()); + mapping.setTerminalName(terminalVO.getTerminalName()); + mapping.setTerminalStatus(terminalVO.getTerminalStatus() == null + ? DeviceTerminalMapping.TerminalStatus.active + : terminalVO.getTerminalStatus()); + mapping.setDeviceId(terminalVO.getDeviceId()); + mapping.setInstallDate(terminalVO.getInstallDate()); + mappingRepository.save(mapping); + + // 4. 封装返回结果 + return assembleTerminalVO(location, mapping); + } + + @Override + @Transactional + public TerminalManageVO updateTerminal(TerminalManageVO terminalVO) { + // 1. 校验终端是否存在(通过位置表查询,复用原有findById方法) + WaterTerminalLocation existingLocation = locationRepository.findById(terminalVO.getTerminalId()) + .orElseThrow(() -> new RuntimeException("终端不存在,无法更新:" + terminalVO.getTerminalId())); + + // 2. 更新终端位置信息(仅更新有值字段,复用原有save方法) + if (terminalVO.getLongitude() != null) { + existingLocation.setLongitude(terminalVO.getLongitude()); + } + if (terminalVO.getLatitude() != null) { + existingLocation.setLatitude(terminalVO.getLatitude()); + } + locationRepository.save(existingLocation); + + // 3. 更新终端映射信息(复用原有findByTerminalId方法查询映射记录) + DeviceTerminalMapping existingMapping = mappingRepository.findByTerminalId(terminalVO.getTerminalId()) + .orElseThrow(() -> new RuntimeException("终端无关联映射信息,无法更新终端名称/状态")); + + if (terminalVO.getTerminalName() != null && !terminalVO.getTerminalName().isEmpty()) { + existingMapping.setTerminalName(terminalVO.getTerminalName()); + } + if (terminalVO.getTerminalStatus() != null) { + existingMapping.setTerminalStatus(terminalVO.getTerminalStatus()); + } + if (terminalVO.getDeviceId() != null) { + existingMapping.setDeviceId(terminalVO.getDeviceId()); + } + if (terminalVO.getInstallDate() != null) { + existingMapping.setInstallDate(terminalVO.getInstallDate()); + } + mappingRepository.save(existingMapping); + + // 4. 封装返回结果 + return assembleTerminalVO(existingLocation, existingMapping); + } + + @Override + @Transactional + public void deleteTerminal(String terminalId) { + // 1. 校验终端是否已绑定设备(使用新增的existsByTerminalId方法) + if (mappingRepository.existsByTerminalId(terminalId)) { + throw new RuntimeException("终端已绑定设备,无法删除,请先解除设备关联"); + } + + // 2. 校验终端是否存在(复用原有existsById方法) + if (!locationRepository.existsById(terminalId)) { + throw new RuntimeException("终端不存在,无需删除:" + terminalId); + } + + // 3. 级联删除数据(先删映射表,再删位置表,保证数据一致性) + mappingRepository.deleteByTerminalId(terminalId); // 新增的批量删除方法 + locationRepository.deleteById(terminalId); // 复用原有删除方法 + } + + @Override + public TerminalManageVO getTerminalById(String terminalId) { + // 1. 查询位置信息(复用原有findById方法) + WaterTerminalLocation location = locationRepository.findById(terminalId) + .orElseThrow(() -> new RuntimeException("终端不存在:" + terminalId)); + + // 2. 查询映射信息(复用原有findByTerminalId方法) + DeviceTerminalMapping mapping = mappingRepository.findByTerminalId(terminalId) + .orElseThrow(() -> new RuntimeException("终端无关联基础信息,请补充映射记录")); + + // 3. 封装返回结果 + return assembleTerminalVO(location, mapping); + } + + @Override + public List getTerminalList(String terminalName) { + // 1. 查询映射表数据(支持名称模糊筛选,使用新增的findByTerminalNameContaining方法) + List mappings; + if (terminalName != null && !terminalName.isEmpty()) { + mappings = mappingRepository.findByTerminalNameContaining(terminalName); + } else { + mappings = mappingRepository.findAll(); // 复用原有查询所有方法 + } + + // 2. 遍历映射记录,关联位置表数据,封装VO列表 + List terminalVOList = new ArrayList<>(); + for (DeviceTerminalMapping mapping : mappings) { + Optional locationOpt = locationRepository.findById(mapping.getTerminalId()); + locationOpt.ifPresent(location -> { + TerminalManageVO vo = assembleTerminalVO(location, mapping); + terminalVOList.add(vo); + }); + } + return terminalVOList; + } + + /** + * 辅助方法:整合位置表和映射表数据,封装为TerminalManageVO + */ + private TerminalManageVO assembleTerminalVO(WaterTerminalLocation location, DeviceTerminalMapping mapping) { + TerminalManageVO vo = new TerminalManageVO(); + vo.setTerminalId(location.getTerminalId()); + vo.setLongitude(location.getLongitude()); + vo.setLatitude(location.getLatitude()); + vo.setTerminalName(mapping.getTerminalName()); + vo.setTerminalStatus(mapping.getTerminalStatus()); + vo.setDeviceId(mapping.getDeviceId()); + vo.setInstallDate(mapping.getInstallDate()); + return vo; + } +} \ No newline at end of file