Hibernate Validator 使用详解

news2024/11/15 19:53:52

目录

Hibernate Validator的依赖

Hibernate Validator 支持注解

空与非空检查

Boolean值检查

 日期检查

数值检查 

 其他

Hibernate-validator扩展约束 

Hibernate Validator 校验

简单对象校验

嵌套对象校验

Hibernate Validator 分组校验

静态分组

动态分组

动态分组优化

Hibernater-Validator 自定义约束注解

SpringBoot 中使用Hibernate Validator

配置Validator

Controller层 请求参数验证

Hibernate Validator 业务校验工具


代码开发过程中,请求参数的有效性校验是一项很繁琐的工作, 如果参数简单,可以直接通过if...else可以搞定,如果参数太多,你如何校验呢? 仍使用if...else就是体力活了, HibernateValidator 是很好的选择。

Hibernate Validator的依赖

SpringBoot 项目,那么spring-boot-starter-web中就已经依赖hibernate-validator

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Spring + Spring  MVC + MyBatis 项目,可以直接添加hibernate-validator依赖

<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.0.17.Final</version>
</dependency>

Hibernate Validator 支持注解

温馨提示:Hibernate-Validator 支持的注解数量大于是22个作用,下面我们按照功能划分执行注解类。

空与非空检查

Boolean值检查

 日期检查

数值检查 

 其他

Hibernate-validator扩展约束 

Hibernate Validator 校验

简单对象校验

@Data
public class Person{

    @NotBlank(message = "姓名不能为空")
    private String name;

    @NotNull(message = "年龄不能为空")
    @Range(min = 0, max = 100, message = "年龄必须在{min}和{max}之间")
    private Integer age;

    @NotNull(message = "是否已婚不能为空")
    private Boolean isMarried;

    @NotEmpty(message = "家庭成员不能为空")
    private Collection collection;

    @NotEmpty(message = "个人学历不能为空")
    private String[] array;

    @Email
    private String email;
  
    /*
    真实场景下面可能还有几十个字段
    省略 ... ...
    */
  
}

测试功能代码:

public class ValidateTest {
    //初始化一个校验器工厂  
    private static ValidatorFactory validatorFactory = Validation
            .byProvider(HibernateValidator.class)
            .configure()
            //校验失败是否立即返回: true-遇到一个错误立即返回不在往下校验,false-校验完所有字段才返回
            .failFast(false)
            .buildValidatorFactory();
    Validator validator = validatorFactory.getValidator();

    /**
     * 简单对象校验
     */
    @Test
    public void testSimple() {
        Person s=new Person ();
        s.setAge(5);
        s.setName(" ");
        s.setEmail("email");

        Set<ConstraintViolation<Person>> result=validator.validate(s);

        System.out.println("遍历输出错误信息:");
        //getPropertyPath() 获取属性全路径名
        //getMessage() 获取校验后的错误提示信息
        result.forEach(r-> System.out.println(r.getPropertyPath()+":"+r.getMessage()));
    }
}

演示结果:

遍历输出错误信息:
    email:不是一个合法的电子邮件地址
    collection:家庭成员不能为空
    array:个人学历不能为空
    name:姓名不能为空
    isMarried:是否已婚不能为空

嵌套对象校验

在实际代码开发过程中,需要数据校验的对象大多数是嵌套对象。

组织机构实体类嵌套关系:机构->雇员->人
|--Org  
|----Employee 
|------List<Person>  

Org.java 

温馨提示:对于嵌套对象校验要注意, 需要在内部引用的对象上用到@Valid注解,否则不会校验被引用对象的内部字段

@Data
public class Org {
    @NotNull
    private Integer id;
  
    @Valid  //如果此处不用Valid注解,则不会去校验Employee对象的内部字段  
    @NotNull(message = "employee不能为空")
    private Employee employee;
}

 Employee.java

@Data
public class Employee {
    @Valid
    @NotNull(message = "person不能为空")

