分布式电商系统核心模块实现说明

2023-11-25 08:40

本文主要是介绍分布式电商系统核心模块实现说明,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

分布式电商系统核心模块

  • es全文检索
  • redis商品详情页
  • cookie购物车
  • 基于jwt的SSO单点登录
  • 社交登录【微博】
  • 支付-订单-库存

es全文检索

  1. 定义es的索引结构

就是将数据库里的 skuId,skuName,skuDesc,catalog3Id,price,skuDefaultImg,productId,skuAttrValueList【颜色,尺寸】数据查出来之后封装成一张表/对象PmsSearchSkuInfo,放到es的索引/库里面存着

PUT gmall0105
{"mappings": {"PmsSkuInfo":{"properties": {"id":{"type": "keyword","index": true},"skuName":{"type": "text","analyzer": "ik_max_word"},"skuDesc":{"type": "text", "analyzer": "ik_smart"},"catalog3Id":{"type": "keyword"},"price":{"type": "double"},"skuDefaultImg":{"type": "keyword","index": false},"hotScore":{"type": "double"},"productId":{"type": "keyword"},"skuAttrValueList":{"properties": {"attrId":{"type":"keyword"},"valueId":{"type":"keyword"}}}} }} 
}
  1. 使用es的java客户端代码批量导入数据到es中
for (PmsSearchSkuInfo pmsSearchSkuInfo : pmsSearchSkuInfos) {Index put = new Index.Builder(pmsSearchSkuInfo).index("gmall0105").type("PmsSkuInfo").id(pmsSearchSkuInfo.getId()+"").build();jestClient.execute(put);
}获取页面传来的查询参数,并构造所需的dsl语句字符串
boolQueryBuilder.filter(termQueryBuilder);  //精准匹配后过滤
boolQueryBuilder.must(matchQueryBuilder);  //模糊匹配
searchSourceBuilder.sort("id", SortOrder.DESC);//排序  searchSourceBuilder.aggregation();  //聚集
searchSourceBuilder.query(boolQueryBuilder); //查询结构,构造完成
Search search = new Search.Builder(searchSourceBuilder).addIndex("gmall0105").addType("PmsSkuInfo").build();
execute = jestClient.execute(search);   发起查询
List<SearchResult.Hit> hits=execute.getHits()得到查询结果
for(){pmsSearchSkuInfos.add(hit.source);}   转成java对象for(pmsSearchSkuInfos.skuAttrValueList){ 得到对应的 attrList  }  根据商品的sku销售属性,得到商品所对应的平台属性,因为需要实现面包屑的效果【需要在整个的平台属性中减去查询出来的商品的平台属性】
将从es中查询到skuInfoList返回给页面

最后测试网址:
http://localhost/listes?catalog3Id=61&valueId=39&valueId=43&valueId=48&keyword=硅谷

  • 各查询参数说明【平台属性,关键字,三级分类ID】
    catalog3Id=61------手机/手机通讯/手机
    valueId=(39,43,48)----屏幕尺寸:4寸以下,内存容量:16G,尺寸:z1
    keyword=硅谷 -----搜索框里输入硅谷进行全文检索

redis商品详情页

在高并发下缓存击穿,穿透,雪崩问题的解决

cookie购物车

在这里插入图片描述

 //存---使用redis的hash数据结构存储购物车数据jedis.hmset("user:"+memberId+":cart",map);map.put(OmsCartItem.getProductSkuId(), JSON.toJSONString(OmsCartItem));
//取---List< String> hvals = jedis.hvals("user:" + userId + ":cart");OmsCartItem omsCartItem = JSON.parseObject(hval, OmsCartItem.class);

注意点:
1、redis中取出来要进行反序列化
2、redis的hash结构是无序的,要进行排序(可以用时间戳或者主键id,倒序排序)
3、如果redis中没有要从数据库中查询,要连带把最新的价格也取出来,默认要显示最新价格而不是当时放入购物车的价格,如果考虑用户体验可以把两者的差价提示给用户。
4、加载入缓存时一定要设定失效时间,保证和用户信息的失效时间一致即可。
5、由于加入购物车时,用户可能存在登录和未登录两种情况,登录前在cookie中保存了一部分购物车信息,如果用户登录了,那么对应的要把cookie中的购物车合并到数据库中,并且刷新缓存。【登陆时:合并购物车,刷新缓存】
6、从对应域名下找cookie
在这里插入图片描述
测试网址: http://localhost:9999/addToCart?skuId=25&quantity=2 添加购物车
http://localhost:9999/cartList 查询购物车

