提交表单,要写点严谨的代码,前后台验证是少不了的,前台页面可以使用JQuery等插件进行验证,后台验证,如果一句一句地判断,那太苦力了,特别是对于一个复杂的表单,后期的维护也是个很大的问题。
javax.validation使用注解便可实现既轻松又优雅的验证,维护起来也特别方便。下面就来看看如何使用javax.validation验证吧,为了方便测试,再省点页面上的代码,这里使用了swagger-ui来代替前台页面提交数据,下面直接上代码。

添加依赖

首先,在pom.xml文件中引入必要的架包;

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-web</artifactId>
  4. </dependency>
  5. <!-- swagger RESTful API 文档 -->
  6. <dependency>
  7. <groupId>io.springfox</groupId>
  8. <artifactId>springfox-swagger2</artifactId>
  9. <version>2.9.2</version>
  10. </dependency>
  11. <!-- swagger ui -->
  12. <dependency>
  13. <groupId>io.springfox</groupId>
  14. <artifactId>springfox-swagger-ui</artifactId>
  15. <version>2.2.2</version>
  16. </dependency>
  17. <!-- javax.validation -->
  18. <dependency>
  19. <groupId>javax.validation</groupId>
  20. <artifactId>validation-api</artifactId>
  21. </dependency>
  22. <!-- com.fasterxml -->
  23. <dependency>
  24. <groupId>com.fasterxml.jackson.core</groupId>
  25. <artifactId>jackson-databind</artifactId>
  26. </dependency>

备注:架包加了不少,每个架包在后面都有特别的用处;

创建测试类

第二步,创建一个测试实体类,把验证注解加上去;

  1. import java.math.BigDecimal;
  2. import java.util.Date;
  3. import javax.validation.constraints.AssertTrue;
  4. import javax.validation.constraints.DecimalMax;
  5. import javax.validation.constraints.Digits;
  6. import javax.validation.constraints.Email;
  7. import javax.validation.constraints.Max;
  8. import javax.validation.constraints.Min;
  9. import javax.validation.constraints.NotBlank;
  10. import javax.validation.constraints.NotEmpty;
  11. import javax.validation.constraints.NotNull;
  12. import javax.validation.constraints.Null;
  13. import javax.validation.constraints.Past;
  14. import javax.validation.constraints.Pattern;
  15. import javax.validation.constraints.Size;
  16. import org.hibernate.validator.constraints.Length;
  17. import org.hibernate.validator.constraints.Range;
  18. import org.springframework.format.annotation.DateTimeFormat;
  19. import com.example.demo.validator.Mobile;
  20. import com.fasterxml.jackson.annotation.JsonFormat;
  21. import io.swagger.annotations.ApiModel;
  22. import io.swagger.annotations.ApiModelProperty;
  23. /**
  24. * 用户实体类
  25. * @author clown
  26. * @Date
  27. */
  28. @ApiModel(value = "用户信息")
  29. public class UserInfo {
  30. @NotNull(message = "用户uid不能为空!")
  31. private String userUid;
  32. @NotEmpty(message = "用户密码不能为空!")
  33. @Size(min=6, max=15,message="密码长度必须在 6 ~ 15 字符之间!")
  34. @Pattern(regexp="^[a-zA-Z0-9|_]+$",message="密码必须由字母、数字、下划线组成!")
  35. private String userPwd;
  36. @NotBlank(message = "用户名不能为空")
  37. @Size(min=2, max=20,message="用户名必须在 2 ~ 20 字符之间!")
  38. private String userName;
  39. @Range(min=1, max=100,message="编码必须在 1 ~ 100 之间!")
  40. private int code;
  41. @Min(value=0,message="最小必须是0")
  42. @Max(value=1,message="最大不能超过1")
  43. private Byte sex;
  44. private String familyAddr;
  45. @Mobile
  46. @ApiModelProperty(value = "用户手机号码")
  47. private String mobile;
  48. @Email(message = "邮箱格式错误!")
  49. @Length(min=5, max=100,message="邮箱必须在 5 ~ 100 字符之间!")
  50. private String email;
  51. private String idCard;
  52. @DateTimeFormat(pattern="yyyy-MM-dd")
  53. @JsonFormat( pattern="yyyy-MM-dd", timezone = "GMT+8")
  54. @Past(message="不能大于当前年月日")
  55. private Date birthday;
  56. @NotNull(message="家庭金额不能为空!")
  57. @Digits(integer=5, fraction=2, message="家庭资金必须是5位整,2位小数!")
  58. @ApiModelProperty(value = "家庭金额")
  59. private Double familyMonney;
  60. @AssertTrue(message="状态必须正常!")
  61. @ApiModelProperty(value = "身体健康状态")
  62. private boolean status;
  63. @Null(message="初始金额必须为空!")
  64. private Double originMonney;
  65. @DecimalMax(value="999999999.00",message="我的金额不能超过999999999.00")
  66. private BigDecimal myMoney;
  67. /**get、set 方法省略**/
  68. }

