springboot学习(七) springboot 各种方式的校验

79 篇文章 0 订阅
6 篇文章 2 订阅

springboot 各种方式的校验

springboot 有各种方式进行校验,下面一一进行介绍

1 Java断言的方式
Java1.4引入断言。可以使用这种方式做参数的校验。下面是一段做校验的例子。assert表达式为false的时候会抛出一个异常。

	@PutMapping("/assert")
    public Employee put2(@RequestBody Employee employee){
        assert employee.getName() != null && !"".equals(employee.getName());
        return employee;
    }

2 Spring Assert方式
同样,使用spring Assert也可以做校验,方式与assert类似,下面是一段例子。name不能为空,否则会抛出一个异常,异常的message就是 “名称不能为空”,这种方式更好用一些,能够自定义错误消息

@PutMapping("/spring/assert")
    public Employee put1(@RequestBody Employee employee){
        Assert.hasText(employee.getName(), "名称不能为空");
        return employee;
    }

3 参数校验方式
通过javax.validation.constraints.xxx的注解对参数修饰。Controller上修饰@org.springframework.validation.annotation.Validated,如下面的例子。

@GetMapping("/param")
    public Employee get1(@Size(min=3, max=5) String name, @Min(3) @Max(5) int id ){
        return new Employee(id, name);
    }

如果不满足条件会抛出MethodArgumentNotValidException异常,通过ControllerAdivisor可以抓取异常,向前台返回异常信息,具体返回异常情况可根据自己项目。ControllerAdivisor抓取异常方式可见上一篇,下面是例子。

@ExceptionHandler(value = ConstraintViolationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public String to400(ConstraintViolationException e){
        StringBuilder result = new StringBuilder();
        result.append("error 400 :");
        Set<ConstraintViolation<?>> cvs = e.getConstraintViolations();
        if(cvs != null){
            for (ConstraintViolation cv: cvs) {
                Path path = cv.getPropertyPath();
                String msg = cv.getMessage();
                result.append(path).append(",").append(msg).append(";");
                //TODO 这里可以使用path 和msg 组合成返回的内容,这里就是做一个拼接
            }
        }

        return result.toString();
    }

4 Bean校验方式
校验Bean的方式可以使用spring的 validation。
引入validation依赖

compile('org.springframework.boot:spring-boot-starter-validation')

bean的参数上添加注解

package com.zqw.springboot.learn.boot.validate.bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;


@Data
@Slf4j
@NoArgsConstructor
@AllArgsConstructor
public class Employee {
    @Max(value=5,message = "最大5")
    @Min(value = 3, message = "最小3")
    private Integer id;
    @Size(min=3,max=5, message = "介于3到5")
    private String name;
}

Controller 注入bean时添加@Valid注解

 @PutMapping("/bean")
    public Employee put3(@Valid @RequestBody Employee employee){
        return employee;
    }

校验失败时会抛出一个MethodArgumentNotValidException 异常,可以在controlleradvisor抓取异常做处理返回前台

@ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public String to400(MethodArgumentNotValidException e){
        StringBuilder result = new StringBuilder();
        result.append("error 400 :");
        BindingResult bindingResult = e.getBindingResult();
        List<FieldError> errors = bindingResult.getFieldErrors();
        if(errors != null){
            for (FieldError error: errors) {
                String field = error.getField();
                String msg = error.getDefaultMessage();
                //TODO 这里可以使用field 和msg 组合成返回的内容,这里就是做一个拼接
                result.append(field).append(",").append(msg).append(";");
            }
        }
        return result.toString();
    }

5 自定义校验
如果是java11需要添加javax.el-api和org.glassfish下的javax.el两个依赖
假设要校验身份证号,不能为空,必须为数字(暂且这么认为),必须为18位。
编写注解类,message为校验失败的默认输出,可以采用国际化的方式定义

@Target({ElementType.METHOD,ElementType.FIELD,ElementType.CONSTRUCTOR,
        ElementType.ANNOTATION_TYPE,ElementType.PARAMETER})
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {CarNoValidator.class})
public @interface CarNoConstraint {
    String message() default "{carNo.constraint.message}";
    Class<?>[] groups() default {};

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

编写Constraint类implements ConstraintValidator<CarNoConstraint, String>,重写initialize 和isValid方法,其中initalize方法可以获取注解的参数,这里没用到所以不用获取。isValid返回校验通过与否,value就是输入的参数值。

public class CarNoValidator implements ConstraintValidator<CarNoConstraint, String> {
    public void initialize(SexConstraint constraintAnnotation) {
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if(StringUtils.isBlank(value)) return false;
        if(value.length() != 18) return false;
        if(!StringUtils.isNumeric(value)) return false;//身份证号可能最后为X,先不管他,暂时认为都是数字

        return true;
    }
}

在使用此注解的bean上添加注解,这里还自定义了一个枚举的校验,详情可参考本文最后的github源码

@Data
@Slf4j
public class Employee {
    @Max(value=5,message = "最大5")
    @Min(value = 3, message = "最小3")
    private Integer id;
    @Size(min=3,max=5, message = "介于3到5")
    private String name;
    @SexConstraint
    private Sex sex;
    @CarNoConstraint
    private String carNo;

