Spring Boot 参数校验 Validation 使用

news2024/11/15 14:00:36

概述

当我们想提供可靠的 API 接口,对参数的校验,以保证最终数据入库的正确性,是必不可少的活。前、后端校验都是保证参数的准确性的手段之一,前端校验并不安全,任何人都可以通过接口来调用我们的服务,就算加了一层token的校验,有心人总会转空子,来传各式各样错误的参数,如果后端不校验,导致数据库数据混乱。传统的方式使用if-else进行参数校验太太繁琐了,如果有几十个字段要校验,那这个方法里面将会变得非常臃肿,实在不够优雅。

虽然使用if else进行参数校验可以实现基本的校验功能,但是这种方式存在以下几个问题:

  1. 代码冗余:如果需要对多个接口进行参数校验,就需要在每个接口中编写相同的校验逻辑,代码冗余,维护成本高。
  2. 可读性差:如果校验逻辑比较复杂,那么使用 if else 进行校验的代码可读性较差,不利于代码的维护和优化。
  3. 安全性差:如果使用 if else 进行校验,那么恶意用户可能会利用漏洞绕过校验,从而导致安全问题。

因此,使用参数校验框架可以有效地解决上述问题,具有以下几个优点:

  1. 简化代码:使用参数校验框架可以简化校验逻辑,减少代码冗余,提高代码的可读性和可维护性。
  2. 提高安全性:参数校验框架可以避免参数注入、SQL 注入、XSS 攻击等安全问题,提高系统的安全性和可靠性。
  3. 提高效率:使用参数校验框架可以提高开发效率,减少开发时间和成本,并且可以方便地进行扩展和定制。

总之,使用参数校验框架可以有效地提高系统的安全性、可靠性和可维护性,减少代码冗余,提高开发效率,是开发过程中不可或缺的一部分。

为什么要使用 Spring Validation 权限校验框架?

有哪些参数校验框架呢?

以下是几个常用的参数校验框架:

  1. Hibernate Validator :Hibernate Validator 是一个基于 Bean Validation 标准的参数校验框架,可以实现对 Java Bean 属性的校验,支持多种校验注解和自定义校验规则。

  2. Spring Validation :Spring Validation 是 Spring 框架提供的参数校验框架,基于 Bean Validation 标准,可以实现对 Java Bean 属性和方法参数的校验,支持多种校验注解和自定义校验规则。

  3. Apache Commons Validator :Apache Commons Validator 是一个通用的参数校验框架,支持多种校验规则和自定义校验规则,可以实现对字符串、数字、日期等数据类型的校验。

  4. JSR-303 :JSR-303 是 Java EE 6 中定义的 Bean Validation 标准,提供了一套参数校验规范和 API,可以实现对 Java Bean 属性的校验,支持多种校验注解和自定义校验规则。

  5. Bean-Validation:Bean-Validation 是一款轻量级的参数校验框架,基于 JSR-303 标准,可以实现对 Java Bean 属性的校验,支持多种校验注解和自定义校验规则。

这些框架都可以实现对参数的校验,提供了一套完整的校验规范和 API ,可以有效地避免非法参数和恶意攻击,提高系统的安全性和可靠性。根据不同的业务需求和技术栈,可以选择不同的框架进行参数校验。

为什么使用 Spring Validation ?

  1. 基于 Bean Validation 标准:Spring Validation 是基于 Bean Validation 标准的参数校验框架,可以实现对 Java Bean 属性和方法参数的校验,提供了一套完整的校验规范和 API,可以很方便地进行扩展和定制。

  2. 支持多种校验注解:Spring Validation 支持多种校验注解,比如 @NotNull、@Size、@Min、@Max 等,可以满足不同的校验需求,同时也支持自定义校验注解。

  3. 集成方便:Spring Validation 是 Spring 框架提供的参数校验框架,与 Spring 框架集成非常方便,可以通过简单的配置实现参数校验。

  4. 可扩展性强:Spring Validation 提供了很好的扩展性,可以自定义校验注解和校验器,满足不同的校验需求。

  5. 可读性高:Spring Validation 的校验注解非常简洁明了,代码可读性高,可以很方便地查看和维护校验逻辑。

总之,使用 pring Validation 参数校验框架可以提高代码的可读性和可维护性,减少代码冗余,提高开发效率,同时还可以有效地避免非法参数和恶意攻击,提高系统的安全性和可靠性。