    /**
     * 此处用到容器元素级别的约束: List<@Valid @NotNull Person>  
     * 会校验容器内部元素是否为null,否则为null时会跳过校验
     * NotNull注解的target包含ElementType.TYPE_USE,因此NotNull可以给泛型注解
     */
    private List<@Valid @NotNull Person> people;
}

Person.java

@Data
public class Person {

    @NotBlank(message = "姓名不能为空")
    private String name;
    
    @NotNull(message = "年龄不能为空")
    @Range(min = 0, max = 100, message = "年龄必须在{min}和{max}之间")
    private Integer age;

    @NotNull(message = "是否已婚不能为空")
    private Boolean isMarried;
    
    @NotNull(message = "是否有小孩不能为空")
    private Boolean hasChild;
    
    @NotNull(message = "小孩个数不能为空")
    private Integer childCount;

    @NotNull(message = "是否单身不能为空")
    private Boolean isSingle;
    
}

测试功能代码:

@Test
public void test() {
    Person p=new Person();
    p.setAge(30);
    p.setName("zhangsan");
    //p.setIsMarried(true);

    Person p2=new Person();
    p2.setAge(30);
    //p2.setName("zhangsan2");
    p2.setIsMarried(false);
    //p2.setHasChild(true);

    Org org=new Org();
    //org.setId(1);

    List<Person> list=new ArrayList<>();
    list.add(p);
    list.add(p2);
    //增加一个null,测试是否会校验元素为null
    list.add(null);

    Employee e=new Employee();
    e.setPeople(list);
    org.setEmployee(e);

    Set<ConstraintViolation<Org>> result=validator.validate(org);

    System.out.println("遍历输出错误信息:");
    result.forEach(r-> System.out.println(r.getPropertyPath()+":"+r.getMessage()));

}

演示结果:

id:不能为null
Employee.people[0].childCount:小孩个数不能为空
Employee.people[0].isSingle:是否单身不能为空
Employee.people[1].hasChild:是否有小孩不能为空
Employee.people[0].isMarried:是否已婚不能为空
Employee.people[1].name:姓名不能为空
Employee.people[1].childCount:小孩个数不能为空
Employee.people[2].<list element>:不能为null
Employee.people[0].hasChild:是否有小孩不能为空
Employee.people[1].isSingle:是否单身不能为空

Hibernate Validator 分组校验

功能需求:当People对象为已婚时(isMarried字段为true),需要校验”配偶姓名“、”是否有小孩“等字段不能为空,当People对象为未婚时,需要校验“是否单身”等其他字段不能为空, 这种需求可以通过分组检验来实现,将校验逻辑分为两个组,然后每次调用校验接口时指定分组即可实现不同的校验。 如果不管“是否已婚”都需要校验的字段(如姓名、年龄这些字段等),则可以同时指定两个分组。

静态分组

静态分组主要在类上面是使用@GroupSequence注解指定一个或者多个分组,用于处理不同的校验逻辑。

@GroupSequence({ Group.UnMarried.class, Group.Married.class })
public class People {
    ... ... 
}

静态分组不是我们关注的重点,已经知晓它的使用,我们直接跳过当前章节。

动态分组

“未婚”和“已婚”两个分组的动态功能代码如下。

温馨提示:分组标识必须是一个Class,而且没有要求实现特定的接口和实现类,仅仅只是一个标记而已,因此我采用接口实现分组标记。

public interface Group {
    //已婚情况的分组校验
    interface Married {}

    //未婚情况的分组校验
    interface UnMarried {}

}

 校验对象:People.java

@Data
public class People {

    //不管是否已婚,都需要校验的字段,groups里面指定两个分组
    @NotBlank(message = "姓名不能为空",groups = {Group.UnMarried.class, Group.Married.class})
    private String name;

    @NotNull(message = "年龄不能为空",groups = {Group.UnMarried.class, Group.Married.class})
    @Range(min = 0, max = 100, message = "年龄必须在{min}和{max}之间",groups = {Group.UnMarried.class, Group.Married.class})
    private Integer age;

