news 2026/7/17 22:19:55

苍穹外卖项目复习笔记 (二) -- 小程序开发,redisTemplate,spring cache

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
苍穹外卖项目复习笔记 (二) -- 小程序开发,redisTemplate,spring cache

一、 微信小程序登录 (后端实现)

后端的核心任务只有一个 拿codeopenid

1. 流程详解后端不直接处理微信界面,而是提供一个接口给小程序调用。

  • 输入:小程序前端传来的临时登录凭证code
  • 处理:后端拿着这个code+appid+secret去找微信服务器核实。
  • 输出:生成一个我们可以控制的token(JWT) 返回给前端,用于后续业务鉴权。

2. 代码示例

Step 1: 用户JWT令牌校验拦截器

/** * jwt令牌校验的拦截器 */@Component@Slf4jpublicclassJwtTokenUserInterceptorimplementsHandlerInterceptor{@AutowiredprivateJwtPropertiesjwtProperties;publicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{if(!(handlerinstanceofHandlerMethod)){returntrue;}// 1、从请求头中获取令牌Stringtoken=request.getHeader(jwtProperties.getUserTokenName());// 2、校验令牌try{log.info("jwt校验:{}",token);// 这里必须使用 UserSecret (用户端密钥) 进行解密,而不是 UserTokenNameClaimsclaims=JwtUtil.parseJWT(jwtProperties.getUserSecretKey(),token);// 这里必须获取 USER_ID,而不是 EMP_IDLonguserId=Long.valueOf(claims.get(JwtClaimsConstant.USER_ID).toString());// 3、设置到上下文BaseContext.setCurrentId(userId);log.info("当前用户id:{}",userId);returntrue;}catch(Exceptionex){log.error("用户端JWT校验失败",ex);// 建议打印异常日志以便调试response.setStatus(401);returnfalse;}}}

Step 2: Controller 层 (接收请求)

@RestController@RequestMapping("/user/user")@Slf4jpublicclassUserController{@AutowiredprivateUserServiceuserService;@PostMapping("/login")publicResult<UserLoginVO>wechatLogin(@RequestBodyUserLoginDTOuserLoginDO){log.info("微信登录,用户数据:{}",userLoginDO);returnuserService.wechatLogin(userLoginDO);}}

Step 3: Service 层 (核心逻辑)
这里模拟了通过HttpClient调用微信接口的过程。

@Service@Slf4jpublicclassUserServiceImplextendsServiceImpl<UserMapper,User>implementsUserService{privatefinalstaticStringWECHAT_LOGIN_URL="https://api.weixin.qq.com/sns/jscode2session";@AutowiredprivateJwtPropertiesjwtProperties;@AutowiredprivateWeChatPropertiesweChatProperties;@OverridepublicResult<UserLoginVO>wechatLogin(UserLoginDTOuserLoginDTO){Stringopenid=getOpenid(userLoginDTO);// 判断openid是否为空if(openid==null){thrownewLoginFailedException(MessageConstant.LOGIN_FAILED);}// 判断是否是新用户Useruser=lambdaQuery().eq(User::getOpenid,openid).one();// 如果是新用户,自动完成注册if(user==null){user=User.builder().openid(openid).build();save(user);}LonguserId=user.getId();// 创建jwt令牌Map<String,Object>map=newHashMap<>();map.put(JwtClaimsConstant.USER_ID,userId);Stringtoken=JwtUtil.createJWT(jwtProperties.getUserSecretKey(),jwtProperties.getUserTtl(),map);// 封装vo对象UserLoginVOuserLoginVO=UserLoginVO.builder().id(userId).openid(userLoginDTO.getCode()).token(token).build();returnResult.success(userLoginVO);}privateStringgetOpenid(UserLoginDTOuserLoginDTO){// 调用微信接口实现登录Map<String,String>Login_Map=newHashMap<>();Login_Map.put("appid",weChatProperties.getAppid());Login_Map.put("secret",weChatProperties.getSecret());Login_Map.put("js_code",userLoginDTO.getCode());Login_Map.put("grant_type","authorization_code");Stringresult=HttpClientUtil.doGet(WECHAT_LOGIN_URL,Login_Map);log.info("微信接口返回数据:{}",result);// 解析JSONObjectjsonObject=JSON.parseObject(result);returnjsonObject.getString("openid");}}

二、 StringRedisTemplate 与 RedisTemplate

为了直观看到区别,我们对比一下如果不加配置直接使用,它们在 Redis 图形化工具(如 RDM)里长什么样。

1. RedisTemplate

(默认情况)Java 对象会被 JDK 序列化,变成二进制流。

@AutowiredprivateRedisTemplateredisTemplate;publicvoidtestRedisTemplate(){// 存一个简单的字符串redisTemplate.opsForValue().set("city","beijing");}

Redis 中实际存储的样子 (乱码):

  • Key:\xac\xed\x00\x05t\x00\x04city
  • Value:\xac\xed\x00\x05t\x00\x07beijing
  • 缺点: 此时如果你去 Redis 命令行执行get city,是查不到数据的,因为 Key 实际上包含了乱码前缀。

2. StringRedisTemplate (推荐)Key 和 Value 都是纯字符串,所见即所得。

@AutowiredprivateStringRedisTemplatestringRedisTemplate;publicvoidtestStringRedisTemplate(){// 存一个简单的字符串stringRedisTemplate.opsForValue().set("city","beijing");// 存一个对象 (通常配合 JSON 工具库)Useruser=newUser(1L,"Jack");StringjsonUser=JSON.toJSONString(user);// 手动转 JSONstringRedisTemplate.opsForValue().set("user:1",jsonUser);}

Redis 中实际存储的样子 (清晰):

  • Key:city
  • Value:beijing
  • Key:user:1
  • Value:{"id":1, "name":"Jack"}
  • 优点: 方便调试,多语言通用。

三、 Spring Cache 注解实战

Spring Cache 的目标是:把缓存逻辑从业务代码中剥离出来
在苍穹外卖中,主要用于C端(用户端)查询套餐时的缓存,提高响应速度。

1. 开启缓存功能在启动类上必须添加注解:

@SpringBootApplication@EnableCaching// <--- 开启注解缓存功能publicclassSkyApplication{publicstaticvoidmain(String[]args){SpringApplication.run(SkyApplication.class,args);}}

###2. 查询时自动缓存 (@Cacheable)场景: 用户查询某个分类下的套餐列表。

@ServicepublicclassSetmealServiceImplimplementsSetmealService{// cacheNames (或 value): 缓存的名称,相当于 Redis 中的文件夹// key: 具体的键名。这里使用 SpEL 表达式,动态获取参数 categoryId// 最终 Redis Key 格式: setmealCache::1001 (假设 categoryId 为 1001)@Cacheable(cacheNames="setmealCache",key="#categoryId")publicList<Setmeal>list(LongcategoryId){// --- 下面的代码只有在缓存未命中时才会执行 ---Setmealsetmeal=newSetmeal();setmeal.setCategoryId(categoryId);setmeal.setStatus(StatusConstant.ENABLE);List<Setmeal>list=setmealMapper.list(setmeal);returnlist;// --- 方法结束后,Spring 会自动将 list 返回值写入 Redis ---}}

3. 修改时清理缓存 (@CacheEvict)场景: 管理员在后台修改了套餐,或者新增了套餐,必须删除缓存,防止用户看到旧数据。

精确清理 (删除特定 key):

// 当执行批量删除套餐时,我们很难知道具体的 categoryId 是多少,或者影响太大// 所以通常不精确删除,而是直接删除整个 setmealCache 下的所有数据

全部清理 (常用):

@ServicepublicclassSetmealServiceImplimplementsSetmealService{// allEntries = true: 表示删除 "setmealCache" 下所有的 key// 无论是 setmealCache::1001 还是 setmealCache::1002 统统删掉@CacheEvict(cacheNames="setmealCache",allEntries=true)publicvoidsave(SetmealDTOsetmealDTO){// 执行正常的数据库新增操作Setmealsetmeal=newSetmeal();BeanUtils.copyProperties(setmealDTO,setmeal);setmealMapper.insert(setmeal);// --- 方法执行完后,Spring 自动清空 setmealCache 下的所有缓存 ---}@CacheEvict(cacheNames="setmealCache",allEntries=true)publicvoidupdate(SetmealDTOsetmealDTO){// update 逻辑...}}

总结 Spring Cache 流程图

  1. 查询请求-> 拦截器 ->Redis 有吗?
  • -> 直接返回数据 (Service 方法体代码不执行)。
  • -> 执行 Service 方法 -> 查数据库 -> 返回结果 ->自动存入 Redis
  1. 修改请求-> 执行 Service 方法 -> 改数据库 ->自动删除 Redis 缓存
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/17 4:13:02

HTTPS DDoS 排查 异常流量到抓包分析

在讨论 HTTPS DDoS 之前&#xff0c;很多人第一反应是防火墙、CDN 或云厂商的防护策略。但在真实项目中&#xff0c;开发者和运维往往最先面对的并不是“怎么防”&#xff0c;而是这到底是不是攻击&#xff0c;攻击长什么样。 而要回答这些问题&#xff0c;抓包几乎是绕不开的一…

作者头像 李华
网站建设 2026/7/18 0:10:23

12、Docker与Kubernetes使用指南

Docker与Kubernetes使用指南 1. Docker基础操作与远程API访问 在Docker的使用中,我们可以通过一些基本命令来管理容器和镜像。例如,使用 docker ps -a 命令可以查看所有容器的信息,包括容器ID、镜像、命令、创建时间和状态等: $ docker ps -a CONTAINER ID IMAGE …

作者头像 李华
网站建设 2026/7/17 8:47:26

行为树优化全攻略(性能翻倍的4个秘密武器)

第一章&#xff1a;行为树的优化在复杂的游戏AI或自动化系统中&#xff0c;行为树&#xff08;Behavior Tree&#xff09;作为核心决策架构&#xff0c;其性能直接影响系统的响应速度与资源消耗。随着节点数量增加和逻辑复杂度上升&#xff0c;未优化的行为树可能导致帧率下降、…

作者头像 李华
网站建设 2026/7/18 1:10:22

直流电机双闭环调速系统仿真模型:转速外环与电流内环PI参数整定指南,无静差跟踪实现功能介绍

直流电机双闭环调速系统仿真模型 1.附带仿真模型参数计算配套文档 2.附带转速外环、电流内环PI参数整定配套文档 功能&#xff1a;双闭环采用转速外环、电流内环&#xff0c;其中PI参数在报告里面有详细的整定教程&#xff0c;可以实现无静差跟踪直流电机双闭环调速仿真这玩意儿…

作者头像 李华
网站建设 2026/7/18 8:08:30

模型压缩技术详解:剪枝、量化与知识蒸馏,让你的大模型轻量化部署

本文系统介绍了深度学习模型压缩的三大核心技术&#xff1a;剪枝通过移除冗余连接减少参数&#xff1b;量化降低数值精度实现存储压缩&#xff1b;知识蒸馏采用"教师-学生"模式让大模型指导小模型学习。文章还详细阐述了技术组合的最佳顺序&#xff1a;知识蒸馏→剪枝…

作者头像 李华