检查带注释的值是否包含潜在的恶意片段,例如三、实体校验 假设当前有个实体叫userInfo 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": "11@qq.com","expireTime":"2020-11-11","birthDate":"2019-11-11","url":"http://www.pomit.cn"
}返回结果:
["0000"
]
四、级联校验 如果一个对象持有另一个对象的引用,可以使用@Valid注解进行级联校验。 如下所示: 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;@Validprivate 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); 进行校验: 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校验的时候被校验到,可以使用分组校验。 假设有两个实体: 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;@Validprivate 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 {@AutowiredValidator 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 {@AutowiredValidator 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数据的验证器。 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> {@Overridepublic void initialize(ZeroOne constraintAnnotation) {}@Overridepublic 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吧! |