登录接口1.1

pull/34/head
hnu202326010122 1 month ago
commit 344121d19a

@ -87,6 +87,8 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>

@ -0,0 +1,25 @@
package main.java.com.campus.water.controller;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.HashMap;
import java.util.Map;
/**
*
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(RuntimeException.class)
public ResponseEntity<Map<String, Object>> handleRuntimeException(RuntimeException e) {
Map<String, Object> response = new HashMap<>();
response.put("code", 401); // 权限相关错误用401其他可调整
response.put("msg", e.getMessage());
response.put("data", null);
return new ResponseEntity<>(response, HttpStatus.OK);
}
}

@ -0,0 +1,35 @@
package com.campus.water.controller; // 修正包路径去掉main.java + 按规范放在common子包
import com.campus.water.entity.dto.request.LoginRequest; // 替换原LoginDTO为规范的LoginRequest
import com.campus.water.entity.vo.LoginVO;
import com.campus.water.service.LoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
/**
*
*/
@RestController
@RequestMapping("/api/common") // 保持统一接口前缀
public class LoginController {
@Autowired
private LoginService loginService;
/**
*
* @param loginRequest LoginDTO
* @return
*/
@PostMapping("/login")
public ResponseEntity<LoginVO> login(@Valid @RequestBody LoginRequest loginRequest) { // 参数类型替换为LoginRequest
LoginVO loginVO = loginService.login(loginRequest); // 同步修改入参类型
return ResponseEntity.ok(loginVO);
}
}

@ -1,7 +1,7 @@
package com.campus.water.controller;
import com.campus.water.entity.*;
import com.campus.water.mapper.*;
import com.campus.water.repository.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;

@ -1,9 +1,9 @@
package com.campus.water.controller;
import com.campus.water.entity.WorkOrder;
import com.campus.water.mapper.WorkOrderRepository;
import com.campus.water.mapper.RepairmanRepository;
import com.campus.water.mapper.AlertRepository;
import com.campus.water.repository.WorkOrderRepository;
import com.campus.water.repository.RepairmanRepository;
import com.campus.water.repository.AlertRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;

@ -0,0 +1,17 @@
// LoginRequest.java原LoginDTO按项目规范重命名
package com.campus.water.entity.dto.request;
import lombok.Data;
import javax.validation.constraints.NotBlank;
@Data
public class LoginRequest { // 命名改为Request符合dto/request分类
@NotBlank(message = "用户名不能为空")
private String username;
@NotBlank(message = "密码不能为空")
private String password;
@NotBlank(message = "用户类型不能为空")
private String userType; // admin/repairer/user
}

@ -0,0 +1,37 @@
package com.campus.water.entity.po;
import lombok.Data;
import javax.persistence.*;
@Data
@Entity
@Table(name = "admin") // 对应数据库admin表
public class AdminPO {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // 主键自增(根据数据库调整)
private String adminId;
@Column(unique = true, nullable = false)
private String username; // 登录用户名
@Column(nullable = false)
private String password; // MD5加密后的密码
private String phone; // 联系电话
// 管理员角色枚举
public enum AdminRole {
SUPER_ADMIN, NORMAL_ADMIN
}
// 管理员状态枚举
public enum AdminStatus {
ACTIVE, INACTIVE
}
@Enumerated(EnumType.STRING) // 枚举以字符串形式存储
private AdminRole role;
@Enumerated(EnumType.STRING)
private AdminStatus status;
}

@ -0,0 +1,35 @@
package com.campus.water.entity.po;
import lombok.Data;
import javax.persistence.*;
@Data
@Entity
@Table(name = "repairer_auth") // 对应数据库表
public class RepairerAuthPO {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // 主键自增Long类型
private Long id; // 主键ID对应Repository的Long主键类型
@Column(unique = true, nullable = false)
private String repairmanId; // 维修人员唯一标识业务ID
@Column(unique = true, nullable = false)
private String username; // 登录用户名
@Column(nullable = false)
private String password; // MD5加密密码
// 账号状态枚举和Repository的AccountStatus匹配
public enum AccountStatus {
active, inactive, locked
}
@Enumerated(EnumType.STRING) // 枚举以字符串存储匹配SQL里的'active'
private AccountStatus accountStatus;
// 补充其他业务字段(按需添加)
private String phone; // 联系电话
private String areaId; // 负责区域ID
private String name; // 维修人员姓名
}