1、SpringBoot之validation

1.1 validation注解说明

validation 包下其它常用的校验注解:

注意: 字段上面的注解千万不要用错了,不然会报内部错误

注解含义
@Null任何类型必须为null。
@NotBlank字符串、字符类不能为null,并且去掉空格后长度大于0。
@NotNull任何类型不能为null。
@Length(min = 6, max = 8, message = “密码长度为6-8位。”)字符串的长度必须在指定的范围内。
@NotEmpty适用于String、Collection集合、Map、数组等,参数不能为null且长度大于0。
@AssertTrueBoolean、boolean属性必须是true。
@AssertFalseBoolean、boolean属性必须是false。
@Min(10)必须是一个数字,且其值必须大于等于指定的最小值(整型)。
@Max(10)必须是一个数字,且其值必须小于等于指定的最大值(整型)。
@DecimalMin(“10”)必须是一个数字,且其值必须大于等于指定的最小值(字符串,可以是小数)。
@DecimalMax(“10”)必须是一个数字,且其值必须小于等于指定的最大值(字符串,可以是小数)。
@Size(max = 10, min = 1)限定集合的大小必须在指定范围内。
@Digits(integer = 3, fraction = 2, message = “请输入有效的数字”)用于验证数字的整数位数和小数位数限制。
@Past时间、日期必须是一个过去的时间或日期。
@Future时间、日期必须是一个未来的时间或日期。
@Email字符串必须是一个有效的邮箱格式。
@Pattern(regexp = “[a-zA-Z]*”, message = “密码不合法”)字符串、字符必须匹配指定的正则表达式。
@Range(max = 150, min = 1, message = “年龄范围应该在1-150内。”)数字类型(原子和包装)必须在指定的范围内。
@URL(protocol=, host=, port=, regexp=, flags=)被注释的字符串必须是一个有效的URL。
@CreditCardNumber被注释的字符串必须通过Luhn校验算法,通常用于银行卡、信用卡等号码。
@ScriptAssert(lang=, script=, alias=)要求存在支持Java Scripting API(JSR 223)的实现。
@SafeHtml(whitelistType=, additionalTags=)要求classpath中存在jsoup包,用于验证HTML内容的安全性。

1.2 @Valid和@Validated区别

@Valid(javax.validation包下) 和 @Validated(org.springframework.validation.annotation包下)注解。两者大致有以下的区别:

名称是否实现声明式校验是否支持嵌套校验是否支持分组校验
@Validfalsetruefalse
@Validatedtruefalsetrue

绝大多数场景下,我们使用 @Validated 注解即可。而在有嵌套校验的场景,我们使用 @Valid 注解添加到成员属性上。

@Valid
  • 来源@Valid 是 JSR-303/JSR-349 Bean Validation API 的一部分,该 API 被广泛称为 Bean Validation 或 Hibernate Validator(尽管 Hibernate Validator 是该 API 的一个流行实现)。
  • 使用场景:它通常用于方法级别的参数验证,如 Spring MVC 控制器中的方法参数。
  • 功能:触发方法参数或返回类型的验证。在 Spring MVC 中,它会自动触发 Spring 的数据绑定和验证机制。
  • 限制:默认情况下,@Valid 不能用在类型级别(如类级别)进行组验证,尽管可以通过一些配置或自定义逻辑来实现。
@Validated
  • 来源@Validated 是 Spring Framework 提供的注解,用于扩展 @Valid 的功能。
  • 使用场景:它不仅可以用于方法级别的参数验证,还可以用于类级别以支持组验证。
  • 功能:除了基本的验证功能外,@Validated 还支持分组验证,允许你根据不同的上下文应用不同的验证规则。
  • 分组验证:这是 @Validated 相对于 @Valid 的主要优势。通过定义不同的验证组,可以在不同的情况下应用不同的验证规则。
比较
  • 基本功能:两者都用于触发 Bean 验证。
  • 来源@Valid 来自 JSR-303/JSR-349 Bean Validation API,而 @Validated 是 Spring 特有的。
  • 分组验证@Validated 支持分组验证,而 @Valid 不直接支持(尽管可以通过其他方式实现)。
  • 使用场景:对于简单的验证场景,@Valid 通常就足够了。但是,如果你需要更复杂的验证逻辑,比如分组验证,那么 @Validated 是更好的选择。
结论

