news 2026/4/26 9:45:58

苍穹外卖项目复习笔记 (二) -- 小程序开发,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/4/22 21:00:12

RAG技术全解析:让大模型轻松掌握你的业务知识

RAG技术通过检索业务数据增强大模型生成能力&#xff0c;解决模型不了解特定业务的问题。核心流程包括&#xff1a;用户提问→检索相关资料→增强提示词→生成回复。关键技术是将文本转换为向量并存储于向量数据库中&#xff0c;实现语义匹配而非简单文本匹配。文章还介绍了索引…

作者头像 李华
网站建设 2026/4/25 12:15:47

产品经理必学!大模型技能助你职场逆袭,收藏这篇就够了

产品经理学习大模型(GPT-3、BERT等)可显著提升工作效率与决策质量&#xff0c;包括用户需求分析、市场趋势预测、项目管理、产品设计及数据分析等方面。掌握大模型技术能帮助产品经理在竞争激烈的市场中保持领先地位。文章提供了系统化学习路线、视频教程、技术文档和实战案例等…

作者头像 李华
网站建设 2026/4/25 10:45:37

编译原理大作业:3-非递归预测分析

1.实验目的 设计一个非递归预测分析器&#xff0c;实现对表达式语言的分析&#xff0c;理解自上而下语法分析方法的基本思想&#xff0c;掌握设计非递归预测分析器的基本方法。 2.实验要求 建立文法及其LL(1)分析表表示的数据结构&#xff0c;设计并实现相应的预测分析器&a…

作者头像 李华
网站建设 2026/4/25 17:13:13

45、Unix文件系统:文件与权限深度解析

Unix文件系统:文件与权限深度解析 1. Unix文件系统基础 在Unix系统中,文件系统的一些特性与其他系统有所不同。首先,由于使用随机访问文件定位系统调用的现有软件都需要更新,这使得相关操作并非易事。为避免大规模升级,大多数供应商允许在新系统中使用旧的32位大小,只要…

作者头像 李华
网站建设 2026/4/22 8:14:56

【高并发系统稳定性保障】:纤维协程异常拦截与日志追踪全解析

第一章&#xff1a;纤维协程的异常捕获处理在现代高并发编程中&#xff0c;纤维&#xff08;Fiber&#xff09;作为一种轻量级的执行单元&#xff0c;广泛应用于异步任务调度。与传统线程不同&#xff0c;纤维由用户态调度器管理&#xff0c;具备极低的上下文切换开销。然而&am…

作者头像 李华