SpringBoot + Mybatis Plus 整合 Redis

server/2025/3/18 17:07:37/

Redis 在用户管理系统中的典型应用场景

结合你的用户增删改查接口,以下是 Redis 的实用场景和具体实现方案:

场景作用实现方案
用户信息缓存减少数据库压力,加速查询响应使用 Spring Cache + Redis 注解缓存
登录 Token 存储分布式 Session 或 JWT Token 管理将 Token 与用户信息绑定,设置过期时间
接口限流防止恶意刷接口基于 Redis 计数器实现滑动窗口限流
重复提交拦截防止用户重复提交表单用 Redis 存储请求唯一标识,设置短期过期
热点数据预加载提前缓存高频访问数据定时任务 + Redis 存储

Mac M1 安装 Redis 详细步骤

1. 通过 Homebrew 安装 Redis
# 安装 Homebrew(如果尚未安装)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"# 安装 Redis
brew install redis
2. 启动 Redis 服务
# 前台启动(测试用,Ctrl+C 退出)
redis-server# 后台启动(推荐)
brew services start redis
3. 验证安装
# 连接 Redis 客户端
redis-cli ping  # 应返回 "PONG"

Spring Boot 3 整合 Redis

1. 添加依赖

pom.xml 中:

		<!-- Spring Cache 核心依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency><!-- Redis 驱动 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></dependency>
2. 配置 Redis 连接

application.yml

spring:data:redis:host: localhostport: 6379# password: your-password  # 如果设置了密码lettuce:pool:max-active: 8max-idle: 8
3. 示例

配置类

package com.example.spring_demo01.config;import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.*;import java.time.Duration;@Configuration
public class RedisConfig {// 配置 RedisTemplate@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(factory);// Key 序列化template.setKeySerializer(new StringRedisSerializer());// Value 序列化为 JSONtemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());// Hash 结构序列化template.setHashKeySerializer(new StringRedisSerializer());template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());return template;}// 配置缓存管理器@Beanpublic CacheManager cacheManager(RedisConnectionFactory factory) {RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())).entryTtl(Duration.ofMinutes(30)); // 设置默认过期时间return RedisCacheManager.builder(factory).cacheDefaults(config).build();}
}

接口限流工具类