    @NotNull(message = "是否已婚不能为空",groups = {Group.UnMarried.class, Group.Married.class})
    private Boolean isMarried;

    //已婚需要校验的字段
    @NotNull(message = "配偶姓名不能为空",groups = {Group.Married.class})
    private String spouseName;

    //已婚需要校验的字段
    @NotNull(message = "是否有小孩不能为空",groups = {Group.Married.class})
    private Boolean hasChild;

    //未婚需要校验的字段
    @NotNull(message = "是否单身不能为空",groups = {Group.UnMarried.class})
    private Boolean isSingle;
}

测试功能代码:通过isMarried的值来动态指定分组校验

@Test
public void testGroup() {
    People p=new People();
    p.setAge(30);
    p.setName(" ");
    p.setIsMarried(false);

    Set<ConstraintViolation<People>> result;
    //通过isMarried的值来动态指定分组校验
    if(p.getIsMarried()){
        //如果已婚,则按照已婚的分组字段
        result=validator.validate(p, Group.Married.class);
    }else{
        //如果未婚,则只校验未婚的分组字段
        result=validator.validate(p, Group.UnMarried.class);
    }

    System.out.println("遍历输出错误信息:");
    result.forEach(r-> System.out.println(r.getPropertyPath()+":"+r.getMessage()));
}

测试结果,p.setIsMarried(true)

遍历输出错误信息:
name:姓名不能为空
isSingle:是否单身不能为空

测试结果,p.setIsMarried(false)

遍历输出错误信息:
name:姓名不能为空
hasChild:是否有小孩不能为空
spouseName:配偶姓名

动态分组优化

针对数据校验,我最初的想法是全部委托给Hibernate-Validator 框架,但在动态分组的校验测试功能代码时,还是添加了额外的业务逻辑判断功能代码: 

  //通过isMarried的值来动态指定分组校验
    if(p.getIsMarried()){
        //如果已婚,则按照已婚的分组字段
        result=validator.validate(p, Group.Married.class);
    }else{
        //如果未婚,则只校验未婚的分组字段
        result=validator.validate(p, Group.UnMarried.class);
    }

还有没有优化提升的空间呢?

解决办法:第一步:通过DefaultGroupSequenceProvider接口,可以实现真正的动态分组校验。

定义PeopleGroupSequenceProvider类实现DefaultGroupSequenceProvider接口,覆写getValidationGroups方法,在其中判断Person.isMarried值,来实现动态设置分组,也就是将校验的额外判断逻辑从校验框架外层转移到了校验框架中,外层业务代码只需要调用校验接口即可,而无需关注具体的校验逻辑.

public class PeopleGroupSequenceProvider implements DefaultGroupSequenceProvider<People> {
    @Override
    public List<Class<?>> getValidationGroups(People bean) {
        List<Class<?>> defaultGroupSequence = new ArrayList<>();
        // 这里必须将校验对象的类加进来,否则没有Default分组会抛异常,这个地方还没太弄明白,后面有时间再研究一下  
        defaultGroupSequence.add(People.class);
        
        if (bean != null) {
            Boolean isMarried=bean.getIsMarried();
            ///System.err.println("是否已婚:" + isMarried + ",执行对应校验逻辑");
            if(isMarried!=null){
                if(isMarried){
                    System.err.println("是否已婚:" + isMarried + ",groups: "+Group.Married.class);
                    defaultGroupSequence.add(Group.Married.class);
                }else{
                    System.err.println("是否已婚:" + isMarried + ",groups: "+Group.UnMarried.class);
                    defaultGroupSequence.add(Group.UnMarried.class);
                }

            }else {
                System.err.println("isMarried is null");
                defaultGroupSequence.add(Group.Married.class);
                defaultGroupSequence.add(Group.UnMarried.class);
            }

        }else{
            System.err.println("bean is null");
        }
        return defaultGroupSequence;
    }
}

