开发注意事项

开发注意事项


1. 参数验证

hibernate.validator

1.导入包

import org.hibernate.validator.constraints.NotBlank;
import javax.validation.constraints.AssertFalse;
import javax.validation.constraints.Pattern;

2.demo

@Getter
@Setter
@NoArgsConstructor
public class DemoModel {
    @NotBlank(message="用户名不能为空")
    private String userName;

    @NotBlank(message="年龄不能为空")
    @Pattern(regexp="^[0-9]{1,2}$",message="年龄不正确")
    private String age;

    @AssertFalse(message = "必须为false")
    private Boolean isFalse;
    /**
     * 如果是空,则不校验,如果不为空,则校验
     */
    @Pattern(regexp="^[0-9]{4}-[0-9]{2}-[0-9]{2}$",message="出生日期格式不正确")
    private String birthday;
}

3.结果返回

@RequestMapping("/demo2")
public void demo2(@RequestBody @Valid DemoModel demo, BindingResult result){
    if(result.hasErrors()){
        for (ObjectError error : result.getAllErrors()) {
            System.out.println(error.getDefaultMessage());
        }
    }
}

4.传入参数

{"userName":"dd","age":120,"isFalse":true,"birthday":"21010-21-12"}

5.输出结果

出生日期格式不正确
必须为false
年龄不正确
3. hibernate的校验模式
1. 普通模式(默认为该模式)
   * 会校验所有属性,然后返回所有的验证失败信息。
2. 快速失败返回模式只要有一个校验失败则返回。
3.  设置方式
// failFast: true 快速失败返回模式,false 普通模式
ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
        .configure()
        .failFast( true )
        .buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
// hibernate.validator.fail_fast: true 快速失败返回模式,false 普通模式
ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
        .configure()
        .addProperty( "hibernate.validator.fail_fast", "true" )
        .buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
  1. hibernate的校验
  • 配置hibernate Validator为快速返回模式:
@Configuration
public class ValidatorConfiguration {
    @Bean
    public Validator validator(){
        ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
                .configure()
                .addProperty( "hibernate.validator.fail_fast", "true" )
                .buildValidatorFactory();
        Validator validator = validatorFactory.getValidator();

        return validator;
    }
}
  1. 请求参数校验
  • 验证请求参数时,在 @RequestBody DemoModel demo 之间加注解 @Valid,然后在后面加 BindindResult 即可;多个参数,可以添加多个 @Valid 和 BindindResult。
public void test()(@RequestBody @Valid DemoModel demo, BindingResult result)
public void test()(@RequestBody @Valid DemoModel demo, BindingResult result,@RequestBody @Valid DemoModel demo2, BindingResult result2)
  1. GET参数校验(@RequestParam参数校验)
    1.controller
@RequestMapping(value = "/demo3", method = RequestMethod.GET)
public void demo3(@RequestParam(name = "grade", required = true) int grade,@RequestParam(name = "classroom", required = true) int classroom) {
    System.out.println(grade + "," + classroom);
}

注:使用 @Valid 注解对 RequestParam 对应的参数时无效的,需要使用 @Validated 注解来使验证生效。

2.MethodValidationPostProcessor 的 Bean

@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
    /**默认是普通模式,会返回所有的验证不通过信息集合*/
    return new MethodValidationPostProcessor();
}

3.或者可对 MethodValidationPostProcessor 进行设置 Validator

  • 此时不是使用 Validator 进行验证,Validator 的配置不起作用
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
    MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor();
    /**设置validator模式为快速失败返回*/
    postProcessor.setValidator(validator());
    return postProcessor;
}

@Bean
public Validator validator(){
    ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
            .configure()
            .addProperty( "hibernate.validator.fail_fast", "true" )
            .buildValidatorFactory();
    Validator validator = validatorFactory.getValidator();

    return validator;
}

4.方法所在的Controller上加注解 @Validated

@RequestMapping("/validation")
@RestController
@Validated
public class ValidationController {
    /**如果只有少数对象,直接把参数写到Controller层,然后在Controller层进行验证就可以了。*/
    @RequestMapping(value = "/demo3", method = RequestMethod.GET)
    public void demo3(@Range(min = 1, max = 9, message = "年级只能从1-9")
                      @RequestParam(name = "grade", required = true)
                      int grade,
                      @Min(value = 1, message = "班级最小只能1")
                      @Max(value = 99, message = "班级最大只能99")
                      @RequestParam(name = "classroom", required = true)
                      int classroom) {
        System.out.println(grade + "," + classroom);
    }
}

5.返回验证信息提示验证不通过,抛出来 ConstraintViolationException 异常,使用统一捕获异常处理

