1. Java中的參數驗證(非Spring版)
1.1. 前言
- 爲何我總遇到這種非正常問題,咱們知道不少時候咱們的參數校驗都是放在controller層的傳入參數進行校驗,咱們經常使用的校驗方式就是引入下列的jar包,在參數中添加
@Validated
,並對Bean對象的參數作不一樣的註解處理就行,對Spring這種經常使用作法你們應該比較熟了
- 但我如今遇到的需求,由於boss追求通用性,咱們的controller入口只有一個,是經過傳入參數中的不一樣tradeCode來區分調用哪一個服務,這時我校驗參數就得放到具體的每一個服務方法上了,這樣通過個人測試,加該註解已經不起做用了
<!--jsr 303-->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
@PostMapping("/save/valid")
public RspDTO save(@RequestBody @Validated UserDTO userDTO) {
userService.save(userDTO);
return RspDTO.success();
}
@Data
public class UserDTO implements Serializable {
private static final long serialVersionUID = 1L;
/*** 用戶ID*/
@NotNull(message = "用戶id不能爲空")
private Long userId;
/** 用戶名*/
@NotBlank(message = "用戶名不能爲空")
@Length(max = 20, message = "用戶名不能超過20個字符")
@Pattern(regexp = "^[\\u4E00-\\u9FA5A-Za-z0-9\\*]*$", message = "用戶暱稱限制:最多20字符,包含文字、字母和數字")
private String username;
/** 手機號*/
@NotBlank(message = "手機號不能爲空")
@Pattern(regexp = "^[1][3,4,5,6,7,8,9][0-9]{9}$", message = "手機號格式有誤")
private String mobile;
/**性別*/
private String sex;
/** 郵箱*/
@NotBlank(message = "聯繫郵箱不能爲空")
@Email(message = "郵箱格式不對")
private String email;
/** 密碼*/
private String password;
/*** 建立時間 */
@Future(message = "時間必須是未來時間")
private Date createTime;
}
1.2. 方案
- 不能用它的註解,但咱們能夠用它的方法,下面我寫了一個用Java代碼驗證參數的例子,拋磚引玉,並不能直接用在本身的系統哦,想要使用請結合本身系統封裝方法,我打算作成註解的形式,利用spring aop切個人服務層,實現的效果就和controller層相似了
1.2.1. 主方法
import org.springframework.validation.annotation.Validated;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.util.Date;
import java.util.Set;
import java.util.stream.Stream;
/**
* @author laoliangliang
* @date 2019/10/22 15:19
*/
public class ValidLearn {
public static void main(String[] args) {
ValidLearn learn = new ValidLearn();
learn.testValid(new Order().setIdcard("33062119981012361X").setName(" ").setCreateDate(new Date()));
}
public void testValid(@Validated Order order) {
ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
Validator validator = validatorFactory.getValidator();
//分組Insert.class則id爲空不檢驗
Set<ConstraintViolation<Order>> validate = validator.validate(order, Insert.class);
Stream.of(validate).forEach(action -> {
for (ConstraintViolation<Order> orderConstraintViolation : action) {
String message = orderConstraintViolation.getMessage();
System.out.println(message);
}
});
}
}
1.2.2. 實體類
/**
* @author laoliangliang
* @date 2019/10/21 16:44
*/
@Data
@Accessors(chain = true)
public class Order {
@NotNull(message = "id不能爲空",groups = Update.class)
private Long id;
@NotEmpty(message = "name is not null",groups = Insert.class)
private String name;
@Future(message = "必須以後的時間")
private Date createDate;
@IdCardValid(message = "idcard 不合法")
private String idcard;
}
- 以上兩個代碼就能夠作到檢驗實體類對象註解,並打印校驗不經過的消息了,能夠改形成存在校驗錯誤消息則拋出異常
- 代碼還涉及了一些細節,好比group分組和自定義註解
1.2.3. group分組
import javax.validation.groups.Default;
/**
* @author laoliangliang
* @date 2019/10/22 16:32
*/
public interface Update extends Default {
}
import javax.validation.groups.Default;
/**
* @author laoliangliang
* @date 2019/10/22 16:32
*/
public interface Insert extends Default {
}
- 我例子代碼中用到了
Insert.class
,表示作插入動做時,存在這個分組的註解纔會起做用,所以我id不傳,id不爲空的註解也不會起做用
1.2.4. 自定義註解
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author laoliangliang
* @date 2019/10/22 15:55
*/
public class IdCardValidator implements ConstraintValidator<IdCardValid, Object> {
private Pattern pattern = Pattern.compile("^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])" +
"\\d{3}$|^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9]|X)$");
@Override
public void initialize(IdCardValid idCardValid) {
}
@Override
public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
Matcher matcher = pattern.matcher(o.toString());
return matcher.matches();
}
}
/**
* @author laoliangliang
* @date 2019/10/22 15:53
*/
@Documented
@Target({ElementType.PARAMETER,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = IdCardValidator.class)
public @interface IdCardValid {
String message() default "身份證不合法";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
- 這裏我以驗證身份證號爲例,寫了個自定義註解,實現
ConstraintValidator
接口,在isValid
方法中實現自定義邏輯便可使用註解
1.3. 總結
- 此篇舉了
Validation
用Java代碼實現驗證的例子,應對service層參數驗證,實際應用到本身代碼能夠本身寫個自定義註解,實現aop切面,在切面中進行驗證