Java微服务构建:打造健壮订单模型的完整指南

2023-10-31 18:28

本文主要是介绍Java微服务构建:打造健壮订单模型的完整指南,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Java微服务构建一个健壮的订单模型(业务,规划,设计与实现)

在设计领域业务模型时,我们通常会追求理论完美,而忽略实践的脆弱性。尽管我们没有贬低领域建模的意图,但事实上,在电商技术发展多年之后,某些系统模型仍然缺乏弹性。本文将结合多年电商交易经验,分享一些个人对设计思路的见解,与大家共同学习、进步。

探究交易的本质:合同签订和履约的全过程

交易是指买卖双方在签订合同并履约的过程中完成的一系列活动。合同签订是正向交易的职责,而履约则包括物流、仓储和发货等服务。合同包含的内容非常丰富,比如卖家售卖什么产品、提供哪些服务、如何履约或违约的赔偿方式、如何维权等。如图1所示,当然图中缺少了维权的部分。如果买家对产品不满意或发现质量问题,可以根据合同中的条款进行退款、换货等。这些条款可能包含一些隐含的要求,例如电商法中的规定。

28c6228b882c30d2cbb858655b2087f4.jpeg


(图1)

在电子商务的交易中一般是人、产品的进行的一次互通的行为。从维基百科的定义来看交易其实包含物品或者服务,可能你既提供产品又提供服务,也可能你只卖服务,这个时候就没有产品。产品也可能不是真实存在的物品,它也可能是一种虚拟的商品,比如虚拟的货币。我先分析一般情况下交易设计的模型。

订单模型

一个实体模型就是一个独立的事物。每个实体都拥有一个唯一的标识符,可以将它的个体性和所有其他类型相同或者不同的实体区分开。许多时候,也许应该说绝大多数时候,实体是可变的。也就是说,它的状态会随着时间发生变化。不过,一个实体不一定必须是可变的,它也可能是不可变的。

在设计的时候关于实体和值对象的区分有时候是比较困难的,不同人可能对实体的理解不一样。比如对订单条目OrderItem是实体还是值对象?有的人认为是实体有的人认为是值对象。订单的话有订单id或者订单号来做唯一标识,这个共识会比较强,那么条目orderItemId是不是订单条目的唯一标识呢?在考虑这个是否是唯一标识的是不是有意义的下,我们可以跟值对象做对比,实体区别于值对象的最大原因是,值对象的值是不可变的,比如我们的收货人信息Receiver,在下单用户选择地址的那一刻就已经确定下来了,在订单域他就是一个地址信息,他的属性在订单的生命周期中不会改变,它只是用来发货的,它也没有唯一标识,所以他是一个值对象。一个订单可能有多个条目,每个条目是可以单独发货,在下单待支付的时候也可以对条目的商品进行改价,收货维权的时候买家或者商家可以选择某个商品进行退款,所以他在订单生命周期中会随着时间的变化而变化,所以它是一个实体,他的唯一标识就是orderItemId。

5945c1602984823fe084bfe8b4d75af3.jpeg

订单关系

订单这个聚合根我们再熟悉不过了,在很多电商领域都会提到这个聚合根,如图1大体的我们一般会得出这样的一个关联关系,这个关系有点单薄。虽然他可以体现出订单这个聚合的大体依赖关系,并且可以表达80%的场景,但是不能比较好的体现销售订单和采购订单的关系。销售订单主要是站在买家的角度阐明买家下单,采购订单主要是站在商家的角度向供应商下单。所以至少我们在订单中需要有一个值对象来标识这个关系,对应的条目其实也有这一层的关系。

ef99e7601570cf3a0836eed1bd32fb28.jpeg

订单条款

一般的电商交易都会有一些显示或者隐私的条款的,隐私的比如物流条款选择的物流配送方式,是自提还是快递或者无需物流,物流的显示条款可能有是否支持运费险。在维权方面还有一些隐性或者显性的条款,比如是否支持7天无理由退货。还要一些活动,比如定金预售,我们在商品下单的时候就会给用户提示下了定金是不支持退款的,我们这边的订单条款主要考虑的是显示的条款,隐私条例一般是电商法需要支持的,是一种默认的条款。

