乐优商城源码/数据库及笔记总结

文章目录

  • 1 源码
  • 2 笔记
    • 2.1 项目概述
    • 2.2 微服务
  • 3 项目优化
  • 4 项目或学习过程中涉及到的设计模式
  • 5 安全问题
  • 6 高内聚低耦合的体现
  • 7 项目中待优化的地方


1 源码

Github个人主页:https://github.com/dianemax

后端源码:leyou

门户网站源码:leyou-portal

后台管理系统源码:leyou-manage-web

乐优商城最新数据库文件:sql.txt


2 笔记

2.1 项目概述

项目概述

2.2 微服务

  • 微服务一:注册微服务:LyRegister

    • 使用Spring Cloud Netflix中的Eureka实现了服务注册中心以及服务注册与发现;
    • 服务间通过Ribbon和Feign实现均衡负载以及服务的消费
    • 为了使得服务集群更为健壮,使用Hystrix的融断机制来避免在微服务架构中个别服务出现异常时引起的故障蔓延;
  • 微服务二:网关微服务:LyGateway

    • 一切对服务的请求都会经过Zuul这个网关,然后再由网关来实现 鉴权、动态路由等等操作,Zuul作为服务的统一入口
  • 微服务三:商品微服务(上):LyItemApplication、商品微服务(下):LyItemApplication

    • 首先分析了商品表结构,最终基于商品类别去设计了表结构,每个分类下的商品规格参数key(参数)和值(参数的值)分开保存,key跟商品分类绑定,值跟商品绑定,解决全品类电商的spu和sku管理问题
    • 实现了品牌的查询,返回结果是总条数、总页数、当前页商品信息,将上述信息封装成PageResult,因为其他微服务也将频繁返回这个分页结果,涉及到的操作有:分页、过滤、排序、查询,最终解析分页结果得到返回值
    • 实现了品牌的新增,但是注意Mapper只能处理单表Brand,无法新增中间表tb_category_brand,因此要自己写sql语句
    • 商品规则组与规格参数的查询
    • 商品的查询
    • 商品的新增,新增界面首先选择商品的分类,之后选定品牌,这时首先需要实现根据商品分类查询品牌的功能;描述商品信息使用富文本编辑器,我们采用的是一款支持Vue的富文本编辑器:vue-quill-editor;添加商品规格参数,首先要根据分类id查询规格参数,查询完成后填写参数,最后提交表单;提交表单即新增商品,同时要更新spu、spu_detail、sku、stock四张表的信息
    • 修改商品信息,修改之前要先查找,除了查找spu信息还要查找sku信息;spu数据可以修改,但是SKU数据无法修改,因为有可能之前存在的SKU现在已经不存在了,或者以前的sku属性都不存在了。比如以前内存有4G,现在没了,因此这里直接删除以前的SKU,然后新增即可
  • 微服务四:上传微服务:LyUpload

    分布式文件上传系统FsatDFS来实现图片的上传,克服传统上传方式存在的问题:

    • 1)文件越传越多,启动加载的速度会越来越慢;
    • 2)tomcat解析静态资源速度非常慢;
    • 3)有单点故障问题,如果一台服务器挂了整体图片功能都会受到影响;
    • 4)无法进行水平扩展,因为多台机器的文件无法共享,会出现访问不到的情况

    实现步骤为:校验格式、校验内容、上传到FastDFS(storageClient.uploadFile(文件流,文件大小,扩展名,null)),最终返回URL路径

  • 微服务五:搜索微服务:LySearchApplication

    • 使用的是Spring提供的Spring Data Elasticsearch(原生的需要自己拼接字符串),并利用ElasticsearchTemplate创建索引和生成映射
    • 分析搜索结果的数据结构,将搜索结果封装为一个类Goods
    • 将查出来的数据导入索引库
    • 实现商品分类和品牌的聚合,再去分页、过滤、查询、解析查询结果
  • 微服务六:页面微服务:LyPageApplication

    • 根据传递来的spuId查询spu信息、spu详情、spu下的所有sku、规格参数等信息,通过Thymeleaf模板引擎渲染后返回到客户端(响应速度从140ms下降到了55ms)
    • 利用静态化技术,将动态HTML页面变成静态内容保存(保存在nginx上,提高并发能力),之后用户请求直接访问静态页面不再经过服务器渲染(响应速度从55ms下降到了10ms)
  • 微服务七:短信微服务:LySmsApplication

    • 短信发送API调用时长的不确定性,为了提高程序的响应速度,短信发送我们都将采用异步发送方式,即短信服务监听MQ消息,收到消息后发送短信;其它服务要发送短信时,通过MQ通知短信微服务
    • Redis的过期机制来保存验证码
  • 微服务八:用户微服务:LyUserApplication

    • 实现用户注册功能(需要调用短信微服务发送验证码)
    • 校验短信验证码、用户名密码等,成功后写入数据库
    • 使用Hibernate-Validator框架完成服务端数据校验,包括密码长度,手机号码格式是否正确等
    • 实现根据用户名查询用户(我们查询的时候只根据用户名来查,因为我们在设计数据库时给用户名这个字段添加了索引,加了索引之后,极大提升了查询的效率,但是如果使用用户名和密码来查询,索引就变得形同虚设)
  • 微服务九:鉴权微服务:LyAuthApplication(授权)、鉴权微服务:LyAuthApplication(鉴权)

    • 授权:接收用户的登录请求,通过用户中心的接口进行校验,通过后使用私钥生成JWT并返回(写入到token中返回);解析token获取用户信息
    • 鉴权:Zuul中完成登录校验拦截(所有请求都会经过Zuul);编写过滤逻辑(获取cookie中的token,通过JWT对Token进行校验,通过则放行)
  • 微服务十:购物车微服务:LyCartApplication

    • 登录状态下商品添加到Redis(其中key是用户,因此此处要做用户鉴权,value是商品信息)中,未登陆状态下商品添加到localstorage(存储数据没有时间限制)中
    • 对购物车中商品数量的修改以及商品本身的增删改查操作的实现
  • 微服务十一:订单微服务:LyOrderApplication

    • 新增订单,填充用户信息、收货人地址、金额信息并写入数据库,同时新增订单详情、订单状态、减库存操作
    • 查询订单,生成订单URL、二维码信息,完成微信支付