@ -0,0 +1,40 @@
package com.campus.water.entity.po;
import lombok.Data;
import javax.persistence.*;
@Data
@Entity
@Table(name = "user") // 对应数据库user表学生用户
public class UserPO {
@Id
// 修正String类型主键不支持IDENTITY自增MySQL自增主键为Long改为手动赋值/UUID
// 若需自增建议将studentId改为Long类型此处保留String并移除IDENTITY
private String studentId; // 学生ID主键学号
@Column(unique = true, nullable = false)
private String username; // 登录用户名/学生姓名
@Column(nullable = false)
private String password; // MD5加密后的密码
private String phone; // 联系电话
private String studentNo; // 学号若studentId已用学号可删除此字段避免冗余
private String college; // 学院
// ========== 补充缺失字段 ==========
@Column(unique = true)
private String email; // 邮箱适配Repository的findByEmail/existsByEmail
// ========== 补充缺失枚举 ==========
// 用户状态枚举适配Repository的findByStatus/findByUsernameContainingAndStatus
public enum UserStatus {
ACTIVE, // 活跃
INACTIVE, // 未激活
LOCKED // 锁定
}
// 状态字段(映射为字符串存储,适配枚举)
@Enumerated(EnumType.STRING)
private UserStatus status;
}

@ -0,0 +1,12 @@
// LoginVO.java保持VO命名无需修改
package com.campus.water.entity.vo;
import lombok.Data;
@Data
public class LoginVO {
private String token; // 登录令牌
private String userId; // 用户ID
private String username; // 用户名
private String userType; // 用户类型
}

