文章目录
再项目开发中,针对前端传递的参数信息,有些接口中需要写大量的if判断,导致代码臃肿,不够优雅。
此时,可以使用@Valid实现基本的字段校验。
spring-boot-starter-web中。spring-boot-starter-validation依赖信息springboot 2.1.4
如果你的springboot版本高于 2.3,需要额外引入下列依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
验证自带的注解,以及实现原理,可以移步到我的另一篇博客中,本篇博客不做过多的阐述。
官方提供的一些常用的注解,有时候并不能适合所有的开发需求。此时可以采取自定义valid的方式,实现其应有的功能。
创建一个自定义的注解
检查排序号是否输入,以及是否满足要求。
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Constraint(validatedBy = POrderParse.class) // 注解对应的处理类
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface POrder {
// 默认提示语句
String message() default "排序号不允许为空,且只允许是1到20的数字!";
// 默认校验正则表达式
String regexp() default "^([1-9])|([1]\\d)|20$";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
定义注解后,还需要定义其指定的处理类,如下所示:
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorContextImpl;
import org.springframework.stereotype.Component;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Component
public class POrderParse implements ConstraintValidator<POrder,Object> {
@Override
public void initialize(POrder constraintAnnotation) {
System.out.println("my para order validator init");
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
// 校验逻辑
ConstraintValidatorContextImpl con = (ConstraintValidatorContextImpl) context;
// 获取注解中的属性值
Map<String, Object> maps = con.getConstraintDescriptor().getAttributes();
// 获取设置的或者默认的正则表达式
String regexp = (String) maps.get("regexp");
// 获取数据值
String param = String.valueOf(value);
// 正则判断
Pattern regexpVo = Pattern.compile(regexp);
Matcher matcher = regexpVo.matcher(param);
return matcher.matches();
}
}
import cn.xj.bi.volid.MyPhone;
import cn.xj.bi.volid.POrder;
import lombok.Data;
@Data
public class User {
@POrder
private Integer order;
}
创建一个测试接口,进行应用测试。
需要使用到
@Valid注解标识
@RestController
@RequestMapping("/test1")
@Api(tags = "测试")
public class TestController {
@PostMapping("/demo4")
@ApiOperation(value = "demo4")
public CommonResult<String> test4(@RequestBody @Valid User user){
return CommonResult.success("6666");
}
)
启动项目,进入swagger进行请求测试。
传递满足正则要求的值,查看返回结果信息。
{
"order": 10
}

参数中传递一个不满足正则表达式的值,观察返回信息。
{
"order": 0
}

每次返回这样的报错信息不够直观,此时可以自定义全局异常监听,如下所示:
import cn.xj.bi.vo.CommonResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.Objects;
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public CommonResult handleScopeFiledException(MethodArgumentNotValidException e) {
log.error("字段合法性校验异常:[{}]", e.getMessage());
// getFieldError() 和 getDefaultMessage() 的区别
return CommonResult.error( Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage(), null);
}
}
重启项目,再次异常测试:

递归参数的意思就是接收对象是一个类,假设是DataScope,但是在这个接收类中,还有一个List<User>这个参数变量,并且User中依旧还含有需要valid校验的字段属性。
再自定义一个valid注解,如下所示:
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Constraint(validatedBy = {MyPhoneValidtor.class})
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyPhone {
String message();
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
valid注解具体处理类:
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class MyPhoneValidtor implements ConstraintValidator<MyPhone,Object> {
@Override
public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
System.out.println("校验");
// 故意返回false,触发异常
return false;
}
}
然后再请求参数接收对象中,定义如下格式:
import cn.xj.bi.volid.POrder;
import lombok.Data;
@Data
public class User {
@POrder
private Integer order;
private Address address;
}
import cn.xj.bi.volid.MyPhone;
import lombok.Data;
import java.io.Serializable;
@Data
public class Address implements Serializable {
@MyPhone(message = "这只是一个测试")
private String phoneNum;
}
重启项目,传递正常的 order 值,观察Address 类中的 phoneNum 是否触发valid校验。
{
"order": 10,
"address":{
"phoneNum":""
}
}

发现并未触发对应的valid校验。
解决方式很简单,没有触发说明注解无效,接口中定义@Valid User 是对user对象进行valid处理,但对象类型的并不在列,只需要在对象类型的变量上增加@Valid注解即可。
import cn.xj.bi.volid.POrder;
import lombok.Data;
import javax.validation.Valid;
@Data
public class User {
@POrder
private Integer order;
@Valid // 迭代valid
private Address address;
}
重启项目,继续按照上面的传参,观察响应信息。

我正在尝试设置一个puppet节点,但rubygems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由rubygems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss
我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun
我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr
我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin
我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano
我使用Ember作为我的前端和GrapeAPI来为我的API提供服务。前端发送类似:{"service"=>{"name"=>"Name","duration"=>"30","user"=>nil,"organization"=>"org","category"=>nil,"description"=>"description","disabled"=>true,"color"=>nil,"availabilities"=>[{"day"=>"Saturday","enabled"=>false,"timeSlots"=>[{"startAt"=>"09:00AM","endAt"=>
我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c