news 2026/5/16 9:57:02

苍穹外卖项目复习笔记 (二) -- 小程序开发,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/5/15 1:20:40

数据洪流的精妙疏导:Ascend C内存层级与数据搬运优化实战

目录 摘要 1. 引言&#xff1a;内存墙下的昇腾突围战 2. 技术原理&#xff1a;Ascend C内存体系架构深度解析 2.1 &#x1f3d7;️ 六级存储体系的设计哲学 2.2 ⚡ 数据搬运的核心机制&#xff1a;DMA引擎详解 2.3 &#x1f4ca; 性能特性实测数据分析 3. 实战部分&…

作者头像 李华
网站建设 2026/5/15 3:40:26

GPT-5.2全面解析:3种方法轻松上手,小白也能玩转最新AI大模型

OpenAI发布GPT-5.2&#xff0c;包含Instant、Thinking和Pro三个版本&#xff0c;性能显著提升&#xff0c;支持256k上下文窗口。GPT-5.2在编程、推理、科学等领域表现优异&#xff0c;但价格有所上涨。文章提供了三种使用方法&#xff1a;第三方充值、苹果礼品卡/Google Pay支付…

作者头像 李华
网站建设 2026/5/9 2:31:10

Laravel 13多模态缓存清理实战(深度优化与陷阱规避)

第一章&#xff1a;Laravel 13多模态缓存清理概述在现代Web应用开发中&#xff0c;缓存机制是提升系统性能的核心手段之一。Laravel 13引入了多模态缓存清理策略&#xff0c;允许开发者针对不同类型的缓存&#xff08;如文件、Redis、数据库、Memcached等&#xff09;执行精细化…

作者头像 李华
网站建设 2026/5/14 12:29:06

大模型热门岗位详解与学习资源,助小白快速入门AI领域

文章主要介绍了AI大模型领域的六大热门岗位&#xff0c;包括模型研发工程师、算法工程师、数据科学家等&#xff0c;详细分析了各岗位的职责、要求及适合人群。同时&#xff0c;提供了系统学习大模型的资源与方法&#xff0c;包括学习路线图、经典书籍、视频教程、实战项目和面…

作者头像 李华
网站建设 2026/5/10 23:22:11

如何确保纤维协程100%释放资源?90%开发者忽略的关键步骤

第一章&#xff1a;纤维协程资源释放的核心挑战在现代高并发系统中&#xff0c;纤维&#xff08;Fiber&#xff09;作为一种轻量级执行单元&#xff0c;被广泛用于提升程序的吞吐能力。然而&#xff0c;随着协程数量的激增&#xff0c;资源释放问题逐渐成为系统稳定性的关键瓶颈…

作者头像 李华