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

【结合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)

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

相关文章:

  • 神经网络压缩
  • PHP基础-运算符
  • 用AI思维重塑人生:像训练神经网络一样优化自己
  • Java EE 导读
  • 【Create my OS】1 最小内核
  • MySQL-DDL语句深度解析与实战指南
  • Web开发实战:Gin + GORM 构建企业级 API 项目
  • RabbitMQ的使用--项目创建、五种工作模式、高级特性
  • Blender 4.4.3三维动画建模和渲染软件Win/Mac双端资源下载
  • 在Jupyter Notebook中使用Conda虚拟环境
  • 芯科科技携最新Matter演示和参考应用精彩亮相Matter开放日和开发者大会
  • 论文阅读:arxiv 2025 Chain of Draft: Thinking Faster by Writing Less
  • Node.js 检测视频链接是否可以播放(批量检测)
  • CSS a标签内文本折行展示
  • 论文阅读:arxiv 2025 Not All Tokens Are What You Need In Thinking
  • 用 HTML、CSS 和 JavaScript 实现五子棋人机对战游戏
  • 【61 Pandas+Pyecharts | 基于Apriori算法及帕累托算法的超市销售数据分析可视化】
  • CIM和建筑风貌管控平台
  • 【QSoundEffect QT 音频文件的播放】
  • 第10章 语句 笔记 待完善
  • 做最好的色书网站/百度推广托管
  • 长沙网站建设icp备/电商seo名词解释
  • 广州网站建设团队/百度收录的网页数量
  • 郑州本地做团购的网站/百度权重划分等级
  • 宾阳网站建设/俄罗斯搜索引擎浏览器官网入口
  • 辽宁做网站和优化哪家好/最全bt搜索引擎入口