但是很遗憾,这些条款信息在我做过的交易里是没有很好的体现(因为历史的债务),甚至有些条款都是没有落库的,有些条款是通过扩展字段存储在订单扩展字段或者条目的扩展字段中。现在我们交易系统在很大程度上解决扩展性问题,都是通过扩展字段来承载,所以有了很多打标的接口,这样处理当然在性能上是有很大的好处,比如解决了性能问题,但是在复杂的业务系统中,其实就隐藏了一部分业务逻辑,在领域设计中是不被允许的,所以在解决性能问题的情况下我们可能需要平衡一些业务。大量的打标服务从而导致扩展字段的急速膨胀,最终解决的办法就是不断的扩充extra字段的长度。

08c8ab387f3316b90b1709b6a73ddd41.jpeg

订单调整

我们在下单支付等过程经常的会对订单进行一些调整,比如我们会对待支付的订单进行改价,这个一般的我们需要一个调整单,显示的记录这个调整。广义上来讲,我们订单的调整还包含一些费用,比如附加费、额外费用,商品或者运费的均摊,这些数据还比较复杂,一般的是作用在订单条目的,如果要在订单条目存储会比较复杂,因为包含的内容还比较多,比如调整价格,原价,调整原因,调整时间等等。所以这些调整信息比较适合单独拎出来存储。调整单的设计在ERP系统比较常见,比如我们在算出入库的时候,在月末结算不均衡的时候会手动入一个入库调整单。这里讲的订单调整不是ERP的调整单,它是针对交易的计算价格的时候,对商品价格的一些调整。

d0247e65021c1498c7267c8a00dc8574.jpeg

一般的,订单调整是指在订单创建后,由于各种原因需要对订单的价格、数量、物品等进行修改的过程。在实际业务中,常见的订单调整场景包括满减活动、优惠券使用、商品退换货等。以满减活动为例,当满足活动条件后,系统会自动计算出优惠的金额并减免相应的金额,然后将修改后的订单金额保存在数据库中。此时,订单状态也会发生相应的变化,例如待支付的订单状态会变成待发货、待收货的订单状态也会相应地发生改变。在调整过程中,需要对订单相关的数据进行验证和更新,保证数据的准确性和一致性,同时还需要对用户进行提示和通知,以避免产生误解和纠纷。

1b65d3da3c5a6fa756296916f1a7dd20.jpeg

订单状态

订单的状态是随着时间推移而发生变化的,订单的状态变化可以通过不同的事件来触发。订单的状态通常包括:创建、待支付、已支付、待发货、已发货、待收货、已收货等。

当买家下单后,订单状态为“创建”,此时卖家需要对订单进行确认并进行库存锁定等操作。如果卖家确认订单信息无误,则将订单状态变更为“待支付”;否则将订单状态变更为“取消”。

当买家完成支付后,订单状态变更为“已支付”。此时,卖家可以开始准备商品进行发货,或者进行拣货、分拣等前置工作。在准备好商品后,订单状态变更为“待发货”。

当卖家将商品发出后,订单状态变更为“已发货”。此时,买家可以开始关注物流信息,并等待商品的到达。如果商品未按时到达或者出现其他问题,买家可以通过平台提供的维权服务进行投诉。

当商品到达买家手中时,订单状态变更为“待收货”。买家需要在收到商品后进行确认,如果确认收货,则订单状态变更为“已收货”,交易完成。如果买家在一定时间内未确认收货,则订单状态会自动变更为“已完成”。

在订单状态变更的过程中,可能会存在一些意外情况,例如买家取消订单、买家申请退货等,这些事件会触发订单状态的相应变化,以确保交易的公正、合法和安全。

订单状态记录着订单生命周期,其实还是比较核心并且复杂的一个实体。不同的订单类型的订单状态流转不一样,这个需要进行一个统一的设计,一般的话我们会考虑用状态机来实现。交易中的订单状态是可以枚举的,一般的我们会把订单状态设计成一个枚举类,但是订单状态其实承载了很多操作和控制状态流转的行为,所以它其实应该是有自己的唯一标识的实体。

