Springboot数据加密篇

一、密码加密

1.1Hash算法(MD5/SHA-512等)

哈希算法,又称摘要算法(Digest),是一种将任意长度的输入通过散列函数变换成固定长度的输出的单向密码体制。这种映射的规则就是哈希算法,而通过原始数据映射之后得到的二进制值串就是哈希值。

哈希算法最重要的特点就是:相同的输入一定得到相同的输出,不同的输入可能得到相同的输出,但不可能通过输出反推出原始输入。这意味着哈希算法可以用于快速比较两个数据是否相同,常用于密码存储、数字签名、数据完整性校验等领域。

Hash算法特性 

  • 唯一性。数据通过hash算法计算的hash值是唯一的
  • 压缩性。例如,任意长度的数据,算出的MD5值的长度是固定的(128位二进制数,32位十六进制数)
  • 不可逆。无法从结果复原源数据信息
  • 抗修改。对原数据的任何改动,hash值完全不同
  • 强抗碰撞。伪造数据非常困难
  • 容易计算。从原数据计算出值很容易

Hash算法无法转换回源数据,因此是签名算法,不是加密/解密算法(无解密)

即,仅判断是不是源数据,不知道源数据是什么。因此适合,验证敏感源数据的正确性。例如,验证密码(如何判断密码正确?) 

 Hash算法缺点

 1.2加Salt算法

Salt(盐)是在密码学中常用的一种安全措施,其本质是一段随机的字符串。在密码加密过程中,Salt会被添加到原始密码中,再通过散列函数进行散列,最终生成一个唯一的散列值。

Salt的主要作用是增加破解密码的难度,因为即使两个用户使用了相同的密码,由于Salt的存在,他们的密码散列值也会不同。这就意味着,攻击者即使获取了数据库中的密码散列值,也无法通过简单的对比找到匹配的原始密码。

 1.3Spring-Security

Spring提供了一套安全框架,处理加密/解密数据信息 提供了包括对称/非对称加密,不同Hash算法等一系列实现

 相关配置

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

相关接口

PasswordEncoder(org.springframework.security.crypto.password)接口

PasswordEncoder接口是Spring Security中用于对密码进行加密的接口。它提供了一种通用的方法来将明文密码转换为加密后的密码,以便在存储和验证过程中使用。

  • String encode(CharSequence rawPassword),编码密码
  • boolean matches(CharSequence rawPassword, String encodedPassword),验证原始密码与编码密码
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

public class PasswordEncoderExample {
    public static void main(String[] args) {
        // 创建PasswordEncoder实例
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

        // 原始密码
        String plainPassword = "myPassword";

        // 加密密码
        String encodedPassword = passwordEncoder.encode(plainPassword);

        System.out.println("原始密码: " + plainPassword);
        System.out.println("加密后的密码: " + encodedPassword);
    }
}

 Pbkdf2PasswordEncoder类,Pbkdf2算法

 Pbkdf2PasswordEncoder类是Spring Security中的一个密码编码器,它使用PBKDF2算法对密码进行加密。PBKDF2是一种密钥导出函数,它可以从用户输入的密码生成一个足够复杂的密钥,以保护存储在数据库中的密码。

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

public class PasswordEncoderExample {
    public static void main(String[] args) {
        // 创建Pbkdf2PasswordEncoder对象
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

        // 原始密码
        String plainPassword = "myPassword";

        // 使用Pbkdf2算法加密密码
        String encodedPassword = passwordEncoder.encode(plainPassword);

        System.out.println("原始密码: " + plainPassword);
        System.out.println("加密后的密码: " + encodedPassword);
    }
}

 BCryptPasswordEncoder类,Bcrypt算法

BCryptPasswordEncoder类是Spring Security中的一个密码编码器,它使用Bcrypt算法对密码进行加密。Bcrypt是一种加密算法,它可以生成一个足够复杂的哈希值来保护存储在数据库中的密码。自动生成随机盐值,并附在结果,避免盐值的单独保存

  • 128bits随机二进制数,16bytes,base64,24chars,特殊算法转为22chars
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

public class PasswordEncoderExample {
    public static void main(String[] args) {
        // 创建BCryptPasswordEncoder对象
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

        // 原始密码
        String plainPassword = "myPassword";

        // 使用Bcrypt算法加密密码
        String encodedPassword = passwordEncoder.encode(plainPassword);

        System.out.println("原始密码: " + plainPassword);
        System.out.println("加密后的密码: " + encodedPassword);
    }
}