package com.example.spring_demo01.utils;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;import java.util.UUID;
import java.util.concurrent.TimeUnit;@Component
public class RateLimiter {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;public boolean allowRequest(String userId) {String key = "rate_limit:" + userId;long now = System.currentTimeMillis();long windowMs = 60_000; // 1 分钟// 移除窗口外的请求记录redisTemplate.opsForZSet().removeRangeByScore(key, 0, now - windowMs);// 统计当前窗口内请求数Long count = redisTemplate.opsForZSet().zCard(key);if (count != null && count >= 10) {return false; // 超过限制}// 记录本次请求redisTemplate.opsForZSet().add(key, UUID.randomUUID().toString(), now);redisTemplate.expire(key, windowMs, TimeUnit.MILLISECONDS);return true;}
}

实体类

package com.example.spring_demo01.entity;import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;import java.io.Serializable;@Data
@TableName("user")
@JsonIgnoreProperties(ignoreUnknown = true) // 防止 JSON 反序列化问题
public class User implements Serializable { // 实现 Serializable@TableId(type = IdType.AUTO) // 主键自增private Long id;private String name;private Integer age;private String email;
}

service层

package com.example.spring_demo01.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.spring_demo01.entity.User;
import com.example.spring_demo01.mapper.UserMapper;
import com.example.spring_demo01.service.UserService;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;import java.io.Serializable;@Service
public class UserServiceImplextends ServiceImpl<UserMapper, User>implements UserService {// 对 MyBatis Plus 的 getById 方法添加缓存@Cacheable(value = "user", key = "#id")@Overridepublic User getById(Serializable id) {return super.getById(id);}// 更新时清除缓存@CacheEvict(value = "user", key = "#entity.id")@Overridepublic boolean updateById(User entity) {return super.updateById(entity);}// 删除时清除缓存@CacheEvict(value = "user", key = "#id")@Overridepublic boolean removeById(Serializable id) {return super.removeById(id);}
}

controller层

package com.example.spring_demo01.controller;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.spring_demo01.annotation.AdminOnly;
import com.example.spring_demo01.entity.User;
import com.example.spring_demo01.service.UserService;
import com.example.spring_demo01.utils.RateLimiter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;import java.time.Duration;
import java.util.List;
import java.util.UUID;@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@Autowiredprivate RedisTemplate<String, Object> redisTemplate;@Autowiredprivate RateLimiter rateLimiter;// ------------------------------ 增 ------------------------------@PostMappingpublic String addUser(@RequestBody User user, @RequestHeader String clientId) {String key = "SUBMIT_LOCK:" + clientId + ":" + user.hashCode();// 10秒内不允许重复提交Boolean success = redisTemplate.opsForValue().setIfAbsent(key, "", Duration.ofSeconds(10));if (Boolean.FALSE.equals(success)) {throw new RuntimeException("请勿重复提交");}userService.save(user);return "新增成功";}// ------------------------------ 删 ------------------------------@DeleteMapping("/{id}")public String deleteUser(@PathVariable Long id) {userService.removeById(id);return "删除成功";}@DeleteMapping("/batch")public String deleteBatch(@RequestBody List<Long> ids) {userService.removeByIds(ids);return "批量删除成功";}// ------------------------------ 改 ------------------------------@PutMappingpublic String updateUser(@RequestBody User user) {userService.updateById(user);return "更新成功";}// ------------------------------ 查 ------------------------------@GetMapping("/{id}")@AdminOnlypublic User getUserById(@PathVariable Long id) {return userService.getById(id);}@GetMapping("/list")public List<User> listUsers(@RequestParam(required = false) String name,@RequestParam(required = false) Integer age) {QueryWrapper<User> wrapper = new QueryWrapper<>();if (name != null) {wrapper.like("name", name); // 模糊查询姓名}if (age != null) {wrapper.eq("age", age);     // 精确查询年龄}return userService.list(wrapper);}@GetMapping("/page")public Page<User> pageUsers(@RequestParam(defaultValue = "1") Integer pageNum,@RequestParam(defaultValue = "10") Integer pageSize,@RequestHeader(value = "Authorization") String token) {// 从 Token 中获取用户IDlog.info("token:{}", token);log.info("User:{}", redisTemplate.opsForValue().get(token.split(" ")[1]));User user = (User) redisTemplate.opsForValue().get(token.split(" ")[1]);if (user == null) throw new RuntimeException("未登录");// 限流校验if (!rateLimiter.allowRequest("PAGE_" + user.getId())) {throw new RuntimeException("请求过于频繁");}return userService.page(new Page<>(pageNum, pageSize));}// ------------------------------ other ------------------------------@GetMapping("/error")public String getError() {throw new RuntimeException();}@PostMapping("/login")public String login(@RequestBody User user) {log.info("login user:{}", user);// 验证用户逻辑(示例简化)User dbUser = userService.getOne(new QueryWrapper<User>().eq("id", user.getId()).eq("name", user.getName()));if (dbUser == null) {throw new RuntimeException("登录失败");}// 生成 Token 并存储String token = "TOKEN_" + UUID.randomUUID();redisTemplate.opsForValue().set(token,dbUser,Duration.ofMinutes(30));return token;}
}

在启动类添加注解:

package com.example.spring_demo01;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cache.annotation.EnableCaching;@SpringBootApplication
@MapperScan("com.example.spring_demo01.mapper")
@ServletComponentScan // 启用 Servlet 组件扫描(如 Filter、Servlet)
@EnableCaching // 启动缓存,Redis使用
public class SpringDemo01Application {public static void main(String[] args) {SpringApplication.run(SpringDemo01Application.class, args);}}

常见问题排查

Q1: 连接 Redis 超时
  • 检查服务状态:运行 redis-cli ping 确认 Redis 是否正常运行
  • 查看端口占用lsof -i :6379
  • 关闭防火墙sudo ufw allow 6379