第二步:People类使用@GroupSequenceProvider注解指定一个GroupSequenceProvider

@GroupSequenceProvider(PeopleGroupSequenceProvider.class)
public class People {
    //字段同上   
    //... ...
}

 测试校验代码:

@Test
public void testGroupSequence(){
    People p=new People();
    p.setAge(30);
    p.setName(" ");

    System.out.println("----已婚情况:");
    p.setIsMarried(true);
    Set<ConstraintViolation<People>> result=validator.validate(p);
    System.out.println("遍历输出错误信息:");
    result.forEach(r-> System.out.println(r.getPropertyPath()+":"+r.getMessage()));

    System.out.println("----未婚情况:");
    p.setIsMarried(false);
    result=validator.validate(p);
    System.out.println("遍历输出错误信息:");
    result.forEach(r-> System.out.println(r.getPropertyPath()+":"+r.getMessage()));
    
}

测试结果:

----已婚情况:
遍历输出错误信息:
name:姓名不能为空
spouseName:配偶姓名不能为空
hasChild:是否有小孩不能为空
----未婚情况:
遍历输出错误信息:
name:姓名不能为空
isSingle:是否单身不能为空

Hibernater-Validator 自定义约束注解

定义自定义约束,有三个步骤

  • 创建约束注解
  • 实现一个验证器
  • 定义默认的错误信息

实战:自定义手机号码校验器

@Documented
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Constraint(validatedBy = {MobileValidator.class})
@Retention(RUNTIME)
@Repeatable(Mobile.List.class)
public @interface Mobile {

    /**
     * 错误提示信息,可以写死,也可以填写国际化的key
     */
    String message() default "手机号码不正确";

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

    String regexp() default "^1([38][0-9]|4[579]|5[0-3,5-9]|6[6]|7[0135678]|9[89])\\d{8}$";

    @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
    @Retention(RUNTIME)
    @Documented
    @interface List {
        Mobile[] value();
    }
}

知识点拓展:自定义约束重点属性讲解

  • message 错误提示信息,可以写死,也可以填写国际化的key
  • groups 分组信息,允许指定此约束所属的验证组(下面会说到分组约束)
  • payload 有效负载,可以通过payload来标记一些需要特殊处理的操作

@Repeatable注解和@List定义可以让该注解在同一个位置重复多次,通常是不同的配置(比如不同的分组和消息)

@Constraint(validatedBy = {MobileValidator.class})该注解是指明我们的自定义约束的验证器。温馨提示 :自定义验证器必须实现javax.validation.ConstraintValidator接口

public class MobileValidator implements ConstraintValidator<Mobile, String> {

    /**
     * 手机验证规则
     */
    private Pattern pattern;

    @Override
    public void initialize(Mobile mobile) {
        pattern = Pattern.compile(mobile.regexp());
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value == null) {
            return true;
        }

        return pattern.matcher(value).matches();
    }
}

实战:自定义枚举类校验器

@Documented
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.AMNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy={EnumValueValidator.class})
public  @interface EnumValue{
    String message() default "{EnumValueValidator's value is invalid}";

    Class<?> groups() default {};

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

    Class<? extends StringCodeEnum> enumClass();

    boolean isRequired() default false;
}
import javax.annotation.Nonnull;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import com.zzg.common.base.web.formatter.StringCodeEnum;

public class EnumValueValidator implements ConstraintValidator<EnumValue, Object> {
    private  Class<? extends StringCodeEnum> enumClass = null;

    private Boolean isRequired =  null;

    private static <E extends StringCodeEnum> E off(@Nonnull Class<E> classType, String value) {
        for(E enumConstant: classType.getEnumConstants()){
            if(enumConstant.getCode().equalsIgnoreCase(value)){
                return enumConstant;
            }
        }
        return null;
    }


    @Override
    public void initialize(EnumValue constraintAnnotation) {
            enumClass = constraintAnnotation.enumClass();
            isRequired  = constraintAnnotation.is
    }