@ -1,32 +1,37 @@
package com.campus.water.mapper;
import com.campus.water.entity.Admin;
import com.campus.water.entity.po.AdminPO; // 替换为PO包下的实体类
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository
public interface AdminRepository extends JpaRepository<Admin, String> {
public interface AdminRepository extends JpaRepository<AdminPO, String> {
// ========== 新增:登录核心方法(必须) ==========
Optional<AdminPO> findByUsername(String username);
// ========== 保留原有业务方法适配PO类 ==========
// 根据管理员ID查询
Optional<Admin> findByAdminId(String adminId);
Optional<AdminPO> findByAdminId(String adminId);
// 根据管理员姓名模糊查询
List<Admin> findByAdminNameContaining(String adminName);
// 根据管理员姓名/用户名模糊查询适配PO的username字段
List<AdminPO> findByUsernameContaining(String username);
// 根据角色查询管理员
List<Admin> findByRole(Admin.AdminRole role);
// 根据角色查询管理员引用PO内的枚举
List<AdminPO> findByRole(AdminPO.AdminRole role);
// 根据状态查询管理员
List<Admin> findByStatus(Admin.AdminStatus status);
// 根据状态查询管理员引用PO内的枚举
List<AdminPO> findByStatus(AdminPO.AdminStatus status);
// 根据手机号查询管理员
Optional<Admin> findByPhone(String phone);
Optional<AdminPO> findByPhone(String phone);
// 按角色和状态查询管理员
@Query("SELECT a FROM Admin a WHERE a.role = ?1 AND a.status = ?2")
List<Admin> findByRoleAndStatus(Admin.AdminRole role, Admin.AdminStatus status);
// 按角色和状态查询管理员JPQL中实体类名改为AdminPO
@Query("SELECT a FROM AdminPO a WHERE a.role = ?1 AND a.status = ?2")
List<AdminPO> findByRoleAndStatus(AdminPO.AdminRole role, AdminPO.AdminStatus status);
// 检查管理员ID是否存在
boolean existsByAdminId(String adminId);

@ -1,26 +1,27 @@
package com.campus.water.mapper;
import com.campus.water.entity.RepairerAuth;
import com.campus.water.entity.po.RepairerAuthPO; // 替换为PO包下的实体类
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository
public interface RepairerAuthRepository extends JpaRepository<RepairerAuth, Long> {
// 根据用户名查询认证信息
Optional<RepairerAuth> findByUsername(String username);
public interface RepairerAuthRepository extends JpaRepository<RepairerAuthPO, Long> {
// 根据用户名查询认证信息适配PO类
Optional<RepairerAuthPO> findByUsername(String username);
// 根据维修人员ID查询认证信息
Optional<RepairerAuth> findByRepairmanId(String repairmanId);
// 根据维修人员ID查询认证信息适配PO类
Optional<RepairerAuthPO> findByRepairmanId(String repairmanId);
// 根据账户状态查询认证信息
List<RepairerAuth> findByAccountStatus(RepairerAuth.AccountStatus accountStatus);
// 根据账户状态查询认证信息引用PO内的枚举
List<RepairerAuthPO> findByAccountStatus(RepairerAuthPO.AccountStatus accountStatus);
// 查找活跃状态的维修人员账号
@Query("SELECT ra FROM RepairerAuth ra WHERE ra.username = ?1 AND ra.accountStatus = 'active'")
Optional<RepairerAuth> findActiveByUsername(String username);
// 查找活跃状态的维修人员账号JPQL实体类名改为RepairerAuthPO
@Query("SELECT ra FROM RepairerAuthPO ra WHERE ra.username = ?1 AND ra.accountStatus = 'active'")
Optional<RepairerAuthPO> findActiveByUsername(String username);
// 检查用户名是否存在
boolean existsByUsername(String username);

@ -1,32 +1,33 @@
package com.campus.water.mapper;
package com.campus.water.mapper; // 核心修正从mapper改为repositoryJPA规范
import com.campus.water.entity.User;
import com.campus.water.entity.po.UserPO; // 替换为PO包下的实体类
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository
public interface UserRepository extends JpaRepository<User, String> {
// 根据学号查找用户
Optional<User> findByStudentId(String studentId);
public interface UserRepository extends JpaRepository<UserPO, String> {
// 根据学号查找用户适配PO类字段名保持studentId不变
Optional<UserPO> findByStudentId(String studentId);
// 根据学生姓名模糊查询
List<User> findByStudentNameContaining(String studentName);
// 根据学生姓名模糊查询适配PO的username字段原studentName对应PO的username
List<UserPO> findByUsernameContaining(String username);
// 根据用户状态查询
List<User> findByStatus(User.UserStatus status);
// 根据用户状态查询引用PO内的UserStatus枚举
List<UserPO> findByStatus(UserPO.UserStatus status);
// 根据手机号查询用户
Optional<User> findByPhone(String phone);
Optional<UserPO> findByPhone(String phone);
// 根据邮箱查询用户
Optional<User> findByEmail(String email);
Optional<UserPO> findByEmail(String email);
// 按姓名模糊查询和状态筛选
@Query("SELECT u FROM User u WHERE u.studentName LIKE %?1% AND u.status = ?2")
List<User> findByStudentNameContainingAndStatus(String studentName, User.UserStatus status);
// 按姓名模糊查询和状态筛选JPQL实体类名改为UserPOstudentName改为username
@Query("SELECT u FROM UserPO u WHERE u.username LIKE %?1% AND u.status = ?2")
List<UserPO> findByUsernameContainingAndStatus(String username, UserPO.UserStatus status);
// 检查学号是否已存在
boolean existsByStudentId(String studentId);
@ -36,4 +37,7 @@ public interface UserRepository extends JpaRepository<User, String> {
// 检查邮箱是否已存在
boolean existsByEmail(String email);
// ========== 新增:登录核心方法(必须) ==========
Optional<UserPO> findByUsername(String username);
}

@ -0,0 +1,28 @@
package com.campus.water.repository;
import com.campus.water.entity.po.AdminPO;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository
public interface AdminRepository extends JpaRepository<AdminPO, String> {
// 登录核心:通过用户名查询
Optional<AdminPO> findByUsername(String username);
// 原有业务方法
Optional<AdminPO> findByAdminId(String adminId);
List<AdminPO> findByUsernameContaining(String username);
List<AdminPO> findByRole(AdminPO.AdminRole role);
List<AdminPO> findByStatus(AdminPO.AdminStatus status);
Optional<AdminPO> findByPhone(String phone);
@Query("SELECT a FROM AdminPO a WHERE a.role = ?1 AND a.status = ?2")
List<AdminPO> findByRoleAndStatus(AdminPO.AdminRole role, AdminPO.AdminStatus status);
boolean existsByAdminId(String adminId);
boolean existsByPhone(String phone);
}

@ -1,4 +1,4 @@
package com.campus.water.mapper;
package com.campus.water.repository;
import com.campus.water.entity.Alert;
import org.springframework.data.jpa.repository.JpaRepository;

@ -1,4 +1,4 @@
package com.campus.water.mapper;
package com.campus.water.repository;
import com.campus.water.entity.Area;
import org.springframework.data.jpa.repository.JpaRepository;

@ -1,4 +1,4 @@
package com.campus.water.mapper;
package com.campus.water.repository;
import com.campus.water.entity.Device;
import org.springframework.data.jpa.repository.JpaRepository;

@ -1,4 +1,4 @@
package com.campus.water.mapper;
package com.campus.water.repository;
import com.campus.water.entity.DeviceTerminalMapping;
import org.springframework.data.jpa.repository.JpaRepository;

@ -1,4 +1,4 @@
package com.campus.water.mapper;
package com.campus.water.repository;
import com.campus.water.entity.DrinkRecommendation;
import org.springframework.data.jpa.repository.JpaRepository;

@ -1,4 +1,4 @@
package com.campus.water.mapper;
package com.campus.water.repository;
import com.campus.water.entity.DrinkRecord;
import org.springframework.data.jpa.repository.JpaRepository;

@ -1,4 +1,4 @@
package com.campus.water.mapper;
package com.campus.water.repository;
import com.campus.water.entity.InspectionRecord;
import org.springframework.data.jpa.repository.JpaRepository;

@ -1,4 +1,4 @@
package com.campus.water.mapper;
package com.campus.water.repository;
import com.campus.water.entity.MaintenancePlan;
import org.springframework.data.jpa.repository.JpaRepository;

@ -1,4 +1,4 @@
package com.campus.water.mapper;
package com.campus.water.repository;
import com.campus.water.entity.MessagePush;
import org.springframework.data.jpa.repository.JpaRepository;

@ -0,0 +1,31 @@
package com.campus.water.repository;
import com.campus.water.entity.po.RepairerAuthPO;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository
public interface RepairerAuthRepository extends JpaRepository<RepairerAuthPO, Long> {
// 登录核心:通过用户名查询
Optional<RepairerAuthPO> findByUsername(String username);
// 按维修人员ID查询
Optional<RepairerAuthPO> findByRepairmanId(String repairmanId);
// 按账号状态查询引用PO内的枚举
List<RepairerAuthPO> findByAccountStatus(RepairerAuthPO.AccountStatus accountStatus);
// 自定义查询:查询活跃状态的用户
@Query("SELECT ra FROM RepairerAuthPO ra WHERE ra.username = ?1 AND ra.accountStatus = 'active'")
Optional<RepairerAuthPO> findActiveByUsername(String username);
// 校验用户名是否存在
boolean existsByUsername(String username);
// 校验维修人员ID是否存在
boolean existsByRepairmanId(String repairmanId);
}

@ -1,4 +1,4 @@
package com.campus.water.mapper;
package com.campus.water.repository;
import com.campus.water.entity.Repairman;
import org.springframework.data.jpa.repository.JpaRepository;

@ -1,4 +1,4 @@
package com.campus.water.mapper;
package com.campus.water.repository;
import com.campus.water.entity.TerminalUsageStats;
import org.springframework.data.jpa.repository.JpaRepository;

@ -0,0 +1,18 @@
package com.campus.water.repository;
import com.campus.water.entity.po.UserPO;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface UserRepository extends JpaRepository<UserPO, String> {
// 登录核心:通过用户名查询
Optional<UserPO> findByUsername(String username);
// 可补充其他业务方法(如按学号查询)
Optional<UserPO> findByStudentNo(String studentNo);
boolean existsByUsername(String username);
boolean existsByStudentNo(String studentNo);
}

@ -1,4 +1,4 @@
package com.campus.water.mapper;
package com.campus.water.repository;
import com.campus.water.entity.WaterMakerRealtimeData;
import org.springframework.data.jpa.repository.JpaRepository;

@ -1,4 +1,4 @@
package com.campus.water.mapper;
package com.campus.water.repository;
import com.campus.water.entity.WaterQualityHistory;
import org.springframework.data.jpa.repository.JpaRepository;

@ -1,4 +1,4 @@
package com.campus.water.mapper;
package com.campus.water.repository;
import com.campus.water.entity.WaterSupplyRealtimeData;
import org.springframework.data.jpa.repository.JpaRepository;

@ -1,4 +1,4 @@
package com.campus.water.mapper;
package com.campus.water.repository;
import com.campus.water.entity.WorkOrder;
import org.springframework.data.jpa.repository.JpaRepository;

@ -0,0 +1,90 @@
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.po.RepairerAuthPO;
import com.campus.water.entity.po.UserPO;
import com.campus.water.entity.vo.LoginVO;
import com.campus.water.repository.AdminRepository;
import com.campus.water.repository.RepairerAuthRepository;
import com.campus.water.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
@Service
public class LoginService {
@Autowired
private AdminRepository adminRepository;
@Autowired
private UserRepository userRepository;
@Autowired
private RepairerAuthRepository repairerAuthRepository;
public LoginVO login(LoginRequest loginRequest) {
String username = loginRequest.getUsername();
// 密码MD5加密和数据库存储的一致
String encryptedPwd = DigestUtils.md5DigestAsHex(
loginRequest.getPassword().getBytes(StandardCharsets.UTF_8)
);
String userType = loginRequest.getUserType();
switch (userType) {
case "admin":
return handleAdminLogin(username, encryptedPwd);
case "user":
return handleUserLogin(username, encryptedPwd);
case "repairer":
return handleRepairerLogin(username, encryptedPwd);
default:
throw new RuntimeException("无效的用户类型:" + userType);
}
}
// 管理员登录复用JPA的findByUsername
private LoginVO handleAdminLogin(String username, String password) {
AdminPO admin = adminRepository.findByUsername(username)
.orElseThrow(() -> new RuntimeException("管理员不存在"));
if (!admin.getPassword().equals(password)) {
throw new RuntimeException("密码错误");
}
return createLoginVO(admin.getAdminId(), username, "admin");
}
// 学生登录
private LoginVO handleUserLogin(String username, String password) {
UserPO user = userRepository.findByUsername(username)
.orElseThrow(() -> new RuntimeException("用户不存在"));
if (!user.getPassword().equals(password)) {
throw new RuntimeException("密码错误");
}
return createLoginVO(user.getStudentId(), username, "user");
}
// 维修人员登录
private LoginVO handleRepairerLogin(String username, String password) {
RepairerAuthPO repairer = repairerAuthRepository.findByUsername(username)
.orElseThrow(() -> new RuntimeException("维修人员不存在"));
if (!repairer.getPassword().equals(password)) {
throw new RuntimeException("密码错误");
}
return createLoginVO(repairer.getRepairmanId(), username, "repairer");
}
// 构建登录响应VO
private LoginVO createLoginVO(String userId, String username, String userType) {
LoginVO vo = new LoginVO();
vo.setUserId(userId);
vo.setUsername(username);
vo.setUserType(userType);
// 临时Token后续可替换为JWT
vo.setToken(UUID.randomUUID().toString().replace("-", ""));
return vo;
}
}

@ -4,9 +4,9 @@ import com.campus.water.config.MqttConfig;
import com.campus.water.entity.Alert;
import com.campus.water.entity.WaterMakerRealtimeData;
import com.campus.water.entity.WaterSupplyRealtimeData;
import com.campus.water.mapper.AlertRepository;
import com.campus.water.mapper.WaterMakerRealtimeDataRepository;
import com.campus.water.mapper.WaterSupplyRealtimeDataRepository;
import com.campus.water.repository.AlertRepository;
import com.campus.water.repository.WaterMakerRealtimeDataRepository;
import com.campus.water.repository.WaterSupplyRealtimeDataRepository;
import com.campus.water.model.WaterMakerSensorData;
import com.campus.water.model.WaterSupplySensorData;
import com.fasterxml.jackson.databind.ObjectMapper;

@ -0,0 +1,74 @@
package com.campus.water.controller.app;
import com.campus.water.test.BaseTest;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import java.util.HashMap;
import java.util.Map;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
/**
* /2
*
*/
public class WorkOrderControllerTest extends BaseTest {
// 工具将Map转为JSON字符串
private final ObjectMapper objectMapper = new ObjectMapper();
// 测试1维修人员抢单正常场景
@Test
public void testGrabWorkOrder() throws Exception {
// 构造请求参数
Map<String, String> params = new HashMap<>();
params.put("orderId", "1001"); // 测试工单ID
params.put("repairId", "REPAIR001"); // 测试维修人员ID
mockMvc.perform(
// 替换为你项目的抢单接口路径,比如/api/app/workOrder/grab
post("/api/app/workOrder/grab")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(params)) // 传入JSON参数
)
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.msg").value("抢单成功"));
}
// 测试2抢已被抢的工单异常场景
@Test
public void testGrabGrabbedOrder() throws Exception {
Map<String, String> params = new HashMap<>();
params.put("orderId", "1001"); // 已被抢的工单ID
params.put("repairId", "REPAIR002");
mockMvc.perform(
post("/api/app/workOrder/grab")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(params))
)
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(500))
.andExpect(jsonPath("$.msg").value("工单已被抢"));
}
// 测试3维修人员拒单
@Test
public void testRejectWorkOrder() throws Exception {
Map<String, String> params = new HashMap<>();
params.put("orderId", "1002");
params.put("repairId", "REPAIR001");
params.put("reason", "设备位置太远"); // 拒单原因
mockMvc.perform(
post("/api/app/workOrder/reject")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(params))
)
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.msg").value("拒单成功"));
}
}

@ -0,0 +1,73 @@
package com.campus.water.controller.common;
import com.campus.water.test.BaseTest;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import java.util.HashMap;
import java.util.Map;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
/**
*
*/
public class LoginControllerTest extends BaseTest {
private final ObjectMapper objectMapper = new ObjectMapper();
// 测试1维修人员正常登录
@Test
public void testRepairLogin() throws Exception {
Map<String, String> loginParams = new HashMap<>();
loginParams.put("username", "REPAIR001");
loginParams.put("password", "123456");
loginParams.put("userType", "repairer"); // 必须指定用户类型
mockMvc.perform(
post("/api/common/login")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(loginParams))
)
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200)) // 正常响应code
.andExpect(jsonPath("$.data.token").isNotEmpty())
.andExpect(jsonPath("$.data.userType").value("repairer"));
}
// 测试2学生登录密码错误
@Test
public void testStudentLoginWithWrongPwd() throws Exception {
Map<String, String> loginParams = new HashMap<>();
loginParams.put("username", "STUDENT001");
loginParams.put("password", "wrong123");
loginParams.put("userType", "user");
mockMvc.perform(
post("/api/common/login")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(loginParams))
)
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(401))
.andExpect(jsonPath("$.msg").value("密码错误"));
}
// 测试3无效用户类型
@Test
public void testInvalidUserType() throws Exception {
Map<String, String> loginParams = new HashMap<>();
loginParams.put("username", "TEST001");
loginParams.put("password", "123456");
loginParams.put("userType", "invalid");
mockMvc.perform(
post("/api/common/login")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(loginParams))
)
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(401))
.andExpect(jsonPath("$.msg").value("无效的用户类型invalid"));
}
}