Q2: Spring Boot 无法注入 RedisTemplate
  • 确认配置类:添加 @EnableCaching@Configuration
  • 检查序列化器:显式配置序列化方式避免 ClassCastException
    @Configuration
    public class RedisConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(factory);template.setKeySerializer(new StringRedisSerializer());template.setValueSerializer(new GenericJackson2JsonRedisSerializer());return template;}
    }
    

总结

通过 Redis 你可以为项目快速实现:

  1. 高性能缓存层 - 降低数据库负载
  2. 分布式会话管理 - 支持横向扩展
  3. 精细化流量控制 - 保障系统稳定性

http://www.ppmy.cn/server/176009.html

相关文章

Unity小框架之单例模式基类

单例模式&#xff08;Singleton Pattern&#xff09;是一种常用的创建型设计模式&#xff0c;其核心目标是确保一个类只有一个实例&#xff0c;并提供一个全局访问点。它常用于需要控制资源访问、共享配置或管理全局状态的场景&#xff08;如数据库连接池、日志管理器、应用配置…

(vue)elementUi中el-upload上传附件之后 点击附件可下载

(vue)elementUi中el-upload上传附件之后 点击附件可下载 handlePreview(file) {console.log(file)const fileUrl https://.../zzy/ file.urlconst a document.createElement(a)a.href fileUrla.download file.namea.style.display none// a.setAttribute(download, file.…

【k8s003】k8s与docker的依赖关系

‌一、早期版本对应关系&#xff08;Kubernetes 1.20 之前&#xff09;‌ ‌Kubernetes 1.13–1.19‌ ‌支持的 Docker 版本范围‌&#xff1a;1.13.1 至 19.03.x‌ ‌说明‌&#xff1a;此阶段 Kubernetes 直接依赖 Docker 作为默认容器运行时&#xff0c;需严格匹配版本以避免…

Linux中安装MySQL

检查是否有MySQL服务并卸载 检查并卸载 在安装MySQL数据库之前&#xff0c;我们需要先检查一下当前Linux系统中&#xff0c;是否安装的有MySQL的相关服务&#xff08;很多linux安装完毕之后&#xff0c;自带了低版本的mysql的依赖包&#xff09;&#xff0c;如果有&#xff0c…

【网络安全 | 漏洞挖掘】$15,000——通过持久token获取个人身份信息(PII)

未经许可,不得转载。 文章目录 绕侧攻击应用程序发现注册流程中的异常token调查token泄露Google Dorking 登场Wayback Machine 的作用影响分析绕侧攻击应用程序 某金融服务平台提供了测试凭据,允许直接登录测试环境。主应用程序包含数百个功能和端点,因此在测试过程中花费了…

课程分享 | 智能网联汽车网络安全测试框架

汽车智能化带来巨大网络安全风险 据公安部2024年1月统计&#xff0c;我国汽车保有量已达3.36亿辆&#xff0c;全国有94座城市汽车保有量超过100万辆。 与此同时&#xff0c;智能网联汽车的发展势头迅猛。2023年我国搭载组合驾驶辅助系统的智能网联乘用车新车销售约950万辆&…

鸿蒙路由 HMrouter 配置及使用一

1、学习链接 HMRouter地址 https://gitee.com/hadss/hmrouter/blob/dev/HMRouterLibrary/README.md 2、工程配置 下载安装 ohpm install hadss/hmrouter 添加编译插件配置 在工程目录下的build-profile.json5中&#xff0c;配置useNormalizedOHMUrl属性为true (我这项目创…

go语言学习教程推荐,零基础到做项目

一、基础入门阶段 官方教程&#xff08;免费&#xff09; • A Tour of Go&#xff1a;交互式入门教程&#xff0c;边学边练 • Go by Example&#xff1a;通过300代码片段学习语法 入门书籍 • &#x1f4d8;《Go语言圣经》中文版&#xff08;免费在线阅读&#xff09;&#…