    @Override
    publlic boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext ) {
        if(o == null) {
            return !isRequired;
        }

        try{
            StringCodeEnum enumObj = off(enumClass, String.valueof(o));
            return enumObj == null ? Boolean.FALSE : Boolean.TRUE;
        } catch(Exception e) {
            return Boolean.TRUE;
        }
    }

}
public BaseOrg{

    ******
    
    @ApiModeProperty("企业备案类别")
    @NotBlank(message ="企业备案类别不能为空")
    @EnumValue(message ="企业备案类别不在取值范围内", enumClass=EQYLBValue, isRequired=true)
    private String qylb;
        
    ******
}

SpringBoot 中使用Hibernate Validator

上面介绍了Validator的一些使用,还有注解的介绍,那么在Spring中我们怎么去使用Hibernate Validator做验证呢?或者说再Web项目中怎么使用Hibernate Validator?

spring-boot-starter-web中是添加了hibernate-validator依赖的,说明Spring Boot本身也是使用到了Hibernate Validator验证框架的

配置Validator

@Configuration
public class ValidatorConfig {

    /**
     * 配置验证器
     *
     * @return validator
     */
    @Bean
    public Validator validator() {
        ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
                .configure()
                // 快速失败模式
                .failFast(true)
                // .addProperty( "hibernate.validator.fail_fast", "true" )
                .buildValidatorFactory();
        return validatorFactory.getValidator();
    }
}

可以通过方法 failFast(true)或 addProperty("hibernate.validator.fail_fast", "true")设置为快速失败模式,快速失败模式在校验过程中,当遇到第一个不满足条件的参数时就立即返回,不再继续后面参数的校验。否则会一次性校验所有参数,并返回所有不符合要求的错误信息。

Controller层 请求参数验证

在Controller参数前加上@Valid或Spring的 @Validated注解,这两种注释都会导致应用标准Bean验证。如果验证不通过会抛出BindException异常,并变成400(BAD_REQUEST)响应;或者可以通过ErrorsBindingResult参数在控制器内本地处理验证错误。另外,如果参数前有@RequestBody注解,验证错误会抛出MethodArgumentNotValidException异常。

第一种情况:请求参数被@Valid + @RequestBody 修饰情况

@Api(tags="楼栋信息", value="楼栋信息")
@RestController
@RequestMapping("/base/building")
public class BaseBuildingController{
    @Resource
    private IBaseBuildingService baseBuildingService;
    
     /**
     * 验证不通过抛出 `MethodArgumentNotValidException`
     */
    @ApiOperation(tags={"楼栋信息新增"}, value="楼栋信息新增")
    @PostMapping(value="/insert")
    public BaseBuildingVO insert(@RequestBody @Validated BaseBuildingDTO dto){
         BaseBuildingBO bo = BeanCopierUtil.copy(dto, BaseBuildingBO.class);
         String id = baseBuildingService.saveGeneratedId(bo);
         if(StringUtils.isNotEmpty(id)){
                return BeanCopierUtil.copy(baseBuildingService.selectById(id), BaseBuildingVO.class);
         }
         return null;
    }
}

配置全局异常处理器。

