用户模块——redis工具类
1. Redis工具类与基础配置
1.1 什么是Redis,为什么使用它?
Redis(Remote Dictionary Server)是一个开源的高性能键值对存储数据库,通常用于缓存数据、存储会话信息等场景。它的主要优点是速度快,支持多种数据结构(如字符串、哈希、列表、集合等)。在开发中,我们经常使用Redis来加速数据读取,减轻数据库压力,提升应用性能。
1.2 为什么要使用Redis工具类?
在实际开发中,我们通常会遇到频繁操作Redis的情况(例如存取数据、设置过期时间等)。如果每次都直接使用StringRedisTemplate
进行操作,代码会变得冗长和重复。为了解决这个问题,我们可以封装一个Redis工具类,将常用的Redis操作封装成简单的方法,方便代码复用,同时也让我们的代码更加简洁。
1.3 配置Redis数据源
首先,我们需要在Spring Boot项目中配置Redis数据源,确保我们的应用可以连接到Redis数据库。通常,我们会在application.properties
或者application.yml
文件中配置Redis的连接信息。以下是一个简单的配置示例:
# application.properties文件
spring.redis.host=localhost # Redis服务器地址
spring.redis.port=6379 # Redis服务器端口
spring.redis.password=yourpassword # Redis密码(如果有的话)
spring.redis.timeout=2000ms # Redis连接超时时间
1.4 创建Redis工具类
现在,我们来创建一个简单的Redis工具类RedisUtils
。该工具类主要使用Spring提供的StringRedisTemplate
来操作Redis。为了简化操作,我们将一些常见的方法封装成静态方法。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;@Component
public class RedisUtils {@Autowiredprivate StringRedisTemplate stringRedisTemplate;// 设置键值对public static void set(String key, String value) {stringRedisTemplate.opsForValue().set(key, value);}// 获取值public static String get(String key) {return stringRedisTemplate.opsForValue().get(key);}// 删除键值对public static void delete(String key) {stringRedisTemplate.delete(key);}// 设置带过期时间的键值对public static void setWithExpiration(String key, String value, long timeout) {stringRedisTemplate.opsForValue().set(key, value, timeout);}
}
代码说明:
set(String key, String value)
:将一个键值对存入Redis。get(String key)
:根据键从Redis中获取值。delete(String key)
:删除指定的键。setWithExpiration(String key, String value, long timeout)
:将键值对存入Redis,并设置一个过期时间(单位为秒)。
1.5 使用Redis工具类
接下来,我们可以在项目中的其他部分通过调用这些工具方法来进行Redis操作。例如,在控制器中获取和存储数据:
@RestController
@RequestMapping("/redis")
public class RedisController {@Autowiredprivate RedisUtils redisUtils;@GetMapping("/set")public String setValue() {redisUtils.set("name", "Redis Tutorial");return "Data has been saved to Redis!";}@GetMapping("/get")public String getValue() {String value = redisUtils.get("name");return value != null ? "Retrieved value: " + value : "No value found!";}
}
代码说明:
setValue()
:通过调用redisUtils.set()
方法将数据存入Redis。getValue()
:通过调用redisUtils.get()
方法从Redis中获取数据。
1.6 小结
通过封装Redis工具类,我们能够简化对Redis的操作,让代码更加简洁和可维护。我们不再需要每次都手动操作StringRedisTemplate
,而是通过工具类提供的方法直接进行存取操作。
在后面的部分,我们将进一步扩展功能,例如如何使用Redisson实现分布式锁,如何使用Redis进行JWT认证等。但无论做什么,掌握好基本的Redis操作都是至关重要的第一步。
2. 分布式锁与Redisson
2.1 什么是分布式锁?
在分布式系统中,多个应用或服务器可能会同时访问同一资源(例如数据库、缓存等),这就可能导致并发冲突和数据不一致的情况。分布式锁是一种用于保证同一时刻只有一个客户端能访问共享资源的机制,确保资源在并发访问时的一致性。
举个简单例子,假设有一个购物车系统,多个用户同时抢购限量商品,如果不加锁,可能会导致商品数量减不下来,甚至超卖。这时,就需要用到分布式锁来控制同时只有一个用户能成功购买。
2.2 为什么需要Redisson?
在Redis中,我们可以利用setnx命令来模拟加锁和解锁操作,但是这种方式有很多不足之处,像锁超时、并发问题等都需要额外的处理。为了简化这一过程,Redisson是一个优秀的工具,它提供了简单易用的分布式锁实现,避免了低级错误。
Redisson是基于Redis的客户端,它封装了很多复杂的操作,例如分布式锁、消息队列、分布式集合等。通过Redisson,开发者可以轻松实现分布式锁,并且避免了很多底层细节。
2.3 如何使用Redisson实现分布式锁?
在Spring Boot项目中,使用Redisson非常简单。我们只需要先引入相关的依赖,然后配置Redisson客户端,最后通过Redisson提供的API来加锁和解锁。
2.3.1 引入Redisson依赖
首先,在pom.xml
中添加Redisson的依赖:
<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.16.3</version>
</dependency>
2.3.2 配置Redisson
接下来,我们需要配置Redisson的客户端,连接到Redis。你可以在application.properties
中添加Redis的连接配置。
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=yourpassword # 可选
spring.redis.timeout=2000ms
然后,我们在配置类中创建Redisson客户端实例:
import org.redisson.api.RedissonClient;
import org.redisson.client.RedisClient;
import org.redisson.config.Config;
import org.redisson.spring.starter.RedissonAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RedissonConfig {@Beanpublic RedissonClient redissonClient() {Config config = new Config();config.useSingleServer().setAddress("redis://localhost:6379"); // 配置Redis服务器地址return Redisson.create(config);}
}
2.3.3 使用Redisson分布式锁
接下来,我们就可以在业务逻辑中使用Redisson提供的分布式锁了。Redisson提供的锁是RLock
类型,类似于ReentrantLock
。
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class OrderService {@Autowiredprivate RedissonClient redissonClient;// 模拟创建订单的操作public void createOrder(String orderId) {RLock lock = redissonClient.getLock("order-lock:" + orderId); // 使用订单ID作为锁的标识try {// 尝试获取锁,最多等待10秒,锁定后最多保持5秒if (lock.tryLock(10, 5, TimeUnit.SECONDS)) {// 如果成功获取锁,则执行下列业务逻辑System.out.println("锁定成功,开始处理订单:" + orderId);// 模拟处理订单的操作Thread.sleep(2000); // 假装正在处理订单System.out.println("订单处理完成:" + orderId);} else {System.out.println("获取锁失败,订单正在处理:" + orderId);}} catch (InterruptedException e) {e.printStackTrace();} finally {// 确保锁被释放if (lock.isHeldByCurrentThread()) {lock.unlock();System.out.println("锁已释放");}}}
}
代码说明:
redissonClient.getLock("order-lock:" + orderId)
:这里我们使用order-lock:{orderId}
作为锁的唯一标识,每个订单使用独立的锁,避免多个用户并发抢购同一订单时发生冲突。lock.tryLock(10, 5, TimeUnit.SECONDS)
:尝试在10秒内获取锁,获取锁后,最多保持5秒。超时后,自动释放锁。lock.unlock()
:释放锁,确保其他线程能够获取锁。
2.4 小结
使用Redisson可以简化分布式锁的实现,它封装了很多底层细节,帮助我们轻松实现分布式环境下的锁机制,确保资源在并发情况下的一致性。在高并发场景中,分布式锁能够有效防止数据竞态问题,提高系统的可靠性。
通过Redisson提供的简单API,我们可以轻松地将分布式锁引入到项目中,确保同一资源只能被一个线程访问,避免了并发冲突。
3. JWT认证与Token管理
3.1 什么是JWT?
JWT(JSON Web Token)是一种用于在网络应用环境中传递声明的方式,主要用于身份认证和信息交换。它是一个由三部分组成的字符串,用于安全地在各方之间传递信息。
JWT的结构如下:
header.payload.signature
- Header(头部):通常包含令牌的类型(JWT)和加密算法(如HMAC SHA256或RSA)。
- Payload(负载):包含声明(claims),也就是传递的信息,比如用户的ID、角色等。这些信息是编码的,但不加密,所以不要在payload中存储敏感信息。
- Signature(签名):通过Header和Payload使用秘钥加密生成,用于验证JWT是否被篡改。
3.2 JWT认证的流程
JWT认证常用于无状态的认证系统。JWT认证流程通常如下:
- 用户登录:用户通过用户名和密码登录系统。
- 生成JWT Token:系统验证用户身份,如果验证成功,服务器生成一个JWT Token,并将其返回给客户端。此Token中包含用户的相关信息(例如用户ID、角色等)。
- Token存储:客户端将JWT Token存储在本地,通常保存在浏览器的
localStorage
或sessionStorage
中。 - 携带Token请求接口:当用户请求受保护的接口时,客户端会将JWT Token放入HTTP请求头中,发送给服务器。
- 服务器验证Token:服务器收到请求后,会检查请求头中的JWT Token是否合法。如果合法,服务器允许访问相应的资源;如果不合法,返回401 Unauthorized错误。
3.3 如何使用JWT生成Token?
在Spring Boot中,我们可以通过使用jjwt库来生成JWT Token。首先,需要在pom.xml
文件中引入jjwt依赖:
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.11.5</version>
</dependency>
3.3.1 创建JWT工具类
接下来,我们创建一个JwtUtils
类,负责生成和解析JWT Token:
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;public class JwtUtils {private static final String SECRET_KEY = "your-secret-key"; // 请使用更安全的秘钥// 生成JWT Tokenpublic static String generateToken(String userId) {return Jwts.builder().setSubject(userId) // 设置JWT的主体.setIssuedAt(new Date()) // 设置Token的发行时间.setExpiration(new Date(System.currentTimeMillis() + 3600000)) // 设置过期时间1小时.signWith(SignatureAlgorithm.HS256, SECRET_KEY) // 使用HS256算法和秘钥签名.compact(); // 构建JWT}// 解析JWT Tokenpublic static String parseToken(String token) {return Jwts.parser().setSigningKey(SECRET_KEY) // 使用秘钥验证Token.parseClaimsJws(token) // 解析Token.getBody().getSubject(); // 获取Token中的用户ID}
}
代码解释:
generateToken(String userId)
:生成JWT Token,包含用户ID(userId
),设置有效期为1小时,并使用HS256算法进行签名。parseToken(String token)
:解析JWT Token,验证签名,并从Token中获取用户ID。
3.4 使用JWT Token进行认证
接下来,我们可以在Spring Boot的登录功能中使用JWT来管理Token。在用户登录时,服务器验证用户信息,生成并返回JWT Token:
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;@RestController
public class AuthController {@PostMapping("/login")public String login(@RequestBody LoginRequest loginRequest) {// 假设用户名和密码已经验证通过String userId = loginRequest.getUsername(); // 获取用户ID(这里简化)// 生成JWT TokenString token = JwtUtils.generateToken(userId);// 返回生成的Tokenreturn "Bearer " + token; // 返回格式为 "Bearer <Token>"}
}
代码解释:
- 用户通过POST请求传递用户名和密码,服务器验证用户身份后,生成JWT Token。
- 登录成功后,返回JWT Token。客户端可以将此Token保存在本地。
3.5 Token验证与使用
客户端每次请求时,都需要将JWT Token放入HTTP请求头中:
Authorization: Bearer <JWT Token>
服务器收到请求后,解析Token,验证其合法性,并根据Token中的信息执行相关操作。
在Spring Boot中,可以通过过滤器来验证Token:
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@WebFilter("/protected/*")
public class JwtFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {String token = request.getHeader("Authorization");if (token != null && token.startsWith("Bearer ")) {token = token.substring(7); // 去掉Bearer前缀try {String userId = JwtUtils.parseToken(token); // 解析Tokenrequest.setAttribute("userId", userId); // 将用户ID添加到请求中} catch (Exception e) {response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // Token无效,返回401return;}}filterChain.doFilter(request, response); // 放行请求}
}
3.6 小结
JWT是一种简洁且高效的身份验证方式,它通过将用户身份信息封装在Token中,避免了频繁查询数据库验证用户身份。我们可以利用JWT进行无状态的认证,实现安全、便捷的API访问。
在这部分,我们介绍了JWT的基本原理、如何生成和解析Token,以及如何在Spring Boot项目中使用JWT来管理用户的认证信息。通过这种方式,我们可以轻松地实现一个安全的认证系统,避免了传统的Session机制带来的许多问题。
4. 综合应用:实现用户登录与分布式锁
在这一部分,我们将结合之前讲到的JWT认证和Redisson分布式锁,创建一个简单的用户登录系统,并在用户登录时使用分布式锁来防止多个请求同时登录,确保系统的并发安全。
4.1 用户登录的流程
用户登录流程通常包含以下步骤:
- 用户提交用户名和密码。
- 服务器验证用户名和密码是否正确。
- 如果验证成功,生成JWT Token并返回给用户。
- 用户使用JWT Token进行后续的API请求认证。
4.2 为什么需要分布式锁?
在高并发场景下,如果多个请求同时试图登录同一个用户,会导致数据的不一致性。例如,多个请求同时向数据库写入用户登录信息,可能会出现覆盖或重复记录的情况。
为了解决这个问题,我们使用分布式锁来确保同一时刻只有一个请求能进行登录操作,其他请求需要等待锁释放后才能继续执行。这样就可以防止出现并发问题。
4.3 使用Redisson实现分布式锁
Redisson是基于Redis的分布式锁实现,它可以帮助我们确保分布式系统中的不同节点在执行某个操作时能够同步,避免多个线程同时执行某个资源的操作。
首先,我们需要在pom.xml
文件中引入Redisson的依赖:
<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.16.2</version>
</dependency>
4.3.1 配置Redisson
我们使用Spring Boot配置Redisson的数据源。可以在application.properties
中添加以下配置:
spring.redis.host=127.0.0.1
spring.redis.port=6379
然后,创建一个RedissonConfig
类来配置Redisson客户端:
import org.redisson.api.RedissonClient;
import org.redisson.client.RedisClient;
import org.redisson.config.Config;
import org.redisson.Redisson;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RedissonConfig {@Beanpublic RedissonClient redissonClient() {Config config = new Config();config.useSingleServer().setAddress("redis://127.0.0.1:6379"); // 连接到本地Redisreturn Redisson.create(config);}
}
4.3.2 实现分布式锁
接下来,我们创建一个LoginService
类,在登录操作中使用分布式锁来防止并发问题:
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class LoginService {@Autowiredprivate RedissonClient redissonClient;// 用于模拟用户登录public String login(String username, String password) {// 锁的名字是"loginLock"RLock lock = redissonClient.getLock("loginLock");try {// 尝试加锁,最多等待10秒,锁住后最多持有30秒if (lock.tryLock(10, 30, java.util.concurrent.TimeUnit.SECONDS)) {try {// 模拟用户验证(实际情况中可以验证用户名密码)if ("user".equals(username) && "password".equals(password)) {// 登录成功,生成JWT TokenString token = JwtUtils.generateToken(username);return "Login successful! Token: " + token;} else {return "Invalid username or password!";}} finally {// 确保释放锁lock.unlock();}} else {return "Please try again later. The system is busy.";}} catch (InterruptedException e) {Thread.currentThread().interrupt();return "An error occurred. Please try again.";}}
}
代码解释:
redissonClient.getLock("loginLock")
:通过Redisson客户端获取名为loginLock
的锁。如果多个请求同时进入这段代码,只有一个请求能够成功获得锁,其他请求会等待。lock.tryLock(10, 30, TimeUnit.SECONDS)
:尝试加锁,如果10秒内无法获取锁,就返回false
;如果加锁成功,锁会持有30秒,之后会自动释放。lock.unlock()
:在完成登录操作后释放锁,以便其他请求可以继续处理。
4.3.3 调用登录接口
在AuthController
中,我们调用LoginService
来处理登录请求:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;@RestController
public class AuthController {@Autowiredprivate LoginService loginService;@PostMapping("/login")public String login(@RequestBody LoginRequest loginRequest) {return loginService.login(loginRequest.getUsername(), loginRequest.getPassword());}
}
代码解释:
- 用户通过POST请求传递用户名和密码,
AuthController
接收请求并将其交给LoginService
处理。 LoginService
使用分布式锁确保同一时刻只有一个请求能执行登录操作,从而防止并发问题。
4.4 总结
在这一部分,我们结合了JWT认证和Redisson分布式锁,创建了一个简单的用户登录系统。在登录时,我们通过分布式锁保证同一时刻只有一个请求可以进行登录操作,避免并发冲突。
- JWT认证:用于生成和管理用户的认证Token。
- Redisson分布式锁:通过分布式锁确保并发情况下的线程安全,避免多个请求同时修改数据。
通过这种方式,我们可以在分布式系统中有效地管理用户登录,同时确保系统的高并发环境下的数据一致性和安全性。
5. 总结:实现用户登录与分布式锁
在本文中,我们详细讲解了如何实现一个带有JWT认证和分布式锁的用户登录系统。通过结合这两者的技术,我们能够在高并发的情况下保证系统的安全性和稳定性。
5.1 主要技术点回顾
-
JWT认证:
- JWT(JSON Web Token) 是一种轻量级的认证机制,用于在客户端和服务端之间传递身份信息。
- 在用户登录成功后,我们生成一个JWT Token,并将其返回给用户,用户后续的每个请求都可以带上这个Token,服务器用它来验证用户身份。
- JWT中包含了用户信息和过期时间等,保证了传输过程中的安全性和有效性。
-
Redisson分布式锁:
- 在多线程或分布式系统中,Redisson分布式锁确保在同一时刻,只有一个请求能执行关键操作,其他请求需等待。
- 通过在关键操作前后加锁与解锁,避免了多个请求同时操作同一资源导致数据不一致的问题。
- Redisson通过Redis提供强大的分布式支持,能够在多个实例之间进行锁的协调,保证操作的原子性。
5.2 如何避免并发问题
在实际开发中,很多时候我们需要处理高并发的情况。以用户登录为例,当多个请求同时尝试登录同一个用户时,如果不加以控制,可能会导致以下问题:
- 多个请求同时更新数据库,可能导致用户信息的覆盖或数据丢失。
- 同时发放多个Token,可能造成安全隐患。
通过引入分布式锁,我们能够在请求进入登录操作时,确保只有一个请求能执行登录逻辑,其他请求会等待锁释放。这样就能有效避免并发冲突。
5.3 结合JWT和Redisson锁的好处
- 安全性:JWT通过加密保证了Token的安全性,避免了Token被篡改的风险。
- 高并发支持:通过Redisson的分布式锁机制,我们在高并发情况下也能保证操作的顺序性和数据的一致性。
- 简化管理:JWT使得我们能够在不同系统间轻松传递身份信息,而Redisson则让我们能够在分布式环境下管理锁,避免了传统分布式系统中的复杂问题。
5.4 最后的一些注意事项
- 在实际生产环境中,使用JWT时需要注意Token的过期时间和更新机制,确保Token不被长期滥用。
- 在Redisson分布式锁的使用中,需要避免锁的“死锁”情况,确保在操作完成后及时释放锁。
- 使用分布式锁时要保证锁粒度尽可能小,避免长时间持有锁,影响其他请求的响应速度。
5.5 小结
今天我们学习了如何结合JWT认证和Redisson分布式锁来实现一个安全且高效的用户登录系统。通过JWT,我们可以确保用户身份的验证和信息的安全性;通过Redisson分布式锁,我们可以解决并发问题,确保系统在高并发环境下的稳定性。
随着分布式系统和微服务的普及,这些技术的应用变得越来越重要。希望通过这篇文章,你能够理解JWT和Redisson分布式锁的基本原理,并能够在实际项目中运用这些技术来解决问题。
相关文章:
用户模块——redis工具类
1. Redis工具类与基础配置 1.1 什么是Redis,为什么使用它? Redis(Remote Dictionary Server)是一个开源的高性能键值对存储数据库,通常用于缓存数据、存储会话信息等场景。它的主要优点是速度快,支持多种数…...
Synology 部署的 WordPress 無法升級至最新版本時,可以透過以下改良版指南進行排查和解決。
當 Synology 部署的 WordPress 無法升級至最新版本時,可以透過以下改良版指南進行排查和解決。我對內容進行了補充和重新組織,希望能幫助你更高效地處理這類問題: 權限相關問題處理 檢查文件和目錄權限: 確保 WordPress 安裝目錄…...
012-Benchmark
Benchmark 以下是一篇关于Google Benchmark库的全面介绍及使用指南,包含完整C代码示例和核心功能覆盖: Google Benchmark:C 性能基准测试指南 一、库简介 Google Benchmark 是一个专为 C 设计的微基准测试库,用于精确测量代码片…...
百某田网任务脚本
自动化操作百田游戏的任务脚本,特别是用于完成每日任务和积分兑换的功能。 主要功能 任务管理: 脚本通过定时任务查询并执行每天的任务,自动完成任务并兑换积分。 每个任务通过调用do_list()和do_task()函数来查询和完成。 多账号支持: 支持多个账号的登录和管理,账号信息…...
使用纯CSS 实现 侧边栏 拖拽效果
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、效果实现原理二、代码演示三.简单解释下样式四 完整的DEMO总结 前言 有不少需求是要拖动改变侧边栏宽高的,以下就是在不适用js ,只使用css 的情…...
c语言笔记 函数入门
c语言的函数就是用来实现某种功能的,如果说我们的程序代码都写在main函数中,这样会显得很难读懂,而且代码太长过于冗余,显得没有质量。所以我们可以把一些功能用分函数的方法实现功能独立分开,实现c程序的工整还有方便…...
运维新手入门——线缆的使用(Beginner‘s Guide to Operations and Maintenance - Cable Usage)
运维新手入门——线缆的使用 近期不断的有朋友问到线缆的传输距离,我们每天都在与线缆打交道,清楚了解线缆的使用才能在项目中得心应手,我们之前有提到过。 本期我们一起再来总结下常用的线缆传输距离。 01) 网线:超…...
JS—闭包:3分钟从入门到放弃
个人博客:haichenyi.com。感谢关注 一. 目录 一–目录二–基础定义三–闭包的运行机制四–闭包实战应用场景五–内存泄漏预防指南六–最佳实践总结 二. 基础定义 闭包:能够访问外部函数作用域的函数,以及其词法环境的组合。举个老生常谈栗…...
python pandas模块
python pandas模块 终于也到介绍pandas的时候了,python中用于处理data的一个lib 从wiki中找到的关于pandas的介绍,如下, Original author(s) Wes McKinney Developer(s) Community Initial release 11 January 2008; 17 years ago [citatio…...
系统部署【信创名录】及其查询地址
一、信创类型 (一)服务器: 1.华为云 2.腾讯云 3.阿里云 (二)中央处理器(CPU): 1.海思,鲲鹏920服务器 (三)中间件 1.人大金仓 ࿰…...
docker-compose部署MongoDB分片集群
前言 MongoDB 使用 keyFile 进行 节点间身份验证,我们需要先创建一个 keyFile 并确保所有副本集的节点使用相同的 keyFile。 openssl rand -base64 756 > mongo-keyfile chmod 400 mongo-keyfiledocker-compose部署分片集群 无密码方式 # docker-compose-mongodb.yml s…...
博奥龙Nanoantibody系列IP专用抗体
货号名称BDAA0260 HRP-Nanoantibody anti Mouse for IP BDAA0261 AbBox Fluor 680-Nanoantibody anti Mouse for IP BDAA0262 AbBox Fluor 800-Nanoantibody anti Mouse for IP ——无轻/重链干扰,更高亲和力和特异性 01Nanoantibody系列抗体 是利用噬菌体展示纳…...
CTFshow 【WEB入门】信息搜集 【VIP限免】 web1-web17
CTFshow 【 WEB入门】、【VIP限免】 web1 ----源码泄露 首先第一步,看源代码 web2----前台JS绕过 简单点击查看不了源代码,可以强制查看 比如 Ctrl Shift ICtrl U或者在url前加一个view-source: view-source:http://79999ca1-7403-46da-b25b-7ba9…...
css 知识点整理
1.css 层叠样式表 中的 inherit、initial、unset 关键字适用属性类型行为逻辑典型场景inherit所有属性强制继承父级值统一子元素样式initial所有属性重置为规范初始值清除自定义或继承样式unset所有属性自动判断继承或重置简化全局样式重置或覆盖 2. sass 常用语法 2.1、变量…...
02.Kubernetes 集群部署
Kubernetes 集群部署 Kubernetes 相关端口 1. Kubernetes 集群组件运行模式 独立组件模式 除 Add-ons 以外,各关键组件以二进制方式部署于节点上,并运行于守护进程;各 Add-ons 以 Pod 形式运行 静态 Pod 模式 控制平面各组件以静态 Pod …...
支持向量机(SVM)原理与应用
背景 支持向量机(Support Vector Machine, SVM)是一种经典的监督学习算法,广泛应用于分类和回归问题。SVM以其强大的数学基础和优异的性能在机器学习领域占据了重要地位。本文将详细介绍SVM的原理、核函数的作用以及如何在Python中使用SVM解决…...
【文献阅读】SPRec:用自我博弈打破大语言模型推荐的“同质化”困境
📜研究背景 在如今的信息洪流中,推荐系统已经成为了我们生活中的“贴心小助手”,无论是看电影、听音乐还是购物,推荐系统都在努力为我们提供个性化的内容。但这些看似贴心的推荐背后,其实隐藏着一个严重的问题——同质…...
【WRF模拟】如何查看 WPS 的输入静态地理数据(二进制格式)?
查看 WPS 的输入静态地理数据方法总结 方法 1:使用 gdal_translate 将二进制数据转换为 GeoTIFFgdal_translate 工具概述使用 gdal_translate 将二进制数据转换为 GeoTIFF方法 2:使用 ncdump 查看 geo_em.dXX.nc方法 3:使用 Python xarray + matplotlib 可视化 geo_em.dXX.n…...
介绍如何使用RDDM(残差噪声双扩散模型)进行知识蒸馏
下面为你详细介绍如何使用RDDM(残差噪声双扩散模型)进行知识蒸馏,从而实现学生RDDM模型的一步去噪。这里假定你已经有了RDDM模型,并且使用PyTorch深度学习框架。 整体思路 数据准备:加载训练数据并进行必要的预处理。…...
【lf中的git实战】
1)开发分支 develop 2)各种功能分支 author/feature_func 3)release分支 4)合并author/feature_func到develop author/feature_func 到 develop时: cd develop git merge --squash author/feature_func 5)develop合并到author/feature_func时: cd author/feature_func g…...
Java实现Consul/Nacos根据GPU型号、显存余量执行负载均衡
Java实现Consul/Nacos根据GPU型号、显存余量执行负载均衡 步骤一:服务端获取GPU元数据 1. 添加依赖 在pom.xml中引入Apache Commons Exec用于执行命令: <dependency><groupId>org.apache.commons</groupId><artifactId>comm…...
编译支持 RKmpp 和 RGA 的 ffmpeg 源码
一、前言 RK3588 支持VPU硬件解码,需要rkmpp进行调用;支持2D图像加速,需要 RGA 进行调用。 这两个库均能通过 ffmpeg-rockchip 进行间接调用,编译时需要开启对应的功能。 二、依赖安装 编译ffmpeg前需要编译 rkmpp 和 RGA…...
布隆过滤器(Bloom Filter)
布隆过滤器是一种概率型数据结构,用于快速判断一个元素是否可能在集合中存在。它的核心特点是: 节省空间:相比哈希表,布隆过滤器占用的存储空间非常小。高效查询:查询时间复杂度为 (O(k)),其中 (k) 是哈希…...
2025-03-10 学习记录--C/C++-C语言 易错点 大总结
C语言 易错点 大总结 一、strlen(strs) 使用错误 ⭐️ 若strs 是一个指针数组(const char* strs[]),则不可用strlen(strs) 计算 strs 的长度,因为 strlen 是用于计算 字符串 的长度,而不是数组的长度。 解决方法 &…...
康谋应用 | 基于多传感器融合的海洋数据采集系统
在海洋监测领域,基于无人艇能够实现高效、实时、自动化的海洋数据采集,从而为海洋环境保护、资源开发等提供有力支持。其中,无人艇的控制算法训练往往需要大量高质量的数据支持。然而,海洋数据采集也面临数据噪声和误差、数据融合…...
SpringMVC (二)请求处理
目录 章节简介 一 请求处理(初级) eg:请求头 二 请求处理(进阶) eg:请求体 三 获取请求头 四 获取Cookie 五 级联封装 六 使用RequestBoby封装JSON对象 七 文件的上传 八 获取整个请求 HttpEntity 九 原生请求 Spring…...
数据结构——单链表list
前言:大家好😍,本文主要介绍数据结构——单链表 目录 一、单链表 二、使用步骤 1.结构体定义 2.初始化 3.插入 3.1 头插 3.2 尾插 3.3 按位置插 四.删除 4.1头删 4.2 尾删 4.3 按位置删 4.4按值删 五 统计有效值个数 六 销毁…...
课程《Deep Learning Specialization》
在coursera上,Deep Learning Specialization 课程内容如下图所示: Week2 assignment, Logistic Regression....
低版本 Linux 系统通过二进制方式升级部署高版本 Docker
一、背景: 在一些 Linux 系统中,由于系统自带的软件源版本较低,或者因网络、权限等限制无法直接通过源文件来升级到最新版本的 Docker。这种情况下,采用二进制方式升级部署高版本 Docker 就成为一种有效的解决方案。下面将详…...
线索二叉树构造及遍历算法
线索二叉树构造以及遍历算法 线索二叉树(中序遍历版)构造线索二叉树构造双向线索链表遍历中序线索二叉树 线索二叉树(中序遍历版) 中序遍历找到对应结点的前驱(土方法) #mermaid-svg-eunGO5d2GhjLxCn5 {fo…...
3. 自定义类型****
目录 1. 内存对齐(必考) 如何计算? 为什么要内存对齐? 2. 联合 2.1 联合的定义 2.2 联合的特点 1. 内存对齐(必考) 结构体内存对齐是一个特别热门的考点。 如何计算? 第一个成员在与结构…...
Redis Sentinel (哨兵模式)深度解析:构建高可用分布式缓存系统的核心机制
一、传统主从复制的痛点 在分布式系统架构中,Redis 作为高性能缓存和数据存储解决方案,其可用性直接关系到整个系统的稳定性。传统的主从复制架构虽然实现了数据冗余,但在面临节点故障时仍存在明显缺陷: 手动故障转移…...
deepseek本地部署
deepseek本地部署 哈喽,兄弟们!大家可以想象一下,如果有一个超级聪明的人机大脑,能帮你解答任何问题,从复杂的数学难题到编程代码,再到那些让你头疼的写作任务,它都能轻松搞定。这不是科幻电影里的场景,而是DeepSeek带来的现实奇迹!DeepSeek,这个名字听起来就充满了…...
责任链模式的C++实现示例
核心思想 责任链模式是一种行为设计模式,允许多个对象都有机会处理请求,从而避免请求的发送者与接收者之间的耦合。请求沿着处理链传递,直到某个对象处理它为止。 解决的问题 解耦请求发送者与处理者:请求的发送者无需知道具…...
【蓝桥杯python研究生组备赛】003 贪心
题目1 股票买卖 给定一个长度为 N 的数组,数组中的第 i 个数字表示一个给定股票在第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 注意:你不能同时参与多笔交易&…...
Banana Pi 与瑞萨电子携手共同推动开源创新:BPI-AI2N
2025年3月11日, Banana Pi 开源硬件平台很高兴宣布,与全球知名半导体解决方案供应商瑞萨电子(Renesas Electronics)正式达成技术合作关系。此次合作标志着双方将在开源技术、嵌入式系统和物联网等领域展开深度合作,为全…...
【算法工具】HDL: 基于摘要统计数据的高维连锁不平衡分析软件
## 前言 在基因组研究中,连锁不平衡(Linkage Disequilibrium, LD)分析是理解遗传变异之间关联的关键步骤。然而,当面对高维数据时,传统分析方法往往面临巨大计算挑战。今天为大家介绍一款强大的工具——HDL (High-Dimensional Linkage diseq…...
虚拟展览馆小程序:数字艺术与文化展示的新形式探索
虚拟展览馆小程序:数字艺术与文化展示的新形式探索 一、传统展览的痛点:物理空间的局限与数字化的必然 在传统的艺术与文化展览中,观众往往需要跨越地理距离、排队数小时才能进入展馆,而许多珍贵展品因保护需求无法长期展出。数据显示,全球90%以上的博物馆藏品常年沉睡于…...
docker 搭建alpine下nginx1.26/mysql8.0/php7.4环境
docker 搭建alpine下nginx1.26/mysql8.0/php7.4环境 docker-compose.yml services:mysql-8.0:container_name: mysql-8.0image: mysql:8.0restart: always#ports:#- "3306:3306"volumes:- ./etc/mysql/conf.d/mysql.cnf:/etc/mysql/conf.d/mysql.cnf:ro- ./var/log…...
java项目之基于ssm的在线学习系统(源码+文档)
项目简介 在线学习系统实现了以下功能: 该系统可以实现论坛管理,通知信息管理,学生管理,回答管理,教师管理,教案管理,公告信息管理,作业管理等功能。 💕💕作…...
macOS 安装配置 iTerm2 记录
都说 macOS 里替换终端最好的就是 iTerm2 ,这玩意儿还是开源的,所以就也根风学习一下,但全是英文的挺麻烦,所以这里记录一下自己的设置,以最简单的安装及设置为主,想要更酷炫、更好看的还请自己百度吧&…...
矩阵分析-浅要理解(深度学习方向)
梯度分析与最优化 在深度学习的任务中,我们所期望的是训练一个神经网络,使得预测结果与真实标签之间的误差最小化,这可以近似看作是一个提供梯度下降等优化找到全局最优解的凸优化问题。 奇异值分解 在信息工程领域,对数据处理的…...
Odoo 18 中的自动字段和预留字段
Odoo 18 中的自动字段和预留字段 作为一个开源平台,Odoo 的价值在于其使用和开发的灵活性、可扩展性和经济性。虽然 Odoo 本身主要用 Python 和 JavaScript 编写,但其作为开源 ERP 系统的价值超越了特定编程语言的范畴,为各行各业的企业提供了…...
【操作系统安全】任务1:操作系统部署
目录 一、VMware Workstation Pro 17 部署 二、VMware Workstation 联网方式 三、VMware 虚拟机安装流程 四、操作系统介绍 五、Kali 操作系统安装 六、Windows 系统安装 七、Windows 系统网络配置 八、Linux 网络配置 CSDN 原创主页:不羁https://blog.csd…...
Linux:自动化构建-make/Makefile
1.背景 一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作…...
maven wrapper的使用
写在前面 考虑这样的场景,张三创建了一个maven项目使用了3.9版本,当李四下载下来去开发配置的却是3.6版本,此时李四就不得不再去配置一个3.9版本的maven,为了解决这个问题,maven引入了maven wrapper的机制(…...
DB-GPT-0.7版本win11安装,最新版本,安装方式变更了
之前两天折腾要死,只因为安装了旧版本问题太多,现在安装最新版本 快速开始_V0.7.0 语雀 DB-GPT 0.7.0 部署教程 - yyhhyys blog DB-GPT 0.7.0 与 DeepSeek 集成使用指南 - yyhhyys blog 首先代码结构换了,python包管理工作也换了…...
树莓集团落子海南,如何重构数字产业生态体系
树莓集团在海南的布局,是其整体商业战略中的关键一环。这背后,是对政策机遇、产业协同、以及区域优势的深度考量。 政策机遇 海南自贸港建设带来前所未有的政策红利,包括贸易、投资、资金等方面的自由便利。树莓集团紧抓这一机遇࿰…...
Spring Boot 项目部署启动异常问题分析与解决:主类缺失与依赖冲突的分析
Spring Boot 项目部署启动异常问题分析与解决 在近期的 Spring Boot 项目部署工作中,遭遇了一起典型的启动异常状况。经过多维度的深入排查以及细致的调试,最终确定问题的根源在于打包插件配置与依赖管理的综合影响。以下将详细阐述整个问题的分析过程以及对应的解决办法。 …...
共享内存(System V)——进程通信
个人主页:敲上瘾-CSDN博客 进程通信: 匿名管道:进程池的制作(linux进程间通信,匿名管道... ...)-CSDN博客命名管道:命名管道——进程间通信-CSDN博客 目录 一、共享内存的原理 二、信道的建立 …...