1.4实现

配置类

package com.passwordencoder;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class SecurityConfiguration {
    // 定义一个名为getPasswordEncoder的方法,返回类型为PasswordEncoder
    @Bean
    public PasswordEncoder getPasswordEncoder() {
        // 创建一个新的BCryptPasswordEncoder对象并返回
        return new BCryptPasswordEncoder();
    }
}

状态类

package com.passwordencoder.vo;

import lombok.Builder;
import lombok.Data;

import java.util.Map;

@Data
@Builder
public class ResultVO {
    private int code;
    private String message;
    private Map<String, Object> data;

    public static ResultVO success(Map<String, Object> data) {
        return ResultVO.builder().code(200).data(data).build();
    }

    public static ResultVO error(int code, String msg) {
        return ResultVO.builder().code(code).message(msg).build();
    }
}

实体类

package com.passwordencoder.entity;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class User04 {
    private String userName;
    private String password;
}

服务类

package com.example.springmvcexamples.example04.passwordencoder.service;

import com.example.springmvcexamples.example04.passwordencoder.entity.User04;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Slf4j // 使用lombok的注解,简化代码并自动生成getter、setter等方法
@Service // 标记这是一个Spring服务类
public class UserService04 {

    // 根据用户名获取用户信息的方法
    public User04 getUser(String userName) {
        // 如果用户名为"BO",则返回一个包含用户名和加密密码的用户对象
        return "BO".equals(userName)
                ? User04.builder() // 使用User04的构建器模式创建一个新的用户对象
                .userName("BO") // 设置用户名为"BO"
                .password("$2a$10$A7OcKw5xxRMh9c4ghWySr.Rjh22gpWyiWExZO5i2B32eJLQrFXcr6") // 设置加密后的密码
                .build() // 构建并返回用户对象
                : null; // 如果用户名不为"BO",则返回null
    }
}

处理类

package com.passwordencoder.controller;



import com.passwordencoder.entity.User04;
import com.passwordencoder.service.UserService04;
import com.passwordencoder.vo.ResultVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@Slf4j
@RestController
@RequestMapping("/api/example04/")
@RequiredArgsConstructor
public class ExampleController04 {

    private final UserService04 userService;
    private final PasswordEncoder passwordEncoder;

    @PostMapping("login")
    public ResultVO login(@RequestBody User04 user) {
        // 先查询用户是否存在
        User04 u = userService.getUser(user.getUserName());
        if (u == null || !passwordEncoder.matches(user.getPassword(), u.getPassword())) {
            log.debug("登录失败");
            return ResultVO.error(401, "用户名密码错误");
        }
        // 登录成功,添加token等操作
        log.debug("登录成功");
        return ResultVO.success(Map.of("user", u));
    }
}

测试

POST http://localhost:8081/api/example04/login
Content-Type: application/json

{
  "userName": "BO",
  "password": "12345"
}

二、序列化与反序列化

  • SpringMVC默认基于Jackson实现序列化/反序列化
  • SpringMVC自动注入Jackson ObjectMapper映射对象到容器
    • String writeValueAsString(T payload),将对象序列化为json字符串
    • T readValue(String content, Class c),将json字符串反序列化为指定类型的Java对象

TypeReference<T>抽象类。创建子类,具体化泛型。可通过创建类似接口的匿名内部类实现

三、token令牌

 3.1概述

Token令牌是一种用于身份验证和授权的凭证,通常由服务器生成并发送给用户。它包含有关用户的信息,例如用户名、角色等,以及一些会话信息,例如过期时间等。当用户尝试访问受保护的资源时,他们需要提供有效的Token令牌以证明其身份和权限。服务器将验证Token令牌的有效性,并根据其中包含的信息授予或拒绝用户的请求。

Restful设计思想,服务器端不再保存用户状态(无HttpSession)

  • 用户登录后,将用户身份/权限信息封装在Token(令牌)
  • ·将token信息加密(Authorization)通过http header返给客户端
  • ·客户端每次需要身份/权限的请求,均需在http header携带Authorization
  • ·服务器端拦截权限请求,从Authorization中解密出Token权鉴

