From 8f8a6b8cca6a232f4885b49753eb536bebcecce9 Mon Sep 17 00:00:00 2001 From: chenxing Date: Mon, 28 Sep 2026 17:07:44 +0800 Subject: [PATCH] =?UTF-8?q?feat(app):=20app=5Fcode/app=5Fnature=20?= =?UTF-8?q?=E7=BC=96=E8=BE=91=E5=BF=85=E5=A1=AB=EF=BC=88C5=EF=BC=8C2026-09?= =?UTF-8?q?-28=20=E6=8B=8D=E6=9D=BF=EF=BC=89=E2=80=94=E2=80=94=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E7=BB=84=20Create=20=E6=89=A9=20{Create,Update}?= =?UTF-8?q?=EF=BC=8C=E5=AD=98=E9=87=8F=20null=20=E5=8E=86=E5=8F=B2?= =?UTF-8?q?=E8=A1=8C=E4=B8=8D=E8=BF=BD=E6=BA=AF=EF=BC=9B=E5=AD=A6=E6=A0=A1?= =?UTF-8?q?=E8=A6=86=E7=9B=96=E5=88=86=E6=94=AF=E7=94=B1=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E5=9B=9E=E4=BC=A0=E5=8E=9F=E5=80=BC=E6=BB=A1=E8=B6=B3=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=EF=BC=88editAppForSchool=20=E5=8F=AA=E8=AF=BB=20name/?= =?UTF-8?q?desc/pcIcon=20=E4=B8=8D=E5=8F=97=E5=BD=B1=E5=93=8D=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/ApplicationInfoRequest.java | 12 +-- .../ApplicationInfoRequestValidationTest.java | 83 +++++++++++++++++++ 2 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 src/test/java/com/yunhai/userbase/model/application/ApplicationInfoRequestValidationTest.java diff --git a/src/main/java/com/yunhai/userbase/model/application/ApplicationInfoRequest.java b/src/main/java/com/yunhai/userbase/model/application/ApplicationInfoRequest.java index db3c4c0..3e0167b 100644 --- a/src/main/java/com/yunhai/userbase/model/application/ApplicationInfoRequest.java +++ b/src/main/java/com/yunhai/userbase/model/application/ApplicationInfoRequest.java @@ -36,18 +36,18 @@ public class ApplicationInfoRequest { private Integer categoryId; /** - * 技术标识(= projman app.name,如 notice),全库唯一,新增必填。
- * 编辑不强制(部分提交场景不回传则保持原值);值域为引用键,改名须盘点引用。 + * 技术标识(= projman app.name,如 notice),全库唯一,新增与编辑均必填。
+ * 编辑必填(2026-09-28 拍板):app_code 是应用身份锚点(消息 jump_app/服务目录键),不许置空; + * 存量 null 历史行不追溯,但编辑提交时必须补填。值域为引用键,改名须盘点引用。 */ - @NotBlank(groups = ValidationGroups.Create.class, message = "技术标识不能为空") + @NotBlank(groups = {ValidationGroups.Create.class, ValidationGroups.Update.class}, message = "技术标识不能为空") @Size(max = 32, message = "技术标识长度不能超过32") private String appCode; /** - * 应用性质:BASE=基石 / BUSINESS=业务,新增必填。
- * 编辑不强制(不回传则保持原值);学校模式覆盖线不涉及本字段。 + * 应用性质:BASE=基石 / BUSINESS=业务,新增与编辑均必填(2026-09-28 拍板,存量 null 行不追溯)。 */ - @NotBlank(groups = ValidationGroups.Create.class, message = "应用性质不能为空") + @NotBlank(groups = {ValidationGroups.Create.class, ValidationGroups.Update.class}, message = "应用性质不能为空") @Size(max = 16, message = "应用性质长度不能超过16") private String appNature; diff --git a/src/test/java/com/yunhai/userbase/model/application/ApplicationInfoRequestValidationTest.java b/src/test/java/com/yunhai/userbase/model/application/ApplicationInfoRequestValidationTest.java new file mode 100644 index 0000000..98c8410 --- /dev/null +++ b/src/test/java/com/yunhai/userbase/model/application/ApplicationInfoRequestValidationTest.java @@ -0,0 +1,83 @@ +package com.yunhai.userbase.model.application; + +import com.yunhai.userbase.common.validation.ValidationGroups; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * app_code / app_nature 编辑必填校验组单测(消息方案 C5,2026-09-28 拍板:新增/编辑均必填, + * 存量 null 历史行不追溯)。Create 组此前已必填;本测试冻结 Update 组同口径—— + * 编辑提交置空 → 校验失败;带值 → 通过。学校模式覆盖线由前端分支原样回传原值满足校验 + * (后端 editAppForSchool 只读 name/desc/pcIcon,其余字段忽略)。 + */ +@DisplayName("ApplicationInfoRequest - app_code/app_nature 新增与编辑均必填") +class ApplicationInfoRequestValidationTest { + + private static Validator validator; + + @BeforeAll + static void setUp() { + ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + validator = factory.getValidator(); + } + + private ApplicationInfoRequest validRequest() { + ApplicationInfoRequest request = new ApplicationInfoRequest(); + request.setId(100011); + request.setName("流程中心"); + request.setCategoryId(2); + request.setAppCode("flow-center"); + request.setAppNature("BUSINESS"); + return request; + } + + private static boolean hasViolation(Set> violations, String field) { + return violations.stream().anyMatch(v -> v.getPropertyPath().toString().equals(field)); + } + + @Test + void edit_空appCode_校验失败() { + ApplicationInfoRequest request = validRequest(); + request.setAppCode(" "); + Set> violations = + validator.validate(request, ValidationGroups.Update.class); + assertTrue(hasViolation(violations, "appCode"), "编辑时技术标识置空必须被 Update 组拦截"); + } + + @Test + void edit_空appNature_校验失败() { + ApplicationInfoRequest request = validRequest(); + request.setAppNature(null); + Set> violations = + validator.validate(request, ValidationGroups.Update.class); + assertTrue(hasViolation(violations, "appNature"), "编辑时应用性质置空必须被 Update 组拦截"); + } + + @Test + void edit_带appCodeAppNature_通过() { + Set> violations = + validator.validate(validRequest(), ValidationGroups.Update.class); + assertFalse(hasViolation(violations, "appCode")); + assertFalse(hasViolation(violations, "appNature")); + } + + @Test + void create_空appCode_校验失败_口径不变() { + ApplicationInfoRequest request = validRequest(); + request.setId(null); + request.setAppCode(null); + Set> violations = + validator.validate(request, ValidationGroups.Create.class); + assertTrue(hasViolation(violations, "appCode"), "新增必填为既有口径,防回归"); + } +}