在大多数基本情况下,@Valid@Validated 可以互换使用,因为它们都触发了 Bean 验证。然而,当你需要利用分组验证或其他 Spring 特有的验证功能时,@Validated 提供了更多的灵活性和控制。因此,在选择使用哪个注解时,你应该根据你的具体需求和上下文来决定。

基本使用

参数校验分为简单校验、嵌套校验、分组校验。

1.3 SpringBoot Validation 快速失败(failFast)

SpringBoot Validation 快速失败是指在使用Spring Boot进行参数校验时,当遇到第一个校验失败的情况时,立即停止后续的校验,并抛出异常。这种机制有助于减少不必要的资源消耗,并使得错误信息更加明确和易于处理。以下是关于SpringBoot Validation 快速失败的一些关键点和实现方式:

1、背景与问题

在使用Spring Boot进行开发时,通常会使用Hibernate Validator(或Spring的spring-boot-starter-validation)来进行参数校验。默认情况下,如果一个对象中有多个字段需要校验,并且这些字段使用了多个校验注解(如@NotNull、@Max等),Hibernate Validator会按顺序依次校验这些字段。如果某个字段校验失败,它不会立即停止校验,而是会继续校验其他字段,直到所有字段都被校验完毕。这可能会导致以下问题:

  • 返回给前端的错误信息过多,不够明确。
  • 浪费系统资源,因为不必要的校验操作仍在继续。
2、实现方式

为了解决上述问题,可以配置Hibernate Validator以启用快速失败模式(failFast)。这样,当遇到第一个校验失败时,就会立即停止后续的校验。以下是几种实现方式:

@Configuration
public class ValidatorConfig {

    // 第一种
    @Bean
    @ConditionalOnMissingBean(Validator.class)
    public LocalValidatorFactoryBean validator() {
        LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
        factoryBean.getValidationPropertyMap().put(BaseHibernateValidatorConfiguration.FAIL_FAST, Boolean.TRUE.toString());
        return factoryBean;
    }

    // 第二种
    @Bean
    public Validator validator(AutowireCapableBeanFactory springFactory) {
        try (ValidatorFactory factory = Validation.byProvider(HibernateValidator.class)
                .configure()
                // 快速失败
                .failFast(true)
                // 解决 SpringBoot 依赖注入问题
                .constraintValidatorFactory(new SpringConstraintValidatorFactory(springFactory))
                .buildValidatorFactory()) {
            return (Validator) factory.getValidator();
        }
    }

}

1.4 validation实战

1、导入依赖

新建项目,导入以下依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>swagger-bootstrap-ui</artifactId>
            <version>1.9.6</version>
        </dependency>
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-annotations</artifactId>
            <version>1.6.1</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
    </dependencies>
2、创建工具类

在项目的根目录下面创建utils包,并在此包下面创建全局统一的返回结果对象Results

/**
 * 用于返回
 * @param <T>
 */
@ApiModel("统一返回类")
public class Results<T> {
    public static final String ERROR = "500";
    public static final String SUCCESS = "200";

    /**
     * 返回码
     */
    @ApiModelProperty("返回码,正确码为:200")
    private String resCode ;

    /**
     * 返回消息
     */
    @ApiModelProperty("返回消息")
    private String msg ;

    /**
     * 返回实体
     */
    @ApiModelProperty("返回实体")
    private T obj;

    public static <T> Results<T> success(){
        return success(SUCCESS,"成功",null);
    }

    public static <T> Results<T> success(String msg){
        return success(SUCCESS,msg,null);
    }

    public static <T> Results<T> success(T obj){
        return success(SUCCESS,"成功",obj);
    }

    public static <T> Results<T> success(String msg,T obj){
        return success(SUCCESS,msg,obj);
    }

    public static <T> Results<T> success(String resCode,String msg,T obj){
        Results<T> result = new Results<T>();
        result.setResCode(resCode);
        result.setMsg(msg);
        result.setObj(obj);
        return result;
    }

    public static <T> Results<T> failed() {
        return failed(ERROR,"失败",null);
    }

    public static <T> Results<T> failed(String msg) {
        return failed(ERROR,msg,null);
    }

    public static <T> Results<T> failed(String msg,T obj) {
        return failed(ERROR,msg,obj);
    }

    public static <T> Results<T> failed(String resCode,String msg) {
        return failed(resCode,msg,null);
    }

    public static <T> Results<T> failed(Integer resCode,String msg) {
        return failed(String.valueOf(resCode),msg);
    }

