【Spring Boot】Spring Boot 中常见的加密方案

Spring Boot 中常见的加密方案

  • MD5
    • [MD5 基本概念](#MD5 基本概念)
    • [MD5 的核心思想](#MD5 的核心思想)
    • [MD5 使用方法](#MD5 使用方法)
  • [SHA 系列](#SHA 系列)
    • [SHA 系列概述](#SHA 系列概述)
    • [SHA 的工作原理(通用流程)](#SHA 的工作原理(通用流程))
    • [SHA 使用方法](#SHA 使用方法)
  • BCrypt
    • [BCrypt 概念](#BCrypt 概念)
    • [BCrypt 的工作原理(内部流程)](#BCrypt 的工作原理(内部流程))
    • [BCrypt 使用方法](#BCrypt 使用方法)
  • Argon2
    • [Argon2 概念](#Argon2 概念)
    • [Argon2 设计思想](#Argon2 设计思想)
    • [Argon2 使用方法](#Argon2 使用方法)
  • [Spring Boot 项目使用](#Spring Boot 项目使用)
  • 总结

MD5

MD5 基本概念

MD5 全称是 Message Digest Algorithm 5 (信息摘要算法第 5 版),由密码学家 Ron Rivest 在 1991 年提出。

它的作用是:

把任意长度的数据(字符串、文件等)"压缩"成一个固定长度的 128 位(16 字节)摘要值

这个摘要值通常用 32 位十六进制字符串表示。

示例

复制代码
输入: "hello"
输出: 5d41402abc4b2a76b9719d911017c592

即使只改变一个字符:

复制代码
输入: "Hello"
输出: 8b1a9953c4611296a827abf8c47804d7

可以看到:输入微小变化,输出完全不同

MD5 的核心思想

MD5 并不是"加密",而是一种哈希算法(Hash Function)

即:

  • 不可逆(你无法从 MD5 值反推出原文)
  • 定长输出(无论输入多长,输出始终是 128 位)
  • 雪崩效应(输入改动一位,输出几乎全变)
  • 高速计算(适合快速校验)

原理简述

MD5 的内部逻辑大致如下:

步骤 描述
填充(Padding) 将输入填充到长度 ≡ 448 mod 512,确保数据能被分为 512 位的块。
附加长度 在数据末尾追加原始长度(64 位)。
初始化缓冲区 定义 4 个 32 位寄存器:A、B、C、D(初始常量)。
迭代运算 每个 512 位块通过一系列非线性函数和位运算(如 AND、OR、XOR、左移)混合处理。
输出结果 最终拼接 A、B、C、D 的值 → 128 位摘要。

简单来说:MD5 把输入"分块 → 混合 → 扰乱 → 压缩"成固定长度摘要。

MD5 的特点

特性 说明
输出长度固定 128 位(16 字节),常以 32 个十六进制字符表示。
不可逆 无法解密回原始内容。
雪崩效应 输入变化 1 bit,输出变化约 50%。
快速计算 算法效率高。
碰撞风险 不同的输入可能生成相同的输出(已被证明)。

MD5 的常见用途

应用场景 说明
文件完整性校验 下载软件时验证文件未被篡改。
数据校验码 快速比较数据内容是否一致。
用户密码加密(旧系统) 曾经常用于存储密码(但已不安全)。
数字签名 在安全性较低场景中生成签名摘要。

MD5 使用方法

使用 Spring 自带工具类

Spring 框架提供了简单的 MD5 工具:

java 复制代码
import org.springframework.util.DigestUtils;

public class MD5Example {
    public static void main(String[] args) {
        String input = "hello";
        String md5 = DigestUtils.md5DigestAsHex(input.getBytes());
        System.out.println(md5);
    }
}

输出:

复制代码
5d41402abc4b2a76b9719d911017c592

使用 Java 原生 API

java 复制代码
import java.security.MessageDigest;

public class MD5Example {
    public static void main(String[] args) throws Exception {
        String input = "hello";
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] hashBytes = md.digest(input.getBytes("UTF-8"));
        StringBuilder hex = new StringBuilder();
        for (byte b : hashBytes) {
            hex.append(String.format("%02x", b));
        }
        System.out.println(hex.toString());
    }
}

给密码加盐(增强安全)

加盐(Salt)可以防止彩虹表攻击。

java 复制代码
import java.security.MessageDigest;

public class SaltedMD5 {
    public static void main(String[] args) throws Exception {
        String password = "123456";
        String salt = "MyApp#2025";
        String input = password + salt;

        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] bytes = md.digest(input.getBytes("UTF-8"));

        StringBuilder hex = new StringBuilder();
        for (byte b : bytes) hex.append(String.format("%02x", b));
        System.out.println(hex.toString());
    }
}

MD5 的安全性问题

MD5 已不安全,不推荐用于密码或安全签名。

原因如下:

问题 描述
碰撞攻击 不同输入可得相同 MD5 值。2004 年被正式破解。
彩虹表攻击 攻击者用预计算表快速反查 MD5 值。
暴力破解 由于算法速度太快,适合 GPU 暴力破解。

SHA 系列

SHA 系列概述

SHA(Secure Hash Algorithm) 是由美国 NSA(国家安全局) 设计、NIST(国家标准与技术研究院) 发布的加密哈希家族。

它的作用与 MD5 类似:将任意长度的数据映射为固定长度的"摘要"(digest),用于校验完整性、签名、认证等。

SHA 家族主要分为以下几代:

系列 代表算法 输出长度(bit) 状态 说明
SHA-0 SHA-0 160 已废弃 原版算法(1993),发现安全漏洞,被迅速弃用
SHA-1 SHA-1 160 已被破解 曾广泛用于 SSL、Git、证书签名等,现在不安全
SHA-2 SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256 224~512 主流标准 当前主流使用的安全哈希算法族(JWT、TLS、密码哈希)
SHA-3 SHA3-224、SHA3-256、SHA3-384、SHA3-512 224~512 新一代标准 与 SHA-2 完全不同,基于 Keccak 算法,更抗攻击

SHA 的工作原理(通用流程)

SHA 的计算过程与 MD5 类似,但逻辑更复杂、更安全:

阶段 说明
预处理 填充数据到 512 位的整数倍,附加长度信息
分块 每个 512 位分块单独处理
初始化变量 设定若干 32 位或 64 位寄存器(A、B、C、D...)
循环压缩 通过逻辑函数、位移、模加等运算混合数据
拼接结果 输出固定长度摘要(如 256 位 = 32 字节)

SHA 的核心是"不可逆的数学混合"。

输入稍有改动,输出完全不同(雪崩效应)。

SHA 使用方法

SHA-1(Secure Hash Algorithm 1)

  • 输出长度:160 位(20 字节)
  • 常见输出格式:40 位十六进制字符串
  • 算法速度:快
  • 安全性:已被破解
java 复制代码
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] result = md.digest("hello".getBytes());

曾用于:

  • SSL/TLS 证书签名(已弃用)
  • Git 文件版本校验(正在过渡到 SHA-256)

已被 Google 和荷兰CWI研究所于 2017 年展示 实际碰撞攻击(SHAttered)

SHA-2 系列(主流标准)

SHA-2 实际是多个算法族的统称:

算法 输出长度 常见用途
SHA-224 224 位 嵌入式、低功耗设备
SHA-256 256 位 最常用(JWT、文件校验)
SHA-384 384 位 高强度安全
SHA-512 512 位 适合 64 位系统

SHA-256 是当前最推荐的通用版本。
SHA-512 性能更高(在 64 位机器上),更安全。

Java 实现示例(SHA-256)

java 复制代码
import java.security.MessageDigest;

public class SHA256Example {
    public static void main(String[] args) throws Exception {
        String input = "hello world";
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] hash = digest.digest(input.getBytes("UTF-8"));

        StringBuilder hex = new StringBuilder();
        for (byte b : hash) {
            hex.append(String.format("%02x", b));
        }
        System.out.println(hex.toString());
    }
}

输出(固定 64 位十六进制串):

复制代码
b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9

Spring Boot 工具类实现(SHA-512)

java 复制代码
import org.apache.commons.codec.digest.DigestUtils;

String sha512 = DigestUtils.sha512Hex("password123");
System.out.println(sha512);

文件校验场景

java 复制代码
import java.io.*;
import java.security.MessageDigest;

public static String getFileSHA256(File file) throws Exception {
    MessageDigest digest = MessageDigest.getInstance("SHA-256");
    try (InputStream fis = new FileInputStream(file)) {
        byte[] buffer = new byte[8192];
        int n;
        while ((n = fis.read(buffer)) > 0) {
            digest.update(buffer, 0, n);
        }
    }
    byte[] hash = digest.digest();
    StringBuilder sb = new StringBuilder();
    for (byte b : hash) sb.append(String.format("%02x", b));
    return sb.toString();
}

SHA-3 系列(Keccak)

  • 发布年份:2015(NIST 新标准)
  • 算法基础:基于海绵结构(Sponge Construction)
  • 代表算法:SHA3-224、SHA3-256、SHA3-384、SHA3-512
  • 区别:与 SHA-2 完全不同的内部结构,更抗攻击。
java 复制代码
MessageDigest sha3 = MessageDigest.getInstance("SHA3-256");
byte[] hash = sha3.digest("Hello SHA3".getBytes());

特点

  • 不与 SHA-2 兼容;
  • 可抗长度扩展攻击;
  • 设计为长期替代 SHA-2。

补充说明:

概念 说明
SHA-2 并不是单一算法 它是一整套算法族(不同输出长度的变种)。例如 SHA-256SHA-512 都属于 SHA-2 家族。
SHA-3 并不是 SHA-2 的改进版 它是全新设计(Keccak 结构),没有继承关系。
输出长度 对应输出摘要长度(bit 位数),例如:SHA-256 输出 256 位(32 字节)。
安全状态 SHA-1 已可被构造碰撞,SHA-2 目前仍安全,SHA-3 为未来标准。

正确理解层级关系

mathematica 复制代码
SHA(安全哈希算法家族)
 ├── SHA-0(不安全,废弃)
 ├── SHA-1(不安全,已被破解)
 ├── SHA-2(主流安全标准)
 │     ├── SHA-224
 │     ├── SHA-256
 │     ├── SHA-384
 │     └── SHA-512
 └── SHA-3(新标准,基于 Keccak)
       ├── SHA3-224
       ├── SHA3-256
       ├── SHA3-384
       └── SHA3-512

BCrypt

BCrypt 概念

BCrypt 是什么?

BCrypt 是一种基于 Blowfish 加密算法 的密码哈希函数,由 Niels Provos 和 David Mazières 在 1999 年设计,最初出现在 OpenBSD 系统中。

它属于 单向加密算法(Hashing Algorithm),常用于存储用户密码。

BCrypt 的核心特点

特点 说明
单向不可逆 无法从哈希值反推明文密码。
自动加盐(Salt) 每次加密自动生成随机盐,避免彩虹表攻击。
可调"复杂度因子"(Cost Factor) 可以调整计算强度,防止暴力破解。
输出固定长度(60字符) 无论输入多长,输出总是 60 个字符。
跨语言支持 在 Java、Python、PHP、Go 等语言中都有官方或成熟实现。

BCrypt 的工作原理(内部流程)

BCrypt 的计算过程大致如下:

复制代码
1. 生成随机盐(Salt)
   ↓
2. 将盐与明文密码结合
   ↓
3. 使用 Blowfish 加密算法多轮加密(2^cost 次)
   ↓
4. 输出最终的哈希字符串(包含盐和成本信息)

BCrypt 哈希的格式如下:

mathematica 复制代码
$2a$10$EIXCh1l6Z7CzWIKQ0s1t8u8mvjU7qg3sK9fRf6RPSZ6bEJ3iRzZ6G
│ │ │ │                      └───────────────────────────── 密文部分(Base64编码)
│ │ │ └── 22字符的盐(Base64编码)
│ │ └──── 10 表示成本(2^10 = 1024 次加密)
│ └─────── 算法版本(2a/2b)
└───────── 起始符号 $

成本因子(Cost Factor)

BCrypt 的强度主要取决于 cost 参数(也叫 work factor)。

默认一般是 10,表示进行 2^10 = 1024 轮加密。

Cost 大约耗时(现代 CPU)
8 < 100ms
10 ~300ms
12 ~1s
14 ~4s

建议值:

Web 应用中推荐使用 10~12 ,兼顾安全与性能。

越高越安全,但登录时耗时也更长。

BCrypt 的安全机制详解

  1. 自动加盐

    每次加密都会自动生成 随机盐(16字节)

    因此即使两个人使用相同密码,哈希值也完全不同。

    复制代码
    $2a$10$abc123...   ← 盐不一样
    $2a$10$xyz987...   ← 哈希也不一样
  2. 自带盐与成本参数

    BCrypt 生成的字符串内部就包含盐和 cost,因此不需要单独存储盐。

BCrypt 使用方法

Spring Security 内置了 BCryptPasswordEncoder,使用极其方便。

示例一:生成密码哈希

java 复制代码
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

public class BCryptExample {
    public static void main(String[] args) {
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String rawPassword = "mySecret123";
        String hashedPassword = encoder.encode(rawPassword);

        System.out.println("原始密码: " + rawPassword);
        System.out.println("加密后: " + hashedPassword);
    }
}

输出示例:

复制代码
原始密码: mySecret123
加密后: $2a$10$e0NR9ZnPS2D2X4xDJH5lBO8xL61jSwB1KkzIUVwFovYCKNH4I5C.O

示例二:验证密码是否匹配

java 复制代码
String inputPassword = "mySecret123";
boolean matches = encoder.matches(inputPassword, hashedPassword);

System.out.println(matches ? "密码正确" : "密码错误");

Argon2

Argon2 概念

什么是 Argon2?

Argon2 是一种用于**密码哈希(Password Hashing)**的算法,诞生于 2015 年,由 Alex Biryukov、Daniel Dinu、Dmitry Khovratovich 等密码学家设计。

它在 2015 年赢得了 Password Hashing Competition (PHC),成为国际标准密码哈希算法。

目标

抵抗暴力破解、GPU 攻击、ASIC 硬件攻击 ------ 并提供可调的计算复杂度与内存占用。

Argon2 的三个变种

版本 主要特征 推荐用途
Argon2d 使用数据相关内存访问(速度快) 抵御 GPU 攻击(不适合并行攻击)
Argon2i 使用数据独立访问(更安全) 防止侧信道攻击(如时间推测)
Argon2id 混合模式(先 i 后 d) 最推荐,兼顾两者优点

在实际项目中:

Argon2id 是目前密码存储的官方推荐版本(RFC 9106 标准)

Argon2 设计思想

传统算法(如 BCrypt)仅考虑"计算耗时",

Argon2 同时考虑 CPU + 内存消耗,让暴力破解更难:

因素 含义 攻击难度影响
Time Cost 运算迭代次数 增加计算量
Memory Cost 占用内存(KB/MB) 降低 GPU 并行破解效率
Parallelism 并行线程数 提升合法加密速度

工作原理(简化流程)

  1. 生成随机盐(16字节或更长)
  2. 结合明文密码 + 盐 + 参数(内存/时间/并行度)
  3. 进行多轮基于内存的哈希计算
  4. 输出哈希字符串(包含所有参数)

输出结果示例:

mathematica 复制代码
$argon2id$v=19$m=65536,t=3,p=4$QWERTYasdfgh1234$NqM6cN6Lk5mZtP4xGVg4xg
│───────││───── 参数说明 ─────││─── Base64盐 ───││────── 哈希结果 ──────│
│  算法  ││版本│内存=64MB,迭代3次,4线程│ 

Argon2 参数详解

参数 含义 推荐值(Web 应用)
t (Time Cost) 迭代次数 2~4
m (Memory Cost) 使用内存大小(KB) 65536 (≈64MB)
p (Parallelism) 并行线程数 1~4
salt length 盐长度 ≥16字节
hash length 输出哈希长度 32字节或更长

安全建议:

  • 盐必须随机且唯一
  • 增加 m(内存)比增加 t(次数)更能防 GPU 攻击
  • 建议使用 Argon2id 模式

为什么 Argon2 比 BCrypt 更安全?

特性 BCrypt Argon2
加盐机制 自动加盐 自动加盐
可调复杂度 cost time + memory + parallel
GPU 防御 强(高内存占用)
并行支持
性能 中等
安全标准 无官方标准 RFC 9106 标准

Argon2 使用方法

Spring Security 从 5.0 版本开始原生支持 Argon2

使用方式与 BCrypt 类似。

添加依赖

在 Spring Boot 项目中引入 Spring Security:

xml 复制代码
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-crypto</artifactId>
</dependency>

创建 Argon2PasswordEncoder

java 复制代码
import org.springframework.security.crypto.argon2.Argon2PasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

public class Argon2Example {
    public static void main(String[] args) {
        // 参数:saltLength, hashLength, parallelism, memoryCost, iterations
        PasswordEncoder encoder = new Argon2PasswordEncoder(16, 32, 1, 65536, 3);

        String rawPassword = "mySecret123";
        String encoded = encoder.encode(rawPassword);

        System.out.println("原始密码: " + rawPassword);
        System.out.println("加密后: " + encoded);

        boolean match = encoder.matches("mySecret123", encoded);
        System.out.println("匹配结果: " + match);
    }
}

输出示例:

复制代码
原始密码: mySecret123
加密后: $argon2id$v=19$m=65536,t=3,p=1$xA4xv2x4lQv4a7g3xA$F6xK3v2n8dQOpxV1u+3Bfw
匹配结果: true

Spring Boot 项目使用

MD5

  • 性质 :哈希算法(不可逆),Spring 不提供原生封装,只是工具类(DigestUtils

  • 使用方式:直接调用工具方法即可

    java 复制代码
    import org.springframework.util.DigestUtils;
    
    String md5 = DigestUtils.md5DigestAsHex("password".getBytes());
  • 配置类不需要

  • 注意事项

    • MD5 已不安全,不建议用作密码存储
    • 可以用于文件校验、数据完整性等场景

SHA 系列(SHA-1、SHA-256、SHA-512、SHA3 等)

  • 性质:哈希算法(不可逆)

  • 使用方式

    • Java 原生:

      java 复制代码
      MessageDigest md = MessageDigest.getInstance("SHA-256");
      byte[] hash = md.digest("password".getBytes());
    • 或 Apache Commons Codec / Spring DigestUtils

  • 配置类不需要,直接在业务代码中调用即可

  • 注意事项

    • 如果用于密码存储,必须加盐 + 多轮迭代

BCrypt

  • 性质:单向加密(哈希 + 自动加盐 + 可调复杂度)

  • Spring Boot 支持 :原生提供 BCryptPasswordEncoder

  • 使用方式

    • 可以直接在业务中 new 一个对象用:

      复制代码
      BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
      String hash = encoder.encode("password");
      boolean match = encoder.matches("password", hash);
    • 推荐写配置类注入 PasswordEncoder,方便 Spring Security 集成:

      java 复制代码
      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 PasswordConfig {
      
          /**
           * BCryptPasswordEncoder 默认 cost = 10
           * cost 越大,计算越慢,安全性越高
           */
          @Bean
          public PasswordEncoder bCryptPasswordEncoder() {
              return new BCryptPasswordEncoder(10); // 可以根据性能调整
          }
      }

      使用示例

      java 复制代码
      @Autowired
      private PasswordEncoder passwordEncoder;
      
      public void register(String rawPassword) {
          String encoded = passwordEncoder.encode(rawPassword);
          // 保存 encoded 到数据库
      }
      
      public boolean login(String rawPassword, String storedHash) {
          return passwordEncoder.matches(rawPassword, storedHash);
      }
  • 配置类推荐,但不是必须

    • 如果项目不使用 Spring Security,也可以直接 new BCryptPasswordEncoder()

Argon2(Argon2id)

  • 性质:现代密码哈希(内存硬化 + 自动加盐 + 可调复杂度)

  • Spring Boot 支持 :Spring Security 5+ 原生提供 Argon2PasswordEncoder

  • 使用方式

    • 直接 new 使用:

      java 复制代码
      Argon2PasswordEncoder encoder = new Argon2PasswordEncoder();
      String hash = encoder.encode("password");
      boolean match = encoder.matches("password", hash);
    • 推荐写配置类注入 PasswordEncoder

      java 复制代码
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.security.crypto.argon2.Argon2PasswordEncoder;
      import org.springframework.security.crypto.password.PasswordEncoder;
      
      @Configuration
      public class PasswordConfig {
      
          /**
           * Argon2PasswordEncoder 参数说明:
           * saltLength: 盐长度(字节)
           * hashLength: 输出哈希长度(字节)
           * parallelism: 并行线程数
           * memory: 内存消耗 (KB)
           * iterations: 哈希迭代次数
           */
          @Bean
          public PasswordEncoder argon2PasswordEncoder() {
              return new Argon2PasswordEncoder(
                      16,       // salt length
                      32,       // hash length
                      1,        // parallelism
                      65536,    // memory cost (64 MB)
                      3         // iterations
              );
          }
      }

      使用示例

      java 复制代码
      @Autowired
      private PasswordEncoder passwordEncoder;
      
      public void register(String rawPassword) {
          String encoded = passwordEncoder.encode(rawPassword);
          // 保存 encoded 到数据库
      }
      
      public boolean login(String rawPassword, String storedHash) {
          return passwordEncoder.matches(rawPassword, storedHash);
      }
  • 配置类推荐

    • 方便全局统一使用,尤其是结合 Spring Security

总结

Spring Boot 项目 中,选择合适的哈希/加密算法主要取决于用途安全性需求

算法 类型 输出长度 安全性 特点与适用场景 Spring Boot 使用方式
MD5 哈希算法 128 位(16 字节) 已不安全 快速计算、雪崩效应强;适合文件校验、数据完整性检测 DigestUtils.md5DigestAsHex() 调用即可,无需配置类
SHA 系列 哈希算法 160~512 位 SHA-1 已不安全,SHA-2/3 安全 可靠的消息摘要算法;文件校验、签名、JWT、加密辅助 Java MessageDigest 或 Apache DigestUtils调用,无需配置类;用于密码需加盐+多轮
BCrypt 密码哈希 60 字符 安全 自动加盐、可调成本(cost)、不可逆;适合用户密码存储 推荐创建配置类 PasswordEncoderBean;可直接 new BCryptPasswordEncoder()
Argon2 密码哈希 可变(Base64) 高安全 自动加盐、可调时间/内存/并行度;防 GPU/ASIC 攻击,现代推荐算法 推荐创建配置类 PasswordEncoderBean,使用 Argon2PasswordEncoder,参数可自定义

建议

  1. 简单数据完整性 (如文件校验、数据摘要)
    • 使用 MD5 或 SHA-2/3 即可
    • 不需要配置类,直接工具类调用
  2. 用户密码存储
    • 强烈建议 使用 BCryptArgon2id
    • MD5、SHA-1、SHA-256 不安全,即使加盐也难抵抗 GPU 彩虹表攻击
    • 在 Spring Boot 项目中,建议通过 配置类统一注入 PasswordEncoder Bean,方便全局使用和与 Spring Security 集成
  3. 性能与安全平衡
    • BCrypt:成本因子(cost)调整计算复杂度
    • Argon2:可调 timeCostmemoryCostparallelism,更安全且支持并行

总结一句话

文件校验用 MD5/SHA,密码存储用 BCrypt/Argon2(推荐 Argon2id),密码算法最好通过配置类统一注入 PasswordEncoder,保证安全性与可维护性。

相关推荐
AskHarries12 分钟前
工具失败时怎么办:重试、回滚、人工确认和风险提示
后端·程序员
苏三说技术2 小时前
Claude Code从失控到起飞,只用了这些技巧
后端
长栎3 小时前
写 for 循环写了十年,你却从没用过迭代器模式最狠的那一面
后端
LiaCode3 小时前
Redis 在生产项目的使用
前端·后端
用户559822481223 小时前
Docker Compose Down 导致容器数据误删——ext4 日志恢复全记录
后端
LiaCode3 小时前
一天学完 redis 的爽翻版核心知识总结
前端·后端
大刚测试开发实战3 小时前
如何内网穿透访问本地私有化部署的TestHub
前端·后端·github
xiaodaoluanzha3 小时前
迄今為止,最簡單的編程語言 Nolang
前端·后端
Csvn3 小时前
Docker 容器管理入门 — 从镜像到容器编排
后端
用户762352425913 小时前
ShardingJDBC
后端