@ -0,0 +1,55 @@
package com.campus.water.controller.web;
import com.campus.water.test.BaseTest;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
/**
* 2
*/
public class DeviceDataControllerTest extends BaseTest {
// 测试1按设备ID查询数据正常场景
@Test
public void testQueryDeviceDataByDeviceId() throws Exception {
mockMvc.perform(
// 替换为你项目的实际接口路径,比如/api/web/device/data
get("/api/web/device/data")
.param("deviceId", "ZSJ001") // 传入测试设备ID
.contentType(MediaType.APPLICATION_JSON)
)
.andExpect(status().isOk()) // 断言返回200
.andExpect(jsonPath("$.code").value(200)) // 断言返回码(如果你的接口有统一返回体)
.andExpect(jsonPath("$.data.deviceId").value("ZSJ001")); // 断言返回的设备ID正确
}
// 测试2按设备ID查询数据设备ID不存在
@Test
public void testQueryDeviceDataWithInvalidId() throws Exception {
mockMvc.perform(
get("/api/web/device/data")
.param("deviceId", "INVALID001")
.contentType(MediaType.APPLICATION_JSON)
)
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(404)) // 断言返回404
.andExpect(jsonPath("$.msg").value("设备不存在")); // 断言提示语
}
// 测试3按时间范围查询数据正常场景
@Test
public void testQueryDeviceDataByTime() throws Exception {
mockMvc.perform(
get("/api/web/device/data")
.param("deviceId", "ZSJ001")
.param("startTime", "2025-11-01 00:00:00")
.param("endTime", "2025-11-01 23:59:59")
.contentType(MediaType.APPLICATION_JSON)
)
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data").isArray()); // 断言返回数组
}
}

@ -0,0 +1,29 @@
package com.campus.water.test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.TestInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
/**
* MockMvc
*/
@SpringBootTest(classes = com.campus.water.CampusWaterApplication.class)
@AutoConfigureMockMvc
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class BaseTest {
protected MockMvc mockMvc;
@Autowired
private WebApplicationContext webApplicationContext;
@BeforeEach
public void setUp() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
}
Loading…
Cancel
Save