@ControllerAdvice
@Component
public class GlobalExceptionHandler {

    @ExceptionHandler
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public String handle(ValidationException exception) {
        if(exception instanceof ConstraintViolationException){
            ConstraintViolationException exs = (ConstraintViolationException) exception;

            Set<ConstraintViolation<?>> violations = exs.getConstraintViolations();
            for (ConstraintViolation<?> item : violations) {
          /**打印验证不通过的信息*/
                System.out.println(item.getMessage());
            }
        }
        return "bad request, " ;
    }
}

6.验证

http://localhost:8080/validation/demo3?grade=18&classroom=888
3. model校验
  • model
@Data
public class Demo2 {
    @Length(min = 5, max = 17, message = "length长度在[5,17]之间")
    private String length;

    /**@Size不能验证Integer,适用于String, Collection, Map and arrays*/
    @Size(min = 1, max = 3, message = "size在[1,3]之间")
    private String age;

    @Range(min = 150, max = 250, message = "range在[150,250]之间")
    private int high;

    @Size(min = 3,max = 5,message = "list的Size在[3,5]")
    private List<String> list;
}

2.校验

@Autowired
private Validator validator;

@RequestMapping("/demo3")
public void demo3(){
    Demo2 demo2 = new Demo2();
    demo2.setAge("111");
    demo2.setHigh(150);
    demo2.setLength("ABCDE");
    demo2.setList(new ArrayList<String>(){{add("111");add("222");add("333");}});
    Set<ConstraintViolation<Demo2>> violationSet = validator.validate(demo2);
    for (ConstraintViolation<Demo2> model : violationSet) {
        System.out.println(model.getMessage());
    }
}
4. 对象级联校验
  • 对象内部包含另一个对象作为属性,属性上加 @Valid,可以验证作为属性的对象内部的验证
@Data
public class Demo2 {
    @Size(min = 3,max = 5,message = "list的Size在[3,5]")
    private List<String> list;

    @NotNull
    @Valid
    private Demo3 demo3;
}

@Data
public class Demo3 {
    @Length(min = 5, max = 17, message = "length长度在[5,17]之间")
    private String extField;
}

校验

/**前面配置了快速失败返回的Bean*/
@Autowired
private Validator validator;

@RequestMapping("/demo3")
public void demo3(){
    Demo2 demo2 = new Demo2();
    demo2.setList(new ArrayList<String>(){{add("111");add("222");add("333");}});

    Demo3 demo3 = new Demo3();
    demo3.setExtField("22");
    demo2.setDemo3(demo3);
    Set<ConstraintViolation<Demo2>> violationSet = validator.validate(demo2);
    for (ConstraintViolation<Demo2> model : violationSet) {
        System.out.println(model.getMessage());
    }
}

5. 分组校验

  • 校验接口
public interface GroupA {
}

public interface GroupB {
}
@Data
public class Person {
    @NotBlank
    @Range(min = 1,max = Integer.MAX_VALUE,message = "必须大于0",groups = {GroupA.class})
    /**用户id*/
    private Integer userId;
    @NotBlank
    @Length(min = 4,max = 20,message = "必须在[4,20]",groups = {GroupB.class})
    /**用户名*/
    private String userName;
    @NotBlank
    @Range(min = 0,max = 100,message = "年龄必须在[0,100]",groups={Default.class})
    /**年龄*/
    private Integer age;
    @Range(min = 0,max = 2,message = "性别必须在[0,2]",groups = {GroupB.class})
    /**性别 0:未知;1:男;2:女*/
    private Integer sex;
}
  • GroupA校验字段userId

  • GroupB校验字段userName、sex

  • Default校验字段age(Default使Validator自带的默认分组)

验证
只验证GroupA和GroupB的分组,以下示例代码

@RequestMapping("/demo5")
public void demo5(){
    Person p = new Person();
    /**GroupA验证不通过*/
    p.setUserId(-12);
    /**GroupA验证通过*/
    //p.setUserId(12);
    p.setUserName("a");
    p.setAge(110);
    p.setSex(5);
    Set<ConstraintViolation<Person>> validate = validator.validate(p, GroupA.class, GroupB.class);
    for (ConstraintViolation<Person> item : validate) {
        System.out.println(item);
    }
}
@RequestMapping("/demo6")
public void demo6(@Validated({GroupA.class, GroupB.class}) Person p, BindingResult result){
    if(result.hasErrors()){
        List<ObjectError> allErrors = result.getAllErrors();
        for (ObjectError error : allErrors) {
            System.out.println(error);
        }
    }
}

4.组序列

  • 指定组的验证顺序,前面组验证不通过,后面组不验证
