提交表单,要写点严谨的代码,前后台验证是少不了的,前台页面可以使用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等等逻辑判断及验证,最后的测试,由于空间有限,并没有把所有注解的测试结果都贴出来,如果感兴趣试一试效果如何。
网友评论