• HbnnMall电子商城系统介绍(功能与技术栈)


            今天在看我个人网站上的文章时,看到了曾经在2020年自己开发的电商系统。那时我已经入职小米有一段时间了,基本已经对各个业务线,各种业务知识有了系统性的了解和学习,所以想自己动手写一个电商系统,以便进一步提高自己的技术。于是趁着疫情那段特殊时期,在业余时间用了几个月的时间把系统写出来了。麻雀虽小,五脏俱全,经过自己几个月的打磨,该有的功能都有了。不过和市面上开源的比,我写的真是相形见绌,都没法供外人展示,当时也纯粹只是为了自己学习。

            当看到自己写的几万行代码时,唯一的感觉就是:这是一场酣畅淋漓的自嗨,虽无大成效但却很痛快。另外一个有意思的是我发现写golang代码会让人难以自拔。毛主席的一首四言诗写道:”与天奋斗,其乐无穷;与地奋斗,其乐无穷;与人奋斗,其乐无穷。“,我改一下:写golang,其乐无穷;写前端,其乐无穷;写代码,其乐无穷。

    一、网站介绍

    整个系统的架构是这样:

            上面也说了,我的初衷是学习,所以并不像很多现成的电商系统,所有东西都揉到一起写的,而是拆分出多个微服务,采用Dubbo+nacos实现服务注册和发现。

    1.首页

    首页实现了商品分类导航,轮播图、优惠活动、商品推荐、排行榜、每日新品等。

    这块儿就是各种后端服务,聚合形成的数据。

    代码示例如下:

    1. public List> execute(HomePageRequest homePageRequest){
    2. List homeGeneralTaskList = new ArrayList<>();
    3. //新品展示
    4. homeGeneralTaskList.add(new DailyNewProductTask(goodsStatService));
    5. //商品推荐
    6. RecommendRequest recommendRequest = new RecommendRequest();
    7. recommendRequest.setBaseReuest(homePageRequest.getBaseReuest());
    8. homeGeneralTaskList.add(new RecommendTask(recommendRequest,recommendService));
    9. //排行榜
    10. homeGeneralTaskList.add(new TopRankTask(goodsStatService));
    11. //秒杀商品列表
    12. homeGeneralTaskList.add(new FlashSaleActivityTask());
    13. //商品展播图
    14. homeGeneralTaskList.add(new BannerTask(goodsStatService));
    15. List> homeFutureResultList = new ArrayList<>();
    16. for (HomeGeneralTask homeGeneralTask:homeGeneralTaskList){
    17. homeFutureResultList.add(homePageExecutor.submit(homeGeneralTask));
    18. }
    19. return homeFutureResultList;
    20. }

    2、商品详情页

            商品详情页涉及到很多,功能包括:

    • 商品左侧图片轮播展示;
    • 商品属性;
    • 商品促销活动;
    • 秒杀页;
    • 标签切换;
    • 立即购买;
    • 加入购物车;
    • 商品详情介绍;
    • 商品评论;
    • 商品参数;
    • 相似商品推荐。

            这个地方我花的时间最多,作为一个后端人员,搞前端的标签切换时,挺痛苦。

            和首页类似,这个地方也是由多个后端服务组成,就是所谓的产品站,这地方是可以做数据异构的。

            代码示例如下:

    1. public List> execute(GoodsDetailRequest goodsDetailRequest, GoodsDetail goodsDetail){
    2. List> goodsDetailFutureResultList = new ArrayList<>();
    3. List goodsDetailGeneralTaskList = new ArrayList<>();
    4. //价格库存服务
    5. goodsDetailGeneralTaskList.add(new GoodsPriceInventoryTask(goodsDetail,goodsPropmotionService,propInventoryService));
    6. //促销活动服务
    7. if(Optional.ofNullable(goodsDetailRequest.getIsNeedActDetailInfo()).orElse(false)){
    8. goodsDetailGeneralTaskList.add(new GoodsPromotionTask(goodsDetail,goodsPropmotionService));
    9. }
    10. //商品详情介绍服务
    11. if(Optional.ofNullable(goodsDetailRequest.getIsNeedPropDetailIntroduction()).orElse(false)){
    12. goodsDetailGeneralTaskList.add(new GoodsIntroductionTask(goodsDetail,goodsDetailRequest,shopGoodImgMapper,djangoUrl));
    13. }
    14. //商户信息服务
    15. if(goodsDetailRequest.getIsNeedMerchantInfo() != null && goodsDetailRequest.getIsNeedMerchantInfo()){
    16. //TODO 增加商户信息
    17. }
    18. //增加shopTag
    19. if(Optional.ofNullable(goodsDetailRequest.getIsNeedShopTag()).orElse(false)){
    20. goodsDetailGeneralTaskList.add(new GoodsTagTask(goodsDetail,goodTagService));
    21. }
    22. for (GoodsDetailGeneralTask goodsDetailGeneralTask:goodsDetailGeneralTaskList){
    23. goodsDetailFutureResultList.add(goodsDetailExecutor.submit(goodsDetailGeneralTask));
    24. }
    25. return goodsDetailFutureResultList;
    26. }

    3、商品搜索

    搜索这块儿我使用的是ES进行查询,写了一个定时任务,会定期全量刷新一遍,当然应该还要有一个增量更新的,只不过我没写,同步的示例代码:

    简易的搜索代码:

    1. MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("name",searchRequest.getName());
    2. //提高搜索精度
    3. matchQueryBuilder = matchQueryBuilder.prefixLength(3);
    4. //默认是or
    5. matchQueryBuilder.operator(Operator.AND);
    6. matchQueryBuilder.minimumShouldMatch("75%");
    7. searchSourceBuilder.query(
    8. QueryBuilders.boolQuery()
    9. .must(matchQueryBuilder)
    10. .filter(QueryBuilders.termQuery("status",1))
    11. );
    12. searchSourceBuilder.from(searchRequest.getPageIndex() == null ? 0 : searchRequest.getPageIndex());
    13. searchSourceBuilder.size(searchRequest.getPageSize() == null ? 15 : searchRequest.getPageSize());
    14. // searchSourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC));
    15. esSearchRequest.source(searchSourceBuilder);
    16. SearchResponse searchResponse = restHighLevelClient.search(esSearchRequest,RequestOptions.DEFAULT);

    4、购物车列表

    购物车实现购物车添加、修改、删除、全选、全部选等等。

    购物车的实现都是通过Redia+lua脚本实现的。

    5、结算页面

    结算页是真正订单结算的页面,让用户知道要付多少钱,这里面涉及到商品,优惠、全局id号(分库分表场景需要全局唯一的订单号)、反作弊、发票、地址等多个服务。还要根据发货主体或者物权主体进行拆单。

    6、支付页

    订单数据已经生成,并成功写入数据表。接下来商户进行支付操作。超时的会自动取消。

    由于支付都是需要企业认证,这里还没实际做支付功能,不过这个不难。

    7、个人中心

    个人中心包括各状态订单、我的收藏、优惠券、地址管理等等。

    8、在线客服

    在线客服也花了几天时间写的,使用了LayUi模板 +Python+channels实现了Websocket。

    9、单点登录

    实现的功能包括:

    • 支持业务系统接入实现第三方登录;
    • 登录方式包括手机验证码登录以及用户名密码登录;
    • token的申请和生成;
    • 通过token解析用户信息,并访问受限资源;
    • token的刷新。

    具体可以看我之前写的文章:用户服务之实现单点登录icon-default.png?t=N7T8https://hbnnforever.cn/article/useservicessologin.html

    10、秒杀服务

    之前小米有个大秒系统,我觉得挺有意思,后来我就想我也整一个,就用Golang写了一个,当然,我写得没那么复杂,就是想体验一把Golang的丝滑。具体代码不展示了,先贴一个工程目录:

    二、技术栈

    1、Web端

    采用的是Python +Django+Vue开发,部署采用Nginx+supervisor+gunicorn的方式;

    2、API 网关

    采用的是Springboot+Netty开发,目前已实现的功能:

    • 统一前端接口调用,支持HTTP,Dubbo协议;
    • HTTP协议至Dubbo协议的转换;
    • 统一鉴权;
    • 限流,主要借鉴sentinel的思想。

    当然,可以看出来,目前实现的网关还比较弱鸡,至少还要加入熔断降级,服务编排,缓存,日志等等。而且,这市面上的API网关太多了,我纯粹是为了学习,实际中我们尽量避免造轮子。

    3、后端业务层

    用到的技术栈:

    • JAVA;
    • Python;
    • Golang:
    • Springboot;
    • Django;
    • Dubbo;
    • Nacos;
    • ZK;
    • Sentinel;
    • Redis;

    JAVA+springboot+Dubbo+Nacos:

    • 用户账户服务;
    • 商品服务;
    • 优惠服务;
    • 库存服务;
    • 订单服务; 
    • 评论服务;
    • 清结算服务;
    • 发票服务;

    用Django+channels实现的:客服服务    Websocket;

    Golang:秒杀服务,用golang+Redis单独写了秒杀服务,参考小米的大秒系统;

    MysqlProxy:实现读写分离+ 分库分表

    Nacos+sentinel:nacos实现注册中心,服务发现,限流熔断配置发现、sentinel熔断限流。

    ZK:订单号,分布式唯一ID生成

    ES:商品存储,用于搜索查询。

    Shardingshpere:订单分库分表,这个也纯粹是练习。

    三、总结

            我开发的电商系统并不是完整的,像支付、物流、退款等都没有写,不过当时在开发的过程中,的确又学到了很多。网上也有很多开源的系统,尤其是听说那些报培训班的都有电商系统开发。虽然本人对培训班嗤之以鼻,不屑于多看他们一眼,但所谓存在的就是合理的,他们弄电商系统也侧面说明这玩意是有实战意义的,实战一段时间后还是有提高的。

            代码就不展示了,如果有对这方面感兴趣的同学可以网上找找更好的开源示例,不过我的代码可以免费私下给。

  • 相关阅读:
    2022绵阳+dp经典问题
    【计算机网络】Tcp详解
    download failed after attempts=6: dial tcp 108.160.169.178:443: i/o timeout问题解决
    【Laravel系列7.9】测试
    React中Immutable的使用
    4项简化IT服务台任务的ChatGPT功能
    QT::QString 很全的使用
    数据结构与算法—双向链表
    Java自定义ClassLoader加载外部类
    教你从零开始画echarts地图
  • 原文地址:https://blog.csdn.net/hbnn111/article/details/137331160