From c6c415dc1341755b804ab2f717849ab818bf3421 Mon Sep 17 00:00:00 2001 From: zichun Date: Wed, 6 May 2026 21:51:26 +0800 Subject: [PATCH] feat(usr): user query DTO + list item VO REQ-USR-003 --- backend/src/main/java/com/xly/erp/module/usr/dto/UserQueryDTO.java | 38 ++++++++++++++++++++++++++++++++++++++ backend/src/main/java/com/xly/erp/module/usr/vo/UserListItemVO.java | 21 +++++++++++++++++++++ backend/src/test/java/com/xly/erp/module/usr/dto/UserQueryDTOValidationTest.java | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 0 deletions(-) create mode 100644 backend/src/main/java/com/xly/erp/module/usr/dto/UserQueryDTO.java create mode 100644 backend/src/main/java/com/xly/erp/module/usr/vo/UserListItemVO.java create mode 100644 backend/src/test/java/com/xly/erp/module/usr/dto/UserQueryDTOValidationTest.java diff --git a/backend/src/main/java/com/xly/erp/module/usr/dto/UserQueryDTO.java b/backend/src/main/java/com/xly/erp/module/usr/dto/UserQueryDTO.java new file mode 100644 index 0000000..09bb579 --- /dev/null +++ b/backend/src/main/java/com/xly/erp/module/usr/dto/UserQueryDTO.java @@ -0,0 +1,38 @@ +package com.xly.erp.module.usr.dto; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.Data; + +/** REQ-USR-003 用户查询参数 DTO(query string 绑定)。 */ +@Data +public class UserQueryDTO { + + @Min(1) + private Integer pageNum = 1; + + @Min(1) + @Max(100) + private Integer pageSize = 20; + + /** 可空:缺省视为不过滤;服务层白名单校验后映射到 column 字段 */ + @Pattern(regexp = "^(username|staffname|userno|department|usertype|language|deleted|lastLoginDate|createdBy)?$", + message = "queryField 非法") + private String queryField; + + /** 可空:默认 contains */ + @Pattern(regexp = "^(contains|notContains|equals)?$", message = "matchType 非法") + private String matchType; + + /** 可空:缺省视为不过滤 */ + @Size(max = 100) + private String queryValue; + + /** 服务层白名单映射后的实际 SQL 列名(如 "u.sUserName")。 + * Jackson 忽略——前端不能也无法直接传入;XML mapper 用 ${query.column} 渲染。 */ + @JsonIgnore + private String column; +} diff --git a/backend/src/main/java/com/xly/erp/module/usr/vo/UserListItemVO.java b/backend/src/main/java/com/xly/erp/module/usr/vo/UserListItemVO.java new file mode 100644 index 0000000..86884bf --- /dev/null +++ b/backend/src/main/java/com/xly/erp/module/usr/vo/UserListItemVO.java @@ -0,0 +1,21 @@ +package com.xly.erp.module.usr.vo; + +import lombok.Data; + +import java.time.LocalDateTime; + +/** REQ-USR-003 用户列表行 VO(含 LEFT JOIN tStaff 出来的 sStaffName / sDepartment)。 */ +@Data +public class UserListItemVO { + private Integer iIncrement; + private String sUserName; + private String sStaffName; + private String sUserNo; + private String sDepartment; + private String sUserType; + private String sLanguage; + private Boolean bDeleted; + private LocalDateTime tLastLoginDate; + private String sCreatedBy; + private LocalDateTime tCreateDate; +} diff --git a/backend/src/test/java/com/xly/erp/module/usr/dto/UserQueryDTOValidationTest.java b/backend/src/test/java/com/xly/erp/module/usr/dto/UserQueryDTOValidationTest.java new file mode 100644 index 0000000..142b90d --- /dev/null +++ b/backend/src/test/java/com/xly/erp/module/usr/dto/UserQueryDTOValidationTest.java @@ -0,0 +1,65 @@ +package com.xly.erp.module.usr.dto; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; +import org.junit.jupiter.api.Test; + +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +class UserQueryDTOValidationTest { + + private static final ValidatorFactory FACTORY = Validation.buildDefaultValidatorFactory(); + private final Validator validator = FACTORY.getValidator(); + + private UserQueryDTO valid() { + UserQueryDTO d = new UserQueryDTO(); + d.setPageNum(1); + d.setPageSize(20); + d.setQueryField("username"); + d.setMatchType("contains"); + d.setQueryValue("alice"); + return d; + } + + @Test + void allValid_yieldsNoViolations() { + Set> v = validator.validate(valid()); + assertThat(v).isEmpty(); + } + + @Test + void pageSizeTooLarge_yieldsViolation() { + UserQueryDTO d = valid(); + d.setPageSize(101); + Set> v = validator.validate(d); + assertThat(v).extracting(cv -> cv.getPropertyPath().toString()).contains("pageSize"); + } + + @Test + void pageSizeTooSmall_yieldsViolation() { + UserQueryDTO d = valid(); + d.setPageSize(0); + Set> v = validator.validate(d); + assertThat(v).extracting(cv -> cv.getPropertyPath().toString()).contains("pageSize"); + } + + @Test + void queryFieldInvalidEnum_yieldsViolation() { + UserQueryDTO d = valid(); + d.setQueryField("invalid_field"); + Set> v = validator.validate(d); + assertThat(v).extracting(cv -> cv.getPropertyPath().toString()).contains("queryField"); + } + + @Test + void queryValueOverSized_yieldsViolation() { + UserQueryDTO d = valid(); + d.setQueryValue("a".repeat(101)); + Set> v = validator.validate(d); + assertThat(v).extracting(cv -> cv.getPropertyPath().toString()).contains("queryValue"); + } +} -- libgit2 0.22.2