注意:上面的注解大部分都是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是自定义的注解,在这里实现如下;

  1. import java.lang.annotation.ElementType;
  2. import java.lang.annotation.Retention;
  3. import java.lang.annotation.RetentionPolicy;
  4. import java.lang.annotation.Target;
  5. import javax.validation.Constraint;
  6. import javax.validation.Payload;
  7. /**
  8. * 验证手机号码的注解类
  9. * @author clown
  10. * @Date
  11. */
  12. @Target({ElementType.METHOD, ElementType.FIELD})
  13. @Retention(RetentionPolicy.RUNTIME)
  14. @Constraint(validatedBy=MobileValidator.class) //对应的验证实现类
  15. public @interface Mobile {
  16. //默认提示
  17. String message() default "手机号码格式错误!";
  18. Class<?>[] groups() default {};
  19. Class<? extends Payload>[] payload() default {};
  20. }
  21. import java.util.regex.Pattern;
  22. import javax.validation.ConstraintValidator;
  23. import javax.validation.ConstraintValidatorContext;
  24. import org.springframework.util.StringUtils;
  25. /**
  26. * 验证手机号码的实现类
  27. * @author 程就人生
  28. * @Date
  29. */
  30. public class MobileValidator implements ConstraintValidator<Mobile, String> {
  31. //验证手机的正则表达式
  32. private String mobileReg = "^1(3|4|5|7|8|9)\\d{9}$";
  33. private Pattern mobilePattern = Pattern.compile(mobileReg);
  34. public void initialize(Mobile mobile) {
  35. }
  36. public boolean isValid(String value, ConstraintValidatorContext arg1) {
  37. //为空时,不进行验证
  38. if (StringUtils.isEmpty(value))
  39. return true;
  40. //返回匹配结果
  41. return mobilePattern.matcher(value).matches();
  42. }
  43. }


在这里,手机号码的验证是自定义验证,也是用的比较多的验证,所以独立了出来,其他的验证,可以根据需要判断是否需要独立,这样方便后期的维护。

增加swagger配置

第四步,增加swagger-ui的配置;

  1. import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import springfox.documentation.builders.ApiInfoBuilder;
  5. import springfox.documentation.builders.PathSelectors;
  6. import springfox.documentation.builders.RequestHandlerSelectors;
  7. import springfox.documentation.service.ApiInfo;
  8. import springfox.documentation.spi.DocumentationType;
  9. import springfox.documentation.spring.web.plugins.Docket;
  10. import springfox.documentation.swagger2.annotations.EnableSwagger2;
  11. /**
  12. * @author clown
  13. * @Date
  14. */
  15. @Configuration
  16. @EnableSwagger2
  17. @ConditionalOnProperty(name = "swagger.enable", havingValue = "true")
  18. //@Profile({"dev","test"})
  19. public class Swagger2 {
  20. @SuppressWarnings("deprecation")
  21. @Bean
  22. public Docket createRestApi() {
  23. ApiInfo apiInfo = new ApiInfoBuilder()
  24. .title("验证测试接口文档")
  25. .description("App服务接口文档,严格遵循RESTful API设计规范。")
  26. .contact("程就人生")
  27. .version("1.0")
  28. .build();
  29. return new Docket(DocumentationType.SWAGGER_2)
  30. .apiInfo(apiInfo)
  31. .select()
  32. //以扫描包的方式
  33. .apis(RequestHandlerSelectors.basePackage("com.example.demo.controller"))
  34. .paths(PathSelectors.any())
  35. .build();
  36. }
  37. }
  38. import org.springframework.context.annotation.Bean;
  39. import org.springframework.context.annotation.Configuration;
  40. import org.springframework.web.filter.HttpPutFormContentFilter;
  41. import org.springframework.web.servlet.config.annotation.EnableWebMvc;
  42. import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
  43. import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
  44. /**
  45. * 允许访问swagger的静态页面
  46. * @author 程就人生
  47. * @Date
  48. */
  49. @SuppressWarnings("deprecation")
  50. @Configuration
  51. @EnableWebMvc
  52. public class WebMvcConfig extends WebMvcConfigurerAdapter{
  53. // @Value("${spring.servlet.multipart.location}")
  54. // private String uploadPath;
  55. /**
  56. * PUT方式提交,无法获取参数
  57. * @return
  58. */
  59. @Bean
  60. public HttpPutFormContentFilter httpPutFormContentFilter() {
  61. return new HttpPutFormContentFilter();
  62. }
  63. @Override
  64. public void addResourceHandlers(ResourceHandlerRegistry registry){
  65. //测试环境图片地址映射,映射成url就可以访问的
  66. // registry.addResourceHandler("/images/**").addResourceLocations("file:" + uploadPath);
  67. registry.addResourceHandler("/swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
  68. registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
  69. }
  70. }

注意:在application.properties配置文件中加上 swagger.enable=true,不然swagger-ui.html页面访问不了。

创建测试Controller

第五步,创建一个Controller,可以通过url访问,这里采用Restful命名风格;

  1. import org.slf4j.Logger;
  2. import org.slf4j.LoggerFactory;
  3. import org.springframework.validation.BindingResult;
  4. import org.springframework.validation.annotation.Validated;
  5. import org.springframework.web.bind.annotation.PostMapping;
  6. import org.springframework.web.bind.annotation.RequestMapping;
  7. import org.springframework.web.bind.annotation.RestController;
  8. import com.example.demo.entity.UserInfo;
  9. import io.swagger.annotations.Api;
  10. import io.swagger.annotations.ApiOperation;
  11. /**
  12. * 用户测试用例
  13. * @author clown
  14. * @Date
  15. */
  16. @Api(tags = "用户信息", description = "UserInfoController")
  17. @RestController
  18. @RequestMapping("/userInfo")
  19. public class UserInfoController {
  20. private static Logger log = LoggerFactory.getLogger(UserInfoController.class);
  21. @PostMapping
  22. @ApiOperation(value = "新增",notes="用户信息", httpMethod="POST")
  23. public UserInfo addUserInfo(@Valid UserInfo userInfo, BindingResult errors){
  24. //对表单进行验证
  25. if (errors.hasErrors()){
  26. //对错误集合进行遍历,有的话,直接放入map集合中
  27. errors.getFieldErrors().forEach(p->{
  28. throw new RuntimeException(p.getDefaultMessage());
  29. });
  30. }
  31. log.info("全部验证通过~!");
  32. return userInfo;
  33. }
  34. }

最后,启动项目访问测试
image.png
输入值
image.png
测试结果