@ControllerAdvice
public Class CommmonGlobalExceptionHandler{
        public static final Logger LOG = LoggerFactory.getLogger(CommmonGlobalExceptionHandler.clas);

     /**
     * hibernate validator 数据绑定验证异常拦截
     *
     * @param e 绑定验证异常
     * @return 错误返回消息
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public R validateErrorHandler(MethodArgumentNotValidException e) {
        ObjectError error = e.getBindingResult().getAllErrors().get(0);
        LOG.info("数据验证异常:{}", error.getDefaultMessage());
        return R.fail(error.getDefaultMessage());
    }

}

第二种情况:请求参数被@Valid + @RequestBody +BindingResult 修饰

@Api(tags="楼栋信息", value="楼栋信息")
@RestController
@RequestMapping("/base/building")
public class BaseBuildingController{
    @Resource
    private IBaseBuildingService baseBuildingService;
    
     /**
     * 验证不通过抛出 `MethodArgumentNotValidException`
     */
    @ApiOperation(tags={"楼栋信息新增"}, value="楼栋信息新增")
    @PostMapping(value="/insert")
    public BaseBuildingVO insert(@RequestBody @Validated BaseBuildingDTO dto, ,BindingResult result){
           // 在控制器内本地处理验证错误
        if (result.hasErrors()) {
            result.getAllErrors().forEach(s -> System.out.println(s.getDefaultMessage()));
             throw new CommonBaseException(ERespCode.ERROR);
        }

         BaseBuildingBO bo = BeanCopierUtil.copy(dto, BaseBuildingBO.class);
         String id = baseBuildingService.saveGeneratedId(bo);
         if(StringUtils.isNotEmpty(id)){
                return BeanCopierUtil.copy(baseBuildingService.selectById(id), BaseBuildingVO.class);
         }
         return null;
    }
}

Hibernate Validator 业务校验工具

在Controller层添加Hibernate-Validator 注解标签基本就能满足日常开发需求,但是还有一种情况下是满足不了的,就是非HTTP接口,在使用Service服务就不能使用这种方式,需要另外的在业务代码中进行校验。这个时候就无法使用BindingResult来直接获取校验结果。怎么办呢?

第一步:添加Hibernate-Validator 业务校验工具类;

public class  ValidatorUtil{

    private static final Validator validatorFast = Validation.byProvider(HibernateValidator.class)
    .configure()
    .failFast(true)
    .buildValidatorFactory()
    .getValidator();

   private static final Validator validatorAll = Validation.byProvider(HibernateValidator.class)
    .configure()
    .failFast(false)
    .buildValidatorFactory()
    .getValidator();

    /**
     * 快速校验: 校验所有字段,抛出第一个不合法字段的异常信息
     *
     */
    public static <T> void validateFast(Collection<T> cols, Class<?>... groups){
        for(T entity : cols) {
            validateFast(entity, groups);
        }
    }
    
    /**
     * 快速校验: 校验所有字段,抛出第一个不合法字段的异常信息
     *
     */
    public static <T> void validateFast(T entity, Class<?>... groups>){
        Set<ConstraintViolation<T>> validateResult = validatorFast.validate(entity, groups);
        if(validateResult.size() > 0) {
            throw new CommonException("", validateResult.iterator().next().getMessage());
        }
    }
    
    /**
     * 快速校验: 校验所有字段,返回第一个不合法字段的异常信息
     *
     */
    public static <T> ConstraintViolation<T> getValidatorFastResult(T entity, Class<?>... groups) {
         Set<ConstraintViolation<T>> validateResult = validatorFast.validate(entity, groups);
         if(validateResult.size() > 0){
                return validateResult.iterator().next();
        }
        return null;
    } 

    /**
     * 全部校验: 校验所有字段,抛出所有不合法字段的异常信息
     *
     */
    public static <T> void validateALL(Collection<T> cols, Class<?>... groups){
        for(T entity : cols) {
            validateAll(entity, groups);
        }
    }
    
     /**
     * 全部校验: 校验所有字段,抛出所有不合法字段的异常信息
     *
     */
    public static <T> void validateAll(T entity, Class<?>... groups){
        Set<ConstraintViolation<T>> validateResult = validatorAll .validate(entity, groups);
        if(validateResult.size() > 0) {
            Iterator<ConstraintViolation<T>> iterator = validateResult.iterator();
            StringJoiner joiner = new StringJoiner(";");
            while(iterator.hasNext()){
                joiner.add(iterator.next().getMessage());
            }
             throw new CommonException("", joiner.toString());
        }
    }