实现

  • ·JWT。流行的认证标准,信息由header/payload/,signature组成,多种实现
  • ·自定义Token。更灵活,数据量小

3.2适合敏感数据的加密传输 

加密/解密算法,适合敏感数据的加密传输

  • 对称加密算法(AES等),通过相同密钥加密/解密
  • 非对称加密算法(RSA等),公钥加密的数据,必须通过私钥才能解密 

密钥生成器

my:
  secretkey: R28K42ZEJ8LWRHU5
  salt: 636eac2534bcfcb0

实体类

package com.example.springmvcexamples.example05;

import lombok.Data;

@Data
public class MyToken {
    public enum Role{
        USER, ADMIN
    }
    private Integer uid;
    private Role role;
}

组件类

package com.example.springmvcexamples.example05.textencryptor;

import com.example.springmvcexamples.example02.handlingexception.exception.MyException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.encrypt.Encryptors;
import org.springframework.security.crypto.encrypt.TextEncryptor;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Map;

@Component
public class EncryptComponent05 {

    private final ObjectMapper objectMapper;
    @Value("${my.secretkey}")
    private String secretKey;
    @Value("${my.salt}")
    private String salt;
    private TextEncryptor encryptor;

    public EncryptComponent05(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    /**
     * 直接基于密钥/盐值创建单例TextEncryptor对象。避免反复创建
     */
    @PostConstruct
    public void getTextEncryptor() {
        encryptor = Encryptors.text(secretKey, salt);
    }

    public String encrypt(Map<String, Object> payload) {
        try {
            String json = objectMapper.writeValueAsString(payload);
            return encryptor.encrypt(json);
        } catch (JsonProcessingException e) {
            throw new MyException(500, "服务器端错误");
        }
    }

    /**
     * 无法验证/解密/反序列化,说明数据被篡改,判定无权限
     * @param auth
     * @return
     */
    public Map<String, Object> decrypt(String auth) {
        try {
            String json = encryptor.decrypt(auth);
            return objectMapper.readValue(json, Map.class);
        } catch (Exception e) {
            throw new MyException(403, "无权限");
        }
    }
}

@Component注解

`@Component`注解是Spring框架中的一个注解,用于标记一个类作为Spring容器中的组件。当Spring容器启动时,会自动扫描带有`@Component`注解的类,并将这些类实例化为对象,然后将这些对象存储在Spring容器中,以便在其他组件中通过依赖注入的方式使用。

测试一

package com.example.springmvcexamples.example05;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.crypto.encrypt.Encryptors;
import org.springframework.security.crypto.encrypt.TextEncryptor;

import java.util.HashMap;
import java.util.Map;

@SpringBootTest
@Slf4j
public class EncryptorTest {
    // 自动注入ObjectMapper对象,用于将对象转换为JSON字符串和将JSON字符串转换为对象
    @Autowired
    private ObjectMapper objectMapper;
    // 从配置文件中获取加密密钥
    @Value("${my.secretkey}")
    private String secretKey;
    // 从配置文件中获取盐值
    @Value("${my.salt}")
    private String salt;
    // 测试方法
    @Test
    public void test_encrypt() {
        // 创建加密器,使用密钥和盐值进行加密
        TextEncryptor encryptor = Encryptors.text(secretKey, salt);
        try {
            // 创建一个包含uid和role的Map对象
            Map<String, Object> map = Map.of("uid", 1384896304762638307L, "role", 9);
            // 将Map对象转换为JSON字符串
            String json = objectMapper.writeValueAsString(map);
            // 使用加密器对JSON字符串进行加密
            String r = encryptor.encrypt(json);
            // 输出加密后的字符串
            log.debug(r);
            // 输出加密后的字符串长度
            log.debug("{}", r.length());
            // 再次使用加密器对JSON字符串进行加密,验证加密结果是否一致
            log.debug(encryptor.encrypt(json));

            // 使用加密器对加密后的字符串进行解密
            String reJson = encryptor.decrypt(r);
            // 将解密后的JSON字符串转换为Map对象
            Map<String, Object> reToken = objectMapper.readValue(reJson, Map.class);
            // 输出解密后的Map对象中的role值
            log.debug(reToken.get("role").toString());
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }
}

测试二

package com.example.springmvcexamples.example05;

import com.example.springmvcexamples.example05.textencryptor.EncryptComponent05;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.Map;

@SpringBootTest
@Slf4j
public class TextEncryptorTest {
    @Autowired
    private EncryptComponent05 encrypt;



