96SEO 2026-04-23 08:42 2
ZuoJava后端开发的朋友,大概dou经历过那种被各种非空判断支配的恐惧吧?尤其是当业务逻辑变得复杂起来比如“Ru果用户选择了A类型,那么B字段就必须填写,否则C字段又不Neng为空”。这种时候,代码里那一坨像乱麻一样的`if-else`判断,简直让人kan了想直接关掉IDE去喝杯咖啡压压惊。

说实话,我也见过太多项目里校验逻辑写得那叫一个随心所欲。有的小伙伴在Zuo字段内容校验时采用的依然是Zui原始的校验方式——获取字段内容,用 if-else 对内容进行验证。这种校验方式当然没问题,代码跑得通,但是维护起来简直是灾难。每一个应用软件dou离不开数据的校验,比如在提交表单时需要对用户提交的字段内容进行长度验证、非空验证等等。Ru果全塞在Controller里那业务代码还Nengkan吗?
今天咱们就来聊点高级的。我们不只聊怎么给单个字段加个`@NotNull`,我们要深入探讨一下如何创建跨字段必填校验注解。这不仅Neng解决Excel导入过程中的头疼问题,还Neng让你的实体类校验逻辑变得既优雅又高效。相信我,学会这一招,你的代码逼格瞬间提升好几个档次。
一、 为什么我们需要自定义校验?在Java开发过程中,我们经常会遇到需要对某些字段进行必填校验的情况。Spring Boot给我们提供了非常便捷的`@Valid`注解,配合`BindingResult`,Neng让我们从那一坨冗长的代码中解脱出来。但是标准的JSR-303注解只Neng针对单个字段生效。
现实业务往往没那么简单。举个栗子:你在Zuo一个用户注册的功Neng,注册方式有“手机号”和“邮箱”两种。这时候,你的要求是“手机号和邮箱至少填一个”。这种情况下你单独给`phone`加`@NotNull`不行,单独给`email`加也不行。这就是典型的跨字段校验场景。
再比如在处理Excel导入时若依这类框架虽然提供了基础支持,但一旦涉及到复杂的业务关联,默认的配置就不够kan了。常见错误现象层出不穷:用户输了一堆空格、换行符或全角空格,表单照样通过;或者用 JS 动态清空了输入框但没重置 validity 状态,导致后续提交跳过校验。这些坑,我dou踩过所以痛定思痛,决定把校验逻辑收拢起来。
二、 基础铺垫:元注解的那些事儿在动手写代码之前,咱们得先温习一下Java注解的“三驾马车”。要创建一个自定义注解,搞懂元注解是必修课。别担心,我不掉书袋,咱们用大白话讲。
2.1 @Target:这贴纸贴哪儿?`@Target`注解就像是说明书,告诉JVM你这个自定义注解到底是用来修饰什么的。是放在方法头上?还是放在字段边上?或者是类上面?
比如我们之前kan到的`@Target`,意思就是这个注解只Neng用在方法上。而Ru果我们想Zuo一个字段校验,通常我们会用到`ElementType.FIELD`,甚至为了Zuo跨字段校验,我们可Neng需要用到`ElementType.TYPE`,也就是用在类级别,这样才Neng同时拿到类里的多个字段进行比对。
2.2 @Retention:这贴纸留多久?`@Retention`则是关于生命周期的。它决定了注解Neng活到什么时候。
SOURCE: 只在源码活着,编译完就没了。像`@Override`就是这种。
CLASS: 编译进class文件,但运行时读不到。默认是这个。
RUNTIME: 这才是我们的Zui爱!一直活到运行时这样我们才Neng通过反射去获取它,进行校验逻辑。
所以创建好的注解类,一般长这样:
@Target
@Retention
public @interface CrossFieldCheck {
// 后面细说这里面放啥
}
三、 动手实战:打造跨字段必填校验注解
好了热身结束,现在开始上干货。我们要实现的效果是:在一个实体类中,当字段A的值满足某个条件时字段B必须是必填的。
3.1 定义注解我们需要创建一个自定义注解来标记必填字段。这个注解不仅要Neng标记字段,还得Neng告诉我们“依赖谁”以及“满足什么条件”。
import java.lang.annotation.*;
@Target
@Retention
public @interface CrossFieldRequire {
/**
* 依赖的字段名
*/
String dependField;
/**
* 依赖字段的期望值,当依赖字段值等于此值时当前字段必填
*/
String dependValue;
/**
* 需要校验必填的目标字段名
*/
String targetField;
/**
* 错误提示信息
*/
String message default "关联字段校验失败";
}
你kan,这个注解是加在类上的,因为它要统筹全局。它记录了三个关键信息:我kan谁,它变成啥样我才管,我要管谁。
3.2 编写校验器注解只是个标签,干活还得靠“人”。在Java里这个“人”就是校验器。我们Ke以利用Spring的校验机制,或者干脆手写一个工具类,利用反射来搞定。
这里我演示一下通过反射获取实体字段的注解信息,并判断是否为必填字段的逻辑。这可是核心中的核心。
import org.springframework.util.StringUtils;
import java.lang.reflect.Field;
public class CrossFieldValidator {
public static void validate throws IllegalAccessException {
// 1. 获取类的字节码
Class> clazz = obj.getClass;
// 2. 检查类上有没有我们的自定义注解
if ) {
return; // 没加注解,直接放过
}
// 3. 获取注解实例
CrossFieldRequire annotation = clazz.getAnnotation;
// 4. 拿到配置的字段名
String dependFieldName = annotation.dependField;
String targetFieldName = annotation.targetField;
String expectedValue = annotation.dependValue;
// 5. 暴力反射获取字段值
Field dependField;
Field targetField;
try {
dependField = clazz.getDeclaredField;
targetField = clazz.getDeclaredField;
// 设置为可访问,哪怕是private的也Neng读
dependField.setAccessible;
targetField.setAccessible;
// 获取实际值
Object dependVal = dependField.get;
Object targetVal = targetField.get;
// 6. 核心判断逻辑
// Ru果依赖字段的值等于期望值,那么目标字段就不Neng为空
if .equals) {
if ))) {
// 抛出异常,或者收集错误信息
throw new RuntimeException);
}
}
} catch {
// 字段名写错了这里Zui好给个明确的提示
throw new RuntimeException;
}
}
}
这段代码的逻辑其实hen清晰:通过反射去“偷kan”对象里的值,然后比对。虽然反射这点开销换来代码的整洁度,绝对是划算的买卖。
四、 结合Excel导入实战:EasyPoi的坑与填坑文章开头提到了Excel导入。在处理Excel自定义注解添加必填校验时EasyPoi是个好帮手,但它也有自己的脾气。
hen多小伙伴在用EasyPoi导入Excel时发现`@Excel`注解里的`isImport`或者`verify`属性并不总是好使。特别是涉及到跨字段校验的时候,EasyPoi自带的验证机制就显得力不从心了。它geng多是关注单列的格式、长度。
这时候,我们上面写的那个`CrossFieldValidator`就派上用场了。
4.1 配置ImportParams在使用EasyPoi时我们通常会创建`ImportParams`对象。为了确保必填字段校验生效,开发者需要从实体类注解和导入参数配置两个方面进行正确设置。
ImportParams params = new ImportParams;
params.setNeedVerify; // 开启校验
// 其他配置...
但是`setNeedVerify`只Neng搞定基础的。对于我们的跨字段逻辑,我们需要在EasyPoi的校验器回调里或者是在导入完成后的数据处理循环里手动调用一下我们的工具类。
// 假设这是导入后的数据列表
List list = ExcelImportUtil.importExcel, YourEntity.class, params);
for {
try {
// 执行我们的跨字段校验
CrossFieldValidator.validate;
// 校验通过存库
saveToDb;
} catch {
// 校验失败,记录日志或抛出异常
log.error);
throw new ExcelImportException);
}
}
这样,Excel导入过程中实现字段必填项校验就变得非常灵活了。不管你的Excel逻辑多复杂,只要实体类上加个注解,校验逻辑自动生效。
五、 避开那些常见的坑写了这么多代码,要是Zui后因为几个小细节导致线上出Bug,那可就太冤了。这里有几个前辈们用血泪换来的经验,大家务必记在小本本上。
5.1 空格的陷阱用户输入数据时手抖多打个空格太正常了。Ru果前端没Zuotrim,后端又没Zuotrim,就会出现“kan起来有值,实际是空格”的情况。比如用户输了一堆空格、换行符或全角空格,表单照样通过。这绝对是个大坑。
所以在校验器里判断字符串的时候,Zui好用`StringUtils.isEmpty`或者手动trim一下。别太相信用户的输入素质。
5.2 状态重置问题Ru果是前后端交互,用JS动态清空了输入框但没重置 validity 状态,导致后续提交跳过校验。这虽然主要是前端的问题,但作为后端开发,我们得守住Zui后一道防线。永远不要因为“前端Yi经校验过了”就放松警惕。后端必须要有自己的一套完整校验体系。
5.3 性Neng考量虽然我们一直在说反射好,但凡事过犹不及。Ru果你在一个超高频、大并发的接口里每次请求dou通过反射去解析注解、获取字段,那CPU可Neng会报警。
优化方案是:在项目启动时或者第一次调用时把类的结构、字段映射关系缓存到Map里。后续校验直接从Map里拿Field对象,而不是每次dou`getDeclaredField`。这个优化Zuo不Zuo,取决于你的业务量级,但知道这一点,说明你Yi经是资深玩家了。
从Zui原始的`if-else`,到Spring Boot的`@Valid`,再到我们今天实现的跨字段必填校验注解,其实是一个代码不断抽象、不断解耦的过程。
本文介绍了如何在Java实体类中设置和校验必填字段,并提供相应的代码示例。我们不仅解决了单个字段的非空问题,还通过自定义注解和反射,优雅地处理了“字段A依赖字段B”这种复杂场景。无论是在普通的表单提交,还是在Excel导入这种复杂的业务中,这套方案douNeng游刃有余。
设计实体类时我们常常要求某些字段是必填的,也就是说这些字段在创建对象时必须要有值。而通过注解的方式,我们将这种约束从业务代码中剥离出来让代码geng加纯粹,geng加专注于业务逻辑本身。
希望这篇文章Neng帮到那些还在为校验逻辑头疼的小伙伴。别让那些繁琐的`if-else`消磨了你的热情,把时间花在geng有价值的逻辑实现上吧!Ru果大家在实践过程中遇到什么问题,或者有geng好的方案,欢迎在社区里一起交流,毕竟独乐乐不如众乐乐嘛。
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback