Files
litemall/doc/2.md
Junling Bu ff7f3387ba update[doc]: 文档中明确用户、管理员、开发者三种角色。
1. 用户指小商场的使用者;
2. 管理者指管理后台的使用者;
3. 开发者指采用本项目开发部署的使用者。
2018-04-21 21:19:33 +08:00

453 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 2 litemall基础系统
目前litemall基础系统主要由litemall数据库、litemall-db模块和litemall-os-api模块组成。
目前存在的问题:
* `严重`数据库采用git每次跟新都是5MB数据影响项目下载速度
* `缺失`litemall-os-api返回的图片不能在浏览器直接显示
* `改善` litemall-db的一些CRUD操作可以基于开源库重构
* `功能`可以参考一些云存储服务的API加强一些功能
## 2.1 litemall.sql
litemall.sql数据库基于nideshop中的[nideshop.sql](https://github.com/tumobi/nideshop/blob/master/nideshop.sql)数据库,然后在实际开发过程中进行了调整和修改:
* 删除了一些目前不必要的表;
* 删除了表中一些目前不必要的字段;
* 行政区域数据litemall_region没有采用原nideshop中的数据而是采用了[Administrative-divisions-of-China](https://github.com/modood/Administrative-divisions-of-China)
* 表中的某些字段采用JSON
* 表中的日期或时间字段采用DATE、DATETIME
* 字段的数据类型粗粒度化例如避免MEDIUMINT而是INT
* 表的数据做了清理、调整和补充(假数据)。
具体不同可以比较litemall-db模块下sql文件夹中nideshop.sql和litemall.sql。
以下讨论一些关键性设计
注意:
> 以下设计基于个人理解,很可能存在不合理或者与实际系统不符合的地方。
### 2.1.1 商品和货品设计
这里商品存在商品,商品属性,商品规格,货品四种表
商品表是一种商品的基本信息,主要包括商品介绍,商品图片,商品所属类目,商品品牌商等;
商品参数表其实也是商品的基本信息但是由于是一对多关系因此不能直接保存在商品表中虽然采用JSON也可以但是不合理
因此采用独立的商品参数表,通常是商品的一些公共基本商品参数;
商品规格表是商品进一步区分货品的标识,例如同样一款衣服,基本信息一致,基本属性一致,但是在尺寸这个属性上可以
把衣服区分成多个货品,而且造成对应的数量和价格不一致。商品规格可以看着是商品属性,但具有特殊特征。
商品规格和规格值存在以下几种关系:
* 单一规格和单一规格值,最常见的,即当前商品存在一种货品;
* 单一规格和多个规格值,较常见,即当前商品基于某个规格存在多种货品,通常价格都是相同的,当然也可能不相同;
* 多个规格和单一规格值,可以简化成第一种情况,或者采用第四种情况,通常实际情况下不常见;
* 多个规格和多个规格值,通常是两种规格或者三种规格较为常见,而且对应的价格不完全相同。
货品则是最终面向开发者购买的商品标识,存在多个规格值、数量和价格。
因此这里一个商品表项存在至少0个多个商品属性表项目存在至少一个多个商品规格表项
存在(至少一个)多个货品表项。
举例如下:
* 一个商品“2018春季衣服商品编号1111111”
* 存在两个商品参数,
* 属性名称“面向人群”,属性值“男士”
* 属性名称“面料”属性值“100%棉”
* 存在两种规格共八个商品规格项,
* 规格名称“尺寸”规则值“S”
* 规格名称“尺寸”规则值“M”
* 规格名称“尺寸”规则值“L”
* 规格名称“尺寸”规则值“XL”
* 规格名称“尺寸”规则值“XXL”
* 规格名称“颜色”,规格值“蓝色”
* 规格名称“颜色”,规格值“灰色”
* 规格名称“颜色”,规格值“黑色”
* 存在15个货品尺寸*颜色=15个货品)
* 货品“S蓝”数量 100 价格 100
* 货品“M蓝”数量 100 价格 100
* 货品“L蓝”数量 100 价格 100
* 货品“XL蓝”数量 100 价格 100
* 货品“XXL蓝”数量 100 价格 100
* 货品“S灰”数量 100 价格 100
* 货品“M灰”数量 100 价格 100
* 货品“L灰”数量 100 价格 100
* 货品“XL灰”数量 100 价格 100
* 货品“XXL灰”数量 100 价格 100
* 货品“S黑”数量 100 价格 100
* 货品“M黑”数量 100 价格 100
* 货品“L黑”数量 100 价格 100
* 货品“XL黑”数量 0 价格 100
* 货品“XXL黑”数量 0 价格 100
以下是一些细节的讨论:
* 商品表中可能存在数量和价格属性,而货品中也存在数量和价格属性,目前设计这样:
* 商品表的价格应该和某个货品的价格一样,通常应该是所有货品价格的最小值,或者基本款式的价格;
* 商品表中的数量和价格应该仅用于展示,而不能用于最终的订单价格计算;
* 商品表的数量应该设置成所有货品数量的总和;
* 在管理后台添加商品时,如果管理员不填写商品表的数量和价格属性,则自动填写合适的值;如果填写,则使用显示。
* 当小商城中,用户查看商品详情时,初始显示商品表的价格,而如果用户选择具体规格后,则商品
详情里面的价格需要自动切换到该规格的价格。
* 商品规格可以存在规格图片,效果是规格名称前放置规格图片
* 货品也可以存在货品图片,效果是所有规格选定以后对应的货品有货,则在货品价格前放置货品图片
* 如果商品是两种规格分别是M个和N个规格值那么通常应该是`M*N`个货品,但是有些货品可能天然不存在。
那么,此时数据库如何来设计,是允许少于`M*N`个项,还是必须等于`M*N`而不存在货品的数量设置为0
*
注意:
> 这里的设计可能与实际项目设计不一致,但是目前是可行的。
> 商品的中文用语“商品”和英语用语“goods”货品的中文用语“货品”和英语用语“product”可能是不正确的。
### 2.1.2 用户和微信用户设计
目前准备支持用户普通账号登录和微信登录两种方式两种登录方式仅仅采用一个litemall-user表可能不是很合适。此外如果进一步支持其他多种第三方登录那么这里需要重新设计。
### 2.1.3 行政区域设计
原nideship.sql中存在region数据但是litemall.sql的region数据则来自
[Administrative-divisions-of-China](https://github.com/modood/Administrative-divisions-of-China)项目。从该项目中导入数据到litemall.sql的litemall-province、litemall-city、litemall-area和litemall-street四个表然后重新生成一个新的litemall-region表。
### 2.1.4 订单设计
订单信息主要由基本信息、商品信息、地址信息、费用信息、快递信息、支付信息和其他信息组成。
* 基本信息
订单创建时的一些基本信息。
* 商品信息
由于订单可以存在多个商品,因此订单的商品信息是由独立的订单商品表记录(可能更应该称为货品)。
* 费用信息
* 快递信息
目前快递信息仅仅记录快递公司、快递单号、快递发出时间、快递接收时间。而如果快递过程中如果存在一些异常例如物品丢失则目前系统难以处理。关于快递费的计算目前采取简单方式即满88元则免费否则10元。
* 支付信息
* 其他信息
#### 2.1.4.1 订单状态
![](pic2/2-1.png)
订单分成几种基本的状态:
* 下单
状态码101此时订单生成记录订单编号、收货地址信息、订单商品信息和订单相关费用信息
* 付款
状态码201此时用户微信支付付款系统记录微信支付订单号、支付时间、支付状态
* 发货
状态码301此时商场已经发货系统记录快递公司、快递单号、快递发送时间。
当快递公司反馈用户签收后,系统记录快递到达时间。
* 收货
状态码401当用户收到货以后点击确认收货系统记录确认时间。
此时,用户可以评价订单商品。
除了这几种正常状态以外,还存在一些非普通的状态:
* 订单取消
状态码102用户在生产订单以后未付款之前点击取消按钮系统记录结束时间
* 订单取消并退款
状态码202用户付款以后未发货前点击取消按钮系统记录结束时间和退款信息
* 系统自动确认收货
状态码402快递反馈商场用户已签收但是用户却不点击确认收货按钮
此时系统在快递到达时间的一段时间后,自动确认收货。
用户不能再点击确认收货按钮,但是可以评价订单商品
当然,以上的基本状态和非普通状态,和实际项目相比仍然相对简单。
此外当订单状态码是102、202、401、402时订单可以设置删除状态此时
用户查看自己订单信息时将看不到这些“已删除”的订单。
#### 2.1.4.2 状态码所支持的操作
不同的状态码下面,用户能够进行的操作是:
* 101
此时,用户可以“订单支付”、“订单取消”
* 102
此时,用户可以“订单删除”
* 201
此时,用户可以“订单取消”(并退款)
* 202
此时,用户可以“订单删除”
* 301
此时,用户可以“确认收货”
* 401
此时,用户可以“订单删除”、“评价”、“再次购买”
* 402
此时,用户可以“订单删除”、“评价”、“再次购买”
#### 2.1.4.3 售后处理
目前不支持售后或退货相关业务。
#### 2.1.4.4 黑名单
从一些资料看,如果用户订单多次取消,应该加入黑名单。
目前不支持。
#### 2.1.5 数据删除
所有表的数据在代码层面都不支持删除,除非数据库管理员连接到数据库删除数据。
在访问层,数据库的删除操作
## 2.2 litemall-db
技术:
* Spring Boot 1.5.10
* MySQL
* Druid
* Mybatis
* PageHelper
* Mybatis Generator
* Mybatis Generator非官方插件mybatis-generator-plugin
因为litemall-db是一个业务模块并不对外直接服务因此无需使用Spring MVC。
![](./pic2/2-2.png)
这里litemall-db模块可以分成以下几种代码
* mybatis generator自动化代码
* 业务代码
* 安全代码
* JSON支持代码
* 配置代码
### 2.2.1 自动化代码
![](./pic2/2-3.png)
如上图所示,双击`mybatis-generator:generate`则mybatis generator插件会
1. 读取`mybatis-generator`文件夹下的`generatorConfig.xml`文件
2. 根据`jdbcConnection`访问数据库
3. 根据`table`, 自动生成三种代码:
* src文件夹`org.linlinjava.litemall.db.domain` 包内的Java代码
* src文件夹`org.linlinjava.litemall.db.domain` 包内的Java代码
* resources文件夹`org.linlinjava.litemall.db.domain.dao` 内的XML文件
以上三种代码即可封装对数据库的操作开发者无需直接操作sql代码
而是直接操作Java代码来完成对数据库的访问处理。
关于如何基于mybatis的Example代码来访问数据库请查阅相关资料
或者参考本模块`org.linlinjava.litemall.db.dservice` 包内的Java代码。
当然为了达到数据库访问效率开发者也可以手动自定义mapper文件和对应的Java代码但目前这里不采用或者不建议采用。
例如当需要访问两个表的数据时这里是在业务层通过Java代码遍历的形式来访问两个表。
这里,以`litemall_brand`表举例说明:
1. mybatis generator插件会根据数据库`table`标签
```
<generatorConfiguration>
<table tableName="litemall_brand">
<generatedKey column="id" sqlStatement="MySql" identity="true" />
<columnOverride javaType="java.time.LocalDateTime" column="add_time"/>
</table>
</generatorConfiguration>
```
2. 自动生产src文件夹下domain包内的LitemallBrand.java类、LitemallBrandExample.java类、
dao包内的LitemallBrandMapper.java接口和resources文件夹下dao包内的LitemallBrandMapper.xml文件。
3. 手动在service包内创建LitemallBrandService.java来对外提供具体的服务。
例如为了得到Brand列表那么创建list方法基于前面创建的三个Java来来实现。
```java
@Service
public class LitemallBrandService {
@Resource
private LitemallBrandMapper brandMapper;
public List<LitemallBrand> query(int offset, int limit) {
LitemallBrandExample example = new LitemallBrandExample();
example.or().andDeletedEqualTo(false);
PageHelper.startPage(offset, limit);
return brandMapper.selectByExample(example);
}
}
```
如果基于一个新表创建新访问组件请阅读下面章节2.2.6
### 2.2.2 业务代码
基于2.2.1的代码,业务代码处理一些具体业务相关的操作,对其他模块提供具体的服务。
### 2.2.3 安全代码
### 2.2.4 JSON支持代码
### 2.2.5 配置代码
采用Java注解的方式来完成一些特定的配置操作。
### 2.2.6 新服务组件
本节介绍如果基于一个表创建新的服务组件。
1. 在数据库里面创建一个表,例如`litemall_demo`:
```sql
CREATE TABLE `litemall`.`litemall_demo` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(45) NULL,
`address` VARCHAR(45) NULL,
PRIMARY KEY (`id`));
INSERT INTO `litemall`.`litemall_demo` (`id`, `name`, `address`)
VALUES ('1', 'hello', 'world');
```
2. 在generatorConfig.xml中增加一个新的table标签
```
<generatorConfiguration>
<table tableName="litemall_demo">
<generatedKey column="id" sqlStatement="MySql" identity="true" />
</table>
</generatorConfiguration>
```
3. 双击mybatis generator插件检查LitemallDemo.java类、LitemallDemoExample.java类、
LitemallDemoMapper.java接口和LitemallDemoMapper.xml是否生产。
4. 在service里面新建LitemallDemoService.java类
```java
@Service
public class LitemallDemoService {
@Resource
private LitemallDemoMapper demoMapper;
public List<LitemallDemo> list() {
LitemallDemoExample example = new LitemallDemoExample();
return demoMapper.selectByExample(example);
}
}
```
5. 可以在`src/test/java/org.linlinjava.litemall.db`包里面创建LitemallDemoTest.java类,
使用Junit进行测试。
```java
@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class LitemallDemoTest {
@Autowired
private LitemallDemoService demoService;
@Test
public void test() {
List<LitemallDemo> litemallDemoList = demoService.list();
Assert.assertTrue(litemallDemoList.size() != 0);
}
}
```
6. 同样地可以在Controller中使用LitemallDemoService来对外提供服务。
```java
@RestController
@RequestMapping("/demo")
public class DemoController {
@Autowired
private LitemallDemoService demoService;
@RequestMapping("/list")
public Object list(){
List<LitemallDemo> demoList = demoService.list();
return demoList;
}
}
```
## 2.3 litemall-core
## 2.4 litemall-os-api
对象存储服务目前的目标是支持图片的上传下载。
作为后台模块之一litemall-os-api并没有对应的前端模块而只是在litemall-admin模块
的对象存储页面中允许管理员修改。
注意:
> 这个模块是可选的,或者说不建议最终部署时所使用。
> 最终部署时建议采用第三方云存储方案。
### 2.4.1 业务
支持服务:
* 列表
* 创建
* 修改
* 读取
* 删除
* 下载,即下载对象数据文件
* 访问,即直接访问对象数据
### 2.4.2 安全
警告
> 目前这里没有任何安全机制,这意味着任何人如果知道对象存储服务的地址,都可以直接存储访问对象数据。
这样简化的目的是对象存储服务建议最终采用云服务,因此这里仅仅实现一个简单的服务面向测试开发。
如果开发者需要局域网部署,那么这里需要加入一定的安全机制。
### 2.4.3 文件Key
每一个上传的文件都会采用一个随机值key作为当前文件的网络访问链接的一部分。
以后可能需要进一步支持自定义Key例如采用原文件名字作为key。
## 2.5 litemall-all
在章节1.5中讨论的部署方案中设计了一种单主机单服务方案,
也就是说三个后台服务和静态文件都部署在一个Spring Boot应用中。
注意:
> 这个模块也是可选的,或者说不是非常建议的,应该仅用在主机内存资源紧张的情况下。
> 最终部署,仍然建议部署多个服务更为安全和稳定。
查看litemall-all模块代码仅仅只有一个Application类。
实际的原理是litemall-all模块内的pom.xml文件
1. 声明打包方式是`war`因此最后会打包war格式
2. 设置`spring-boot-starter-tomcat`包是`provided`,因此最终不会打包
3. 申明依赖`litemall-os-api`、`litemall-wx-api`和`litemall-admin-api`
因此最终会打包;
在Application类里面通过`scanBasePackages`即可把三个后台服务模块
的服务启动。此外在tomcat中启动需要采用继承`SpringBootServletInitializer`类
的Application。
4. 利用maven-resources-plugin插件将litemall-admin模块下编译得到dist文件下的
静态文件打包到static目录中。
注意这里只是简单的复制。因此开发者需要保证litemall-all打包前litemall-admin
模块内dist目录下静态文件已经生成。
最终打包以后则是一个war格式的项目包包含了三个后台服务和静态文件。