赞
踩
Redis 是高性能的,基于键值对的,写入缓存的 内存存储系统。它支持多种数据结构如字符串、哈希表、列表、集合、有序集合等,并提供了丰富的操作命令。项目中引入 Redis 的地方是:查询店铺营业状态 ,像这种店铺营业状态,本项目无非就两个状态:营业中/打样。而且它属于高频查询。只要用户浏览到这个店铺,前端就要自动发送请求到后端查询店铺状态。Redis 是基于键值对这种形式存储的,而且 Redis 也把将数据放到缓存中,而不是磁盘,有效缓解了这种高频查询给磁盘带来的压力。
缓存菜品 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大。**结果:**系统响应慢、用户体验差。通过Redis来缓存菜品数据,减少数据库查询操作。
缓存套餐(用到的是Spring Cache)
苍穹外卖这个项目中用户在查看店铺状态时,需要让数据库与 redis 高度保持一致,因为如果店铺没有营业的话就不能点单了,所以它要求时效性比较高,所以采用的读写锁保证的强一致性。我们采用的是 redisson 实现的读写锁,在读的时候添加共享锁,可以保证读读不互斥,读写互斥。当我们更新数据的时候,添加排他锁,它是读写,读读都互斥,这样就能保证在写数据的同时是不会让其他线程读数据的,避免了脏数据。这里面需要注意的是读方法和写方法上需要使用同一把锁才行。
Redis 的 IO 多路复用是一种技术,允许 Redis 同时监听多个客户端连接,并在有数据到达时及时处理,提高了 IO 效率和性能。它通过一种机制来管理和处理多个连接,使得 Redis 能够高效地处理大量客户端请求。
悲观锁
之所以叫做悲观锁,是因为这是一种对数据的修改持有悲观态度的并发控制方式。总是假设最坏的情况,每次读取数据的时候都默认其他线程会更改数据,因此需要进行加锁操作,当其他线程想要访问数据时,都需要阻塞挂起。悲观锁的实现:
Httpclient是一个服务器端进行 HTTP 通信的库,他使得后端可以发送各种 HTTP 请求和接收 HTTP 响应,使用 HTTPClient,可以轻松的发送 GET, POST, PUT, DELETE 等各种类型的的请求。
在我们的项目中,在进行微信登录开发时,后端在使用登录凭证校验接口的时候就需要发送指定请求到给定的 URL 中。因此我们使用 Httpclient 去完成该任务。
通过微信登录的流程,如果要完成微信登录的话,最终就要获得微信用户的openid。在小程序端获取授权码后,向后端服务发送请求,并携带授权码,这样后端服务在收到授权码后,就可以去请求微信接口服务。最终,后端向小程序返回openid和token等数据。
(DAY01用户登录模块
(DAY06微信登录模块
用户登录 – 认证通过 – 生成jwt token返回给前端 – 前端发起请求时携带token – 拦截器请求验证token – 放行/不放行
客户端发起的每一次请求都是一个单独的线程
拦截器验证通过 将用户id通过TreadLocal放入内存,在serviceImpl阶段使用时从内存中拿出获取用户id(在程序中我们已经将TreadLocal封装成一个类 BaseContext
二者区别
①Cookie可以存储在浏览器或者本地,Session只能存在服务器
②session 能够存储任意的 java 对象,cookie 只能存储 String 类型的对象
③Session比Cookie更具有安全性(Cookie有安全隐患,通过拦截或本地文件找得到你的cookie后可以进行攻击)
④Session占用服务器性能,Session过多,增加服务器压力
⑤单个Cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个Cookie,Session是没有大小限制和服务器的内存大小有关。
拦截器的作用是校验JWT令牌 并将用户id通过ThreadLocal放入内存
定义拦截器
在配置类中配置拦截器
PageHelper是MyBatis的一个插件,内部实现了一个PageInterceptor拦截器。Mybatis会加载这个拦截器到拦截器链中。在我们使用过程中先使用PageHelper.startPage这样的语句在当前线程上下文中设置一个ThreadLocal变量,再利用PageInterceptor这个分页拦截器拦截,从ThreadLocal中拿到分页的信息,如果有分页信息拼装分页SQL(limit语句等)进行分页查询,最后再把ThreadLocal中的东西清除掉。
PageHelper.startPage(int pageNum, int pageSize)
方法设置分页的参数,调用该方法时,通过 ThreadLocal 存储分页信息。PageHelper
利用 MyBatis 提供的插件 API(Interceptor
接口)来拦截原始的查询语句。MyBatis 执行任何 SQL 语句前,都会先通过其插件体系中的拦截器链,PageHelper
正是在这个环节介入的。PageHelper
会根据分页参数动态地重写或添加 SQL 语句,使其成为一个分页查询。PageHelper
会自动执行一个派生的查询,以计算原始查询(不包含分页参数)的总记录数。这通常通过移除原始 SQL 的排序(ORDER BY
)和分页(LIMIT
、OFFSET
等)条件,加上 COUNT(*)
的包装来实现。PageInfo
对象中(或其他形式的分页结果对象),这个对象除了包含当前页的数据列表外,还提供了总记录数、总页数、当前页码等分页相关的信息,方便在应用程序中使用。反射是一种在程序运行时检查和操作类的机制,通过获取类的信息并动态调用方法、创建对象等。这种机制让程序能够在运行时根据需要动态地获取和操作类的结构和成员。
Spring Task(Spring 任务调度)是 Spring 框架提供的一种任务调度框架,用于执行定时任务、异步任务、任务监听、任务调度等。
在苍穹外卖项目中使用 Spring task
- 通过定时任务每分钟检查一次是否存在支付超时订单(下单后超过15分钟仍未支付则判定为支付超时订单),如果存在则修改订单状态为“已取消”
- 通过定时任务每天凌晨1点检查一次是否存在“派送中”的订单,如果存在则修改订单状态为“已完成”
== 或许也可以用RabbitMQ中的延迟队列???==
使用 Websocket 来实现用户端和商家端通信:
WebSocket 是一种在 Web 应用程序中实现双向通信的协议。它允许客户端和服务器之间建立持久的、双向的通信通道,使得服务器可以主动向客户端推送消息,而无需客户端发送请求。
客户端和服务器之间可以实时地发送消息和接收消息,不需要频繁地发起请求。这样可以减少网络流量和延迟,并提供更好的用户体验。
- 通过WebSocket实现管理端页面和服务端保持长连接状态
用户下单并且支付成功后,需要第一时间通知外卖商家。
来单提醒
用户在小程序中点击催单按钮后,需要第一时间通知外卖商家。
*客户催单
HTTP 协议和 WebSocket 协议对比:
不能使用 WebSocket 并不能完全取代 HTTP,它只适合在特定的场景下使用,原因如下:
我在涉及多表操作时使用了事务(Transaction): 将涉及到的数据库操作封装在一个事务中。在事务中,要么所有的数据库操作都成功提交,要么全部失败回滚,保证了数据的一致性。如果发生异常,可以通过捕获异常并执行回滚操作来保证数据的一致性。
** 具体操作: **
** 项目具体用处 **
在用户下单功能的serviceImpl中
出现的问题是在order表中插入数据成功而因为在orderDetail的mapper.xml中sql语句编写的错误导致orderDetail表中插入数据失败,因此此时需要事务回滚
Spring的事务管理就是对AOP的进一步封装,会为我们提供好一个增强类
Apache POI 是一个处理Miscrosoft Office各种文件格式的开源项目。简单来说就是,我们可以使用 POI 在 Java 程序中对Miscrosoft Office各种文件进行读写操作。
一般情况下,POI 都是用于操作 Excel 文件。
Apache POI 的应用场景:
** 产品原型 **
在数据统计页面,有一个数据导出的按钮,点击该按钮时,其实就会下载一个文件。这个文件实际上是一个Excel形式的文件,文件中主要包含最近30日运营相关的数据。表格的形式已经固定,主要由概览数据和明细数据两部分组成。真正导出这个报表之后,相对应的数字就会填充在表格中,就可以进行存档。
项目中的业务规则:
SpringCache 是 Spring 框架提供的一个抽象层,旨在提供一种透明的方式来缓存应用中的数据。SpringCache 不是一个具体的缓存实现,而是一个集成不同缓存解决方案的接口,如 EHCache、Caffeine、Guava、Redis 等。它允许开发者通过简单的注解来控制方法的缓存行为,例如,使用 @Cacheable
来标记一个方法的返回值应该被缓存,以及使用 @CacheEvict
来标记何时移除缓存。SpringCache 为应用提供了一致的缓存视图,而开发者不需要关心具体使用哪种缓存技术。
简单的说:它也是一种缓存技术,使得所用工具不局限于 Redis。相比较于使用 Redis 的时候需要把相关代码内嵌到方法体种,Spring Cache 是一种基于注解方式来达到内嵌代码相同的效果。
存在问题: 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大。
结果: 系统响应慢、用户体验差
通过Redis来缓存菜品数据,减少数据库查询操作。
缓存逻辑分析:
为了保证数据库和Redis中的数据保持一致,修改管理端接口 DishController 的相关方法,加入清理缓存逻辑。
缓存套餐
1). 导入Spring Cache和Redis相关maven坐标
2). 在启动类上加入@EnableCaching注解,开启缓存注解功能
3). 在用户端接口SetmealController的 list 方法上加入@Cacheable注解
4). 在管理端接口SetmealController的 save、delete、update、startOrStop等方法上加入CacheEvict注解
Spring的事务管理就是对AOP的进一步封装,会为我们提供好一个增强类
Spring管理的事务 底层就是AOP,AOP底层用的是动态代理
代理模式:
二十三种设计模式中的一种,属于结构型模式。它的作用就是通过提供一个代理类,让我们在调用目标方法的时候,不再是直接对目标方法进行调用,而是通过代理类间接调用。让不属于目标方法核心逻辑的代码从目标方法中剥离出来——解耦。调用目标方法时先调用代理对象的方法,减少对目标方法的调用和打扰,同时让附加功能能够集中在一起也有利于统一维护。
== 静态代理==
静态代理,主动创建代理类,将被代理的目标对象声明为成员变量,附加功能由代理类中的代理方法来实现,通过目标对象来实现核心业务逻辑。
静态代理确实实现了解耦,但是由于代码都写死了,完全不具备任何的灵活性。就拿日志功能来说,将来其他地方也需要附加日志,那还得再声明更多个静态代理类,那就产生了大量重复的代码,日志功能还是分散的,没有统一管理。
提出进一步的需求:将日志功能集中到一个代理类中,将来有任何日志需求,都通过这一个代理类来实现。这就需要使用动态代理技术了。
== 动态代理==
动态代理技术分类
选用阿里云的OSS服务进行文件存储
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。