3 项目优化

  1. 品牌和商品分类是多对多关系,有一张中间表tb_category_brand,但是这张表没有设置外键约束,这是因为电商中更注重性能电商中需要频繁的增删改查操作,设置外键影响数据库读写的效率,并且数据删除时会很麻烦。既然没有设置外键那么只能靠代码来维护关系。

  2. Feign实现服务间调用
    在搜索微服务中需要展示搜索结果,比如查询spu信息、查询sku信息等,很多操作我们都在商品微服务中实现过了,直接从商品微服务中复制过来时可以的,但是有两个问题:

    • 代码冗余。尽管不用写实现,只是写接口,但服务调用方要写与服务controller一致的代码,有几个消费者就要写几次。
    • 增加开发成本。调用方还得清楚知道接口的路径,才能编写正确的FeignClient

    最终的实现方式

    • 我们的服务提供方不仅提供实体类,还要提供api接口声明
    • 调用方不用字节编写接口方法声明,直接继承提供方给的Api接口即可
  3. 页面展示时候有搜索过滤选项,比如5-6英寸,这时我们对索引的存储就要有一个优化,这样我们搜索的时候就做的不是范围匹配,而是精确匹配提升了搜索效率
    乐优商城源码/数据库及笔记总结_第1张图片
    此外, 过滤 是也进行优化,比如过滤选项选中了屏幕尺寸,过滤条件设置为6英寸以上,那么我们可以发现除了屏幕尺寸以外的其他参数信息的过滤选项也少了很多,这是因为我们当前展示页面展示的过滤参数选项是当前过滤条件 过滤后 商品的 参数集合

  4. 京东搜索 苹果 出现了分类,如 红富士 蛇果 以及手机规格参数等,假如用户想搜索的是水果苹果而不是苹果手机,那么下面的机身尺寸等参数就没必要显示的,因此我们做一个优化:在未确定商品分类之前不展示规格参数。我们在后台需要对聚合得到的商品分类数量进行判断,如果等于1,我们才继续进行规格参数的聚合

  5. 但是不同的商品,在item.html中展示的内容也不同,我们有两个思路,

    思路一:
    统一跳转到item.html页面,然后异步加载商品数据,渲染页面。
    优点:页面加载快,异步处理,用户体验好
    缺点:会向后台发起多次请求,增加服务器压力

    思路二:
    将请求交给tomcat处理,在后台完成数据的渲染,给不同的商品生成不同的页面后,返回给用户。
    优点:后台处理页面后返回,用户拿到的是最终数据,不会再向后台发起请求。
    缺点:在后台处理页面,服务端压力过大,tomcat并发能力差

    两种思路各有优缺点,我们将其做一个整合。现在选择用tomcat来处理请求,然后通过Thymeleaf模板引擎渲染后返回到客户端,此时响应速度从140ms下降到了55ms。但是在后台需要大量的数据查询,而后渲染得到HTML页面。会对数据库造成压力,并且请求的响应时间过长,并发能力不高。我们对此还可以进行优化

    我们采用静态化技术,静态化是指把动态生成的HTML页面变为静态内容保存,以后用户的请求到来,直接访问静态页面,不再经过服务的渲染。而静态的HTML页面可以部署在nginx中,从而大大提高并发能力,减小tomcat压力,用此方法响应速度从55ms下降到了10ms

  6. 商品微服务中商品的删改操作如何和搜索微服务、页面微服务同步呢?——消息队列
    利用中间件技术RabbitMQ优化搜索微服务和页面微服务

  7. 短信发送API调用时长的不确定性,为了提高程序的响应速度,短信发送我们都将采用异步发送方式

  8. JWT与RSA非对称加密

    • 因为JWT签发的token中已经包含了用户的身份信息,并且每次请求都会携带,这样服务端就无需保存用户信息,甚至无需去数据库查询,完全符合了Rest的无状态规范
    • 没有RSA加密时每次鉴权都需要访问鉴权中心,系统间的网络请求频率过高,效率略差,鉴权中心的压力较大
    • JWT和RSA相结合,私钥保存在授权中心,公钥保存在Zuul和各个微服务,用户请求登录,随后授权中心校验,通过后用私钥对JWT进行签名加密并返回JWT给用户,之后每一次你用户携带JWT访问,Zuul直接通过公钥解密JWT,进行验证,验证通过则放行,请求到达微服务,微服务直接用公钥解析JWT,获取用户信息,无需访问授权中心
  9. 只要用户有操作就应该重新刷新token(重新生成token并写入),否则用户在浏览商品的时候不经意间过了30分钟有效期,准备下单时让用户重新登陆,影响用户体验。

  10. 购物车的价格是加入时的价格,当价格发生变化时要有降价的友好提示提升用户体验,通过查询当前商品的价格和加入购物车时商品的价格做差值,将价格差值显示在页面上,作为友好提示

  11. 在购物车微服务中我们不仅要添加购物车,还有修改、删除购物车信息,每一步操作都需要用户信息key,所以每个地方都需要鉴权,显然在每个操作都做一次鉴权会使得代码很臃肿,我们需要的是统一解析而不是一次又一次的写,因此我们把这部分功能抽取出来,此时我们想到SpringMVC的拦截器——interceptor,通过拦截器我们可以统一处理每个请求,然后再进入controller层处理

  12. 订单数据的量级是非常大的,所以需要数据库分表、分库,此时的分表指的是水平分表,就是每张表字段是一样的,所以传统的主键自增长就不适用了,需要采用一个全局唯一的ID,其中redis的主键自增长策略,可以实现全局唯一ID,但是生成速度有限,此外还有一种雪花算法可以实现,最终我们选择雪花算法