    @Test
    public void test_encrypt() {
//        MyToken Token = new MyToken();
//        Token.setUid(1);
//        Token.setRole(MyToken.Role.ADMIN);
        Map<String, Object> map = Map.of("uid", 1384896304762638307L, "role", 9);
        String r = encrypt.encrypt(map);
        log.debug(r);
        log.debug("{}", r.length());
        log.debug(encrypt.encrypt(map));
    }

    @Test
    public void test_decrypt() {
        String auth = "b3a60e67dfcd220874e36569f623829ea97d556d646b4eb208c2f43" +
                "b452bbf61a3e5982e0a52810517bcc734a5561e2dc53a9e3854d5fd4afebf0b15b7c1ad5c";
        Map<String, Object> token = encrypt.decrypt(auth);
        log.debug("{}", token.get("uid"));
        log.debug("{}", token.get("role"));
    }
}

四、拦截器

HandlerInterceptor (org.springframework.web.servlet.HandlerInterceptor)接口

  • Boolean preHandle()方法:controller方法执行前回调,返回false,则不会继续执行。登录验证等
  • Void postHandle()方法:perHandle()返回true后,controller方法执行后
  • afterCompletion方法:postHandle()执行后,回调
  • Object handle,封装被拦截方法对象

拦截器类

InterceptorRegistry

  • addInterceptor(),添加拦截器组件
  • addPathPatterns(),添加拦截路径
  • excludePathPatterns(),添加排除路径
  • 可声明多个拦截器,按顺序拦截
package com.example.springmvcexamples.example06.interceptor.interceptor;

import com.example.springmvcexamples.example02.handlingexception.exception.MyException;
import com.example.springmvcexamples.example05.textencryptor.EncryptComponent05;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

@Component // 将LoginInterceptor06类标记为Spring容器中的组件
@Slf4j // 使用log4j进行日志记录
@RequiredArgsConstructor // 通过构造函数注入依赖,避免在实例化时需要手动注入依赖
public class LoginInterceptor06 implements HandlerInterceptor {
    private final EncryptComponent05 encryptComponent; // 注入加密组件

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getHeader("token"); // 从请求头中获取token
        if (token == null) {
            throw new MyException(401, "未登录"); // 如果token为空,抛出自定义异常
        }
        Map<String, Object> result = encryptComponent.decrypt(token); // 解密token,获取用户信息
        request.setAttribute("role", result.get("role")); // 将用户角色设置到请求属性中,以便后续处理中使用
        return true; // 返回true表示继续执行后续的拦截器和处理器
    }
}

 配置类

package com.example.springmvcexamples;

import com.example.springmvcexamples.example06.interceptor.interceptor.LoginInterceptor06;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@RequiredArgsConstructor
public class WebMvcConfiguration implements WebMvcConfigurer {

    private final LoginInterceptor06 adminInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(adminInterceptor)
                .addPathPatterns("/api/example06/admin/**");
    }

}

五、定时服务(Timer Service)

定时服务(Timer Service):用以调度安排所有基于定时通知的工作流程

支持指定时间、某一时间后、指定时间间隔内的定时通知

Spring Task Execution and Scheduling

  • 基于TaskExecutor,TaskScheduler接口
  • 基于注解
  • 基于Quartz Scheduler第三方库

@Scheduled

@Scheduled注解是Spring框架中的一个注解,用于标记一个方法为定时任务。它可以与@Scheduled注解一起使用,或者与TaskScheduler接口一起使用。

使用@Scheduled注解的方法会在指定的时间间隔内自动执行

定时任务方法声明在组件内,方法必须无返回值

  • fixedRate,每次执行间隔时间,即使上一任务未执行完依然执行任务(毫秒)
  • fixedDelay,每次执行完成到下一次开始执行间隔时间,即上一任务执行结束后,过指定时间执行任务(毫秒)
  • initialDelay,第一次执行前的延迟时间(毫秒)
  • Cron,指定执行时间表达式

Cron表达式

顺序:秒、分、时、日、月、星期(数字或单词缩写)、年(可省略,即每年)。值为数字或符号

默认不支持从后计算(不支持L) 

启动类

package com.example.springmvcexamples;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;

