当前位置: 首页 > ai >正文

【结合JSR380自定义校验】

根据你提供的代码,NEbServiceAreaDto 类继承自 EbServiceArea 并包含了一些额外的字段和嵌套对象列表(ebServiceAreaRegionListebServiceAreaSupplierList)。这些嵌套对象也有各自的校验注解。接下来,我会基于你的需求提供一些建议,确保在不同场景下都能正确地进行参数校验。

✅ 一、你的理解完全正确!

  1. Validator.validate() 的前提条件:
    是的!只有在实体类字段上使用了校验注解(如 @NotBlank, @NotNull 等)时,Validator.validate(dto) 才能生效。

比如你在 NEbServiceAreaDto 上写了:

@NotBlank(message = "服务范围代码不能为空")
private String serviceAreaCode;

那么当你调用:

validator.validate(nEbServiceAreaDto);
这个字段为空时,就会触发错误信息。

1. 本地调用时的手动校验

既然你提到希望在 Service 层中直接调用而不是通过 Controller 来触发校验逻辑,那么你需要手动处理校验逻辑。以下是几种实现方法:

方法一:使用 Validator 进行校验
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.ConstraintViolation;
import java.util.Set;@Service
public class EbServiceAreaService {private final Validator validator;public EbServiceAreaService() {ValidatorFactory factory = Validation.buildDefaultValidatorFactory();validator = factory.getValidator();}public JsonResponse saveServiceArea(NEbServiceAreaDto nEbServiceAreaDto) {// 手动校验Set<ConstraintViolation<NEbServiceAreaDto>> violations = validator.validate(nEbServiceAreaDto);if (!violations.isEmpty()) {String errorMsg = violations.stream().map(ConstraintViolation::getMessage).collect(Collectors.joining("; "));return JsonResponse.fail(errorMsg);}// 校验嵌套对象列表for (EbServiceAreaRegion region : nEbServiceAreaDto.getEbServiceAreaRegionList()) {Set<ConstraintViolation<EbServiceAreaRegion>> regionViolations = validator.validate(region);if (!regionViolations.isEmpty()) {String errorMsg = regionViolations.stream().map(ConstraintViolation::getMessage).collect(Collectors.joining("; "));return JsonResponse.fail(errorMsg);}}for (EbServiceAreaSupplier supplier : nEbServiceAreaDto.getEbServiceAreaSupplierList()) {Set<ConstraintViolation<EbServiceAreaSupplier>> supplierViolations = validator.validate(supplier);if (!supplierViolations.isEmpty()) {String errorMsg = supplierViolations.stream().map(ConstraintViolation::getMessage).collect(Collectors.joining("; "));return JsonResponse.fail(errorMsg);}}// 后续业务逻辑...return JsonResponse.success("成功");}
}
方法二:封装校验工具类

为了简化校验逻辑,可以将校验逻辑封装到一个工具类中:

import javax.validation.Validator;
import javax.validation.Validation;
import javax.validation.ConstraintViolation;
import java.util.Set;
import java.util.stream.Collectors;@Component
public class DtoValidator {private final Validator validator;public DtoValidator() {ValidatorFactory factory = Validation.buildDefaultValidatorFactory();validator = factory.getValidator();}public <T> void validate(T dto) throws IllegalArgumentException {Set<ConstraintViolation<T>> violations = validator.validate(dto);if (!violations.isEmpty()) {String errorMsg = violations.stream().map(ConstraintViolation::getMessage).collect(Collectors.joining("; "));throw new IllegalArgumentException(errorMsg);}}
}

然后在 Service 中使用这个工具类:

@Service
public class EbServiceAreaService {@Autowiredprivate DtoValidator dtoValidator;public JsonResponse saveServiceArea(NEbServiceAreaDto nEbServiceAreaDto) {try {dtoValidator.validate(nEbServiceAreaDto);for (EbServiceAreaRegion region : nEbServiceAreaDto.getEbServiceAreaRegionList()) {dtoValidator.validate(region);}for (EbServiceAreaSupplier supplier : nEbServiceAreaDto.getEbServiceAreaSupplierList()) {dtoValidator.validate(supplier);}} catch (IllegalArgumentException e) {return JsonResponse.fail(e.getMessage());}// 后续业务逻辑...return JsonResponse.success("成功");}
}

2. Feign 调用时的注意事项

如果你确实需要通过 Feign 调用该接口,那么请注意以下几点:

  • 确保接口暴露了 HTTP 接口:只有当 /v1/save-service-area 是一个独立的服务并且可以通过 HTTP 访问时,才能使用 Feign 调用。
  • Feign Client 配置:定义 Feign Client 并配置好服务名和路径。
@FeignClient(name = "service-b", path = "/api")
public interface ServiceBClient {@PostMapping("/v1/save-service-area")JsonResponse saveServiceArea(@RequestBody NEbServiceAreaDto dto);
}
  • Controller 层的校验依然有效:当你通过 Feign 调用该接口时,@Valid 注解依然会生效,因为它是 Spring MVC 的一部分。

3. 总结与建议

  • 如果是在同一个服务内部,建议直接调用 Service 方法,并手动添加校验逻辑。这样可以避免不必要的网络开销和延迟。
  • 如果确实需要跨服务调用,那么使用 Feign 是合适的,但请确保你已经正确配置了 Feign Client,并且目标服务的接口是公开可访问的。

通过上述方法,你可以确保无论是在本地调用还是通过 Feign 调用时,参数校验都能正常工作。如果你有更多具体的需求或问题,请随时告诉我!

=======================================================
好的!我们来结合你之前发给我的代码和问题,一步一步地解释清楚:


🧾 你的原始问题背景

你有一组 DTO 和实体类,结构如下:

NEbServiceAreaDto(主 DTO)

public class NEbServiceAreaDto extends EbServiceArea {@NotBlank(message = "服务范围代码不能为空")private String serviceAreaCode;@NotBlank(message = "服务范围名称不能为空")private String serviceAreaName;@NotNull(message = "生效日期不能为空")private Date effectDate;@NotNull(message = "失效日期不能为空")private Date failureDate;@Validprivate List<EbServiceAreaRegion> ebServiceAreaRegionList;@Validprivate List<EbServiceAreaSupplier> ebServiceAreaSupplierList;
}

EbServiceAreaRegion(子对象)

public class EbServiceAreaRegion extends BaseDomain {@NotBlank(message = "区域地点类型不能为空")private String cterType;// 其他字段...
}

EbServiceAreaSupplier(子对象)

public class EbServiceAreaSupplier extends BaseDomain {@NotBlank(message = "承运商代码不能为空")private String supplierCode;@NotBlank(message = "承运商名称不能为空")private String supplierName;// 其他字段...
}

🚩 你遇到的问题

你说你在 Service 中调用了:

ebServiceAreaService.saveServiceArea(nEbServiceAreaDto);

而不是通过 Controller 的接口 /v1/save-service-area 来触发校验。

于是你担心:

Controller 上的 @Valid 校验是不是没生效?

是的,确实不会生效。因为 @Valid 是 Spring MVC 的功能,只在 HTTP 请求时起作用,不能跨方法、跨类自动生效


✅ 解决方案:手动添加校验逻辑

我们要做的就是:在 Service 层手动对 DTO 及其嵌套对象进行参数校验。

下面我用最清晰的方式,一步步写出完整代码并解释每一行的作用


✅ 第一步:注入 Validator

Spring Boot 默认已经集成了 Hibernate Validator,所以你可以直接注入使用:

@Service
public class EbServiceAreaService {@Autowiredprivate Validator validator; // 自动注入 Validator
}

✅ 第二步:定义保存方法

@Transactional(rollbackFor = Exception.class)
public JsonResponse saveServiceArea(NEbServiceAreaDto nEbServiceAreaDto) {// Step 1: 校验主 DTOSet<ConstraintViolation<NEbServiceAreaDto>> mainViolations = validator.validate(nEbServiceAreaDto);if (!mainViolations.isEmpty()) {String errorMsg = mainViolations.stream().map(v -> v.getMessage()).collect(Collectors.joining("; "));return JsonResponse.fail(errorMsg);}// Step 2: 校验嵌套列表 - ebServiceAreaRegionListfor (EbServiceAreaRegion region : CollectionUtil.emptyIfNull(nEbServiceAreaDto.getEbServiceAreaRegionList())) {Set<ConstraintViolation<EbServiceAreaRegion>> regionViolations = validator.validate(region);if (!regionViolations.isEmpty()) {String errorMsg = regionViolations.stream().map(v -> v.getMessage()).collect(Collectors.joining("; "));return JsonResponse.fail("区域信息校验失败:" + errorMsg);}}// Step 3: 校验嵌套列表 - ebServiceAreaSupplierListfor (EbServiceAreaSupplier supplier : CollectionUtil.emptyIfNull(nEbServiceAreaDto.getEbServiceAreaSupplierList())) {Set<ConstraintViolation<EbServiceAreaSupplier>> supplierViolations = validator.validate(supplier);if (!supplierViolations.isEmpty()) {String errorMsg = supplierViolations.stream().map(v -> v.getMessage()).collect(Collectors.joining("; "));return JsonResponse.fail("承运商信息校验失败:" + errorMsg);}}// Step 4: 执行业务逻辑(插入或更新)if (ObjectUtil.isEmpty(nEbServiceAreaDto.getId())) {Long count = this.insert(nEbServiceAreaDto);return JsonResponse.success(count);} else {int count = this.updateSelective(nEbServiceAreaDto);return JsonResponse.success(count);}
}

🔍 逐行解释说明

代码片段解释
Set<ConstraintViolation<NEbServiceAreaDto>> mainViolations = validator.validate(nEbServiceAreaDto);对主 DTO 进行校验,返回所有违反约束的错误
if (!mainViolations.isEmpty()) { ... }如果有错误,就收集提示信息并返回失败
for (EbServiceAreaRegion region : ...)遍历区域列表
validator.validate(region)对每个区域对象进行校验
return JsonResponse.fail(...)如果发现错误,立即中断流程并返回错误信息
this.insert(...) / this.updateSelective(...)没有错误的话,继续执行业务逻辑

✅ 工具类说明(可选)

