优化JSON字符串验证逻辑:冗长重复代码的改进方案与设计模式选择
JSON字段验证逻辑优化问题
现有JSON示例
{ "productName": "Gold", "offerStartDate": "01152023", "offerEndDate": "01152024", "offerAttributes": [ { "id": "TGH-DAD3KVF3", "storeid": "STG-67925", "availability": true } ], "offerSpecifications": { "price": 23.25 } }
当前验证逻辑(Java代码)
Map<String, Object> map = mapper.readValue(json, Map.class); String productNameValue = (String)map.get("productName"); if(productNameValue == null && productNameValue.isEmpty()) { throw new Exception(); } String offerStartDateValue = (String)map.get("offerStartDate"); if(offerStartDateValue == null && offerStartDateValue.isEmpty()) { throw new Exception(); } List<Object> offerAttributesValue = (List)map.get("offerAttributes"); if(offerAttributesValue == null && offerAttributesValue.isEmpty()) { throw new Exception(); } Map<String, Object> offerSpecificationsValue = (Map)map.get("offerSpecifications"); if(offerSpecificationsValue == null && offerSpecificationsValue.isEmpty() && ((String)offerSpecificationsValue.get("price")).isEmpty()) { throw new Exception(); }
问题描述
上述仅为JSON响应的部分内容,实际响应包含48个以上字段且结构更复杂,现有代码对所有字段均采用上述重复冗长的方式验证。请问如何优化该验证逻辑?适合采用哪种设计模式?已知Builder模式,但不知如何在此场景应用。
优化方案与设计模式推荐
1. 优先采用验证器模式(Validator Pattern)+ Builder模式
这种组合能让你灵活构建可复用的验证规则,彻底告别重复的if判断代码。
核心思路
- 定义通用
Validator接口,统一验证行为; - 为不同类型的字段/结构编写具体验证器(比如字符串非空验证、列表非空验证、嵌套结构验证等);
- 用Builder模式把这些验证器组装成完整的验证规则链,最后一键执行所有验证。
代码实现示例
首先定义基础Validator接口:
public interface Validator { void validate(Map<String, Object> data) throws Exception; }
然后编写具体验证器实现:
// 验证字符串非空且不为空串 public class NotEmptyStringValidator implements Validator { private final String fieldName; public NotEmptyStringValidator(String fieldName) { this.fieldName = fieldName; } @Override public void validate(Map<String, Object> data) throws Exception { String value = (String) data.get(fieldName); if (value == null || value.isEmpty()) { throw new Exception(String.format("字段'%s'不能为空或空字符串", fieldName)); } } } // 验证列表非空且不为空集合 public class NotEmptyListValidator implements Validator { private final String fieldName; public NotEmptyListValidator(String fieldName) { this.fieldName = fieldName; } @Override public void validate(Map<String, Object> data) throws Exception { List<Object> value = (List<Object>) data.get(fieldName); if (value == null || value.isEmpty()) { throw new Exception(String.format("字段'%s'不能为空或空列表", fieldName)); } } } // 验证嵌套Map及内部字段 public class NestedMapValidator implements Validator { private final String parentField; private final List<Validator> nestedValidators; public NestedMapValidator(String parentField, List<Validator> nestedValidators) { this.parentField = parentField; this.nestedValidators = nestedValidators; } @Override public void validate(Map<String, Object> data) throws Exception { Map<String, Object> nestedMap = (Map<String, Object>) data.get(parentField); if (nestedMap == null || nestedMap.isEmpty()) { throw new Exception(String.format("嵌套字段'%s'不能为空或空Map", parentField)); } // 执行嵌套字段的验证 for (Validator validator : nestedValidators) { validator.validate(nestedMap); } } } // 验证数值非空 public class NotNullNumberValidator implements Validator { private final String fieldName; public NotNullNumberValidator(String fieldName) { this.fieldName = fieldName; } @Override public void validate(Map<String, Object> data) throws Exception { Number value = (Number) data.get(fieldName); if (value == null) { throw new Exception(String.format("字段'%s'不能为空", fieldName)); } } }
接着用Builder模式封装验证规则的组装:
public class ValidationBuilder { private final List<Validator> validators = new ArrayList<>(); public ValidationBuilder addNotEmptyString(String fieldName) { validators.add(new NotEmptyStringValidator(fieldName)); return this; } public ValidationBuilder addNotEmptyList(String fieldName) { validators.add(new NotEmptyListValidator(fieldName)); return this; } public ValidationBuilder addNestedMap(String parentField, ValidationBuilder nestedBuilder) { validators.add(new NestedMapValidator(parentField, nestedBuilder.validators)); return this; } public ValidationBuilder addNotNullNumber(String fieldName) { validators.add(new NotNullNumberValidator(fieldName)); return this; } public void validate(Map<String, Object> data) throws Exception { for (Validator validator : validators) { validator.validate(data); } } }
最后使用Builder完成验证:
// 构建验证规则链 ValidationBuilder validation = new ValidationBuilder() .addNotEmptyString("productName") .addNotEmptyString("offerStartDate") .addNotEmptyList("offerAttributes") .addNestedMap("offerSpecifications", new ValidationBuilder().addNotNullNumber("price")); // 执行验证 Map<String, Object> map = mapper.readValue(json, Map.class); validation.validate(map);
2. 可选方案:使用注解+反射(结合成熟框架)
如果不想手动实现验证器,也可以用Hibernate Validator这类框架,通过注解快速定义验证规则:
- 先创建与JSON结构对应的Java实体类,给字段添加
@NotNull、@NotEmpty、@Valid(用于嵌套验证)等注解; - 直接用框架的Validator验证实体对象,无需手写大量判断逻辑。
示例实体类:
public class Offer { @NotNull @NotEmpty private String productName; @NotNull @NotEmpty private String offerStartDate; @NotNull @NotEmpty private List<OfferAttribute> offerAttributes; @NotNull @Valid private OfferSpecifications offerSpecifications; // Getters & Setters } public class OfferAttribute { @NotNull @NotEmpty private String id; // 其他字段... } public class OfferSpecifications { @NotNull private BigDecimal price; }
验证代码:
ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); Validator validator = factory.getValidator(); Offer offer = mapper.readValue(json, Offer.class); Set<ConstraintViolation<Offer>> violations = validator.validate(offer); if (!violations.isEmpty()) { throw new ConstraintViolationException(violations); }
这种方式代码量极少,适合复杂结构的验证,唯一的小成本是引入第三方框架依赖。
内容的提问来源于stack exchange,提问作者User27854
相关产品推荐
相关产品推荐

