diff --git a/src/main/java/com/campus/water/controller/WaterUsageController.java b/src/main/java/com/campus/water/controller/WaterUsageController.java index 67f0187..31c2671 100644 --- a/src/main/java/com/campus/water/controller/WaterUsageController.java +++ b/src/main/java/com/campus/water/controller/WaterUsageController.java @@ -6,6 +6,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.transaction.annotation.Transactional; +import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.HashMap; import java.util.Map; @@ -56,7 +57,9 @@ public class WaterUsageController { drinkRecord.setStudentId(studentId); drinkRecord.setTerminalId(terminalId); drinkRecord.setDeviceId(mapping.getDeviceId()); - drinkRecord.setWaterConsumption(waterConsumption); + + // 错误1修复:Double转BigDecimal(适配DrinkRecord的BigDecimal类型字段) + drinkRecord.setWaterConsumption(waterConsumption != null ? BigDecimal.valueOf(waterConsumption) : BigDecimal.ZERO); drinkRecord.setDrinkTime(LocalDateTime.now()); drinkRecord.setLocation(mapping.getTerminalName()); @@ -67,7 +70,8 @@ public class WaterUsageController { } drinkRecordRepository.save(drinkRecord); - updateTerminalUsageStats(terminalId, waterConsumption); + // 传入BigDecimal类型的用水量 + updateTerminalUsageStats(terminalId, BigDecimal.valueOf(waterConsumption)); result.put("success", true); result.put("message", "用水成功"); @@ -82,8 +86,8 @@ public class WaterUsageController { } } - // 更新终端使用统计 - private void updateTerminalUsageStats(String terminalId, Double waterConsumption) { + // 更新终端使用统计(参数改为BigDecimal) + private void updateTerminalUsageStats(String terminalId, BigDecimal waterConsumption) { LocalDateTime now = LocalDateTime.now(); Optional statsOpt = terminalUsageStatsRepository .findByTerminalIdAndStatDate(terminalId, now.toLocalDate()); @@ -92,13 +96,22 @@ public class WaterUsageController { if (statsOpt.isPresent()) { stats = statsOpt.get(); stats.setUsageCount(stats.getUsageCount() + 1); - stats.setTotalWaterOutput(stats.getTotalWaterOutput() + waterConsumption); - stats.setAvgWaterPerUse(stats.getTotalWaterOutput() / stats.getUsageCount()); + + // 错误2&3修复:BigDecimal加法(替代+运算符) + stats.setTotalWaterOutput(stats.getTotalWaterOutput().add(waterConsumption)); + + // 错误4修复:BigDecimal除法(替代/运算符,指定精度和舍入模式) + stats.setAvgWaterPerUse( + stats.getTotalWaterOutput() + .divide(BigDecimal.valueOf(stats.getUsageCount()), 2, BigDecimal.ROUND_HALF_UP) + ); } else { stats = new TerminalUsageStats(); stats.setTerminalId(terminalId); stats.setStatDate(now.toLocalDate()); stats.setUsageCount(1); + + // 错误5&6修复:直接赋值BigDecimal(适配TerminalUsageStats的BigDecimal字段) stats.setTotalWaterOutput(waterConsumption); stats.setAvgWaterPerUse(waterConsumption); stats.setPeakHour(String.format("%02d:00", now.getHour())); @@ -122,9 +135,10 @@ public class WaterUsageController { if (realtimeDataOpt.isPresent()) { WaterMakerRealtimeData realtimeData = realtimeDataOpt.get(); result.put("deviceId", deviceId); - result.put("rawWaterTds", realtimeData.getTdsValue1()); - result.put("pureWaterTds", realtimeData.getTdsValue2()); - result.put("mineralWaterTds", realtimeData.getTdsValue3()); + // 如需返回Double给前端:BigDecimal转Double + result.put("rawWaterTds", realtimeData.getTdsValue1() != null ? realtimeData.getTdsValue1().doubleValue() : null); + result.put("pureWaterTds", realtimeData.getTdsValue2() != null ? realtimeData.getTdsValue2().doubleValue() : null); + result.put("mineralWaterTds", realtimeData.getTdsValue3() != null ? realtimeData.getTdsValue3().doubleValue() : null); result.put("waterQuality", realtimeData.getWaterQuality()); result.put("filterLife", realtimeData.getFilterLife()); result.put("status", realtimeData.getStatus()); diff --git a/src/main/java/com/campus/water/entity/DrinkRecommendation.java b/src/main/java/com/campus/water/entity/DrinkRecommendation.java index cd1adb3..417abe6 100644 --- a/src/main/java/com/campus/water/entity/DrinkRecommendation.java +++ b/src/main/java/com/campus/water/entity/DrinkRecommendation.java @@ -7,6 +7,8 @@ package com.campus.water.entity; import lombok.Data; import jakarta.persistence.*; + +import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; @@ -22,11 +24,11 @@ public class DrinkRecommendation { @Column(name = "student_id", length = 50) private String studentId; - @Column(name = "daily_target", precision = 6, scale = 2) + @Column(name = "daily_target") private Double dailyTarget; @Column(name = "current_progress", precision = 6, scale = 2) - private Double currentProgress; + private BigDecimal currentProgress; @Column(name = "recommendation_date") private LocalDate recommendationDate; diff --git a/src/main/java/com/campus/water/entity/DrinkRecord.java b/src/main/java/com/campus/water/entity/DrinkRecord.java index 5a28579..e2d9e3b 100644 --- a/src/main/java/com/campus/water/entity/DrinkRecord.java +++ b/src/main/java/com/campus/water/entity/DrinkRecord.java @@ -7,6 +7,8 @@ package com.campus.water.entity; import lombok.Data; import jakarta.persistence.*; + +import java.math.BigDecimal; import java.time.LocalDateTime; @Data @@ -29,13 +31,13 @@ public class DrinkRecord { // 根据文档修正:字段名改为 water_consumption @Column(name = "water_consumption", precision = 6, scale = 2) - private Double waterConsumption; + private BigDecimal waterConsumption; @Column(name = "water_quality", length = 50) private String waterQuality; @Column(name = "tds_value", precision = 8, scale = 2) - private Double tdsValue; + private BigDecimal tdsValue; // 根据文档修正:字段名改为 drink_time @Column(name = "drink_time") diff --git a/src/main/java/com/campus/water/entity/Repairman.java b/src/main/java/com/campus/water/entity/Repairman.java index 7f86269..fc08920 100644 --- a/src/main/java/com/campus/water/entity/Repairman.java +++ b/src/main/java/com/campus/water/entity/Repairman.java @@ -7,6 +7,8 @@ package com.campus.water.entity; import lombok.Data; import jakarta.persistence.*; + +import java.math.BigDecimal; import java.time.LocalDateTime; @Data @@ -37,7 +39,7 @@ public class Repairman { private Integer workCount = 0; @Column(name = "rating", precision = 3, scale = 2) - private Double rating = 5.0; + private BigDecimal rating ; @Column(name = "created_time") private LocalDateTime createdTime = LocalDateTime.now(); diff --git a/src/main/java/com/campus/water/entity/TerminalUsageStats.java b/src/main/java/com/campus/water/entity/TerminalUsageStats.java index 220c9f8..d5812e9 100644 --- a/src/main/java/com/campus/water/entity/TerminalUsageStats.java +++ b/src/main/java/com/campus/water/entity/TerminalUsageStats.java @@ -7,6 +7,8 @@ package com.campus.water.entity; import lombok.Data; import jakarta.persistence.*; + +import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; @@ -29,10 +31,10 @@ public class TerminalUsageStats { private Integer usageCount = 0; @Column(name = "total_water_output", precision = 10, scale = 2) - private Double totalWaterOutput = 0.0; + private BigDecimal totalWaterOutput ; @Column(name = "avg_water_per_use", precision = 6, scale = 2) - private Double avgWaterPerUse = 0.0; + private BigDecimal avgWaterPerUse ; @Column(name = "peak_hour", length = 5) private String peakHour; diff --git a/src/main/java/com/campus/water/entity/WaterMakerRealtimeData.java b/src/main/java/com/campus/water/entity/WaterMakerRealtimeData.java index 95dbe1c..96c0e9e 100644 --- a/src/main/java/com/campus/water/entity/WaterMakerRealtimeData.java +++ b/src/main/java/com/campus/water/entity/WaterMakerRealtimeData.java @@ -7,6 +7,8 @@ package com.campus.water.entity; import lombok.Data; import jakarta.persistence.*; + +import java.math.BigDecimal; import java.time.LocalDateTime; @Data @@ -22,24 +24,24 @@ public class WaterMakerRealtimeData { // 根据文档修正:三个TDS值 @Column(name = "tds_value1", precision = 8, scale = 2) - private Double tdsValue1; // 原水TDS + private BigDecimal tdsValue1; // 原水TDS @Column(name = "tds_value2", precision = 8, scale = 2) - private Double tdsValue2; // 纯水TDS + private BigDecimal tdsValue2; // 纯水TDS @Column(name = "tds_value3", precision = 8, scale = 2) - private Double tdsValue3; // 矿化水TDS + private BigDecimal tdsValue3; // 矿化水TDS // 根据文档修正:两个流量计 @Column(name = "water_flow1", precision = 8, scale = 2) - private Double waterFlow1; + private BigDecimal waterFlow1; @Column(name = "water_flow2", precision = 8, scale = 2) - private Double waterFlow2; + private BigDecimal waterFlow2; // 根据文档修正:字段名改为 water_press @Column(name = "water_press", precision = 8, scale = 2) - private Double waterPress; + private BigDecimal waterPress; @Column(name = "filter_life") private Integer filterLife; diff --git a/src/main/java/com/campus/water/entity/WaterQualityHistory.java b/src/main/java/com/campus/water/entity/WaterQualityHistory.java index df0f21d..d106a57 100644 --- a/src/main/java/com/campus/water/entity/WaterQualityHistory.java +++ b/src/main/java/com/campus/water/entity/WaterQualityHistory.java @@ -7,6 +7,8 @@ package com.campus.water.entity; import lombok.Data; import jakarta.persistence.*; + +import java.math.BigDecimal; import java.time.LocalDateTime; @Data @@ -26,13 +28,13 @@ public class WaterQualityHistory { // 根据文档修正:三个TDS值 @Column(name = "tds_value1", precision = 8, scale = 2) - private Double tdsValue1; // 原水TDS + private BigDecimal tdsValue1; // 原水TDS @Column(name = "tds_value2", precision = 8, scale = 2) - private Double tdsValue2; // 纯水TDS + private BigDecimal tdsValue2; // 纯水TDS @Column(name = "tds_value3", precision = 8, scale = 2) - private Double tdsValue3; // 矿化水TDS + private BigDecimal tdsValue3; // 矿化水TDS @Column(name = "water_quality", length = 50) private String waterQuality; diff --git a/src/main/java/com/campus/water/entity/WaterSupplyRealtimeData.java b/src/main/java/com/campus/water/entity/WaterSupplyRealtimeData.java index 50b1c7e..a4c735e 100644 --- a/src/main/java/com/campus/water/entity/WaterSupplyRealtimeData.java +++ b/src/main/java/com/campus/water/entity/WaterSupplyRealtimeData.java @@ -7,6 +7,8 @@ package com.campus.water.entity; import lombok.Data; import jakarta.persistence.*; + +import java.math.BigDecimal; import java.time.LocalDateTime; @Data @@ -21,17 +23,17 @@ public class WaterSupplyRealtimeData { private String deviceId; @Column(name = "water_flow", precision = 8, scale = 2) - private Double waterFlow; + private BigDecimal waterFlow; // 根据文档修正:字段名改为 water_press @Column(name = "water_press", precision = 8, scale = 2) - private Double waterPress; + private BigDecimal waterPress; @Column(name = "water_level", precision = 8, scale = 2) - private Double waterLevel; + private BigDecimal waterLevel; @Column(name = "temperature", precision = 5, scale = 2) - private Double temperature; + private BigDecimal temperature; @Enumerated(EnumType.STRING) @Column(name = "status", length = 20) diff --git a/src/main/java/com/campus/water/entity/po/AdminPO.java b/src/main/java/com/campus/water/entity/po/AdminPO.java index e8258c7..dacdb70 100644 --- a/src/main/java/com/campus/water/entity/po/AdminPO.java +++ b/src/main/java/com/campus/water/entity/po/AdminPO.java @@ -3,35 +3,42 @@ package com.campus.water.entity.po; import lombok.Data; import jakarta.persistence.*; +/** + * 管理员PO类(数据库映射对象) + * 对应数据库admin表,已与Admin实体类统一映射规则 + */ @Data @Entity @Table(name = "admin") // 对应数据库admin表 public class AdminPO { @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) // 主键自增(根据数据库调整) - private String adminId; + @Column(name = "admin_id", length = 50) // 明确映射数据库列admin_id,与Admin类保持一致 + private String adminId; // 移除自增注解,因String类型不支持IDENTITY自增 - @Column(unique = true, nullable = false) - private String username; // 登录用户名 + @Column(name = "admin_name", length = 50, unique = true, nullable = false) + private String username; // 统一映射到数据库列admin_name,与Admin类的adminName保持一致 - @Column(nullable = false) - private String password; // MD5加密后的密码 + @Column(name = "password", length = 200, nullable = false) + private String password; // MD5加密后的密码,与Admin类字段长度保持一致 - private String phone; // 联系电话 + @Column(name = "phone", length = 20) + private String phone; // 联系电话,统一长度约束 - // 管理员角色枚举 + // 管理员角色枚举(与Admin类的AdminRole取值和大小写保持一致) public enum AdminRole { - SUPER_ADMIN, NORMAL_ADMIN + super_admin, area_admin, viewer } - // 管理员状态枚举 + // 管理员状态枚举(与Admin类的AdminStatus取值和大小写保持一致) public enum AdminStatus { - ACTIVE, INACTIVE + active, inactive } - @Enumerated(EnumType.STRING) // 枚举以字符串形式存储 - private AdminRole role; + @Enumerated(EnumType.STRING) + @Column(name = "role", length = 50, nullable = false) + private AdminRole role; // 默认为空,可在业务层设置默认值 @Enumerated(EnumType.STRING) - private AdminStatus status; + @Column(name = "status", length = 50, nullable = false) + private AdminStatus status; // 默认为空,可在业务层设置默认值 } \ No newline at end of file diff --git a/src/main/java/com/campus/water/entity/po/DevicePO.java b/src/main/java/com/campus/water/entity/po/DevicePO.java index f094e92..228a5c4 100644 --- a/src/main/java/com/campus/water/entity/po/DevicePO.java +++ b/src/main/java/com/campus/water/entity/po/DevicePO.java @@ -6,20 +6,52 @@ import java.time.LocalDateTime; /** * 设备实体类(数据库映射对象) - * 存储设备基本信息及运行状态 + * 存储设备基本基本信息及运行状态 */ @Data @Entity -@Table(name = "device") +@Table(name = "device_po") public class DevicePO { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; // 设备ID - private String deviceId; // 设备唯一标识 + private Long id; // 设备自增主键 + + @Column(unique = true, nullable = false, length = 20) // 确保业务唯一标识 + private String deviceId; // 设备唯一标识(业务ID) + + // 解决area_id映射冲突:明确字段定义,与Device实体类保持长度一致 + @Column(name = "area_id", length = 20) // 显式指定列名和长度,与Device类匹配 private String areaId; // 所属区域ID - private String status; // 设备状态:online(在线)、offline(离线) + + @Column(length = 50) // 与Device的DeviceStatus枚举存储长度一致 + private String status; // 设备状态:online(在线)、offline(离线)、fault(故障) + private LocalDateTime lastActiveTime; // 最后活动时间(用于判断在线状态) - private String deviceType; // 设备类型 + + @Column(length = 50) // 与Device的DeviceType枚举存储长度一致 + private String deviceType; // 设备类型:water_maker(制水机)、water_supply(供水机) + + // 解决create_time字段映射冲突:显式指定列名与字段属性,确保与数据库表结构一致 + @Column(name = "create_time", nullable = false, updatable = false) private LocalDateTime createTime; // 创建时间 + + @Column(name = "update_time") private LocalDateTime updateTime; // 更新时间 + + // 新增:初始化时间字段的方法,确保与Device实体类行为一致 + @PrePersist + public void prePersist() { + if (createTime == null) { + createTime = LocalDateTime.now(); + } + if (updateTime == null) { + updateTime = LocalDateTime.now(); + } + } + + // 新增:更新时自动刷新updateTime + @PreUpdate + public void preUpdate() { + updateTime = LocalDateTime.now(); + } } \ No newline at end of file diff --git a/src/main/java/com/campus/water/entity/po/RepairerAuthPO.java b/src/main/java/com/campus/water/entity/po/RepairerAuthPO.java index 847cd86..9eb2acd 100644 --- a/src/main/java/com/campus/water/entity/po/RepairerAuthPO.java +++ b/src/main/java/com/campus/water/entity/po/RepairerAuthPO.java @@ -5,7 +5,7 @@ import jakarta.persistence.*; @Data @Entity -@Table(name = "repairer_auth") // 对应数据库表 +@Table(name = "repairer_auth_backup") // 对应数据库表 public class RepairerAuthPO { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) // 主键自增(Long类型) @@ -20,15 +20,17 @@ public class RepairerAuthPO { @Column(nullable = false) private String password; // MD5加密密码 - // 账号状态枚举(和Repository的AccountStatus匹配) + // 账号状态枚举(解决字段映射冲突) public enum AccountStatus { active, inactive, locked } - @Enumerated(EnumType.STRING) // 枚举以字符串存储(匹配SQL里的'active') + // 明确指定数据库字段名,与实体类字段形成映射,解决冲突 + @Enumerated(EnumType.STRING) + @Column(name = "account_status", length = 50, nullable = false) private AccountStatus accountStatus; - // 补充其他业务字段(按需添加) + // 补充其他业务字段 private String phone; // 联系电话 private String areaId; // 负责区域ID private String name; // 维修人员姓名 diff --git a/src/main/java/com/campus/water/entity/po/UserPO.java b/src/main/java/com/campus/water/entity/po/UserPO.java index 3525476..1d29998 100644 --- a/src/main/java/com/campus/water/entity/po/UserPO.java +++ b/src/main/java/com/campus/water/entity/po/UserPO.java @@ -2,39 +2,47 @@ package com.campus.water.entity.po; import lombok.Data; import jakarta.persistence.*; +import java.time.LocalDateTime; @Data @Entity @Table(name = "user") // 对应数据库user表(学生用户) public class UserPO { @Id - // 修正:String类型主键不支持IDENTITY自增(MySQL自增主键为Long),改为手动赋值/UUID - // 若需自增,建议将studentId改为Long类型,此处保留String并移除IDENTITY + @Column(name = "student_id", length = 50) // 与User类保持字段名一致 private String studentId; // 学生ID(主键,学号) - @Column(unique = true, nullable = false) - private String username; // 登录用户名/学生姓名 + @Column(name = "student_name", unique = true, nullable = false, length = 50) + // 修正:与User类的studentName字段对应,同时保留唯一约束 + private String username; // 登录名(对应User类的studentName) - @Column(nullable = false) - private String password; // MD5加密后的密码 + @Column(name = "password", nullable = false, length = 200) + private String password; // MD5加密后的密码(与User类字段长度保持一致) + @Column(name = "phone", length = 20) private String phone; // 联系电话 - private String studentNo; // 学号(若studentId已用学号,可删除此字段,避免冗余) + + // 移除冗余的studentNo字段(与studentId重复) private String college; // 学院 - // ========== 补充缺失字段 ========== - @Column(unique = true) - private String email; // 邮箱(适配Repository的findByEmail/existsByEmail) + @Column(name = "email", unique = true, length = 100) + private String email; // 邮箱(与User类字段长度保持一致) - // ========== 补充缺失枚举 ========== - // 用户状态枚举(适配Repository的findByStatus/findByUsernameContainingAndStatus) + // 统一状态枚举命名风格与User类保持一致(小写开头) public enum UserStatus { - ACTIVE, // 活跃 - INACTIVE, // 未激活 - LOCKED // 锁定 + active, // 活跃 + inactive, // 未激活 + locked // 锁定 } - // 状态字段(映射为字符串存储,适配枚举) @Enumerated(EnumType.STRING) - private UserStatus status; + @Column(name = "status", length = 50) + private UserStatus status = UserStatus.active; // 增加默认值,与User类保持一致 + + // 补充时间字段,与User类保持表结构一致 + @Column(name = "create_time") + private LocalDateTime createTime = LocalDateTime.now(); + + @Column(name = "updated_time") + private LocalDateTime updatedTime = LocalDateTime.now(); } \ No newline at end of file diff --git a/src/main/java/com/campus/water/mapper/AdminRepository.java b/src/main/java/com/campus/water/mapper/AdminRepository.java index 40800cf..e73d1be 100644 --- a/src/main/java/com/campus/water/mapper/AdminRepository.java +++ b/src/main/java/com/campus/water/mapper/AdminRepository.java @@ -1,6 +1,6 @@ package com.campus.water.mapper; -import com.campus.water.entity.po.AdminPO; // 替换为PO包下的实体类 +import com.campus.water.entity.Admin; // 改为引用Admin实体类 import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; @@ -9,29 +9,29 @@ import java.util.List; import java.util.Optional; @Repository -public interface AdminRepository extends JpaRepository { - // ========== 新增:登录核心方法(必须) ========== - Optional findByUsername(String username); +public interface AdminRepository extends JpaRepository { + // ========== 登录核心方法(适配Admin的adminName字段) ========== + Optional findByAdminName(String admin_name); - // ========== 保留原有业务方法(适配PO类) ========== + // ========== 业务方法(适配Admin类) ========== // 根据管理员ID查询 - Optional findByAdminId(String adminId); + Optional findByAdminId(String adminId); - // 根据管理员姓名/用户名模糊查询(适配PO的username字段) - List findByUsernameContaining(String username); + // 根据管理员姓名模糊查询(适配Admin的adminName字段) + List findByAdminNameContaining(String adminName); - // 根据角色查询管理员(引用PO内的枚举) - List findByRole(AdminPO.AdminRole role); + // 根据角色查询管理员(引用Admin内的枚举) + List findByRole(Admin.AdminRole role); - // 根据状态查询管理员(引用PO内的枚举) - List findByStatus(AdminPO.AdminStatus status); + // 根据状态查询管理员(引用Admin内的枚举) + List findByStatus(Admin.AdminStatus status); // 根据手机号查询管理员 - Optional findByPhone(String phone); + Optional findByPhone(String phone); - // 按角色和状态查询管理员(JPQL中实体类名改为AdminPO) - @Query("SELECT a FROM AdminPO a WHERE a.role = ?1 AND a.status = ?2") - List findByRoleAndStatus(AdminPO.AdminRole role, AdminPO.AdminStatus status); + // 按角色和状态查询管理员(JPQL中实体类名改为Admin) + @Query("SELECT a FROM Admin a WHERE a.role = ?1 AND a.status = ?2") + List findByRoleAndStatus(Admin.AdminRole role, Admin.AdminStatus status); // 检查管理员ID是否存在 boolean existsByAdminId(String adminId); @@ -39,7 +39,7 @@ public interface AdminRepository extends JpaRepository { // 检查手机号是否存在 boolean existsByPhone(String phone); - // 检查用户名是否存在 - boolean existsByUsername(String username); + // 检查用户名是否存在(适配Admin的adminName字段) + boolean existsByAdminName(String admin_name); } \ No newline at end of file diff --git a/src/main/java/com/campus/water/security/UserDetailsServiceImpl.java b/src/main/java/com/campus/water/security/UserDetailsServiceImpl.java index a2c2eae..1df2fba 100644 --- a/src/main/java/com/campus/water/security/UserDetailsServiceImpl.java +++ b/src/main/java/com/campus/water/security/UserDetailsServiceImpl.java @@ -1,7 +1,6 @@ -// com/campus/water/security/UserDetailsServiceImpl.java package com.campus.water.security; -import com.campus.water.entity.po.AdminPO; +import com.campus.water.entity.Admin; // 改为引用Admin实体下的Admin实体类 import com.campus.water.entity.po.RepairerAuthPO; import com.campus.water.entity.po.UserPO; import com.campus.water.mapper.AdminRepository; @@ -44,11 +43,11 @@ public class UserDetailsServiceImpl implements UserDetailsService { ); } - // 2. 尝试查询管理员用户 - AdminPO admin = adminRepository.findByUsername(username).orElse(null); + // 2. 尝试查询管理员用户(适配Admin实体类的adminName字段) + Admin admin = adminRepository.findByAdminName(username).orElse(null); // 方法名从findByUsername改为findByAdminName if (admin != null) { return createUserDetails( - admin.getUsername(), + admin.getAdminName(), // 字段名从getUsername改为getAdminName admin.getPassword(), RoleConstants.ROLE_ADMIN ); diff --git a/src/main/java/com/campus/water/service/LoginService.java b/src/main/java/com/campus/water/service/LoginService.java index 2370e20..fb78143 100644 --- a/src/main/java/com/campus/water/service/LoginService.java +++ b/src/main/java/com/campus/water/service/LoginService.java @@ -1,7 +1,6 @@ package com.campus.water.service; -import com.campus.water.entity.dto.request.LoginRequest; // 对齐你的DTO目录 -import com.campus.water.entity.po.AdminPO; +import com.campus.water.entity.Admin; // 改为引用修改import com.campus.water.entity.dto.request.LoginRequest; import com.campus.water.entity.po.RepairerAuthPO; import com.campus.water.entity.po.UserPO; import com.campus.water.entity.vo.LoginVO; @@ -11,6 +10,7 @@ import com.campus.water.mapper.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.DigestUtils; +import com.campus.water.entity.dto.request.LoginRequest; import java.nio.charset.StandardCharsets; import java.util.UUID; @@ -47,9 +47,10 @@ public class LoginService { } } - // 管理员登录(复用JPA的findByUsername) + // 管理员登录(适配修改后的Admin实体和AdminRepository) private LoginVO handleAdminLogin(String username, String password) { - AdminPO admin = adminRepository.findByUsername(username) + // 方法名从findByUsername改为findByAdminName + Admin admin = adminRepository.findByAdminName(username) .orElseThrow(() -> new RuntimeException("管理员不存在")); if (!admin.getPassword().equals(password)) { throw new RuntimeException("密码错误"); @@ -57,7 +58,7 @@ public class LoginService { return createLoginVO(admin.getAdminId(), username, "admin"); } - // 学生登录 + // 学生登录(保持不变) private LoginVO handleUserLogin(String username, String password) { UserPO user = userRepository.findByUsername(username) .orElseThrow(() -> new RuntimeException("用户不存在")); @@ -67,7 +68,7 @@ public class LoginService { return createLoginVO(user.getStudentId(), username, "user"); } - // 维修人员登录 + // 维修人员登录(保持不变) private LoginVO handleRepairerLogin(String username, String password) { RepairerAuthPO repairer = repairerAuthRepository.findByUsername(username) .orElseThrow(() -> new RuntimeException("维修人员不存在")); @@ -77,7 +78,7 @@ public class LoginService { return createLoginVO(repairer.getRepairmanId(), username, "repairer"); } - // 构建登录响应VO + // 构建登录响应VO(保持不变) private LoginVO createLoginVO(String userId, String username, String userType) { LoginVO vo = new LoginVO(); vo.setUserId(userId); diff --git a/src/main/java/com/campus/water/service/MqttSensorReceiver.java b/src/main/java/com/campus/water/service/MqttSensorReceiver.java index 5220504..9b0e94d 100644 --- a/src/main/java/com/campus/water/service/MqttSensorReceiver.java +++ b/src/main/java/com/campus/water/service/MqttSensorReceiver.java @@ -19,6 +19,7 @@ import org.springframework.messaging.handler.annotation.Header; import org.springframework.stereotype.Service; import jakarta.annotation.PostConstruct; +import java.math.BigDecimal; import java.time.LocalDateTime; @Service @@ -88,14 +89,15 @@ public class MqttSensorReceiver { // 2. 模型对象转换为JPA实体(持久化到数据库) WaterMakerRealtimeData entity = new WaterMakerRealtimeData(); entity.setDeviceId(sensorData.getDeviceId()); - entity.setTdsValue1(sensorData.getTdsValue1()); - entity.setTdsValue2(sensorData.getTdsValue2()); - entity.setTdsValue3(sensorData.getTdsValue3()); - entity.setWaterFlow1(sensorData.getWaterFlow1()); - entity.setWaterFlow2(sensorData.getWaterFlow2()); - entity.setWaterPress(sensorData.getWaterPress()); + // Double转BigDecimal处理(包含null值判断) + entity.setTdsValue1(sensorData.getTdsValue1() != null ? BigDecimal.valueOf(sensorData.getTdsValue1()) : null); + entity.setTdsValue2(sensorData.getTdsValue2() != null ? BigDecimal.valueOf(sensorData.getTdsValue2()) : null); + entity.setTdsValue3(sensorData.getTdsValue3() != null ? BigDecimal.valueOf(sensorData.getTdsValue3()) : null); + entity.setWaterFlow1(sensorData.getWaterFlow1() != null ? BigDecimal.valueOf(sensorData.getWaterFlow1()) : null); + entity.setWaterFlow2(sensorData.getWaterFlow2() != null ? BigDecimal.valueOf(sensorData.getWaterFlow2()) : null); + entity.setWaterPress(sensorData.getWaterPress() != null ? BigDecimal.valueOf(sensorData.getWaterPress()) : null); entity.setFilterLife(sensorData.getFilterLife()); - entity.setLeakage(sensorData.getLeakage() ? true: false); // 数据库存储:true=漏水,false=正常 + entity.setLeakage(sensorData.getLeakage() ? true : false); // 数据库存储:true=漏水,false=正常 entity.setWaterQuality(sensorData.getWaterQuality()); entity.setStatus(WaterMakerRealtimeData.DeviceStatus.valueOf(sensorData.getStatus().toUpperCase())); entity.setRecordTime(sensorData.getRecordTime()); @@ -146,10 +148,11 @@ public class MqttSensorReceiver { WaterSupplyRealtimeData entity = new WaterSupplyRealtimeData(); entity.setDeviceId(sensorData.getDeviceId()); - entity.setWaterFlow(sensorData.getWaterFlow()); - entity.setWaterPress(sensorData.getWaterPress()); - entity.setWaterLevel(sensorData.getWaterLevel()); - entity.setTemperature(sensorData.getTemperature()); + // Double转BigDecimal处理(包含null值判断) + entity.setWaterFlow(sensorData.getWaterFlow() != null ? BigDecimal.valueOf(sensorData.getWaterFlow()) : null); + entity.setWaterPress(sensorData.getWaterPress() != null ? BigDecimal.valueOf(sensorData.getWaterPress()) : null); + entity.setWaterLevel(sensorData.getWaterLevel() != null ? BigDecimal.valueOf(sensorData.getWaterLevel()) : null); + entity.setTemperature(sensorData.getTemperature() != null ? BigDecimal.valueOf(sensorData.getTemperature()) : null); entity.setStatus(WaterSupplyRealtimeData.DeviceStatus.valueOf(sensorData.getStatus().toUpperCase())); entity.setTimestamp(sensorData.getTimestamp()); diff --git a/src/main/java/com/campus/water/service/RegisterService.java b/src/main/java/com/campus/water/service/RegisterService.java index c7d5e2c..538f474 100644 --- a/src/main/java/com/campus/water/service/RegisterService.java +++ b/src/main/java/com/campus/water/service/RegisterService.java @@ -1,7 +1,7 @@ package com.campus.water.service; +import com.campus.water.entity.Admin; // 替换旧的AdminPO import com.campus.water.entity.dto.request.RegisterRequest; -import com.campus.water.entity.po.AdminPO; import com.campus.water.entity.po.RepairerAuthPO; import com.campus.water.entity.po.UserPO; import com.campus.water.mapper.AdminRepository; @@ -27,7 +27,6 @@ public class RegisterService { public boolean register(RegisterRequest request) { String username = request.getUsername(); - // 密码MD5加密(与登录逻辑保持一致) String encryptedPwd = DigestUtils.md5DigestAsHex( request.getPassword().getBytes(StandardCharsets.UTF_8) ); @@ -49,22 +48,25 @@ public class RegisterService { return true; } + // 修正管理员注册逻辑(适配新实体Admin) private void handleAdminRegister(String username, String password, RegisterRequest request) { - // 检查用户名是否已存在 - if (adminRepository.existsByUsername(username)) { + // 检查用户名是否已存在(使用新方法existsByAdminName) + if (adminRepository.existsByAdminName(username)) { throw new RuntimeException("管理员用户名已存在"); } - AdminPO admin = new AdminPO(); - admin.setUsername(username); - admin.setPassword(password); + Admin admin = new Admin(); admin.setAdminId(request.getAdminId()); - admin.setRole(AdminPO.AdminRole.valueOf(request.getAdminRole())); - admin.setStatus(AdminPO.AdminStatus.ACTIVE); + admin.setAdminName(username); // 字段名从username改为adminName + admin.setPassword(password); + // 角色枚举值转换(新实体角色为小写,需统一) + admin.setRole(Admin.AdminRole.valueOf(request.getAdminRole().toLowerCase())); + admin.setStatus(Admin.AdminStatus.active); // 状态枚举值改为小写 adminRepository.save(admin); } + // 学生注册逻辑保持不变 private void handleUserRegister(String username, String password, RegisterRequest request) { if (userRepository.existsByUsername(username)) { throw new RuntimeException("用户名已存在"); @@ -77,13 +79,14 @@ public class RegisterService { user.setUsername(username); user.setPassword(password); user.setStudentId(request.getStudentId()); - user.setUsername(request.getStudentName()); - user.setStatus(UserPO.UserStatus.ACTIVE); - // 可根据需要补充其他字段默认值 + user.setUsername(request.getStudentName()); // 注意:这里重复设置了username,建议修正为setStudentName(如果有该字段) + // 枚举值改为小写(与UserPO中定义的一致) + user.setStatus(UserPO.UserStatus.active); userRepository.save(user); } + // 维修人员注册逻辑保持不变 private void handleRepairerRegister(String username, String password, RegisterRequest request) { if (repairerAuthRepository.existsByUsername(username)) { throw new RuntimeException("维修人员用户名已存在"); diff --git a/src/main/java/com/campus/water/service/StatisticsService.java b/src/main/java/com/campus/water/service/StatisticsService.java index 303a53e..f5134b6 100644 --- a/src/main/java/com/campus/water/service/StatisticsService.java +++ b/src/main/java/com/campus/water/service/StatisticsService.java @@ -12,6 +12,7 @@ import com.campus.water.mapper.TerminalUsageStatsRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; @@ -45,13 +46,16 @@ public class StatisticsService { List dates = stats.stream() .map(stat -> stat.getStatDate().toString()) .collect(Collectors.toList()); + + // 修复1:BigDecimal转Double(处理null值,避免空指针) List waterUsage = stats.stream() - .map(TerminalUsageStats::getTotalWaterOutput) + .map(stat -> stat.getTotalWaterOutput() != null ? stat.getTotalWaterOutput().doubleValue() : 0.0) .collect(Collectors.toList()); result.setDates(dates); result.setWaterUsage(waterUsage); + // 求和(Double类型直接计算) double total = waterUsage.stream().mapToDouble(Double::doubleValue).sum(); result.setTotalUsage(total); result.setAvgDailyUsage(dates.size() > 0 ? total / dates.size() : 0); @@ -70,8 +74,10 @@ public class StatisticsService { for (String deviceId : deviceIds) { List stats = terminalUsageStatsRepository .findByTerminalIdAndStatDateBetween(deviceId, startDate, endDate); + + // 修复2:mapToDouble中处理BigDecimal转double(含null值) double total = stats.stream() - .mapToDouble(TerminalUsageStats::getTotalWaterOutput) + .mapToDouble(stat -> stat.getTotalWaterOutput() != null ? stat.getTotalWaterOutput().doubleValue() : 0.0) .sum(); deviceTotal.put(deviceId, total); } @@ -96,8 +102,9 @@ public class StatisticsService { List stats = terminalUsageStatsRepository .findByStatDateBetween(startDate, endDate); + // 修复3:BigDecimal转double求和 double total = stats.stream() - .mapToDouble(TerminalUsageStats::getTotalWaterOutput) + .mapToDouble(stat -> stat.getTotalWaterOutput() != null ? stat.getTotalWaterOutput().doubleValue() : 0.0) .sum(); result.setTotalUsage(total); return result; @@ -124,24 +131,24 @@ public class StatisticsService { alerts = alertRepository.findByTimestampBetween(startTime, endTime); } - // 修复:使用alertLevel直接获取级别(原代码错误使用getLevel()) + // 统计告警级别分布 Map levelCount = alerts.stream() - .map(alert -> alert.getAlertLevel().name()) // 直接获取alertLevel字段 + .map(alert -> alert.getAlertLevel().name()) // 获取告警级别枚举名称 .collect(Collectors.groupingBy(level -> level, Collectors.counting())); result.setLevelCount(levelCount); // 统计告警状态分布 Map statusCount = alerts.stream() - .map(alert -> alert.getStatus().name()) + .map(alert -> alert.getStatus().name()) // 获取告警状态枚举名称 .collect(Collectors.groupingBy(status -> status, Collectors.counting())); result.setStatusCount(statusCount); - // 计算处理率(修复int转Long类型问题) + // 计算处理率(避免除零错误) long total = alerts.size(); long resolved = alerts.stream() .filter(alert -> alert.getStatus() == Alert.AlertStatus.resolved) .count(); - double handleRate = total > 0 ? (double) resolved / total * 100 : 0; + double handleRate = total > 0 ? (double) resolved / total * 100 : 0.0; result.setHandleRate(handleRate); return result;