@SpringBootApplication
@EnableScheduling
public class SpringmvcExamplesApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringmvcExamplesApplication.class, args);
    }
}

 @EnableScheduling注解

@EnableScheduling注解是Spring框架中的一个注解,用于开启定时任务功能。在Spring Boot应用中,可以通过在主类上添加该注解来启用定时任务。

组件类

package com.example.springmvcexamples.example07.timer;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class MyTimer {
    @Scheduled(cron = "0 0 8 10 * ?")
    public void paySalary() {
        log.debug("Your salary has been paid!");
    }
}

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PMP项目管理 - 整合管理

系列文章目录 系统架构设计 PMP项目管理 - 质量管理 PMP项目管理 - 采购管理 PMP项目管理 - 资源管理 PMP项目管理 - 风险管理 PMP项目管理 - 沟通管理 现在的一切都是为将来的梦想编织翅膀&#xff0c;让梦想在现实中展翅高飞。 Now everything is for the future of dream…

Amazon Toolkit — CodeWhisperer 使用

tFragment--> 官网&#xff1a;https://aws.amazon.com/cn/codewhisperer/?trkcndc-detail 最近学习了亚马逊云科技的 代码工具&#xff0c;感慨颇多。下面是安装 和使用的分享。 CodeWhisperer&#xff0c;亚马逊推出的实时 AI 编程助手&#xff0c;是一项基于机器学习…

C语言struct,union内存对齐

测试环境&#xff1a; #include<stdio.h> int main(){//1字节对齐struct XXX{unsigned char ch;unsigned int in;unsigned short si;}__attribute__((packed));struct XXX xxx;printf("%zd\n",sizeof(xxx));//7#pragma pack(1)struct YYY{unsigned char ch;u…

文心一言 VS 讯飞星火 VS chatgpt (161)-- 算法导论13.1 1题

一、用go语言&#xff0c;按照图 13-1(a)的方式&#xff0c;画出在关键字集合(1&#xff0c;2&#xff0c;…&#xff0c;15)上高度为 3 的完全二叉搜索树。以三种不同方式向图中加入 NIL 叶结点并对各结点着色&#xff0c;使所得的红黑树的黑高分别为2、3和4。 文心一言&…

Eigen库之Quaterniond

Eigen::Quaterniond 是 Eigen C++ 库中用于表示四元数的类,四元数在计算机图形学、机器人学等领域中广泛用于表示旋转操作。 四元数是一种数学结构,通常用于表示和计算三维空间中的旋转。一个四元数由一个实部和三个虚部组成,可以写成如下形式: 主要性质和运算: 以下是如何…

R语言【cli】——cli_warn可以更便捷的在控制台输出警告信息

Package cli version 3.6.2 cli_warn(message, ..., .envir parent.frame()) 参数【message】&#xff1a;它是通过调用 cli_bullets() 进行格式化的。进一步地&#xff0c;还需要调用 inline-makeup&#xff08;内联标记&#xff09;。 参数【...】&#xff1a;传递给 rlan…

Lamda表达式和匿名内部类

文章目录 前言一、匿名内部类是什么&#xff1f;1.实现接口和抽象类(普通类也可以&#xff09;2.可实现接口或继承抽象类&#xff1a;3. 访问外部变量&#xff1a; 二、Lambda表达式1.语法三.区别&#xff1a; 总结 前言 匿名内部类和抽象类总是往&#xff0c;现在来写一篇文章…

如何用DevEcoStudio创建本地模拟器

第一步&#xff1a;打开devEcoStudio 工具 第二步&#xff1a;点击IDE 右上角previewer - Device Manager 第三步&#xff1a;选择Local Emulator 的tab &#xff0c;如果要创建的设备类型为Phone 选中即可 第四步&#xff1a;点击界面的右下角 New Emulator 第五步&#xff…

ansible的脚本---playbook剧本

ansible的脚本---playbook剧本 playbook组成部分 1、tasks任务&#xff1a;包含要在目标主机上执行的操作&#xff0c;使用模块定义这些操作&#xff0c;每个任务都是一个模块的调用 2、varlables变量&#xff1a;存储和传递数据&#xff0c;变量可以自定义&#xff0c;可以…

Android 大版本升级变更截图方法总结