  • CollectionUtil.emptyIfNull(...):防止空指针异常,如果 list 为 null 返回一个空集合。
  • ObjectUtil.isEmpty(...):Apache Commons 或 Hutool 提供的工具类,用于判断对象是否为空。

如果你没有这些工具类,可以换成:

if (nEbServiceAreaDto.getEbServiceAreaRegionList() == null || nEbServiceAreaDto.getEbServiceAreaRegionList().isEmpty()) {// 处理空的情况
}

✅ 最后总结一句话:

当你在 Service 中直接调用 saveServiceArea(dto) 而不是走 HTTP 接口时,Controller 上的 @Valid 不会生效。你需要自己手动调用 Validator.validate() 来完成校验,包括嵌套对象。


🎯 建议你这样做:

  1. 把上面这段校验代码复制到你的项目中。
  2. 确保你引入了 spring-boot-starter-validation 依赖(Spring Boot 默认已包含)。
  3. 在测试的时候故意传空值(比如空的 serviceAreaCode),看看能不能正确返回提示。
  4. 后续如果有多个类似的 DTO,可以把校验封装成一个通用方法。

如果你希望我帮你:

  • 封装成一个通用的校验工具类
  • 支持嵌套 List、Map 等复杂结构
  • 使用分组校验(Group Validation)
  • 结合统一异常处理器(@ControllerAdvice)

欢迎继续问我,我可以一步步带你实现 😊

http://www.xdnf.cn/news/13950.html

相关文章:

  • Altera系列FPGA基于ADV7180解码PAL视频,纯verilog去隔行,提供2套Quartus工程源码和技术支持
  • 智慧物流园区——解读华为智慧物流园区解决方案【附全文阅读】
  • 上海市计算机学会竞赛平台2022年4月月赛丙组圆环独立集(一)
  • 基于 Spring Cloud Gateway + Sentinel 实现高并发限流保护机制
  • PHP基础-控制结构
  • 全链路实时感知:网络专线端到端监控运维
  • SwiftUI隐藏返回按钮保留右滑手势方案
  • MyBatis原理
  • 关于阿里云-云消息队列MQTT的连接和使用,以及SpringBoot的集成使用
  • P8784 [蓝桥杯 2022 省 B] 积木画
  • 基于 STM32 七段数码管显示模块详解
  • 如何设置爬虫的访问频率?
  • 基于51单片机的直流电机运动控制proteus仿真
  • vue二级路由的写法,以及动态路由的匹配和获取动态参数的值
  • FreeSWITCH mod_curl 和 mod_xml_rpc 测试
  • JVM 内存、JMM内存与集群机器节点内存的联系
  • 【redis——缓存穿透】
  • 基于PSO粒子群优化的VMD-LSTM时间序列预测算法matlab仿真
  • git 下载安装并连接gitee
  • 一键给你的网页增加 ios26 液态玻璃效果
  • Android 手机如何实现本地视频音频提取?实战教程来了
  • 提示词Prompts(2)
  • 提示词Prompts(1)
  • iOS-SM3加密算法N种集成
  • MySql基础教程:事务基础知识
  • 通信安全员A,B,C证有什么区别?
  • 一文讲清网络变压器、芯片和 RJ45 之间的接线
  • WebView工作原理全解析:如何实现混合开发的无缝衔接
  • python transformers库笔记(BertTokenizerFast类)
  • 高频面试之12 HBase