    public static <T> Results<T> failed(String resCode,String msg,T obj) {
        Results<T> result = new Results<T>();
        result.setResCode(resCode);
        result.setMsg(msg);
        result.setObj(obj);
        return result;
    }

    public static <T> Results<T> failedNoPermission() {
        return failed(90005,"没有权限");
    }
    public static <T> Results<T> failedNoPermission(String msg) {
        return failed(90005,msg);
    }


    public static <T> Results<T> failedParameterException() {
        return failed(90004,"参数异常");
    }
    public static <T> Results<T> failedParameterException(String msg) {
        return failed(90004,msg);
    }

    public static <T> Results<T> failedLoginException() {
        return failed(90002,"登录失败");
    }
    public static <T> Results<T> failedLoginException(String msg) {
        return failed(90002,msg);
    }

    public String getResCode() {
        return resCode;
    }

    public void setResCode(String resCode) {
        this.resCode = resCode;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getObj() {
        return obj;
    }

    public void setObj(T obj) {
        this.obj = obj;
    }

    @Override
    public String toString() {
        return "Results{" +
                "resCode='" + resCode + '\'' +
                ", msg='" + msg + '\'' +
                ", obj=" + obj +
                '}';
    }
}
3、创建全局异常处理类

在项目的根目录下面创建config包,并在此包下面创建全局统一的返回结果对象ExceptionControllerAdvice

  • 缺少参数抛出的异常是MissingServletRequestParameterException

  • 单参数校验失败后抛出的异常是ConstraintViolationException

  • get请求的对象参数校验失败后抛出的异常是BindException

  • post请求的对象参数校验失败后抛出的异常是MethodArgumentNotValidException

不同异常对象的结构不同,对异常消息的提取方式也就不同。

  • ConstraintViolationException:单个参数校验失败(后端实际接收的一个字段)

  • BindException:表单对象参数违反约束,仅对于表单提交有效(接收参数没有加@RequestBody注解),对于以json格式提交将会失效

  • MethodArgumentNotValidException:JSON请求参数违反约束,为json格式有效(接收参数加上@RequestBody注解)

  • MissingServletRequestParameterException:参数缺失

  • MethodArgumentTypeMismatchException:请求参数的类型与处理器方法参数类型不匹配

  • HttpMessageNotReadableException:请求体为空、无效的JSON格式、无法将JSON转换为目标对象

@RestControllerAdvice
public class ExceptionControllerAdvice {

