SpringBoot精选

SpringBoot 整合 javax.validation 优

2020-03-11  本文已影响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等等逻辑判断及验证,最后的测试,由于空间有限,并没有把所有注解的测试结果都贴出来,如果感兴趣试一试效果如何。

上一篇下一篇

猜你喜欢

热点阅读