1 购物车在不登陆的情况下,也可以使用
需要引入对浏览器cookie的操作2 购物车在登录的情况下,需要使用mysql和redis来存储数据
Redis作为购物车的缓存3 在缓存情况下,或者用户已经添加购物车后,允许购物车中的数据和原始商品数据的不一致性4 购物车同步问题
什么时候同步(结算、登录)
同步购物车后,是否需要删除cookie数据5 用户在不同的客户端同时登录
如何处理购物车数据

在这里插入图片描述

基于jwt的SSO单点登录

服务应该是并行的,而非串行的【购物车挂了,后续流程都挂】

  • 为何要使用sso单点登录
    因为分布式下session无法跨顶级域名共享,且安全性不高,保存在cookie里面的session的唯一标识jsseionId容易被截取。
//京东的首页,商品页,商品详情页,全文检索页,购物车等每个模块都是一个独立的系统,有自己的域名
https://www.jd.com/  			京东首页https://list.jd.com/list.html?cat=9987,653,655    	三级分类下的商品页【9987一级分类,653二级分类,655三级分类】https://item.jd.com/49405721859.html     		商品详情页【sku=49405721859】https://search.jd.com/search?keyword=电脑&cid3=672	全文检索页【关键词电脑,平台属性cid3为672------》电脑/笔记本】https://cart.jd.com/cart.action?r=0.35325141737280386    	购物车【当前是未登录状态,使用cookie保存了购物车的信息】所以我在实现的时候,这几个模块的controller不应该放在同一个web模块下。

社交登录【微博】

(A)用户打开客户端以后,客户端要求用户给予授权。
(B)用户同意给予客户端授权。
(C)客户端使用上一步获得的授权,向认证服务器申请令牌。
(D)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。
(E)客户端使用令牌,向资源服务器申请获取资源。
(F)资源服务器确认令牌无误,同意向客户端开放资源。

1、【微博开放平台创建应用(填写用户授权后的网页授权回调地址)】点击微博登录—》跳转到
https://api.weibo.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&response_type=code&redirect_uri=YOUR_REGISTERED_REDIRECT_URI
在这里插入图片描述
2、用户同意授权【输入用户的微博号和密码,对接微博登录成功】,页面跳转至 xxx/?code=CODE

http://www.gulishop.com/success?code=fef987b3f9ad1169955840b467bfc661

3、使用返回的code,换取access token
5、使用返回的code,换取access token
4、使用access token调用开发API获取用户信息(去访问任何微博开放平台的API)
1)、code用后即毁
2)、access_token在几天内是一样的
社交登录开发完毕
在这里插入图片描述

String show_user_url = "https://api.weibo.com/2/users/show.json?access_token="+access_token+"&uid="+uid;String user_json = HttpclientUtil.doGet(show_user_url);  //对接微博,获取用户信息Map<String,Object> user_map = JSON.parseObject(user_json,Map.class);// 将用户信息保存数据库,用户类型设置为微博用户UmsMember umsMember = new UmsMember();umsMember.setSourceType("2");umsMember.setAccessCode(code);umsMember.setAccessToken(access_token);umsMember.setNickname((String)user_map.get("screen_name"));

支付-订单-库存

从购物车用户点击结算,生成订单,订单状态是未付款,用户确认订单后点击付款,此时锁定库存,再发消息给订单,更新订单状态为库存已锁定,然后发消息给支付,开始支付,支付成功,就更新订单状态为已支付,假如在支付的时候,由于账户不足,导致支付失败,就进行消息回滚,其实更新订单,锁定库存事务也会进行回滚

//提交订单
@RequestMapping("alipay/submit")@LoginRequired(loginSuccess = true)@ResponseBodypublic String alipay(String outTradeNo, BigDecimal totalAmount, 数量){alipayClient.pageExecute(alipayRequest【订单号,购买数量】).getBody(); //调用SDK生成表单// // 向消息中间件发送一个检查支付状态(支付服务消费)的延迟消息队列----起点paymentService.sendDelayPaymentResultCheckQueue(outTradeNo,5);//发消息到一个队列里面return form;  //跳转到阿里的扫码支付页面
}Queue payhment_success_queue = session.createQueue("PAYMENT_CHECK_QUEUE");MessageProducer producer = session.createProducer(payhment_success_queue);
// 为消息加入延迟时间mapMessage.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY,1000*60); producer.send(mapMessage);@JmsListener(destination = "PAYMENT_CHECK_QUEUE",containerFactory = "jmsQueueListener")public void consumePaymentCheckResult(MapMessage mapMessage) throws JMSException {
// 调用paymentService的支付宝检查接口   
paymentService.updatePayment(paymentInfo);====Queue payhment_success_queue = session.createQueue("PAYHMENT_SUCCESS_QUEUE");MessageProducer producer = session.createProducer(payhment_success_queue);
producer.send(mapMessage);@JmsListener(destination = "PAYHMENT_SUCCESS_QUEUE",containerFactory = "jmsQueueListener")public void consumePaymentResult(MapMessage mapMessage) throws JMSException { orderService.updateOrder(omsOrder);【已支付】=====》Queue payhment_success_queue = session.createQueue("ORDER_PAY_QUEUE"); @JmsListener(destination = "ORDER_PAY_QUEUE", containerFactory = "jmsQueueListener")public void receiveOrder(TextMessage textMessage) throws JMSException { // 库存削减【锁库存】gwareService.lockStock(orderTask);//库存正常就锁库存,异常就 //库存超卖 记录日志,返回错误状态wareSkuMapper.incrStockLocked(wareSku);
}     
1. 假如库存中有10件商品,a提交完订单(数量9件),此时(锁定数量9),此时还没调用付款,b马上提交了订单数量为2件,此时锁定数量为11就超过了库存数量,b操作失败【页面提示库存不足】2. 库存中有10件商品,A,锁定的3件,隔段时间b锁定了4件,总的锁定就为7件,此时假设仓库管理员把a的商品3件出库了,此时出库数量为3,总锁定数量为4件,库存数量变为73. 库存中有10件商品,A,锁定了3件,但此时由于a的卡上余额不足,则进行回退撤销a锁定的3键,锁定数量变为零,支付失败。
1. 提交订单时,先校验数据库中的价格是否有变动?库存,比如你购买了十件,他会去查看仓库里是否有十件货,【验证库存数量--数量不足就return null】,而不是锁库存的数量,也不是库存减去所库存的数量2. 此时订单创建完毕,就跳转到支付3. 支付--》订单--》库存要保证分布式事务的一致性,如果抛异常就进行事务的回滚向支付成功队列里面发送支付成功的消息,然后提交事务订单业务收到消息更新订单状态为已付款..向库存发消息库存系统进行锁库存【更新库存锁定数量字段比如为2】,比如说库存数量更新为二,更新订单状态为商品准备出库,比如库存只有十件,但是我库存却出现了20件这时候数据库里所库存阶段维持,然后抛出错误,抄卖一场的日志到日志文件里面订单更新完状态之后又会通知物流系统,实时物流系统会发送物品及物品出库此时库存数量会减,然后以出库数量会增加然后订单状态更新为已出库

我们正常不可能在同一时间点击按钮多次,但是黑客通过程序可以实现在同一时间发送多个请求,并且用同一个交易码,这就可能导致高并发下(通过一个交易码多次提交订单,正常情况下是一个交易码,只能提交一次订单

购物车里有五件商品,也相当于有五个订单,你提交的时候,如果一个商品及其中的一个订单,他没有库存了,那你如果把所有的五个订单都回滚,用户体验不太好(京东是直接替用户做决定的,把你不合格的那个订单直接给他删了在购物车里给他删了这其实是不好的你应该直接让用户重新操作,重新去修改订单,直到他教研通过为止)

交易订单号是自己程序,可以选择生成的,可以用你的私钥加上当前时间出来申请订单号,然后再用支付宝借口的时候传入订单号

saveorder,在保存订单时删除购物车的数据

使用dubbo的时候可以指令协议,默认的是dubbo协议

服务器和服务器之间可以通过一步进行信息的交流,如支付宝直接对支付服务器发送银行转账已完成的这种消息

实际库存数量就是仓库里实际有的商品
锁定库存数量就是当前用户下单,付完钱之后买了两件商品

决定要不要拆单试看一个sku能不能在库存表里面一次完成?鸡你买了十个红色手机,那这十个红色手机能否在一个库存,里面取出来,因为我们的仓库可能有多个,比如北京有一个仓库,南京有一个仓库,可能北京的仓库里面有三个红色手机,南京的仓库里面有七个红色手机,那就需要进行三把十个手机分成3和7,然后从三号上号上面

该订单的商品都在一个库存里面,所以直接调用首库存就可以了,如果发生拆单,那就循环进行锁库存

这篇关于分布式电商系统核心模块实现说明的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/423471

相关文章

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

C++高效内存池实现减少动态分配开销的解决方案

《C++高效内存池实现减少动态分配开销的解决方案》C++动态内存分配存在系统调用开销、碎片化和锁竞争等性能问题,内存池通过预分配、分块管理和缓存复用解决这些问题,下面就来了解一下... 目录一、C++内存分配的性能挑战二、内存池技术的核心原理三、主流内存池实现:TCMalloc与Jemalloc1. TCM

OpenCV实现实时颜色检测的示例

《OpenCV实现实时颜色检测的示例》本文主要介绍了OpenCV实现实时颜色检测的示例,通过HSV色彩空间转换和色调范围判断实现红黄绿蓝颜色检测,包含视频捕捉、区域标记、颜色分析等功能,具有一定的参考... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间

Before和BeforeClass的区别及说明

《Before和BeforeClass的区别及说明》:本文主要介绍Before和BeforeClass的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Before和BeforeClass的区别一个简单的例子当运行这个测试类时总结Before和Befor

Python pip下载包及所有依赖到指定文件夹的步骤说明

《Pythonpip下载包及所有依赖到指定文件夹的步骤说明》为了方便开发和部署,我们常常需要将Python项目所依赖的第三方包导出到本地文件夹中,:本文主要介绍Pythonpip下载包及所有依... 目录步骤说明命令格式示例参数说明离线安装方法注意事项总结要使用pip下载包及其所有依赖到指定文件夹,请按照以

Python实现精准提取 PDF中的文本,表格与图片

《Python实现精准提取PDF中的文本,表格与图片》在实际的系统开发中,处理PDF文件不仅限于读取整页文本,还有提取文档中的表格数据,图片或特定区域的内容,下面我们来看看如何使用Python实... 目录安装 python 库提取 PDF 文本内容:获取整页文本与指定区域内容获取页面上的所有文本内容获取

基于Python实现一个Windows Tree命令工具

《基于Python实现一个WindowsTree命令工具》今天想要在Windows平台的CMD命令终端窗口中使用像Linux下的tree命令,打印一下目录结构层级树,然而还真有tree命令,但是发现... 目录引言实现代码使用说明可用选项示例用法功能特点添加到环境变量方法一:创建批处理文件并添加到PATH1

Java使用HttpClient实现图片下载与本地保存功能

《Java使用HttpClient实现图片下载与本地保存功能》在当今数字化时代,网络资源的获取与处理已成为软件开发中的常见需求,其中,图片作为网络上最常见的资源之一,其下载与保存功能在许多应用场景中都... 目录引言一、Apache HttpClient简介二、技术栈与环境准备三、实现图片下载与保存功能1.

canal实现mysql数据同步的详细过程

《canal实现mysql数据同步的详细过程》:本文主要介绍canal实现mysql数据同步的详细过程,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的... 目录1、canal下载2、mysql同步用户创建和授权3、canal admin安装和启动4、canal

Nexus安装和启动的实现教程

《Nexus安装和启动的实现教程》:本文主要介绍Nexus安装和启动的实现教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、Nexus下载二、Nexus安装和启动三、关闭Nexus总结一、Nexus下载官方下载链接:DownloadWindows系统根