73b32d64183340d48f3c63c9763b01ab.jpeg

这篇关于Java微服务构建:打造健壮订单模型的完整指南的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

java实现延迟/超时/定时问题

《java实现延迟/超时/定时问题》:本文主要介绍java实现延迟/超时/定时问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java实现延迟/超时/定时java 每间隔5秒执行一次,一共执行5次然后结束scheduleAtFixedRate 和 schedu

Java Optional避免空指针异常的实现

《JavaOptional避免空指针异常的实现》空指针异常一直是困扰开发者的常见问题之一,本文主要介绍了JavaOptional避免空指针异常的实现,帮助开发者编写更健壮、可读性更高的代码,减少因... 目录一、Optional 概述二、Optional 的创建三、Optional 的常用方法四、Optio

Spring Boot项目中结合MyBatis实现MySQL的自动主从切换功能

《SpringBoot项目中结合MyBatis实现MySQL的自动主从切换功能》:本文主要介绍SpringBoot项目中结合MyBatis实现MySQL的自动主从切换功能,本文分步骤给大家介绍的... 目录原理解析1. mysql主从复制(Master-Slave Replication)2. 读写分离3.

idea maven编译报错Java heap space的解决方法

《ideamaven编译报错Javaheapspace的解决方法》这篇文章主要为大家详细介绍了ideamaven编译报错Javaheapspace的相关解决方法,文中的示例代码讲解详细,感兴趣的... 目录1.增加 Maven 编译的堆内存2. 增加 IntelliJ IDEA 的堆内存3. 优化 Mave

Python从零打造高安全密码管理器

《Python从零打造高安全密码管理器》在数字化时代,每人平均需要管理近百个账号密码,本文将带大家深入剖析一个基于Python的高安全性密码管理器实现方案,感兴趣的小伙伴可以参考一下... 目录一、前言:为什么我们需要专属密码管理器二、系统架构设计2.1 安全加密体系2.2 密码强度策略三、核心功能实现详解

Java String字符串的常用使用方法

《JavaString字符串的常用使用方法》String是JDK提供的一个类,是引用类型,并不是基本的数据类型,String用于字符串操作,在之前学习c语言的时候,对于一些字符串,会初始化字符数组表... 目录一、什么是String二、如何定义一个String1. 用双引号定义2. 通过构造函数定义三、St

springboot filter实现请求响应全链路拦截

《springbootfilter实现请求响应全链路拦截》这篇文章主要为大家详细介绍了SpringBoot如何结合Filter同时拦截请求和响应,从而实现​​日志采集自动化,感兴趣的小伙伴可以跟随小... 目录一、为什么你需要这个过滤器?​​​二、核心实现:一个Filter搞定双向数据流​​​​三、完整代码

SpringBoot利用@Validated注解优雅实现参数校验

《SpringBoot利用@Validated注解优雅实现参数校验》在开发Web应用时,用户输入的合法性校验是保障系统稳定性的基础,​SpringBoot的@Validated注解提供了一种更优雅的解... 目录​一、为什么需要参数校验二、Validated 的核心用法​1. 基础校验2. php分组校验3

Java Predicate接口定义详解

《JavaPredicate接口定义详解》Predicate是Java中的一个函数式接口,它代表一个判断逻辑,接收一个输入参数,返回一个布尔值,:本文主要介绍JavaPredicate接口的定义... 目录Java Predicate接口Java lamda表达式 Predicate<T>、BiFuncti

Nginx中配置HTTP/2协议的详细指南

《Nginx中配置HTTP/2协议的详细指南》HTTP/2是HTTP协议的下一代版本,旨在提高性能、减少延迟并优化现代网络环境中的通信效率,本文将为大家介绍Nginx配置HTTP/2协议想详细步骤,需... 目录一、HTTP/2 协议概述1.HTTP/22. HTTP/2 的核心特性3. HTTP/2 的优