litemall数据库基于nideshop中的nideshop.sql数据库, 然后在实际开发过程中进行了调整和修改:
litemall数据库由三个sql文件组成,在litemall-db文件夹下面的sql文件夹中:
作用是创建空数据库、创建用户、设置访问权限。
开发者开发测试阶段可以使用,但是部署生产阶段一定要注意修改这里的默认用户名和密码。
注意,这里的sql文件不一定需要运行,开发者可以自己手动或命令行或IDE进行对应的操作即可。
作用是创建数据库表,但是没有创建任何数据。
因此,开发者可以在部署生产阶段直接使用。
作用是创建测试数据。
开发者开发测试阶段可以使用,但是部署开发阶段应该使用自己的数据。
综上,这里litemall真正必须运行的sql文件是litemall_table.sql,其他两个sql文件开发者自行决定如何是否使用。
接下来讨论一些数据表的关键细节。
这里商品存在商品表(litemall_goods),商品属性表(litemall_goods_attribute),商品规格表(litemall_goods_specification),商品货品表(litemall_goods_product)四种表
商品表是一种商品的基本信息,主要包括商品介绍,商品图片,商品所属类目,商品品牌商等;
商品参数表其实也是商品的基本信息,但是由于是一对多关系,因此不能直接保存在商品表中(虽然采用JSON也可以但是不合理), 因此采用独立的商品参数表,通常是商品的一些公共基本商品参数;
商品规格表是商品进一步区分货品的标识,例如同样一款衣服,基本信息一致,基本属性一致,但是在尺寸这个属性上可以 把衣服区分成多个货品,而且造成对应的数量和价格不一致。商品规格可以看着是商品属性,但具有特殊特征。
商品规格和规格值存在以下几种关系:
商品货品表则是最终实现商品库存管理、购买业务的实体对象,存在多个规格值、数量和价格。 例如,同样的衣服品牌,可能因为不能尺寸和颜色而存在最终的货品,这里每个货品的价格可以一样,也可以不一样。
总结一下,一个普通商品,实际上在数据库中,存在一个商品表项,存在(至少0个)多个商品属性表项目,存在(至少一个)多个商品规格表项, 存在(至少一个)多个货品表项。
举例如下:
以下是一些细节的讨论:
M*N
个货品,但是有些货品可能天然不存在。
目前这里要求所有货品信息都应该存在,如果实际中货品不存在,也要设置商品数量为0.注意:
这里的设计可能与实际项目设计不一致,但是目前是可行的。 商品的中文用语“商品”和英语用语“goods”,货品的中文用语“货品”和英语用语“product”可能是不正确的。
目前准备支持用户普通账号登录和微信登录两种方式,两种登录方式仅仅采用一个litemall-user表可能不是很合适。
外,如果进一步支持其他多种第三方登录,那么这里需要重新设计。
litemall_region表保存了行政区域信息,包括省级、市级、县级三个等级,
原nideship.sql中存在region数据,但是litemall.sql的region数据则来自 Administrative-divisions-of-China项目。
订单信息主要由基本信息、商品信息、地址信息、费用信息、快递信息、支付信息和其他信息组成, 由litemall_order表和litemall_order_goods表保存。
订单创建时的一些基本信息,例如用户、订单状态和订单留言等。 其中订单状态是最重要的信息。
由于订单可以存在多个商品,因此订单的商品信息是由独立的订单商品表记录(可能更应该称为货品)。
订单一些费用情况,例如商品总价、优惠减免和实际付费等。
用户下单时选择的收货地址以及联系人信息。
目前快递信息仅仅记录快递公司、快递单号、快递发出时间。 而如果快递过程中如果存在一些异常,例如物品丢失,则目前系统难以处理。
支付时间和支付订单ID。
订单商品的评论情况。
订单分成几种基本的状态:
状态码101,此时订单生成,记录订单编号、收货地址信息、订单商品信息和订单相关费用信息;
状态码201,此时用户微信支付付款,系统记录微信支付订单号、支付时间、支付状态;
状态码301,此时商场已经发货,系统记录快递公司、快递单号、快递发送时间。 当快递公司反馈用户签收后,系统记录快递到达时间。
状态码401,当用户收到货以后点击确认收货,系统记录确认时间。
以上是一个订单成功完成的基本流程,但实际中还存在其他情况。
状态码102,用户下单后未付款之前,点击取消按钮,系统记录结束时间
状态码103,用户下单后半小时未付款则系统自动取消,系统记录结束时间
状态码202,用户付款以后未发货前,点击退款按钮,系统进行设置退款状态,等待管理员退款操作
状态码203,管理员在管理后台看到用户的退款申请,点击退款按钮进行退款操作。
状态码402,用户已签收却不点击确认收货,超期7天以后,则系统自动确认收货。 用户不能再点击确认收货按钮,但是可以评价订单商品。
此外,当订单状态码是102、103、203、401和402时,订单可以执行删除操作。 目前的设计是不执行物理删除,而是逻辑删除,因此用户查看自己订单时将看不到这些“已删除”的订单。
注意:
在上图中可以看到
101
到101
的状态变化,这里只是小商场用户的操作,不会影响订单状态码。 如果用户点击付款时,后端服务会生成预支付会话id,但是不会影响订单状态。 如果而用户支付过程中,放弃支付,则也不会影响订单状态。
小商场用户在小商场点击下单
按钮,此时小商城后端服务会生产商户订单。
所对应的后台服务方法是litemall-wx-api模块的WxOrderController.submit
方法。
这里开发者可能会奇怪,这里存在101->101的变化,这里表明后台没有响应
小程序端的请求,但是这里的响应没有导致订单状态实际的变化。这里所指的
响应小程序端请求是指下单成功以后小程序端自动请求付款或者用户在订单页面中
点击付款
所导致的对后台服务的预支付请求。
关于微信支付流程,可以参看官方文档的小程序支付业务流程 也就是说这里小商城后台服务会返回付支付信息。
所对应的后台服务方法是litemall-wx-api模块的WxOrderController.prepay
小商城接收返回的预支付信息后,会在小程序端出现支付页面。 如果用户放弃支付,则不会出现任何效果,不会向小商场后台服务发送任何信息。 如果用户支付,则会导致微信商户平台向小商场后台服务推送支付结果。
如果用户没有支付,那么此时用户可以点击取消订单
按钮来放弃当前订单。
所对应的后台服务方法是litemall-wx-api模块的WxOrderController.cancel
如果用户没有支付,也没有点击取消订单
按钮,那么系统会定时查询数据库的订单信息。
如果发现存在订单未支付状态超时半小时,此时系统会自动取消订单,来释放商品资源。
对应的应该是litemall-admin-api模块的系统定时任务的OrderJob.checkOrderUnpaid
如果用户支付,微信商户平台会向小商场后台服务推送支付结果。 而响应结果表示支付成功,则订单状态信息设置201,表示支付成功。
所对应的后台服务方法是litemall-wx-api模块的WxOrderController.payNotify
当用户支付以后,管理员未发货前,用户可以点击退款
申请退款取消订单。
通常用户点击退款以后系统可以基于微信商户平台的退款接口实现自动退款,
但是这里考虑到安全原因,不支持系统自动退款操作。
相应地,这里小商场后台服务只是设置订单状态,表示退款申请中。
所对应的后台服务方法是litemall-wx-api模块的WxOrderController.refund
这里退款操作是由管理员在微信商户平台手动退款,然后在本项目的
管理平台里面点击退款确认
按钮,此时订单状态会设置成203,表明
退款已经成功,同时系统会自动恢复订单商品数量。
所对应的后台服务方法是litemall-admin-api模块的AdminOrderController.refundConfirm
当订单支付以后,管理员进行订单发货,然后在管理平台点击发货
,填写快递信息,
设置订单状态是301,表示管理员已发货状态。
所对应的后台服务方法是litemall-admin-api模块的AdminOrderController.ship
当用户收到商品以后,用户点击收货确认
按钮,设置订单状态401,表示用户成功收货。
所对应的后台服务方法是litemall-wx-api模块的WxOrderController.confirm
当管理员发货以后,用户一直没有确认收货,系统定时检测订单状态,如果发现发货以后 七天用户都没有收货,此时系统自动确认用户收货,设置订单状态402。
应该改为 litemall-admin-api模块的系统定时任务OrderJob.checkOrderUnconfirm
注意:
上述订单状态变化中具体的逻辑处理可以参考相应模块文档和模块代码。
订单状态码标识了订单的状态,但是对于用户而言,真正关心的只是他们能够进行的操作, 也就是在小商场的小程序端用户可以进行点击的按钮操作,目前支持:
支付
,如果下单后未立即支付,则订单详情页面会出现支付
按钮;取消
,如果用户未支付,则订单详情页面会出现取消
按钮;退款
,如果用户支付后但是管理员未发货,则订单详情页面会出现退款
按钮;确认收货
,如果管理员已发货,则订单详情页面会出现确认收货
按钮;申请退货
,如果用户已经确认收货同时未超过一段时间,则订单详情页面会出现申请退货
按钮;
注意,这里如果是系统超时自动确认收货,则不会出现;去评价
,如果用户确认收货以后,则订单详情页面会出现去评价
按钮;再次购买
,如果用户确认收货以后,则订单详情页面会出现再次购买
按钮;删除
,如果当前订单状态码是102、103、203、401和402时,则订单详情页面会出现删除订单
按钮;
注意,这里的删除操作是逻辑删除,即设置订单的删除状态deleted
。
因此订单状态码和小商场用户操作之间存在映射关系:
用户可以支付
、取消
用户可以删除
用户可以删除
用户可以退款
用户可以删除
用户可以确认收货
用户可以删除
、去评价
、申请售后
、再次购买
用户可以删除
、去评价
、申请售后
、再次购买
当用户确认收货或者系统自动确认收货以后,订单可以申请售后。 目前仅支持订单整体售后,而不支持订单商品独立售后。 这是因为:订单存在商品售价、优惠券减免、团购减免以及物流运费属性, 如果要支持单个商品退款,那么存在一个需要解决的问题就是单个商品的 退款金额如何计算。如果开发者这里考虑清楚,也可以参考当前代码实现 订单商品独立售后
litemall_order表中存在aftersale_status
字段,记录订单售后状态。
而具体的售后记录则是litemall_aftersale表记录。
这里type
字段表示当前售后类型,目前存在三种类型:
需要注意的是:当前实现中,如果是“退货退款”类型,那么管理员在进行退款以后,系统会自动恢复货品数量。 这是因为管理员完成“退货退款”售后,说明管理员已经收到用户的退货。 开发者可以改变这里的实现逻辑,例如采用独立的退货入库流程。
status
字段表示当前售后状态,分别是:
这里需要补充的是:订单litemall_order表的aftersale_status
字段,和订单售后litemall_aftersale
表的status
字段是完全一致的,方便前端分别查询订单状态和订单售后状态。
amount
字段表示当前售后退款金额,正如前面所述当前仅支持订单整体售后,因此目前设计的退款金额是
订单实际付款-订单运费。
在litemall_order表中存在comments
字段,表示有几个订单商品没有评价;
而在litemall_order_goods表中存在comment
字段,表示当前订单商品的评论ID。
comments
设置当前订单中未评价的商品数量。而comment
设置0;comments
会减一,而comment
指向新创建的评论;comments
会设置0,而comment
设置-1;评论表litemall_comment保存评论相关的信息,其中最关键的是type
字段和value_id
字段。
这里type
字段表示当前评论类型,目前存在两种类型:
admin_content
字段则拥有记录管理后台管理员对用户评论的回复。
团购是由团购规则表litemall_groupon_rules和团购活动表litemall_groupon组成。
管理员在管理后台对一些商品配置团购规则,保存在litemall_groupon_rules表中。
用户在小商场中则看到团购规则给出的优惠信息。 接下来用户存在两种操作: 第一种是,用户开团,保存在litemall_groupon中,用户主动分享商品团购页面给朋友; 第二张是,用户参团,也保存在litemall_groupon中。
只有开团人数符合团购规则条件,创建的订单才会有效,否则管理员需要退款取消当前团购。
优惠券由litemall_coupon表和litemall_coupon_user表组成:
type字段,标识优惠券发送的方式,目前支持:
goods_type字段,标识优惠券所能使用的商品范围:
time_type字段,标识优惠券有效期;
status字段,标识优惠券的当前状态。
这里需要指出的是,litemall_coupon表和litemall_coupon_user表都有status字段。
litemall_coupon表的status字段,包含以后三种状态:
litemall_coupon_user表的status字段,包含以后三种状态:
系统配置表litemall_system保存系统的配置信息。
这里需要注意的是,在Java代码层系统配置表只能执行更新操作, 不能执行创建和删除操作。也就是说,系统配置数据都应该是开发者 基于系统的配置需求在数据库中手动创建。
存储对象表litemall_storage保存上传文件信息。
当用户或者管理员上传图像时,图像文件会保存到本地或者第三方云存储服务器中, 同时在存储对象表中记录一下。
业务日志表litemall_log记录管理员的关键性操作。
需要讨论的是,很多项目的业务日志模块采用注解方式,即加上方法注解,因此可以自动捕获 用户的操作行为。虽然这样做很方便且不会影响业务代码,但是实际上最终是粗颗粒地记录,反而记录意义不大。
因此本项目采用在方法内手写业务日志代码方式记录业务操作行为及结果。 虽然比较繁琐,但是可以保证记录是细颗粒的。而且,如果管理员最终关心的操作较少,那么 实际上需要写的代码不是很多。
考虑到语义,操作业务应该是“谁做了什么操作,结果成功还是失败,失败原因是什么,补充信息是什么”, 因此这里设计的业务日志表关键字段如下:
这里的日志类型设计成四种(当然开发者需要可以扩展)
当然建议开发者应该和最终用户讨论交流,记录真正关键性的业务操作,例如登录相关或订单相关等。
如果操作成功,可以使用操作结果字段记录被操作的对象。 当然,有些操作没有具体对象,那么可以省略。
如果操作失败,也可以使用操作结果字段记录失败的原因。
虽然这里有操作状态字段和操作结果字段,可以记录操作失败的状态。 但是通常失败操作不会对系统或者数据库带来影响,因此实际上开发者其实不需要 记录太多操作失败的日志,而是记录操作成功的日志,告诉系统管理员当前状态的变化。
当然,是否记录操作失败取决于开发者或者最终用户是否需要。 例如,登录这里应该记录用户登录失败的日志,因为保存的IP地址可以帮助管理员了解 系统被访问的情况。
除了以上表,数据库还存在其他一些业务表,例如专题表litemall_topic, 但是都很直观,不需要多讨论。
以下是一些表设计中无具体业务意义可通用的字段。
除极少数表,其他所有表都存在deleted
字段,支持逻辑删除。
因此目前删除数据时,不会直接删除数据,而是修改deleted
字段。
当然,数据库管理员可以连接到数据库直接删除数据,或者开发者
可以修改这里的逻辑采用物理删除。
除极少数表,其他所有表都存在add_time
字段,记录数据创建时间。
除极少数表,其他所有表都存在update_time
字段,记录数据修改时间。
此外,此外开发者可以利用update_time来实现乐观锁更新机制。