    /**
     * BindException:表单对象参数违反约束,仅对于表单提交有效(接收参数没有加@RequestBody注解),对于以json格式提交将会失效
     * MethodArgumentNotValidException:JSON请求参数违反约束,为json格式有效(接收参数加上@RequestBody注解)
     * ConstraintViolationException:单个参数校验失败(后端实际接收的一个字段)
     * @param e
     * @return
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(value = {BindException.class,ConstraintViolationException.class, MethodArgumentNotValidException.class})
    public Results MethodArgumentNotValidExceptionHandler(Exception e) {
        // 从异常对象中拿到ObjectError对象
        BindingResult br = null;
        if (e instanceof MethodArgumentNotValidException) {
            br = ((MethodArgumentNotValidException) e).getBindingResult();
        } else if (e instanceof BindException) {
            br = ((BindException) e).getBindingResult();
        } else if (e instanceof ConstraintViolationException) {
            Set<ConstraintViolation<?>> violations = ((ConstraintViolationException) e).getConstraintViolations();
            if (CollectionUtils.isEmpty(violations)) {
                return Results.failed(String.valueOf(500));
            }
            Map<String, String> map = violations.stream()
                    .collect(Collectors.toMap(o -> {
                        PathImpl x = (PathImpl) o.getPropertyPath();
                        return x.getLeafNode().toString();
                    }, ConstraintViolation::getMessage, (k1, k2) -> k1));
            return Results.failed(400,map.toString());
        }
        if (br.hasFieldErrors()) {
            List<FieldError> fieldErrorList = br.getFieldErrors();
            List<String> errors = new ArrayList<>(fieldErrorList.size());
            for (FieldError error : fieldErrorList) {
                errors.add(error.getField() + ":" + error.getDefaultMessage());
            }
            // 然后提取错误提示信息进行返回
            return Results.failed(400,errors.toString());
        }
        // 然后提取错误提示信息进行返回
        return Results.failed("校验错误");
    }
    
}
4、创建实体类

在项目的根目录下面创建model包,并在此包下面创建全局统一的返回结果对象User

@Data
public class User {

    @NotNull(message = "用户名不能为空")
    @Size(min = 5, max = 20, message = "用户名长度必须在5到20之间")
    private String username;

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

    @NotNull(message = "年龄不能为空")
    @Min(value = 18, message = "年龄必须大于18")
    private Integer age;

    @Email(message = "邮箱格式不对")
    private String email;
    
    @NotEmpty(message = "爱好不能为空")
    private List<String> hobbies;

}
5、创建视图层Controller

在项目的根目录下面创建controller包,并在此包下面创建全局统一的返回结果对象TestController

@Validated // 单/多个参数校验需要加的注解,不加参数校验不生效
@RestController
public class TestController {

        // 会进入到MethodArgumentNotValidException异常处理方法
    @PostMapping("/post")
    public Results post(@RequestBody @Validated User user) {
        try {
            return Results.success(user);
        } catch (Exception e) {
            return Results.failed();
        }
    }

    // 多个参数校验需要在controller类上面添加@Validated注解(会进入到ConstraintViolationException全局异常方法里面)
    @GetMapping("/getConstraint")
    public Results getConstraint(@NotBlank(message = "姓名不能为空") String name, @NotNull(message = "年龄不能为空")
    @Min(value = 18, message = "年龄必须大于18") Integer age) {
        try {
            return Results.success();
        } catch (Exception e) {
            return Results.failed();
        }
    }

    // 会进入到BindException异常处理方法
    @GetMapping("/getBindException")
    public Results getBindException(@Validated User user) {
        try {
            return Results.success(user);
        } catch (Exception e) {
            return Results.failed();
        }
    }

    // 自定义BindException异常,会进入到BindException异常处理方法
    @PostMapping("/testBindException")
    public Results testBindException(@RequestBody @Valid User user, BindingResult bindingResult) {
        try {
            // 检查验证结果
            if (bindingResult.hasErrors()) {
                // 手动抛出BindException,触发异常处理
                throw new BindException(bindingResult);
            }
            return Results.success(user);
        } catch (Exception e) {
            return Results.failed();
        }
    }

}
6、测试结果

post方法
在这里插入图片描述

getConstraint方法

在这里插入图片描述

getBindException方法

在这里插入图片描述

1.5 分组校验

使用方式(示例说明)

准备工作:自定义两个分组。

提示: 继承Default并不是必须的。只是说,如果继承了Default,那么@Validated(value = Create.class)的校验范畴就
为【Create】和【Default】;如果没继承Default,那么@Validated(value = Create.class)的校验范畴只
为【Create】,而@Validated(value = {Create.class, Default.class})的校验范畴才为【Create】和【Default】。

注: Default组和无参构造机制类似,当没有指定分组时,会默认当前校验属于Default组,但是一旦主动给当前校验指定
了分组(如上图中的name字段,主动指定了属于Create组),那么就不会再额外指定属于Default组了。
追注:当然,也可以画蛇添足的主动指定所属分组为Default。

1、在User类里面添加以下内容
    @NotBlank(message = "密码不能为空",groups = {Add.class})
    private String password;

    @NotNull(message = "id不能为空",groups = {Update.class})
    private Integer id;

    public interface Update {
    }
    public interface Add extends Default {
    }
2、在controller里面添加以下内容
    @PostMapping("/addUser")
    public Results addUser(@Validated(User.Add.class) @RequestBody User uer) {
        try {
            return Results.success();
        } catch (Exception e) {
            return Results.failed();
        }
    }

    @PostMapping("/updateUser")
    public Results updateUser(@Validated(User.Update.class) @RequestBody User user) {
        try {
            return Results.success();
        } catch (Exception e) {
            return Results.failed();
        }
    }
3、测试

addUser方法

在这里插入图片描述

updateUser方法

在这里插入图片描述

1.6 多级嵌套模型的校验

1、在model下面创建用户相关的类

Address

@Data
public class Address {
    @NotBlank(message = "城市不能为空",groups = {User.Add.class})
    private String city;
    @NotBlank(message = "城市编码不能为空",groups = {User.Add.class})
    private String zipCode;
}

UserProfile

@Data
public class UserProfile {
    @NotBlank(message = "个人简介不能为空",groups = {User.Add.class})
    private String bio;
    @NotBlank(message = "头像URL不能为空",groups = {User.Add.class})
    private String avatarUrl;
    @NotBlank(message = "社交媒体链接不能为空",groups = {User.Add.class})
    private String linkedinUrl;
}
2、在User类里面添加以下内容
  	@Valid
    private Address address;

    @Valid
    private UserProfile userProfile;
3、测试

addUser方法

在这里插入图片描述

非常感谢以下博主:

https://blog.csdn.net/weixin_51262499/article/details/129910551

https://blog.csdn.net/csdnzhang365/article/details/129141189

https://blog.csdn.net/justry_deng/article/details/86571671

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

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

相关文章

springboot电影购票系统-计算机毕业设计源码85384

目录 摘要 1 绪论 1.1 选题背景与意义 1.2国内外研究现状 1.3论文结构与章节安排 2系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1系统开发流程 2.2.2 用户登录流程 2.2.3 系统操作流程 2.2.4 添加信息流程 2.2.5 修改信息流程 2.2.6 删除信息流程 2.3 系统功能…

ComfyUI插件:ComfyUI layer style 节点(三)

前言&#xff1a; 学习ComfyUI是一场持久战&#xff0c;而ComfyUI layer style 是一组专为图片设计制作且集成了Photoshop功能的强大节点。该节点几乎将PhotoShop的全部功能迁移到ComfyUI&#xff0c;诸如提供仿照Adobe Photoshop的图层样式、提供调整颜色功能&#xff08;亮度…

哪里可以找到数据恢复软件?5 款顶级数据恢复软件分享

在当今的数字时代&#xff0c;我们的数据既是我们最宝贵的资产&#xff0c;也是我们最大的弱点。由于硬件故障、意外删除或软件问题&#xff0c;丢失重要文档、珍贵照片或对职业至关重要的项目的风险始终存在。值得庆幸的是&#xff0c;强大的数据恢复软件可以帮助找回最初看似…

[每周一更]-(第108期):如何保护你的JavaScript代码

文章目录 一、框架如何实现JS的保护1. 模块化和组件化2. 使用环境变量3. 代码混淆和最小化vue.config.js 4. 使用请求库和拦截器axios.js 文件在组件中使用 Axios 拦截器 5. 服务端处理敏感逻辑6. 安全最佳实践使用 CSP 7. 依赖前端框架的内置安全特性8. 数据验证和清理 二、原…

【linux】【操作系统】内核之traps.c源码阅读

C 文件traps.c 是 Linux 内核的一部分&#xff0c;主要处理硬件陷阱和故障。文件中包含多个函数来处理不同类型的异常和错误。下面是详细的解析&#xff1a; 概览 目的&#xff1a;此文件负责处理各种硬件异常和故障。它包括了处理特定类型错误以及初始化异常处理器的函数。文…

uniapp0基础编写安卓原生插件和调用第三方jar包(Ch34的jar包)和如何解决android 如何Application初始化

前言 我假设你会uniapp安卓插件开发了,如果不会请看这篇文章,这篇文章是0基础教学。 这篇文章我们将讲一下如何使用CH34XUARTDriver.jar进行开发成uniapp插件。 它的难点是:uniapp如何Application初始化第三方jar包 先去官网下载CH340/CH341的USB转串口安卓免驱应用库:h…

Spring实现自定义注解

一&#xff0c; 背景 目前部门有一个培训&#xff0c;需要讲一下Spring的使用&#xff0c;看到有同学提出问题&#xff0c;想自定义实现一个打日志的注解&#xff0c;下面就记录一下实现过程。 环境&#xff1a; Spring 6.1.5, 不使用Spring Boot. 二&#xff0c;实现步骤 …

Mysql--权限与安全管理

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 一、权限表 MySQL服务器通过权限表来控制用户对数据库的访问&#xff0c;权限表存放在MySQL数据库中&#xff0c;由MySQL_install_db脚本初始化。存储…

【工具篇】华为VRP通用操作系统 —— 配置文件管理

文章目录 配置文件分类配置文件命令配置文件工作原理 配置文件分类 设备的配置文件通常有两种类型&#xff1a; 1、启动配置文件&#xff08;Startup Configuration&#xff09;&#xff1a; 这是设备启动时加载的配置文件&#xff0c;包含了设备的基本配置信息&#xff0c;如…

Linux 内核源码分析---资源分配及系统总线

资源管理 Linux提供通用的构架&#xff0c;用于在内存中构建数据结构。这些结构描述了系统中可用的资源&#xff0c;使得内核代码能够管理和分配资源。 其中关键的数据结构resource如下&#xff1a; 用于连接parent, child, sibling成员规则如下&#xff1a; 1、每个子结点只…

接口测试学习笔记1

一、行业背景和测试分层 1、招聘需求 1&#xff09;手工测试&#xff1a;业务需求、业务逻辑 2&#xff09;自动化测试&#xff1a;业务逻辑 技术规范 功能自动化 QTP、Selenium 性能自动化 LoadRunner、JMeter 接口自动化 Postman、Fiddler、JMeter、SoapUI... …

值得一读!六本网络安全学习必备书籍推荐

在网络安全领域不断发展的今天&#xff0c;深入学习和掌握相关知识显得尤为重要。以下为大家推荐六本有助于提升网络安全技能的经典书籍。 一、《白帽子讲 Web 安全》 这本书由吴翰清撰写&#xff0c;涵盖了 Web 安全的诸多方面&#xff0c;包括常见的攻击手段、防御方法以及安…

XML 学习笔记

简介&#xff1a; &#xff08;1&#xff09;XML&#xff1a;可扩展性标记语言&#xff0c;用于传输和存储数据&#xff0c;而不是展示数据&#xff0c;是W3C 推举的数据传输格式。 XML的标签必须自定义&#xff0c;但是在写标签名的时候一定要有含义。 XML 只能有一个根节点…

微积分-微分应用7(优化问题)

解决优化问题的步骤&#xff1a; 理解问题 首先要仔细阅读问题&#xff0c;直到完全理解。问问自己&#xff1a;未知数是什么&#xff1f;已知量是什么&#xff1f;给定的条件是什么&#xff1f; 画图 在大多数问题中&#xff0c;画图并在图中标出给定和所需的量是有用的。 引…

用闲置的阿里云服务器使用 NPS 实现内网穿透

最近有个项目需要给外地的同事预览一下&#xff0c;但是公司没有可以公网访问的测试服务器&#xff0c;所以想到用内网穿透的方式让外地同事可以访问到我的本机。刚好我有一台阿里云的服务器&#xff0c;双十一打折买了3年&#xff0c;1000左右&#xff0c;2核8G&#xff0c;买…

24年税务师考试补报名即将开始啦

⏰税务师补报名重要时间节点 1⃣️补报名时间&#xff1a;8月6日10:00至8月16日17:00 2⃣️补报名缴费时间&#xff1a;8月6日10:00至8月18日24&#xff1a;00 3️⃣准考证打印时间&#xff1a;10月28日10:00至11月3日15:00 4⃣️考试时间&#xff1a;11月2日、3日 ✅税务…

c#中的BitConverter的java实现

最近在做c#项目的java迁移&#xff0c;发现部分C#方法java中没有对应实现如图&#xff1a; 且java中的数字类型都是有符号的所以转无符号的时候需要进行手动对符号位& 0xFFFF进行处理&#xff0c;目前只整理了项目中使用到的方法&#xff0c;后续有用到其他方法在进行追加如…

HarmonyOS 与 OpenHarmony 的区别详解

随着科技的不断进步&#xff0c;操作系统在我们日常生活中的重要性日益凸显。华为推出的 HarmonyOS 和 OpenHarmony 正是当前备受关注的两大操作系统。它们虽然紧密相关&#xff0c;但在理念、目标和应用场景上有显著的区别。本文将详细探讨这两者的不同之处。 一、概念解析 …

C++复习的长文指南(二)

C复习的长文指南&#xff08;二&#xff09; 一、面向对象基础知识5. 文件操作5.1文本文件5.1.1写文件5.1.2读文件 5.2 二进制文件5.2.1 二进制文件5.2.2 二进制读文件 6. c面向对象的个人心得开发流程6.16.26.36.46.5注意细节6.16.26.3 二、泛型编程1. 模板1.1 模板的概念1.2 …

GRFB UNet——基于多尺度注意网络盲道检测算法实现与模型C++部署

1. 概述 盲道是视障人士安全出行的重要辅助设施。识别盲道的形状和位置&#xff0c;对于增强视障人士的自主移动能力至关重要&#xff0c;而视觉分割技术正是应对这一挑战的有效工具。为了显著提升盲道分割的精确度和稳定性&#xff0c;本文提出了一种创新的分割方法&#xff…