// GroupA > GroupB > Default
@GroupSequence({GroupA.class, GroupB.class, Default.class})
public interface GroupOrder {
}
5. 自定义校验器
  1. 大小写校验器
public enum CaseMode {
    UPPER,
    LOWER;
}


@Target( { ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = CheckCaseValidator.class)
@Documented
public @interface CheckCase {
    String message() default "";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    CaseMode value();
}


public class CheckCaseValidator implements ConstraintValidator<CheckCase, String> {
    private CaseMode caseMode;
    public void initialize(CheckCase checkCase) {
        this.caseMode = checkCase.value();
    }

    public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
        if (s == null) {
            return true;
        }

        if (caseMode == CaseMode.UPPER) {
            return s.equals(s.toUpperCase());
        } else {
            return s.equals(s.toLowerCase());
        }
    }
}

2.Demo

public class Demo{
    @CheckCase(value = CaseMode.LOWER,message = "userName必须是小写")
    private String userName;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }
}
  1. Validator配置
@Bean
public Validator validator(){
    ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
            .configure()
            .addProperty( "hibernate.validator.fail_fast", "true" )
            .buildValidatorFactory();
    Validator validator = validatorFactory.getValidator();

    return validator;
}
  1. 校验测试
@RequestMapping("/demo4")
public void demo4(){
    Demo demo = new Demo();
    demo.setUserName("userName");
    Set<ConstraintViolation<Demo>> validate = validator.validate(demo);
    for (ConstraintViolation<Demo> dem : validate) {
        System.out.println(dem.getMessage());
    }
}
6. 自定义手动校验工具类
public class ValidateUtil {
    public ValidateUtil() {
    }

    public static String validateModel(Object obj) {
        StringBuffer buffer = new StringBuffer();
        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        Set<ConstraintViolation<Object>> constraintViolations = validator.validate(obj, new Class[0]);
        Iterator iter = constraintViolations.iterator();

        while(iter.hasNext()) {
            String message = ((ConstraintViolation)iter.next()).getMessage();
            buffer.append(message).append("; ");
        }

        return buffer.toString();
    }
}
7. 常见的注解
No. 注解 解释
01 @Null 检查该字段为空
02 @NotNull 不能为 null
03 @NotBlank 不能为空,检查时会将空格忽略
04 @NotEmpty 不能为空,这里的空是指空字符串
05 @AssertTrue 用于boolwan字段,只能为true
06 @AssertFalse 用于boolwan字段,只能为false
07 @CreditCardNumber 对信用卡进行一个大致的校验
08 @DecimalMin(value) 数值类型,只能小于或等于value
09 @DecimalMax(value) 数值类型,只能大于或等于value
10 @Digits(integer=2,fraction=20) 限制必须为一个小数,整数部分位数不能超过integer,小数部分位数不能超过fraction
11 @Email 检查是否是一个有效的email地址
12 @Past 检查该字段的日期是否属于过去的日期
13 @Future 检查该字段的日期是否属于将来的日期
14 @Length(min=,max=) 检查该字段的长度是否在min和max之间,只能用于字符串
15 @Size(min=,max=) 检查该字段的size是否在min和max之间,可以是字符串、数组、集合、map等
16 @Min(value) 小于等于value
17 @Max(value) 大于等于value
18 @URL(protocol=,host,port) 检查是否是一个有效的URL,如果提供来protocol,host等,则该url还需满足提供的条件
19 @Valid 该注解只要用于字段为一个包含其他对象的集合或map或数组的字段,或该字段直接为一个其他对象的引用(这样在检查当前对象的同时也会检查该字段所引用的对象)

2. 基本数据类型

Java的8种基本数据类型
关于Java的8种基本数据类型,其名称、位数、默认值、取值范围及示例如下表所示:

序号 数据类型 位数 默认值 取值范围 举例说明
1 byte(位) 8 0 -2^7 - 2^7-1 byte b = 10;
2 short(短整数) 16 0 -2^15 - 2^15-1 short s = 10;
3 int(整数) 32 0 -2^31 - 2^31-1 int i = 10;
4 long(长整数) 64 0 -2^63 - 2^63-1 long l = 10l;
5 float(单精度) 32 0.0 -2^31 - 2^31-1 float f = 10.0f;
6 double(双精度) 64 0.0 -2^63 - 2^63-1 double d = 10.0d;
7 char(字符) 16 0 - 2^16-1 char c = ‘c’;
8 boolean(布尔值) 8 false true、false boolean b = true;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-87IAobPy-1571651775728)(en-resource://database/2014:1)]
注:其中需要注意int对应的是Integer,char对应的Character,其他6个都是基本类型首字母大写即可

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章