美文网首页SpringBoot精选
SpringBoot 整合 javax.validation 优

SpringBoot 整合 javax.validation 优

作者: 程就人生 | 来源:发表于2020-03-11 21:34 被阅读0次

    提交表单,要写点严谨的代码,前后台验证是少不了的,前台页面可以使用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 程就人生
     * @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 程就人生
     * @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-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;
    
    /**
     * 在线文档生成,参考网址:https://hacpai.com/article/1534735914420
     * https://blog.csdn.net/sanyaoxu_2/article/details/80555328
     * @author 程就人生
     * @Date
     */
    @Configuration
    @EnableSwagger2
    @ConditionalOnProperty(name = "swagger.enable", havingValue = "true")
    //@Profile({"dev","test"}) 
    public class Swagger2 {
    
        @SuppressWarnings("deprecation")
        @Bean
        public 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
    @EnableWebMvc
    public class WebMvcConfig extends WebMvcConfigurerAdapter{
        
    //  @Value("${spring.servlet.multipart.location}")
    //  private String uploadPath;
        
      /**
       * PUT方式提交,无法获取参数
       * @return
       */
      @Bean
      public HttpPutFormContentFilter httpPutFormContentFilter() {
          return new HttpPutFormContentFilter();
      }
      
      @Override
      public 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,可以通过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 程就人生
     * @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(@Validated UserInfo userInfo, BindingResult errors){
            //对表单进行验证
            if (errors.hasErrors()){
               //对错误集合进行遍历,有的话,直接放入map集合中
                errors.getFieldErrors().forEach(p->{
                   throw new RuntimeException(p.getDefaultMessage());
               });
            }
            log.info("全部验证通过~!");
            return userInfo;
        }
    }
    

    最后,启动项目访问测试

    输入值
    测试结果

    总结
    使用javax.validation验证确实方便了不少,省了不少if、else等等逻辑判断及验证,最后的测试,由于空间有限,并没有把所有注解的测试结果都贴出来,如果感兴趣试一试效果如何。

    相关文章

      网友评论

        本文标题:SpringBoot 整合 javax.validation 优

        本文链接:https://www.haomeiwen.com/subject/kjmhjhtx.html