檢查帶註釋的值是否包含潛在的惡意片段,例如三、實體校驗
假設當前有個實體叫userInfo
3.1 實體
package com.cff.springbootwork.validator.vo;
import java.util.Date;
import java.util.List;
import javax.validation.constraints.AssertFalse;
import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.Digits;
import javax.validation.constraints.Email;
import javax.validation.constraints.Future;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.Negative;
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.Positive;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.Range;
import org.hibernate.validator.constraints.URL;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class UserInfo {
@Null(message = "創建時間不能填")
@JsonFormat(pattern = "yyyy-MM-dd", locale = "zh", timezone = "GMT+8")
private Date createTime;
@NotEmpty(message = "用戶名不能爲空")
private String userName;
@NotBlank(message = "姓名不能爲空或空字符串")
private String name;
@Negative(message = "冬天溫度在0°以下")
private Integer temperatureWinter;
@Positive(message = "夏天溫度在0°以上")
private Integer temperatureSummer;
@Digits(integer = 11, message = "手機號是11位整數哦", fraction = 0)
private String mobile;
@NotNull(message = "年齡不能爲空")
@Min(value = 10, message = "年齡太小了")
@Max(value = 35, message = "年齡太大了")
private Integer age;
@Size(min = 0, max = 2, message = "你女朋友個數在0-2之間")
private List<String> girlFrinds;
@Range(min = 0, max = 100, message = "你錢包裏的錢在0-2之間")
private Integer money;
@Length(min = 4, max = 64, message = "地址在4-64之間")
private String address;
@AssertTrue(message = "對象必須是人")
private Boolean people;
@AssertFalse(message = "不能上來就刪除")
private Boolean delete;
@Pattern(regexp="[0-9]{6}",message = "密碼格式錯誤")
private String password;
@Email(message = "email格式錯誤")
private String email;
@JsonFormat(pattern = "yyyy-MM-dd", locale = "zh", timezone = "GMT+8")
@Future(message = "失效時間比當前時間晚")
private Date expireTime;
@JsonFormat(pattern = "yyyy-MM-dd", locale = "zh", timezone = "GMT+8")
@Past(message = "出生日期比當前時間早")
private Date birthDate;
@URL(message = "url填寫錯誤")
private String url;
}
3.2 Web層數據接收
只需要加上@Valid註解即可,然後通過BindingResult來接收校驗錯誤。
@RequestMapping(value = "/test")
public List<String> set(@Valid @RequestBody UserInfo userInfo, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
List<String> errorMsg = bindingResult.getAllErrors().stream().map(s -> s.getDefaultMessage())
.collect(Collectors.toList());
return errorMsg;
}
return Collections.singletonList("0000");
}
這裏,是打印了所有錯誤結果,如果只校驗是否錯誤,拋出第一個錯誤,這樣寫即可:
@RequestMapping(value = "/test")
public List<String> set(@Valid @RequestBody UserInfo userInfo, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
String errorMsg = bindingResult.getAllErrors().get(0).getDefaultMessage();
return Collections.singletonList(errorMsg);
}
return Collections.singletonList("0000");
}
3.3 校驗不通過測試
請求參數:
{
"createTime":"2018-08-09",
"userName": "",
"name": " ",
"age": 9,
"mobile": "123123123",
"girlFrinds": ["1號","2號","3號"],
"money": 101,
"temperatureWinter": 0,
"temperatureSummer": -1,
"address": "12",
"people": false,
"delete": true,
"password": "123",
"email": "11@",
"expireTime":"2019-11-11",
"birthDate":"2020-11-11",
"url":"qwe"
}
返回結果:
[
"你女朋友個數在0-2之間",
"地址在4-64之間",
"密碼格式錯誤",
"email格式錯誤",
"創建時間不能填",
"你錢包裏的錢在0-2之間",
"對象必須是人",
"出生日期比當前時間早",
"冬天溫度在0°以下",
"年齡太小了",
"失效時間比當前時間晚",
"url填寫錯誤",
"夏天溫度在0°以上",
"不能上來就刪除",
"姓名不能爲空或空字符串",
"用戶名不能爲空"
]
3.4 校驗通過測試
請求參數:
{
"createTime":"",
"userName": " ",
"name": "cff",
"age": 11,
"mobile": "13333333333",
"girlFrinds": ["1號","2號"],
"money": 100,
"temperatureWinter": -1,
"temperatureSummer": 12,
"address": "12345",
"people": true,
"delete": false,
"password": "123456",
"email": "[email protected]",
"expireTime":"2020-11-11",
"birthDate":"2019-11-11",
"url":"http://www.pomit.cn"
}
返回結果:
[
"0000"
]
四、級聯校驗
如果一個對象持有另一個對象的引用,可以使用@Valid註解進行級聯校驗。 如下所示:
4.1 實體
package com.cff.springbootwork.validator.vo;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class UserRole {
@NotEmpty(message = "用戶名不能爲空")
private String userName;
@NotNull(message = "roleId不能爲空")
private Integer roleId;
@Valid
private UserInfo userInfo;
}
4.2 測試Web
@RequestMapping(value = "/test1")
public List<String> test1(@Valid @RequestBody UserRole userRole, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
List<String> errorMsg = bindingResult.getAllErrors().stream().map(s -> s.getDefaultMessage())
.collect(Collectors.toList());
return errorMsg;
}
return Collections.singletonList("0000");
}
4.3 測試結果
請求數據:
{
"userName": "",
"roleId": 1,
"userInfo":{
"createTime":"2018-08-09",
"userName": "",
"name": " ",
"age": 9,
"mobile": "123123123",
"girlFrinds": ["1號","2號","3號"],
"money": 101,
"temperatureWinter": 0,
"temperatureSummer": -1,
"address": "12",
"people": false,
"delete": true,
"password": "123",
"email": "11@",
"expireTime":"2019-11-11",
"birthDate":"2020-11-11",
"url":"qwe"
}
}
返回結果:
[
"失效時間比當前時間晚",
"用戶名不能爲空",
"用戶名不能爲空",
"你女朋友個數在0-2之間",
"密碼格式錯誤",
"你錢包裏的錢在0-2之間",
"姓名不能爲空或空字符串",
"url填寫錯誤",
"冬天溫度在0°以下",
"對象必須是人",
"email格式錯誤",
"不能上來就刪除",
"年齡太小了",
"夏天溫度在0°以上",
"地址在4-64之間",
"創建時間不能填",
"出生日期比當前時間早"
]
五、手動校驗
有時候,不用使用@Valid 自動校驗,需要手動調起validator進行校驗,可以使用validator.validate(roleInfo); 進行校驗:
5.1 實體
package com.cff.springbootwork.validator.vo;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class RoleInfo {
@NotNull(message = "roleId不能爲空")
private Integer roleId;
@NotEmpty(message = "roleName不能爲空")
private String roleName;
}
5.2 測試
Validator(import javax.validation.Validator;) 在SpringBoot中,可以作爲bean之間被注入。
@Autowired
Validator validator;
@RequestMapping(value = "/test2")
public List<String> test2(@RequestParam("roleId") Integer roleId, @RequestParam("roleName") String roleName) {
RoleInfo roleInfo = new RoleInfo(roleId, roleName);
Set<ConstraintViolation<RoleInfo>> sets = validator.validate(roleInfo);
if(sets.isEmpty())return Collections.singletonList("0000");
List<String> errorMsg = sets.stream().map(s -> s.getMessage()).collect(Collectors.toList());
return errorMsg;
}
六、分組校驗
分組校驗就是處理特殊情況下的校驗,使不同的調用走不同的校驗組。
如,一個對象A持有另一個對象B的引用,對象B中某些字段不想在對象A校驗的時候被校驗到,可以使用分組校驗。
6.1 實體
假設有兩個實體:
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class UserRoleInfo {
@NotEmpty(message = "用戶名不能爲空")
private String userName;
@NotNull(message = "roleId不能爲空")
private Integer roleId;
@Valid
private RoleInfo roleInfo;
}
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class RoleInfo {
@NotNull(message = "roleId不能爲空", groups=RoleGroup.class)
private Integer roleId;
@NotEmpty(message = "roleName不能爲空", groups=RoleGroup.class)
private String roleName;
}
注意,這裏的groups必須是接口。接口內容任意,只是個標識而已。
public interface RoleGroup {
}
Default.class(javax.validation.groups.Default) 是默認分組,不需要自己建立.
6.2 測試不帶分組
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import javax.validation.groups.Default;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.cff.springbootwork.validator.vo.RoleGroup;
import com.cff.springbootwork.validator.vo.RoleInfo;
import com.cff.springbootwork.validator.vo.UserRoleInfo;
@RestController
@RequestMapping("/valid")
public class ValidatorRest {
@Autowired
Validator validator;
@RequestMapping(value = "/test3")
public List<String> test3(@RequestParam("roleId") Integer roleId, @RequestParam("userName") String userName,
@RequestParam("roleName") String roleName) {
UserRoleInfo userRoleInfo = new UserRoleInfo();
userRoleInfo.setRoleId(roleId);
userRoleInfo.setUserName(userName);
RoleInfo roleInfo = new RoleInfo(roleId, roleName);
userRoleInfo.setRoleInfo(roleInfo);
Set<ConstraintViolation<UserRoleInfo>> sets = validator.validate(userRoleInfo);
if (sets.isEmpty())
return Collections.singletonList("0000");
List<String> errorMsg = sets.stream().map(s -> s.getMessage()).collect(Collectors.toList());
return errorMsg;
}
}
結果:
請求參數:
roleId:1
userName:
roleName:
返回結果:
[
"用戶名不能爲空"
]
6.2 測試帶分組
注意,Default.class 是默認分組。
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import javax.validation.groups.Default;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.cff.springbootwork.validator.vo.RoleGroup;
import com.cff.springbootwork.validator.vo.RoleInfo;
import com.cff.springbootwork.validator.vo.UserRoleInfo;
@RestController
@RequestMapping("/valid")
public class ValidatorRest {
@Autowired
Validator validator;
@RequestMapping(value = "/test3")
public List<String> test3(@RequestParam("roleId") Integer roleId, @RequestParam("userName") String userName,
@RequestParam("roleName") String roleName) {
UserRoleInfo userRoleInfo = new UserRoleInfo();
userRoleInfo.setRoleId(roleId);
userRoleInfo.setUserName(userName);
RoleInfo roleInfo = new RoleInfo(roleId, roleName);
userRoleInfo.setRoleInfo(roleInfo);
Set<ConstraintViolation<UserRoleInfo>> sets = validator.validate(userRoleInfo, RoleGroup.class, Default.class);
if (sets.isEmpty())
return Collections.singletonList("0000");
List<String> errorMsg = sets.stream().map(s -> s.getMessage()).collect(Collectors.toList());
return errorMsg;
}
}
結果:
請求參數:
roleId:1
userName:
roleName:
返回結果:
[
"roleName不能爲空",
"用戶名不能爲空"
]
七、自定義註解校驗
有時候,我們仍需要自定義校驗註解,如,我這裏定義一個只校驗0或1數據的驗證器。
7.1 自定義註解
package com.cff.springbootwork.validator.custom;
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;
@Target(value = {ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy=TypeZeroOneValidator.class)
public @interface ZeroOne {
String message() default "參數有誤";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
7.2 自定義Validator
package com.cff.springbootwork.validator.custom;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class TypeZeroOneValidator implements ConstraintValidator<ZeroOne, Object> {
@Override
public void initialize(ZeroOne constraintAnnotation) {
}
@Override
public boolean isValid(Object obj, ConstraintValidatorContext context) {
if (obj == null)
return true;
int curNum = 0;
if (obj instanceof String) {
String s = (String) obj;
curNum = Integer.parseInt(s);
} else if (obj instanceof Boolean) {
boolean b = ((Boolean) obj).booleanValue();
if (b) {
curNum = 1;
}
} else if (obj instanceof Long) {
curNum = ((Long) obj).intValue();
} else {
curNum = ((Integer) obj).intValue();
}
if (curNum == 0 || curNum == 1)
return true;
return false;
}
}
7.3 測試實體
package com.cff.springbootwork.validator.vo;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import com.cff.springbootwork.validator.custom.ZeroOne;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class RoleInfoZeroOne {
@NotNull(message = "roleId不能爲空")
private Integer roleId;
@NotEmpty(message = "roleName不能爲空")
private String roleName;
@ZeroOne(message = "deleted只能爲0/1")
private Integer deleted;
}
7.4 測試Web
跟普通使用方法一樣,無需更改。
@RequestMapping(value = "/test4")
public List<String> test4(@Valid @RequestBody RoleInfoZeroOne roleInfoZeroOne, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
List<String> errorMsg = bindingResult.getAllErrors().stream().map(s -> s.getDefaultMessage())
.collect(Collectors.toList());
return errorMsg;
}
return Collections.singletonList("0000");
}
7.5 測試結果
請求參數:
{
"roleId":1,
"deleted":3,
"roleName": "cff"
}
返回結果:
[
"deleted只能爲0/1"
]
品茗IT-博客專題:https://www.pomit.cn/lecture.html彙總了Spring專題、Springboot專題、SpringCloud專題、web基礎配置專題。
快速構建項目
Spring項目快速開發工具:
一鍵快速構建Spring項目工具
一鍵快速構建SpringBoot項目工具
一鍵快速構建SpringCloud項目工具
一站式Springboot項目生成
Mysql一鍵生成Mybatis註解Mapper
Spring組件化構建
SpringBoot組件化構建
SpringCloud服務化構建
喜歡這篇文章麼,喜歡就加入我們一起討論Java Web吧!
|