订单微服务主要功能模块介绍
订单模块介绍
在把心仪的商品添加到购物车并确定需要购买的商品和对应的数量后,就可以执行提交订单的操作。此时就由购物车模块切换到另一个电商流程——订单流程。接下来主要介绍订单模块相关功能的开发。关于订单的生成和后续处理流程,不同的公司或不同的商城项目的需求与业务场景会有一些差异,但是从订单生成到订单完成大体的流程是类似的。
新蜂商城中从订单生成到订单完成,主要有以下几个步骤,如图 8-1 所示。
-
提交订单(由新蜂商城用户发起)。
-
订单入库(后台逻辑,用户无感知)。
-
支付订单(由新蜂商城用户发起)。
-
订单处理(包括确认订单、取消订单、修改订单信息等操作,新蜂商城用户和管理员用户都可以对订单进行处理)。

订单模块的表结构设计
-
订单主表及关联表设计
新蜂商城系统的订单模块主要涉及数据库中的三张表。一次下单行为可能购买一件商品,也可能购买多件商品,因此除订单主表
tb_newbee_mall_order
外,还有订单项表tb_newbee_mall_order_item
和订单地址表tb_newbee_mall_order_address
。订单主表中存储订单的相关信息,而订单项表中主要存储关联的商品字段。订单主表
tb_newbee_mall_order
表结构设计的主要字段如下。-
user_id
:用户的id
。根据这个字段来确定是哪个用户下的订单。 -
order_no
:订单号。订单号是订单的唯一标识,在后续查询订单时会用到。这是每个电商系统都有的设计。 -
paystatus
、paytype
、pay_time
:支付信息字段,包括支付状态、支付方式、支付时间。 -
order_status
:订单状态字段。 -
create_time
:订单生成时间。
订单主表的主要字段代码如下:
CREATE DATABASE /*!32312 IF NOT EXISTS*/'newbee_mall_cloud_order_db' /*!40100 DEFAULT CHARACTER SET utf8 */; USE 'newbee_mall_cloud_order_db'; DROP TABLE IF EXISTS 'tb_newbee_mall_order'; CREATE TABLE 'tb_newbee_mall_order' ( `order_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '订单主表主键 id', `order_no` varchar(20) NOT NULL DEFAULT '' COMMENT '订单号', `user_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '用户主键 id', `total_price` int(11) NOT NULL DEFAULT '1' COMMENT '订单总价', `pay_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '支付状态 0:未支付 1:支付成功 -1:支付失败', `pay_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0:无 1:支付宝支付 2:微信支付', `pay_time` datetime DEFAULT NULL COMMENT '支付时间', `order_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '订单状态 0:待支付 1:已支付 2:配货完成 3:出库成功 4:交易成功 -1:手动关闭 -2:超时关闭 -3:商家关闭', `extra_info` varchar(100) NOT NULL DEFAULT '' COMMENT '订单 body', `is_deleted` tinyint(4) NOT NULL DEFAULT '0' COMMENT '删除标记字段(0:未删除 1:已删除)', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最新修改时间', PRIMARY KEY (`order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
订单项表
tb_newbee_mall_order_item
表结构设计的主要字段如下。-
order_id
:关联的订单主键id
,标识该订单项是哪个订单中的数据。 -
goodsid
、goodsname
、goodscoverimg
、sellingprice
、goodscount
:订单中的商品信息,记录当时的商品信息。 -
create_time
:记录生成时间。
订单项表的字段代码如下:
USE 'newbee_mall_cloud_order_db'; DROP TABLE IF EXISTS 'tb_newbee_mall_order_item'; CREATE TABLE 'tb_newbee_mall_order_item' ( 'order_item_id' bigint(20) NOT NULL AUTO_INCREMENT COMMENT '订单关联购物项主键id', 'order_id' bigint(20) NOT NULL DEFAULT 0 COMMENT '订单主键id', 'goods_id' bigint(20) NOT NULL DEFAULT 0 COMMENT '关联商品id', 'goods_name' varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '下单时商品的名称(订单快照)', 'goods_cover_img' varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '下单时商品的主图(订单快照)', 'selling_price' int(11) NOT NULL DEFAULT 1 COMMENT '下单时商品的价格(订单快照)', 'goods_count' int(11) NOT NULL DEFAULT 1 COMMENT '数量(订单快照)', 'create_time' datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY ('order_item_id') USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
订单地址表
tb_newbee_mall_order_address
表结构设计的主要字段如下。-
order_id
:关联的订单主键id
,标识该地址是哪个订单中的收货地址数据。 -
username
、userphone
、user_address
:收货信息字段,最好在订单主表或关联表中设置这几个字段,后端API
项目中设计成tb_newbee_mall_order
表和tb_newbee_mall_order_address
表,二者为一对一的关系,将地址关联表中的字段全部设置在订单主表中也是可以的。有些商城的收货地址设计只关联一个地址id
字段,这样做是不合理的,因为该id
关联的地址表中的记录可以被修改和删除。也就是说,如果修改或删除,那么订单中的收件信息就不是下单时的数据了。因此,需要把这些字段放到订单主表中,并记录下单时的收货信息。
用户收货地址表和订单地址表的字段代码如下:
USE 'newbee_mall_cloud_order_db'; DROP TABLE IF EXISTS 'tb_newbee_mall_order_address'; CREATE TABLE 'tb_newbee_mall_order_address' ( 'order_id' bigint(20) NOT NULL, 'user_name' varchar(30) NOT NULL DEFAULT '' COMMENT '收货人姓名', 'user_phone' varchar(11) NOT NULL DEFAULT '' COMMENT '收货人手机号', 'province_name' varchar(32) NOT NULL DEFAULT '' COMMENT '省', 'city_name' varchar(32) NOT NULL DEFAULT '' COMMENT '市', 'region_name' varchar(32) NOT NULL DEFAULT '' COMMENT '区', 'detail_address' varchar(64) NOT NULL DEFAULT '' COMMENT '收货详细地址(街/道/楼宇/单元)', PRIMARY KEY ('order_id') ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='订单地址表'; DROP TABLE IF EXISTS 'tb_newbee_mall_user_address'; CREATE TABLE 'tb_newbee_mall_user_address' ( 'address_id' bigint(20) NOT NULL AUTO_INCREMENT, 'user_id' bigint(20) NOT NULL DEFAULT '0' COMMENT '用户主键id', 'user_name' varchar(30) NOT NULL DEFAULT '' COMMENT '收货人姓名', 'user_phone' varchar(11) NOT NULL DEFAULT '' COMMENT '收货人手机号', 'default_flag' tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否为默认 0:非默认 1:默认', 'province_name' varchar(32) NOT NULL DEFAULT '' COMMENT '省', 'city_name' varchar(32) NOT NULL DEFAULT '' COMMENT '城', 'region_name' varchar(32) NOT NULL DEFAULT '' COMMENT '区', 'detail_address' varchar(64) NOT NULL DEFAULT '' COMMENT '收货详细地址(街道/楼宇/单元)', 'is_deleted' tinyint(4) NOT NULL DEFAULT '0' COMMENT '删除标识字段(0:未删除 1:已删除)', 'create_time' timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '添加时间', 'update_time' timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', PRIMARY KEY ('address_id') ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户收货地址表';
每个字段对应的含义在上面的
SQL
语句中都有介绍,读者可以对照理解,并正确地把建表语句导入数据库。关于两张表中的快照字段,包括收件信息字段和商品信息字段,读者可以参考淘宝网的订单快照来理解。这些信息都是可以更改的,因此不能只关联一个主键id
。比如,订单中存储的是下单时的数据,而商品信息是可以随时更改的,如果没有这几个字段,只用商品id
关联,则商品信息一旦被更改,订单信息也随之被更改,就不再是下单时的数据了,这不符合逻辑。 -
-
订单项表的设计思路
下面介绍订单项表
tb_newbee_mall_orderitem
和购物项表tb_newbee_mall_shopping_cart_ite
的差异,以及单独设计一张订单项表的原因。购物车模块的购物项和订单模块的订单项是很多商城项目都有的设计。只是有些商城项目为了简化开发,在实现的时候选择将两者等同。本来应该设计两张表,减少为只设计一张购物项表,订单生成后会在购物项表中增加与订单主键
id
的关联。其实订单项和购物项二者的区别是很明显的,它们是相似却完全不同的两个对象。购物项是商品与购物车之间抽象出的一个对象,而订单项是商品与订单之间抽象出的一个对象。它们都与商品相关,并且在页面数据展示时也类似,所以有简化为一张表的实现方式。但是笔者并不赞同这种实现方式,虽然二者很相似,但是依然有很多不同的地方。购物项的相关操作在购物车中,而在生成订单后该购物项就不再存在了,即该对象已经被删除了,它的生命周期到此为止。既然生命周期已经终结,再与订单做关联就说不通了。
以订单快照为例,它需要记录下单时的商品内容和订单信息。比如,淘宝网的订单设计,下单时的订单快照数据就是下单时的商品数据,而不是最新的商品数据。购物车则不需要快照,直接读取最新的商品相关信息即可。
购物车模块的购物项和订单模块的订单项是两个不同的对象,因此笔者选择分别设计两张表。
-
用户收货地址表
最终实战的微服务架构项目中有用户收货地址管理的模块,用户收货地址管理页面如图 8-2 所示。在确认订单页面中可以选择收货地址,也可以添加收货地址,再提交并生成一个订单信息。
Figure 2. 图8-2 用户收货地址管理页面用户收货地址表
tb_newbee_mall_user_address
的字段代码如下:USE 'newbee_mall_cloud_order_db'; DROP TABLE IF EXISTS 'tb_newbee_mall_user_address'; CREATE TABLE 'tb_newbee_mall_user_address' ( 'address_id' bigint(20) NOT NULL AUTO_INCREMENT, 'user_id' bigint(20) NOT NULL DEFAULT '0' COMMENT '用户主键 id', 'user_name' varchar(30) NOT NULL DEFAULT '' COMMENT '收货人姓名', 'user_phone' varchar(11) NOT NULL DEFAULT '' COMMENT '收货人手机号', 'default_flag' tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否为默认 0:非默认 1:默认', 'province_name' varchar(32) NOT NULL DEFAULT '' COMMENT '省', 'city_name' varchar(32) NOT NULL DEFAULT '' COMMENT '城', 'region_name' varchar(32) NOT NULL DEFAULT '' COMMENT '区', 'detail_address' varchar(64) NOT NULL DEFAULT '' COMMENT '收货详细地址(街道/楼宇/单元)', 'is_deleted' tinyint(4) NOT NULL DEFAULT '0' COMMENT '删除标识字段(0:未删除 1:已删除)', 'create_time' datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '添加时间', 'update_time' datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', PRIMARY KEY ('address_id') ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='收货地址表';
每个字段对应的含义在上面的
SQL
语句中都有介绍,读者可以对照理解,并正确地把建表语句导入数据库。
订单模块中的主要功能分析
-
商城中的订单确认步骤
订单确认步骤是订单生成过程中一个很重要的功能,日常使用的商城项目基本上都有这个步骤。以淘宝网的订单确认页面为例,如图 8-3 所示。
这个页面中有用户在购物车中选择的商品信息,还有收货地址信息、运费信息、优惠信息等。在购物车中只有商品信息,而订单确认页面是多种信息的集合。只有信息齐全才能够生成订单数据。订单确认页面的设置可以理解为一个信息确认的过程,所有信息都确认无误后,才能进行提交订单的操作,之后生成一条订单记录。
订单确认步骤是在购物车页面发起的,如图 8-4 所示。单击购物车页面中的 “结算” 按钮即可进入订单确认页面。
根据购物车中的待结算商品数量来判断 “结算” 按钮是否显示正常。如果购物车中无数据,则页面中无商品列表展示,也没有 “结算” 按钮。只有购物车列表数据正常,才会出现 “结算” 按钮,单击后才能进入订单确认页面。
Figure 3. 图8-3 淘宝网的订单确认页面Figure 4. 图8-4 新蜂商城的购物车页面订单确认页面显示的商品数据与购物车列表中显示的商品数据类似,除此之外,还有用户数据和支付数据,以及收件人的收货地址信息,其他的内容还有运费金额、优惠金额、实际支付金额等。新蜂商城的订单确认页面显示的信息如图 8-5 所示。
Figure 5. 图8-5 新蜂商城的订单确认页面显示的信息因此,这里需要编写一个接口,用于查询订单确认页面的数据,根据用户所选择的购物项查询订单确认页面中需要显示的信息。
-
订单生成功能
在订单确认页面处理完毕后,紧接着就是生成订单的环节。此时用户单击 “提交订单” 按钮,商城系统就会对应生成一笔订单数据并保存在数据库中。
用户单击 “提交订单” 按钮后,后台会进行一系列的操作,包括数据查询、数据判断、数据整合等。因此,这里需要编写一个接口,用于生成一条订单数据,并删除对应的购物项数据,修改商品的库存数据。
新蜂商城的订单生成流程如图 8-6 所示。
Figure 6. 图8-6 新蜂商城的订单生成流程当然,订单生成只是订单模块中的第一步,后续还有一些步骤需要完成。
-
订单支付模拟接口实现
前端在接收到生成订单接口的成功响应后,会在订单确认页面中显示一个支付的底部弹窗,即模拟支付功能也在订单确认页面,如图 8-7 所示。由于没有公司资质,无法申请微信和支付宝相关的接口接入权限,因此只能模拟订单支付的功能。
Figure 7. 图8-7 订单模拟支付窗口单击模拟支付窗口中的任意一个按钮,就会向支付回调地址发送请求,该按钮是模拟支付成功的接口回调,表示已经支付成功,可以修改订单的状态了。
这里需要编写一个接口,用于模拟订单支付成功的过程,根据订单号查询订单,并进行非空判断和订单状态的判断。如果订单已经不是 “待支付” 状态下的订单,则不进行后续操作。如果验证通过,则将该订单的相关状态和支付时间进行修改,之后调用数据层的方法进行实际的入库操作。
-
订单详情功能
制作订单详情页面是订单流程中非常重要的一个环节,该页面是商家与用户之间最直接的一个纽带。对于商家来说,体现了商家提供的销售服务,商品信息、订单信息、物流信息都在该页面实时展示给用户。对于用户来说,该页面会显示订单的重要信息,用户关心的所有信息都显示在这里,用户也可以在该页面实时关注订单的变化和新的动态。
订单详情页面主要有两个功能。
(1)显示基本的订单信息。
-
订单基本信息:订单号、订单状态、价格等信息。
-
配送信息:物流信息、收货地址信息。
-
商品信息:商品名称、商品图、购买数量等。
-
发票信息:发票信息和开票状态。
-
客服:线上联系商家或拨打电话。
(2)为用户提供订单操作。
用户可以在订单详情页面进行支付订单、取消订单、确认订单等操作。
这里需要编写一个接口,用于查询订单详情页面所需的数据,包括订单的基本信息,如订单号、订单状态、下单时间等,以及订单中所关联的商品数据,如商品图片、名称、单价等,如图 8-8 所示。
-
-
“我的订单” 列表功能
订单生成后就能够在个人中心的订单列表中看到相关数据了。各种状态的订单都会在这个列表中显示,并且商城端的订单列表支持分页功能。新蜂商城订单列表页面如图 8-9 所示。
Figure 8. 图8-8 订单详情页面Figure 9. 图8-9 订单列表页面这里需要编写一个接口,用于查询当前登录用户的订单列表数据。订单列表是一个
List
对象,后端返回数据时需要一个订单列表对象。对象中的字段有订单主表中的字段,也有订单项表中的字段。在列表数据中有订单状态、订单交易时间、订单总价、商品标题字段、商品预览图字段、商品价格字段、商品购买数量字段。一个订单中可能有多个订单项,所以订单VO
对象中也有一个订单项VO
的列表对象。订单模块除具有以上主要功能外,还有商城用户取消订单的功能及后台管理系统中的订单管理功能,主要包括如下几个接口:
-
管理员用户查询所有订单分页列表的接口;
-
管理员用户修改订单状态的接口;
-
管理员用户/商家关闭订单的接口;
-
管理员用户查看订单详情的接口。
-
订单处理流程及订单状态的介绍
-
订单处理流程
订单模块是整个电商系统的重中之重,甚至可以说它是电商系统的 “心脏”,贯穿了电商系统的大部分流程。各个环节都与它密不可分,从用户提交订单并成功生成订单开始,后续的流程都是围绕着订单模块进行的,包括从支付成功到确认收货的正常订单流程,也包括订单取消、订单退款等一系列的异常订单流程。
正常订单流程如图 8-10 所示。
Figure 10. 图8-10 正常订单流程在订单生成后,用户正常进行支付操作,商家正常进行订单确认和订单发货操作,由用户进行最后一个步骤——确认收货。这样,整个订单流程就正常走完了。
异常订单流程如图 8-11 所示。
在订单入库后,用户选择不支付而直接取消订单,或者用户正常支付但是在后续流程中选择取消订单,于是订单就不是正常状态的订单了,因为它的流程并没有如预想的那样。不只是用户可以关闭订单,如果流程中出现了意外事件,商城管理员用户也可以在后台管理系统中关闭订单。
-
订单状态的介绍
订单流程完善的编码实践都是围绕着订单状态的改变来做的功能实现。理解订单状态及如何发生状态转变的逻辑,对读者理解代码、理解商城业务有很大的帮助。

订单主表中的 order_status
字段就是订单状态字段,新蜂商城订单状态的设计如下。
-
0:待支付。
-
1:已支付。
-
2:配货完成。
-
3:出库成功。
-
4:交易成功。
-
-1:手动关闭。
-
-2:超时关闭。
-
-3:商家关闭。
以上是新蜂商城的订单状态存储的值及值对应的含义,与主流的商城设计类似,可能文案上有些小差别。比如,状态 0,新蜂商城用 “待支付” 表示,其他商城可能用 “待付款” 表示。数字的使用也可能有差异。比如,新蜂商城中订单的初始状态用数字 0 表示,其他的商城在实现时可能用数字 1 表示。
接下来详细介绍一下这些状态。
(1)待支付/待付款。
新蜂商城用数字 0 来表示这个状态。
用户提交订单后,会进行订单的入库、商品库存修改等操作,此时是订单的初始状态。目前主流的商城或常用的外卖平台,基本上在订单生成后就会唤起支付操作,所以订单的初始状态就被称为 “待支付” 或 “待付款”。其实它的含义是订单成功入库,也就是初始状态。新蜂商城用 “待支付” 表示。
(2)已支付/已付款/待确认。
新蜂商城用数字 1 来表示这个状态。
用户完成订单支付,系统需要记录订单支付时间及支付方式等信息,等待商家进行订单确认以便进行后续操作。这个状态被称为 “已支付” 或 “已付款”,也可以被称为 “待商家确认”。这些称谓一般由产品经理或项目负责人来决定。新蜂商城用 “已支付” 表示。
(3)配货完成/已确认/待发货。
新蜂商城用数字 2 来表示这个状态。
商家确认订单正常,并且可以进行发货操作,就将订单状态修改为 “已确认”、“待发货”、“配货完成”。新蜂商城用 “配货完成” 表示。
(4)出库成功/待收货/已发货。
新蜂商城用数字 3 来表示这个状态。
订单中的商品在出库并提交给物流系统后就进入了这个状态。对于仓库来说是 “出库成功”,对于用户来说是 “待收货”,而对于商家来说是 “已发货”。新蜂商城用 “出库成功” 表示。
(5)交易成功/订单完成。
新蜂商城用数字 4 来表示这个状态。
用户收到购买的商品,单击商城订单系统中的 “确认收货” 按钮,表示订单已经完成了所有的正向步骤,此次交易成功。这个状态被称为 “交易成功” 或 “订单完成”。新蜂商城用 “交易成功” 表示。
(6)订单关闭/已取消。
新蜂商城分别用数字 -1、-2、-3 来表示 “手动关闭”、“超时关闭”、“商家关闭”的状态。
它们属于订单异常的状态,在付款之前取消订单或在其他状态下选择主动取消订单都会进入这种状态,也可以统一称为 “订单关闭” 或 “已取消”。
当然,现实中的订单流程还会涉及客服功能、订单售后、订单退款等逻辑,这些功能在本书的实战项目中并没有做具体的实现。
订单生成和各个状态的转换涉及多张表的数据更改,在测试时一定要注意数据库中商品、购物项、订单等数据是否被正确修改。