4 项目或学习过程中涉及到的设计模式

设计模式根本记不住,只有三秒钟的记忆,以下内容瞎写的 -_-

1.单例模式

  • Spring本身就是单例的
  • 读取配置类的工具类是单例的,如果每次需要使用都要new一个出来,那么就会有很多,但是实例只需要一个
  • 所有对象的创建都是单例的
  • 数据库连接池,因为数据库连接池是一种数据库资源,节省打开/关闭数据库带来的连接损耗
  • 比如Hibernate项目中通过SessionFactory来获取Session

2.建造者模式

  • 将token写入cookie中。在参数较多的情况下,比如,是否可以跨域访问、生命周期的设置、编码格式等,如果一个构造器参数只有上述三个,但是突然有需要加一个参数 是否仅允许http访问,那么就要重写一个构造函数,或者重载构造函数,这就很不方便,因此此处使用了建造者模式,可以解决复杂对象的构造逻辑,可以将赋值方法给Builder对象连续调用,Builder中创建了对象的各个属性赋值方法,不需要重载构造函数只需要确定Builder实例调用哪个赋值方法就可以了

3.适配器模式

  • IO实现的源码
  • 可能外部系统的数据格式和自己系统的数据格式并不相同,这事就可以利用适配器模式来实现

4.桥接模式

  • JDBC访问数据库