Android 大版本升级变更截图方法总结 一、Android R (11) 平台二、Android S (12) 平台三、Android U (14) 平台 Android 原生的截屏功能是集成在 SystemUI 中&#xff0c;因此我们普通应用想要获取截图方法&#xff0c;就需要研读下 SystemUI 截屏部分的功能实现。 一、Androi…

Java--包,访问修饰符,多态数组,==和equals,hashcode,toString

包 同一个包里面不能有重复的类&#xff0c;不同的包可以有相同的类&#xff0c;包和包之间互不干涉。一个包下面有很多的类。 包的命名规则&#xff1a; 只能包含数字&#xff0c;字母&#xff0c;下划线&#xff0c;小圆点&#xff0c;但不能用数字开头&#xff0c;不能是关…

Databend 开源社区上榜 2023 年度 OSCHINA 优秀开源技术团队

2023 年 12 月 8 日&#xff0c;OSCHINA 对其平台上众多认证的官方技术团队和开源社区进行了全面评估&#xff0c;并颁发了“ 2023 年度优秀开源技术团队”奖项&#xff0c;以表彰各团队在推动中国开源生态系统发展方面所展现的创新能力和显著贡献。 在这一评选中&#xff0c;…

【开源软件】2022年最佳开源软件-排名第一:AlmaLinux

自我介绍 做一个简单介绍&#xff0c;酒架年近48 &#xff0c;有20多年IT工作经历&#xff0c;目前在一家500强做企业架构&#xff0e;因为工作需要&#xff0c;另外也因为兴趣涉猎比较广&#xff0c;为了自己学习建立了三个博客&#xff0c;分别是【全球IT瞭望】&#xff0c;【…

网络编程 DAY6 作业

1.使用数据库创建一个工人信息库&#xff0c;包含工号&#xff08;主键&#xff09;、姓名、年龄、薪资 2.添加三条工人信息&#xff08;可以完整信息&#xff0c;也可以非完整信息&#xff09; 3.修改某一个人的薪资&#xff08;确定的一个&#xff09; 4.展示出工资在10000到…

C++ Qt开发:StringListModel字符串列表映射组件

Qt 是一个跨平台C图形界面开发库&#xff0c;利用Qt可以快速开发跨平台窗体应用程序&#xff0c;在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置&#xff0c;实现图形化开发极大的方便了开发效率&#xff0c;本章将重点介绍QStringListModel字符串映射组件的常用方法及…

智慧工地一体化云平台APP源码:监管端、工地端、危大工程、智慧大屏、物联网、塔机、吊钩、升降机

智慧工地管理平台是依托物联网、互联网建立的大数据管理平台&#xff0c;是一种全新的管理模式&#xff0c;能够实现劳务管理、安全施工、绿色施工的智能化和互联网化。 智慧工地源码技术说明 1.微服务架构JavaSpring Cloud UniApp MySql 2.支持多端展示&#xff08;PC端、手…

istio 认证:对等身份认证+服务请求认证

istio 中有两种不同的身份认证方式&#xff1a; 基于 mTLS 的对等身份认证 PeerAuthentication基于 JWT&#xff08;JSON Web Token&#xff09;令牌的服务请求认证 RequestAuthentication 对等身份认证 PeerAuthentication 概念 提供服务到服务的认证服务网格的主要场景就…

循环神经网络中的梯度消失或梯度爆炸问题产生原因分析

循环神经网络中&#xff0c;通过时间反向传播&#xff08;backpropagation through time&#xff0c;BPTT&#xff09;实际上是循环神经网络中反向传播技术的一个特定应用。 &#xff08;1&#xff09;它要求我们将循环神经网络的计算图以此展开一个时间步&#xff0c;以获得模…

Redis BitMap(位图)

这里是小咸鱼的技术窝&#xff08;CSDN板块&#xff09;&#xff0c;我又开卷了 之前经手的项目运行了10多年&#xff0c;基于重构&#xff0c;里面有要实现一些诸如签到的需求&#xff0c;以及日历图的展示&#xff0c;可以用将签到信息存到传统的关系型数据库&#xff08;MyS…

BBS项目--登录

BBS阶段性测试总要求 django登录报错 Error: [WinError 10013] 以一种访问权限不允许的方式做了一个访问套接字的尝试。 原因分析&#xff1a;出现这种情况在Windows中很常见&#xff0c;就是端口被占用 解决措施&#xff1a;这时我们只需改一下端口便可以了 登录前端页面(HTML…