     /**
     * 全部校验: 校验所有字段,返回不合法字段的信息
     *
     */
    public static <T> Set<ConstraintViolation<T>> getValidatorAllResult(T entity, Class<?>... groups) {
        return validatorAll.validate(entity, groups);
    }

}

第二步:在Service中调用Hibernate-Validator 工具类。

private void writerValidatorMessage(BaseHouse house) {

        Set<ConstraintViolation<BaseHouse>> validateResult = ValidatorUtil.getValidatorAllResult(house);

        List<BaseDataDealDetail> errorRecordList= new CopyWriteArrayList<BaseDataDealDetail>();

    if(validateResult.size() > 0 ){

                validateResult.parallelStream().forEach((validateItem ->{

                  // 插入字段错误详情记录信息

        }))

   }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/83487.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【软件测试】刚入职后,快速适应新的工作需要做啥?

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 入职一家新公司后&a…

基于AD8226的环境光传感器电路

人们越来越多地认为环境光是一种能源,可用于驱动心率监控器、浴室灯具、远程天气传感器和其他低功耗器件。对于能量采集系统,最关键的是精确测量环境光的能力。本设计思路将描述一种简单的低成本电路,可以根据环境光的强度按一定比例提供电压。 所用传感器是一款光敏电阻(L…

spring framework 容器

org.springframework.beans 和 org.springframework.context 包是 Spring Framework 的 IoC 容器的基础。 这里需掌握两个体系结构&#xff0c;BeanFactory 和 ApplicationContext。 BeanFactory 主要接口&#xff0c;可分为三级&#xff1a; BeanFactory 是顶层容器&#xf…

Nacos 配置中心之主动拉取

客户端 客户端的配置有两种方式来维持,一是客户端主动拉取,而是客户端长轮询更新 配置文件的种类 1、本地配置文件: 本地就已经存在的配置文件 2、 本地缓存文件: 从服务端获取的保存在了本地 (本地生成了文件) 3、 cacheData 缓存数据: 内存中缓存的配置文件数据 客户端主动获…

【分享】学浪PC端登录分析及实现

本文所有教程及源码、软件仅为技术研究。不涉及计算机信息系统功能的删除、修改、增加、干扰,更不会影响计算机信息系统的正常运行。不得将代码用于非法用途,如侵立删!学浪PC端登录分析及实现 环境 win10Fiddlerchrome学浪PC端登录:aHR0cHM6Ly9zdHVkZW50LWFwaS5peWluY2Fpc2…

AE 动效制作和交付方案

在界面设计中&#xff0c;设计师利用动效让整个界面更加活泼&#xff0c;给界面元素带来生命力&#xff0c;解决功能上的问题&#xff0c;在更好地展示产品功能的基础上&#xff0c;凸显品牌的特色。而作为用户&#xff0c;动效增强了体验者的审美感受、情感需要&#xff0c;让…

德才论

目录 1015:德才论 输入格式&#xff1a; 输出格式&#xff1a; 输入样例&#xff1a; 输出样例&#xff1a; 思路: 1.技巧&#xff1a; 1.2结构体代码: 2.分类: 1.德才分类 1.2德才分类代码: 2.cmp函数 2.1 cmp函数代码: 3.超时问题(易错&#xff0c;算法要优化) 总代码…

神经网络优化

提升深度神经网络&#xff1a;超参数调节&#xff0c;正则化&#xff0c;优化 之前已经学习了如何构建神经网络&#xff0c;本章将继续学习如何有效运行神经网络&#xff0c;内容涉及超参数调优&#xff0c;如何构建数据以及如何确保优化算法快速运行&#xff0c;从而使学习算…

LVM卷在线扩容报错:resize would cause inodes_count overflow

一、问题描述 某次在线环境&#xff0c;存储使用率告警在线扩容时&#xff0c;文件系统扩容失败&#xff0c;报错如下&#xff1a; Size of logical volume sihua/video changed from <162.00 TiB (42467321 extents) to <258.00 TiB (67633142 extents).Logical volu…

[附源码]计算机毕业设计付费自习室管理小程序Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; Springboot mybatis MavenVue等等组成&#xff0c;B/S模式…

【JDBC上篇】什么是JDBC

文章目录1、对JDBC本质的理解2、代码模拟JDBC的本质3、JDBC编程的六步4、通过类加载的方式注册驱动5、属性配置文件与JDBC6、处理查询结果集1、对JDBC本质的理解 Java DataBase Connectivity&#xff08;Java语言连接数据库&#xff09;&#xff0c;其本质是SUN公司指定的一套…

CSP22.3 T4通信系统管理

之前在CCF CSP认证2022年3月完整题解这篇博客记录了自己花了两天时间乱搞出来的方法&#xff0c;但是实际上动态维护区间最值&#xff0c;通过setsetset实现会更简洁&#xff0c;用优先队列需要额外开数组记录堆中节点的有效性。 而且在处理额度失效上&#xff0c;我也使用了最…

教你用响应式建站平台搭建网站

响应式网站搭建大家知道是什么吗&#xff1f;我们可以经常听到PC端网站、移动端网站&#xff0c;这些就是为特定终端而制作的网站版本&#xff0c;而响应式网站就是一个网站能够兼容多个终端&#xff0c;而不是为每个终端做一个特定的版本。那么我们怎么用响应式建站平台搭建网…

基于极限学习机(ELM)进行多变量用电量预测(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️❤️&#x1f4a5;&#x1f4a5;&#x1f4a5; &#x1f389;作者研究&#xff1a;&#x1f3c5;&#x1f3c5;&#x1f3c5;本科计算机专业&#xff0c;研究生电气学硕…

使用adb命令导出hprof文件

我们可以使用android studio profiler导入hprof文件分析android应用的内存问题。那么如何从手机上面导出这份文件呢&#xff1f; 把应用的heap 区的数据取出来保存在一个hprof文件上&#xff0c;然后把hprof文件导入到可以查看这个文件的工具上&#xff08;如android studio p…

Spring Security总结

目录 介绍 项目搭建 Security认证 UserDetailsService 内存认证 数据库认证 PasswordEncoder密码解析器 自定义登录页面 退出登录 CSRF防护 Remember me Security授权 RBAC 权限表设计 查询访问权限 配置类设置访问权限 自定义访问控制逻辑 注解设置访问权限 Secured Pre…

29.前端笔记-HTML-Html5的新特性

目录1、HtML5新增的语义化标签2、HTML5新增的多媒体标签&#xff08;1&#xff09;音频标签&#xff1a;< audio>audio的常见属性&#xff08;2&#xff09;视频标签&#xff1a;< video>video常见属性3、新增表单元素input的类型type4、新增表单属性1、HtML5新增的…

R语言中的生存分析Survival analysis晚期肺癌患者4例

第1部分&#xff1a;生存分析简介 最近我们被客户要求撰写关于生存分析的研究报告&#xff0c;包括一些图形和统计输出。本演示文稿将介绍生存分析 &#xff0c;参考&#xff1a; Clark, T., Bradburn, M., Love, S., & Altman, D. (2003). Survival analysis part I: Ba…

06 数学软件与建模---拟合

一、知识储备 1.曲线拟合问题的提法 已知一组&#xff08;二维&#xff09;数据&#xff0c;即平面上 n个点&#xff08;xi,yi) i1,…,n, 寻求一个函数&#xff08;曲线&#xff09;yf(x), 使 f(x) 在某种准则下与所有数据点最为接近&#xff0c;即曲线拟合得最好&#xff0…

前后端分离项目-Springboot 【后端框架搭建,SSM】

1.创建新项目 点击File->New->Project 选择Spring Initializr 填写信息 修改Group修改Artifact修改管理类型Maven&#xff08;带有文件目录&#xff09;修改Java version 选择依赖 这里只需要选择Web->Spring Web即可 创建的文件目录如下 2.创建文件目录 controlle…