校验参数的6大神功!

360影视 日韩动漫 2025-05-15 22:16 1

摘要:public class UserDTO { @NotBlank(message = "名称要填,皮这一下很开心?") private String name; @NotNull @Min(value = 18, message = "未成年禁止入内") @M

新手司机翻车实录

"哥,注册接口又被刷爆了!

"某一个周末下午,我接到电话,打开日志一看,NullPointerException堆栈里有38个不同位置的校验逻辑。

原来新人小王在Controller里写满了这样的代码:

// 典型错误示范(转载自某小厂祖传代码)public String register(UserDTO user) { if (user.getName == null) { return "名字不能为空"; } if (user.getAge == null) { return "年龄不能为空"; } if (user.getAge

这才是代码界的"九转大肠"——每个入口都让人窒息。

作为一位有很多开发经验的老司机,今天,老夫带你修炼参数校验的6大神功。

希望对你会有所帮助。

第一重:JSR规范基础功

1.1 HibernateValidator瞬炼大法

可以使用Hibernate中Validator框架做参数校验,具体代码如下:

public class UserDTO { @NotBlank(message = "名称要填,皮这一下很开心?") private String name; @NotNull @Min(value = 18, message = "未成年禁止入内") @Max(60) private Integer age; @Pattern(regexp = "^1[3-9]\\d{9}$", message = "这手机号是哪国来的?") private String phone;}// Controller层启用校验(新手必知第一步)@PostMapping("/register")public Result register(@Valid @RequestBody UserDTO user) { // 业务代码...}

我们需要对异常进行统一拦截。

这样在出现参数校验异常,比如空指针时,不会把服务的内部错误信息直接输出给用户。

通过@RestControllerAdvice和@ExceptionHandler注解实现统一异常拦截器的功能。

具体代码如下:

@RestControllerAdvicepublic class GlobalExceptionHandler { // 专治各种不服校验 @ExceptionHandler(MethodArgumentNotValidException.class) public Result handleValidException(MethodArgumentNotValidException e) { BindingResult result = e.getBindingResult; return Result.fail(result.getFieldError.getDefaultMessage); }}// 返回格式规范(示例)public class Result { private Integer code; private String msg; private T data; public static Result fail(String message) { return new Result(500, message, null); }}

有时候,Hibernate Validator框架或者其他校验框架定义的校验不满足需求,我们需要自定义校验规则。

则可以自定义注解,实现ConstraintValidator接口,来实现具体的自定义的校验逻辑。

自定义注解@Contact在字段上使用。

具体代码如下:

@Target({FIELD, PARAMETER})@Retention(RUNTIME)@Constraint(validatedBy = ContactValidator.class)public @interface Contact { String message default "联系方式格式错误"; Class groups default {}; Class payload default {};}// 校验逻辑实现(不要相信前端的下拉框!)public class ContactValidator implements ConstraintValidator { private static final Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$"); private static final Pattern EMAIL_PATTERN = Pattern.compile("^\\w+@\\w+\\.\\w+$"); @Override public boolean isValid(String value, ConstraintValidatorContext context) { return PHONE_PATTERN.matcher(value).matches || EMAIL_PATTERN.matcher(value).matches; }}

对于增删改查中,对于实体对象中的同一个参数,在不同的应用场景中需要做不同分组校验。

具体代码如下:

// 定义校验组别(划分阵营)public interface CreateGroup {}public interface UpdateGroup {}// DTO根据场景应用分组public class ProductDTO { @Null(groups = UpdateGroup.class) @NotNull(groups = CreateGroup.class) private Long id; @NotBlank(groups = {CreateGroup.class, UpdateGroup.class}) private String name;}// 控制层按需激活校验组 @PostMapping("/create")public Result create(@Validated(CreateGroup.class) @RequestBody ProductDTO dto) { // 创建逻辑}

如果存在跨字段关系校验的情况,即组合条件校验,比如:用户密码和确认密码,可以将自定义注解作用在类上。

具体代码如下:

@Target(TYPE)@Retention(RUNTIME)@Constraint(validatedBy = PasswordValidator.class)public @interface PasswordValid { String message default "两次密码不一致"; // ...}public class PasswordValidator implements ConstraintValidator { @Override public boolean isValid(UserDTO user, ConstraintValidatorContext context) { return user.getPassword.equals(user.getConfirmPassword); }}// 应用到类级别@PasswordValidpublic class UserDTO { private String password; private String confirmPassword;}

风控新法

适用于订单金额与优惠券匹配等业务规则DDD值对象的天然场景

第六重:规则引擎之天机策

天机殿的自动化战场

新来的产品小妹指着参数校验文档:"每次改个手机号正则都要等发版?

"我默默掏出了祖传的规则引擎。

这种政商联动的需求,是时候施展大型工程的必杀技了!

6.1 规则引擎的三层境界

第一境:硬编码校验(青铜段位的if-else)第二境:配置化校验(黄金段位的数据库规则表)第三境:热力场作战(王者段位的动态规则引擎)

6.2 Drools天机大阵部署实录

战场场景:信贷额度动态校验(每小时调整风控模型) 。

天机规则文件如下:

// 天机规则文件(credit_rule.drl)rule "白领贷基础校验" when $req : LoanRequest( occupation == "白领", salary > 10000, age >= 25 && age

布阵心法

阵法要诀

规则文件按业务线拆分(金融/电商/社交各立山头)使用kie-maven-plugin自动编译规则文件KieScanner监听规则变更(天机更新不重启服务)

6.3 SpringBoot接引天机大阵

法咒集成

@Configurationpublic class DroolsConfig { @Bean public KieContainer kieContainer { KieServices ks = KieServices.Factory.get; KieFileSystem kfs = ks.newKieFileSystem; // 加载天机卷轴(规则文件) Resource resource = new ClassPathResource("rules/credit_rule.drl"); kfs.write(ks.getResources.newInputStreamResource(resource.getInputStream) .setTargetPath("credit_rule.drl")); KieBuilder kieBuilder = ks.newKieBuilder(kfs).buildAll; return ks.newKieContainer(kieBuilder.getKieModule.getReleaseId); }}// Controller层调用天尊之力@PostMapping("/apply")public Result applyLoan(@RequestBody LoanRequest request) { kieSession.insert(request); kieSession.fireAllRules; // 执行天机推演 return riskService.process(request);}

天机沙箱防御

限制规则中eval的使用次数(防CPU过载)为每个请求创建独立KieSession(防线程污染)设置规则执行超时熔断(天机殿也有算不动的时候)

6.4 天机策反制诀窍

某次上线后,规则引擎的神操作:

rule "特殊时段放水" when $req : LoanRequest(hour > 2 && hour

反制方案

规则提交走审批流(太上长老团联署制)生产环境禁用update/modify关键字(防自动夺舍)规则版本回滚机制(祭出玄天宝镜倒转时空)段位招式名称修炼难度适用场景破坏力青铜if-else硬编码★☆☆小型工具类⚡⚡⚡白银JSR注解大法★★☆常规CRUD⚡⚡黄金全局异常拦截★★★RESTful API⚡铂金定制校验规则★★★☆复杂业务规则⚡钻石组合条件校验★★★★跨字段业务约束⚡王者规则引擎整合★★★★★动态风控场景✨不过三:Controller层校验不要超过三层(应该转给Service)见好就收:业务规则校验与基础格式校验分离防君子更防小人:服务端校验必须存在(前端校验是防君子用的)语义明确:错误提示避免暴露敏感信息(比如"用户不存在"改为"账号或密码错误")

最后提醒各位大侠:好的参数校验就像空气——你平时感受不到它的存在,但一旦失去它,整个系统瞬间崩塌!(代码fields正提刀赶来)

来源:墨码行者

相关推荐