提交表单,要写点严谨的代码,前后台验证是少不了的,前台页面可以使用JQuery等插件进行验证,后台验证,如果一句一句地判断,那太苦力了,特别是对于一个复杂的表单,后期的维护也是个很大的问题。
javax.validation使用注解便可实现既轻松又优雅的验证,维护起来也特别方便。下面就来看看如何使用javax.validation验证吧,为了方便测试,再省点页面上的代码,这里使用了swagger-ui来代替前台页面提交数据,下面直接上代码。
添加依赖
首先,在pom.xml文件中引入必要的架包;
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- swagger RESTful API 文档 --><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version></dependency><!-- swagger ui --><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.2.2</version></dependency><!-- javax.validation --><dependency><groupId>javax.validation</groupId><artifactId>validation-api</artifactId></dependency><!-- com.fasterxml --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></dependency>
创建测试类
第二步,创建一个测试实体类,把验证注解加上去;
import java.math.BigDecimal;import java.util.Date;import javax.validation.constraints.AssertTrue;import javax.validation.constraints.DecimalMax;import javax.validation.constraints.Digits;import javax.validation.constraints.Email;import javax.validation.constraints.Max;import javax.validation.constraints.Min;import javax.validation.constraints.NotBlank;import javax.validation.constraints.NotEmpty;import javax.validation.constraints.NotNull;import javax.validation.constraints.Null;import javax.validation.constraints.Past;import javax.validation.constraints.Pattern;import javax.validation.constraints.Size;import org.hibernate.validator.constraints.Length;import org.hibernate.validator.constraints.Range;import org.springframework.format.annotation.DateTimeFormat;import com.example.demo.validator.Mobile;import com.fasterxml.jackson.annotation.JsonFormat;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;/*** 用户实体类* @author clown* @Date*/@ApiModel(value = "用户信息")public class UserInfo {@NotNull(message = "用户uid不能为空!")private String userUid;@NotEmpty(message = "用户密码不能为空!")@Size(min=6, max=15,message="密码长度必须在 6 ~ 15 字符之间!")@Pattern(regexp="^[a-zA-Z0-9|_]+$",message="密码必须由字母、数字、下划线组成!")private String userPwd;@NotBlank(message = "用户名不能为空")@Size(min=2, max=20,message="用户名必须在 2 ~ 20 字符之间!")private String userName;@Range(min=1, max=100,message="编码必须在 1 ~ 100 之间!")private int code;@Min(value=0,message="最小必须是0")@Max(value=1,message="最大不能超过1")private Byte sex;private String familyAddr;@Mobile@ApiModelProperty(value = "用户手机号码")private String mobile;@Email(message = "邮箱格式错误!")@Length(min=5, max=100,message="邮箱必须在 5 ~ 100 字符之间!")private String email;private String idCard;@DateTimeFormat(pattern="yyyy-MM-dd")@JsonFormat( pattern="yyyy-MM-dd", timezone = "GMT+8")@Past(message="不能大于当前年月日")private Date birthday;@NotNull(message="家庭金额不能为空!")@Digits(integer=5, fraction=2, message="家庭资金必须是5位整,2位小数!")@ApiModelProperty(value = "家庭金额")private Double familyMonney;@AssertTrue(message="状态必须正常!")@ApiModelProperty(value = "身体健康状态")private boolean status;@Null(message="初始金额必须为空!")private Double originMonney;@DecimalMax(value="999999999.00",message="我的金额不能超过999999999.00")private BigDecimal myMoney;/**get、set 方法省略**/}
注意:上面的注解大部分都是javax.validation架包里面的;
@ApiModel、@ApiModelProperty是swagger-ui里面的注解;
@DateTimeFormat(pattern=”yyyy-MM-dd”) 来自于org.springframework.format.annotation.DateTimeFormat,这个注解也很常用,主要用来接收前台传过来的格式化的日期;
@JsonFormat(pattern=”yyyy-MM-dd”, timezone = “GMT+8”)来自于com.fasterxml.jackson.annotation.JsonFormat,这个注解也很常用,主要是把后台的日期类型的数据转换成格式化过的字符串数据。
加入自定义注解
第三步,在上面的实体类中,@Mobile是自定义的注解,在这里实现如下;
import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import javax.validation.Constraint;import javax.validation.Payload;/*** 验证手机号码的注解类* @author clown* @Date*/@Target({ElementType.METHOD, ElementType.FIELD})@Retention(RetentionPolicy.RUNTIME)@Constraint(validatedBy=MobileValidator.class) //对应的验证实现类public @interface Mobile {//默认提示String message() default "手机号码格式错误!";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};}import java.util.regex.Pattern;import javax.validation.ConstraintValidator;import javax.validation.ConstraintValidatorContext;import org.springframework.util.StringUtils;/*** 验证手机号码的实现类* @author 程就人生* @Date*/public class MobileValidator implements ConstraintValidator<Mobile, String> {//验证手机的正则表达式private String mobileReg = "^1(3|4|5|7|8|9)\\d{9}$";private Pattern mobilePattern = Pattern.compile(mobileReg);public void initialize(Mobile mobile) {}public boolean isValid(String value, ConstraintValidatorContext arg1) {//为空时,不进行验证if (StringUtils.isEmpty(value))return true;//返回匹配结果return mobilePattern.matcher(value).matches();}}
在这里,手机号码的验证是自定义验证,也是用的比较多的验证,所以独立了出来,其他的验证,可以根据需要判断是否需要独立,这样方便后期的维护。
增加swagger配置
第四步,增加swagger-ui的配置;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import springfox.documentation.builders.ApiInfoBuilder;import springfox.documentation.builders.PathSelectors;import springfox.documentation.builders.RequestHandlerSelectors;import springfox.documentation.service.ApiInfo;import springfox.documentation.spi.DocumentationType;import springfox.documentation.spring.web.plugins.Docket;import springfox.documentation.swagger2.annotations.EnableSwagger2;/*** @author clown* @Date*/@Configuration@EnableSwagger2@ConditionalOnProperty(name = "swagger.enable", havingValue = "true")//@Profile({"dev","test"})public class Swagger2 {@SuppressWarnings("deprecation")@Beanpublic Docket createRestApi() {ApiInfo apiInfo = new ApiInfoBuilder().title("验证测试接口文档").description("App服务接口文档,严格遵循RESTful API设计规范。").contact("程就人生").version("1.0").build();return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo).select()//以扫描包的方式.apis(RequestHandlerSelectors.basePackage("com.example.demo.controller")).paths(PathSelectors.any()).build();}}import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.filter.HttpPutFormContentFilter;import org.springframework.web.servlet.config.annotation.EnableWebMvc;import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;/*** 允许访问swagger的静态页面* @author 程就人生* @Date*/@SuppressWarnings("deprecation")@Configuration@EnableWebMvcpublic class WebMvcConfig extends WebMvcConfigurerAdapter{// @Value("${spring.servlet.multipart.location}")// private String uploadPath;/*** PUT方式提交,无法获取参数* @return*/@Beanpublic HttpPutFormContentFilter httpPutFormContentFilter() {return new HttpPutFormContentFilter();}@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry){//测试环境图片地址映射,映射成url就可以访问的// registry.addResourceHandler("/images/**").addResourceLocations("file:" + uploadPath);registry.addResourceHandler("/swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");}}
注意:在application.properties配置文件中加上 swagger.enable=true,不然swagger-ui.html页面访问不了。
创建测试Controller
第五步,创建一个Controller,可以通过url访问,这里采用Restful命名风格;
import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.validation.BindingResult;import org.springframework.validation.annotation.Validated;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import com.example.demo.entity.UserInfo;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;/*** 用户测试用例* @author clown* @Date*/@Api(tags = "用户信息", description = "UserInfoController")@RestController@RequestMapping("/userInfo")public class UserInfoController {private static Logger log = LoggerFactory.getLogger(UserInfoController.class);@PostMapping@ApiOperation(value = "新增",notes="用户信息", httpMethod="POST")public UserInfo addUserInfo(@Valid UserInfo userInfo, BindingResult errors){//对表单进行验证if (errors.hasErrors()){//对错误集合进行遍历,有的话,直接放入map集合中errors.getFieldErrors().forEach(p->{throw new RuntimeException(p.getDefaultMessage());});}log.info("全部验证通过~!");return userInfo;}}
最后,启动项目访问测试
输入值
测试结果