    public Employee( Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Employee() {
    }


}

国际化配置在resource下面添加文件夹i18n,文件夹下添加messages.properties和messages_zh_CN.properteis文件

sex.constraint.message=the sex is ont valid
carNo.constraint.message=the carNo must be number, the length must be 18
sex.constraint.message=\u6027\u522b\u975e\u6cd5
carNo.constraint.message=\u8eab\u4efd\u8bc1\u4e0d\u80fd\u4e3a\u7a7a\uff0c\u5fc5\u987b\u4e3a\u6570\u5b57\uff0c\u5fc5\u987b\u4e3a18\u4f4d

添加I18nConfig配置

@Configuration
public class I18nConfig {

    @Bean
    public LocaleResolver localeResolver() {
        return new I18nLocaleResolver();
    }

    /**
     * 获取请求头国际化信息
     */
    static class I18nLocaleResolver implements LocaleResolver {

        @NotNull
        @Override
        public Locale resolveLocale(HttpServletRequest httpServletRequest) {
            String language = httpServletRequest.getHeader("content-language");
            Locale locale = Locale.getDefault();
            if (StrUtil.isNotBlank(language)) {
                String[] split = language.split("_");
                locale = new Locale(split[0], split[1]);
            }
            return locale;
        }

        @Override
        public void setLocale(@NotNull HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {

        }
    }
}

添加ValidatorConfig配置:

@Configuration
public class ValidatorConfig {
    @Autowired
    private MessageSource messageSource;

    /**
     * 配置校验框架 快速返回模式
     */
    @Bean
    public Validator validator() {
        LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
        // 设置国际化源
        factoryBean.setValidationMessageSource(messageSource);
        // 设置使用 HibernateValidator 校验器
        factoryBean.setProviderClass(HibernateValidator.class);
        Properties properties = new Properties();
        // 设置 快速异常返回
        properties.setProperty("hibernate.validator.fail_fast", "true");
        factoryBean.setValidationProperties(properties);
        // 加载配置
        factoryBean.afterPropertiesSet();
        return factoryBean.getValidator();
    }
}

校验不通过时会抛出MethodArgumentNotValidException异常,异常抓取方式可参见bean校验处。
当然校验的注解也可以直接作用在参数上,参见第3中参数的校验。这里的校验如下:

@GetMapping("/carNo/param")
    public String get1(@CarNoConstraint String carNo ){
        return carNo;
    }

6、 嵌套对象校验
在嵌套的属性上添加@Valid注解就好,下面是例子

package com.iscas.biz.model.deployment;

import com.iscas.common.k8s.tools.model.volume.KcVolume;
import com.iscas.common.k8s.tools.model.volume.KcVolumeClaimTemplate;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;

/**
 * 服务编辑信息
 *
 * @author zhuquanwen
 * @vesion 1.0
 * @date 2021/1/1 18:50
 * @since jdk1.8
 */
@Data
@Accessors(chain = true)
public class DepEditor {
    /**
     * 基本信息
     * */
    @NotNull(message = "'baseEditor' {not.null}")
    @Valid
    private DepBaseEditor baseEditor;

    /**
     * 发布信息
     * */
    private DepPublishEditor publishEditor;

    /**
     * 容器配置
     * */
    private List<DepContainerEditor> containerEditors;

    /**
     * 初始化容器配置
     * */
    private List<DepContainerEditor> initContainerEditors;

    /**服务标签*/
    private List<String[]> labels = new ArrayList<>();

    /**annotations*/
    private List<String[]> annotations = new ArrayList<>();

    /**volumes,数据卷*/
    private List<KcVolume> volumes = new ArrayList<>();

    /**数据卷声明(仅在statefulset模式下使用)*/
    private List<KcVolumeClaimTemplate> volumeClaimTemplates = new ArrayList<>();

}

package com.iscas.biz.model.deployment;

import com.iscas.biz.valid.anno.NameConstraint;
import lombok.Data;
import lombok.experimental.Accessors;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

/**
 * 服务基本编辑信息
 *
 * @author zhuquanwen
 * @vesion 1.0
 * @date 2021/1/1 19:08
 * @since jdk1.8
 */
@Data
@Accessors(chain = true)
public class DepBaseEditor {

    /**名称,字母数字短横杠*/
    @NotEmpty(message = "'name' {not.empty}" )
    @NameConstraint
    private String name;

    /**副本数量*/
    @Min(value = 1, message="{replication.constraint.message}")
    private int repSum = 1;

    /**镜像仓库密钥, 可以为空*/
    private String imageRepSecret;

    /**用户*/
    private String username = "default";

    /**容器组重启策略*/
    @Pattern(regexp = "^(IfNotPresent|Always|Never)$", message = "{restart.policy.constraint.message}")
    private String restartPolicy = "Always";

}


github 源码
springboot学习 上一篇 springboot异常处理
springboot学习 下一篇 自定义监听

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值