5.装饰模式

  • java.io.BufferedInputStream

5 安全问题

  1. 用户微服务中,为了安全考虑对password和salt添加了注解@JsonIgnore,这样在json序列化时,就不会把password和salt返回

  2. cookie的生命周期,默认是-1,代表一次会话,浏览器关闭cookie就失效,选择这种方式更为安全

  3. cookie中有域的概念 domain 例如一个cookie只能在www.baidu.com生效,无法在别的域下生效, 给cookie绑定一个域,防止别的网站访问你的cookie,也是一种安全措施

  4. 订单业务中减库存操作涉及到的分布式事务问题与线程安全问题

  5. 订单详情页上我们发现商品的价格标题参数等信息都有但是为什么这里我们只传递ID这一个参数呢?这是因为安全问题,因为我们的URL是对外暴露的,防止有人利用insomnia等工具修改价格,之后再进行订单的提交,造成损失
    乐优商城源码/数据库及笔记总结_第2张图片

6 高内聚低耦合的体现

1.微服务本身

2.持久化(JPA,Java Persistence API):

  • 用来操作实体对象,执行CRUD操作,框架在后台替我们完成所有的事情,开发者从繁琐的JDBC和SQL代码中解脱出来
  • 将运行期的实体对象持久化到数据库中。
  • 通过面向对象非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合

ORM(Object-Relation-Mapping),即对象关系映射技术,是对象持久化的核心

7 项目中待优化的地方

  • 商品的下架功能
    • 商品下架要提供清空下架商品的功能实现
  • 商品移入收藏夹
    • 需要单独的表结构,类似于购物车的数据结构,只是不需要商品数量
  • 商品的优惠功能:需要一个单独的微服务,因为优惠功能略复杂,关键问题在于优惠条件,比如:
    • 用户权限:哪些用户可享受优惠,哪些用户不可享受优惠
    • 商品限制:哪些商品可以用,那些商品不可以用
    • 价格限制:满足一定的购买条件才可以享受优惠,比如购买一定量的金额,或者一定的数量
    • 优惠方案:满减或者打折
    • 商品组合:某几个商品组合起来可享受优惠
    • 店铺问题:哪些店铺可用,哪些店铺不可用,是否可以跨店铺享受优惠
    • 结算问题:解算时候优惠的计算以及发生退款情况时如何处理
  • 登录后购物车合并
    • 如果登录:
      • 首先检查用户的LocalStorage中是否有购物车信息,
      • 如果有,则提交到后台保存,
      • 清空LocalStorage
    • 如果未登录,直接查询即可

你可能感兴趣的:(乐优商城,乐优商城笔记,乐优商城总结)