Commit 6bde3331 authored by Junling Bu's avatar Junling Bu
Browse files

update[doc]: 更新文档,主要是上线方案。

parent 516d19da
......@@ -150,7 +150,7 @@ V 3.0.0 完成以下目标:
* `小商场`简单运费计算
* `小商场`专题评价
* `管理后台`禁止管理员修改超级管理员信息
* `部署`自动脚本util/lazy.sh和util/upload.sh
* `基础系统`自动脚本util/lazy.sh和util/upload.sh
* V 0.3.0,
* `小商场`的后台服务加密用户账号密码
* `小商场`如果用户选择货品,则显示货品对应的价格;否则显示商品价格
......@@ -168,7 +168,7 @@ V 3.0.0 完成以下目标:
* `基础系统`litemall-os-api的链接从`storage/index/index`调整至`os/index/index`
* `基础系统`litemall-os-api支持浏览器显示。
* `基础系统`新增litemall-core模块,综合了litemall-os-api、litemall-wx-api
和litemall-admin-api的共性代码,目前主要是配置和util代码
和litemall-admin-api的共性代码
* `基础系统`新增litemall-all模块作为包裹模块,支持三个后台服务和静态文件
打包成一个war项目包
......
......@@ -118,6 +118,81 @@ litemall是一个简单的商场系统,基于现有的开源项目,重新实
注意:
> 以上特点并不一定是优点。
接下来,从项目的开发、部署(测试)和上线三个阶段介绍litemall。
![](pic1/1-10.png)
首先需要明确的是三个不同阶段:
* dev
即develop或者development, 这里指开发阶段,通常代码是直接在本地编译、运行和测试。
此外,这里服务访问地址通常是localhost。这里的“用户”主要是指开发者本身。
* dep
即deploy或者deployment,这里指部署(测试阶段),通常代码已经编译打包运行在远程主机中,
可以对外服务。此外,这里服务访问地址通常是IP地址。如果IP是公网IP,那么
部署以后就可以对外服务;如果是内网地址,那么只能内网访问。这里的“用户”主要是
指开发者本身、测试者;当然,如果是局域网或者不介意IP访问的,那么这里的“用户”
也可能是最终使用者用户。
* prod
即product或者production,这里指上线阶段,通常也是代码编译打包运行在远处主机中可以对外服务。
此外,这里服务访问地址通常是域名地址,同时端口是80web端口。上线以后直接面向的是最终用户。
虽然服务的代码本身和dep是完全一样的,但是考虑到场景的不同,上线阶段可能在运行环境方面需要做
调整,例如采用反向代理屏蔽内部实际项目结构。此外,最大的不同应该是上线环境下要使用域名和80端口,
而部署阶段则更为自由。
其次,需要明确的是,这里划分三种阶段不是简单的文档说明,还直接影响项目本身的行为
和代码编译结果,因此开发者需要清晰的了解:
* dev
项目的各个模块采用dev来编译配置代码行为。
* vue技术栈的模块采用dev配置文件编译,见litemall-admin/config/dev.env.js
* 小程序技术栈的模块采用dev配置,见litemall-wx/config/api.js
* spring boot技术栈的模块采用dev配置,例如见litemall-wx-api/src/main/resources/application-dev.properties,
此外,在代码中也可以采用`Profile(dev)`来直接定义代码在dev阶段的行为。
* dep
项目的各个模块采用dep来编译配置代码行为。
* vue技术栈的模块采用dep配置文件编译,见litemall-admin/config/dep.env.js
* 小程序技术栈的模块采用dep配置,见litemall-wx/config/api.js
* spring boot技术栈的模块采用dep配置,例如见litemall-wx-api/src/main/resources/application-dep.properties,
此外,在代码中也可以采用`Profile(dep)`来直接定义代码在dev阶段的行为。
* prod
项目的各个模块采用prod来编译配置代码行为。
* vue技术栈的模块采用prod配置文件编译,见litemall-admin/config/prod.env.js
* 小程序技术栈的模块采用prod配置,见litemall-wx/config/api.js
* spring boot技术栈的模块采用prod配置,例如见litemall-wx-api/src/main/resources/application-prod.properties,
此外,在代码中也可以采用`Profile(prod)`来直接定义代码在dev阶段的行为。
最后,其实dep和prod不存在先后关系。例如,如果开发者已经存在域名和生产环境,可以直接
跳过dep阶段,而直接部署在线上环境中。因此有些时候,这里部署和上线是一个阶段。
当然,这里仍然建议先dep后prod,是因为对于第一次开发而言,先dep阶段可以避免对域名、https证书等非业务相关工作的干扰。
此外,有些业务功能(例如微信支付)必须是域名访问,那么开发和部署阶段可以先采用模拟或跳过的形式,
先不开发和测试这样业务功能,等其他功能开发完毕和部署测试成功以后,再来开发这些线上环境才能
运行的功能,此时会有一个好的基础。
注意:
> 以上三种阶段是基于个人理解,有可能有误或不当的地方。
> 此外,可能有人会认为需要存在测试阶段置于dev和dep之间。
> 但是,本人认为测试过程存在于三个不同阶段内部可能更为适宜,
> 即项目测试过程这里不会作为独立的一个阶段。
讨论:
> 对于内网IP,例如"192.168.0.1",是应该认为属于开发阶段的配置,还是应该认为属于部署阶段的配置?
> 本人认为,这里可能不一定,看开发者的实际需要,不过更倾向于开发阶段。
>
> 场景1,开发者本机是"192.168.0.1",那么此时litemall-wx模块的api.js中,如果采用localhost,那么
> 本机的微信开发者工具可以访问,但是局域网内手机测试则不能访问;而如果采用本机的IP地址,那么
> 本机微信开发者工具可以访问,同时局域网内手机测试也能访问。此时,设置IP地址应该属于开发阶段。
>
> 场景2,局域网内管理后台代码部署到局域网服务器中,用户基于局域网的内网IP来访问管理平台,
> 此时,设置IP地址应该属于部署阶段(甚至可以认为是“上线阶段”)。
## 1.4 开发方案
![](pic1/1-2.png)
......@@ -138,18 +213,23 @@ litemall是一个简单的商场系统,基于现有的开源项目,重新实
1. 本项目目前采用MySQL,请上网下载安装MySQL 5.7.x
注意:
> 目前发现一个问题是,MySQL必须安装5.7.x, 如果是5.6或者最新的8.0都会存在错误。
> 目前原因还没有找到(可能是采用JSON引起),希望开发者注意或者有好的解决方案。
> 1. MySQL必须安装5.7.x, 如果是5.6或者最新的8.0都会存在错误。
> 目前原因还没有找到(可能是采用JSON引起),希望开发者注意或者有好的解决方案。
> 2. 如果采用IDE工具导入数据,建议采用MySQL Workbench。如果采用navicat可能有时导入失败。
> 这里失败的原因应该是sql文件是MySQL Workbench导出的,因此可能存在不兼容的格式。
2. 数据库文件存放在litemall-db/sql文件夹中,其中litemall_schema.sql创建数据库和用户权限,
而litemall.sql则是具体的表和数据。开发者可以采用命令或者软件导入数据。
注意:
> 不要运行nideshop.sql文件,这只是所参考nideshop项目的原始数据库,仅用于对比。
### 1.4.1 Spring Boot开发环境
1. 安装JDK8
2. 安装Maven
3. 安装Git(可选)
4. 安装IDEA Community,建议安装Maven插件和git插件
4. 安装IDEA Community,建议安装Maven插件和git插件。Eclipse没有试过,但是应该也是可行的。
5. IDEA导入本项目
6. 采用Maven命令安装依赖库
......@@ -470,16 +550,30 @@ source ./litemall-db/litemall.sql
```
其中123456是开发者所设置的MySQL的管理员密码。
#### 1.5.3.5 Tomcat
#### 1.5.3.5 Tomcat/Nginx
本项目中采用二进制jar包方式来部署Spring Boot后端应用,因此可以不需要部署在tomcat中。
但是,litemall-admin前端项目最终会编译出静态文件,需要部署在服务器中,
因此这里需要安装tomcat或者nginx(或者其他服务器)。
1. 本项目中采用二进制jar包方式来部署Spring Boot后端应用,因此可以不需要部署在tomcat中。
但是,litemall-admin前端项目最终会编译出静态文件,需要部署在服务器中,因此这里仍需安装tomcat(或者其他服务器)。
这里可能有点绕:
1. 开发方案,无需tomcat/nginx,直接用VSC即可;
2. 部署方案,采用tomcat,这里是因为80端口可能需要云主机备案;
3. 上线方案. 采用nginx,通过反向代理访问后台服务。
因此目前这里采用tomcat部署静态文件,通过8080端口访问管理后台。
当然,这里没有严格限制,开发者也可以直接配置好nginx,在部署方案就使用nginx来
部署静态文件服务,通过80web端口访问管理后台。
* Tomcat部署静态文件
1. 安装tomcat
```bash
sudo apt-get install tomcat8
```
2. 为了配置tomcat支持外部文件夹中,修改tomcat的server文件的`Host`标签
2. 配置tomcat指向`delpoy/litemall-admin/dist`目录
```bash
sudo vi /var/lib/tomcat8/conf/server.xml
......@@ -493,14 +587,35 @@ source ./litemall-db/litemall.sql
</Host>
```
3. 重启tomcat
3. 运行/重启tomcat
```
sudo service tomcat8 stop
sudo service tomcat8 start
sudo service tomcat8 restart
```
* Nginx部署静态文件
#### 1.5.3.5 项目打包
这里可以参考http://www.nginx.cn/4723.html
1. 安装nginx
```bash
sudo apt-get update
sudo apt-get install nginx
```
2. 配置nginx指向`delpoy/litemall-admin/dist`目录
3. 运行/重启nginx
```
sudo service nginx stop
sudo service nginx start
sudo service nginx restart
```
#### 1.5.3.6 项目打包
1. Spring Boot打包
......@@ -533,7 +648,7 @@ cnpm run build:prod
此时,litemall-admin模块的dist文件夹中就是最终部署时的代码,可以先压缩,上传到云主机,再解压缩。
#### 1.5.3.6 项目部署运行
#### 1.5.3.7 项目部署运行
https://docs.spring.io/spring-boot/docs/1.5.10.RELEASE/reference/htmlsingle/#deployment-service
......@@ -635,4 +750,238 @@ https://docs.spring.io/spring-boot/docs/1.5.10.RELEASE/reference/htmlsingle/#dep
注意:
> 虽然这里介绍了这种方案,但是本项目的开发、测试和部署是基于1.5.3方案,
> 因此开发者可能需要做一些配置方面的调整,例如三个后台服务地址调整。
\ No newline at end of file
> 因此开发者可能需要做一些配置方面的调整,例如三个后台服务地址调整。
## 1.6 上线方案
在1.5节部署方案中,我们介绍了多种部署的方案,但是实际上这些方案都不能直接用于正式环境:
1. 正式环境需要域名和HTTPS证书
2. 小商场的小程序端对服务器域名存在接入要求。
本节采用`www.example.com`域名作为示例。
注意
> `www.example.com`仅作为实例,不是真实环境下的域名。
这里列举一种可行的单机上线方案,开发者可以基于自身业务采用其他上线方案。
### 1.6.1 域名
1. 注册域名,通常商业性的网站采用`.com`
2. 解析域名到服务器公网IP,采用`ping`命令查看是否解析成功
3. 备案
### 1.6.2 nginx
https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-16-04
在部署方案中建议安装了tomcat来访问管理后台,而这里上线方案中则建议使用nginx,
此时我们可以卸载tomcat(当然不卸载也可以,即同时支持8080端口访问)。
#### 1.6.2.1 nginx安装
采用命令
```bash
sudo apt-get update
sudo apt-get install nginx
```
有的文档会指出需要防火墙设置,但是腾讯云主机防火墙默认没有开启。
开发者这里自己可以开启设置,或者直接不开启。
打开浏览器,输入以下地址:
```
http://www.example.com
```
此时,如果看到nginx的欢迎页面,则安装成功。
安装以后:
* `/var/www/html`:默认静态web文件目录
* `/etc/nginx`:
* `/etc/nginx/nginx.conf`:
* `/etc/nginx/sites-avaiable`:
* `/etc/nginx/sites-enabled`:
* `/etc/nginx/snippets`:
* `/var/log/nginx/access.log`:
* `/var/log/nginx/error.log`:
#### 1.6.2.2 https
1. 申请证书
可以参考[腾讯云 域名型证书申请流程](https://cloud.tencent.com/document/product/400/6814)
2. 下载证书
这里使用nginx文件夹下面的密钥文件,例如`1_www.example.com_bundle.crt`和`2_www.example.com.key`
3. 部署证书到nginx
可以参考[腾讯云 证书安装指引](https://cloud.tencent.com/document/product/400/4143)
把两个密钥文件保存的`/etc/nginx`文件夹,然后修改`/etc/nginx/nginx.conf`文件:
```
server {
listen 443;
server_name www.example.com;
ssl on;
ssl_certificate /etc/nginx/1_www.example.com_bundle.crt;
ssl_certificate_key /etc/nginx/2_www.example.com.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
}
```
4. 重启nginx
打开浏览器,输入以下地址:
```
https://www.example.com
```
此时,可以看到https协议的nginx欢迎页面。
#### 1.6.2.3 litemall-admin静态文件
修改`/etc/nginx/nginx.conf`文件,配置nginx静态web文件目录
```
server {
location / {
root /home/ubuntu/deploy/litemall-admin/dist;
index index.html index.htm;
}
}
```
打开浏览器,输入以下地址:
```
https://www.example.com
```
此时,可以看到管理后台的页面。
#### 1.6.2.3 反向代理三个后台服务
继续修改`/etc/nginx/nginx.conf`文件,配置nginx静态web文件目录
```
server {
location ^~ /os {
proxy_pass http://localhost:8081;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ^~ /wx {
proxy_pass http://localhost:8082;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ^~ /admin {
proxy_pass http://localhost:8083;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
```
打开浏览器,输入以下地址:
```
https://www.example.com/os/index/index
https://www.example.com/wx/index/index
https://www.example.com/admin/index/index
```
此时,看到后台数据说明反向代理配置成功。
#### 1.6.2.4 全站加密
服务器自动把http的请求重定向到https
```
server {
listen 80;
server_name www.example.com;
rewrite https://$server_name$request_uri? permanent;
}
```
打开浏览器,输入以下地址:
```
http://www.example.com
```
总结,经过以上不同方面的配置,nginx这里最终的配置是如下:
1. 证书`1_www.example.com_bundle.crt`和`2_www.example.com.key`放置在
`/etc/nginx/`文件夹内。
2. 把`/etc/nginx/nginx.conf`文件进行修改,具体可以参考[本项目的nginx.conf](./pic/nginx.conf)
3. 重启nginx
注意:
> 本人对nginx也不了解,仅仅依靠网络知识配置了简单的效果。
> 更多配置方法和功能,请开发者自行学习。
### 1.6.3 小商场的小程序端上线
这里参考小程序官方文档,上线自己的小商城。
上线之前需要修改代码或者配置文件:
1. litemall-wx-api模块的WxOrderController类的payNotify方法的链接换成合适的地址。
注意:
> 换成什么地址都可以,但是这里不应该暴露出来。也就是说这个地址是微信支付平台
> 和这里的小商场后台服务之间的交互API,对外公开会存在安全隐患。
2. litemall-wx-api模块需要配置prod.properties
```
wx.app-id=
wx.app-secret=
wx.mch-id=
wx.mch-key=
wx.notify-url=
```
这里的`wx.notify-url`就是前面开发者自定义的地址。
3. litemall-wx模块的`project.config.json`文件调整相应的值,
特别是`appid`要设置成开发者申请的appid。
### 1.6.4 上线脚本
### 1.6.5 优化
以下是部署方案中出现而在上线方案中可以优化的一些步骤。
#### 1.6.5.1 卸载tomcat
如果部署方案中采用tomcat而8080端口访问后台,而这里配置nginx后,
可以直接采用80端口访问,因此tomcat可以卸载。
#### 1.6.5.2 静态文件托管CDN
在上节中,建议采用卸载tomcat,采用nginx托管管理后台的静态文件。
这里可以进一步地,把静态文件托管到CDN,当然这里是需要收费。
#### 1.6.5.3 后台服务内部访问
原来后台服务可以通过域名或者IP直接对外服务,而这里采用nginx反向代理后可以
通过80端口访问后台服务。因此,会存在这样一种结果:
* 用户可以https协议的80端口访问后台服务(nginx反向代理)
* 用户也可以通过http协议的8081、8082、8083访问后台服务(spring boot)
由于http不是安全的,这里可能存在安全隐患
而如果取消后台服务的对外访问,这样可以保证用户只能采用安全的https协议访问后台服务。
同时,对外也能屏蔽内部具体技术架构细节。
#### 1.6.5.4 nginx优化
本人对nginx不是很熟悉,而nginx还存在很多可以调整优化的部分,这里建议开发者
根据自己业务或架构情况优化。
\ No newline at end of file
# 2 litemall基础系统
目前litemall基础系统主要由litemall数据库、litemall-db模块和litemall-os-api模块组成。
目前litemall基础系统主要由litemall数据库、litemall-core模块、litemall-db模块、
litemall-os-api模块和litemall-all模块组成。
实际上,属于litemall**真正的基础系统**是litemall-core模块和litemall-db模块。
litemall-os-api模块只是为了减少开发中对第三方图片存储服务依赖而实现的简单图像存储服务,
建议开发者最终部署时切换到第三方图片存储服务。litemall-all模块只是一个包裹模块,
没有任何代码,其作用是融合三个spring boot模块和litemall-adminm模块静态文件到
一个单独spring boot应用中,并最终打包成war格式的项目安装包。
目前存在的问题:
* `严重`数据库采用git,每次跟新都是5MB数据,影响项目下载速度
* `缺失`litemall-os-api返回的图片不能在浏览器直接显示
* `改善` litemall-db的一些CRUD操作可以基于开源库重构
* `功能`可以参考一些云存储服务的API加强一些功能
......@@ -140,32 +146,48 @@ litemall.sql数据库基于nideshop中的[nideshop.sql](https://github.com/tumob
订单分成几种基本的状态:
* 下单
* 已下单
状态码101,此时订单生成,记录订单编号、收货地址信息、订单商品信息和订单相关费用信息;
* 付款
* 已付款
状态码201,此时用户微信支付付款,系统记录微信支付订单号、支付时间、支付状态;
* 发货
* 已发货
状态码301,此时商场已经发货,系统记录快递公司、快递单号、快递发送时间。
当快递公司反馈用户签收后,系统记录快递到达时间。
* 收货
* 已确认
状态码401,当用户收到货以后点击确认收货,系统记录确认时间。
此时,用户可以评价订单商品。
除了这几种正常状态以外,还存在一些非普通的状态:
* 订单取消
状态码102,用户在生产订单以后未付款之前,点击取消按钮,系统记录结束时间
* 订单取消并退款
状态码202,用户付款以后未发货前,点击取消按钮,系统记录结束时间和退款信息
* 系统自动确认收货
状态码402,快递反馈商场用户已签收,但是用户却不点击确认收货按钮,
此时系统在快递到达时间的一段时间后,自动确认收货。
用户不能再点击确认收货按钮,但是可以评价订单商品
* 已取消
状态码102,用户下单后未付款之前,点击取消按钮,系统记录结束时间
* 系统自动取消
状态码103,用户下单后半小时未付款则系统自动取消,系统记录结束时间
* 已退款取消
状态码202,用户付款以后未发货前,点击取消按钮,系统进行退款操作,并记录结束信息
* 系统自动确认
状态码402,快递反馈商场用户已签收而用户却不点击确认,超期7天以后,则系统自动确认收货,
用户不能再点击确认收货按钮,但是可以评价订单商品。
当然,以上的基本状态和非普通状态,和实际项目相比仍然相对简单。
此外,当订单状态码是102、202、401、402时,订单可以设置删除状态,此时
用户查看自己订单信息时将看不到这些“已删除”的订单。
此外,当订单状态码是102、103、202、401、402时,订单可以执行删除操作。
虽然并没有最终真正删除,但是用户查看自己订单时将看不到这些“已删除”的订单。
#### 2.1.4.2 状态码所支持的操作
......@@ -173,19 +195,21 @@ litemall.sql数据库基于nideshop中的[nideshop.sql](https://github.com/tumob
不同的状态码下面,用户能够进行的操作是:
* 101
此时,用户可以“订单支付”、“订单取消”
用户可以“订单支付”、“订单取消”
* 102
此时,用户可以“订单删除”
用户可以“订单删除”
* 103
用户可以“订单删除”
* 201
此时,用户可以“订单取消”(并退款)
用户可以“订单退款取消”
* 202
此时,用户可以“订单删除”
用户可以“订单删除”
* 301
此时,用户可以“确认收货”
用户可以“确认收货”
* 401
此时,用户可以“订单删除”、“评价”、“再次购买”
用户可以“订单删除”、“评价”、“再次购买”
* 402
此时,用户可以“订单删除”、“评价”、“再次购买”
用户可以“订单删除”、“评价”、“再次购买”
#### 2.1.4.3 售后处理
......@@ -196,14 +220,36 @@ litemall.sql数据库基于nideshop中的[nideshop.sql](https://github.com/tumob
从一些资料看,如果用户订单多次取消,应该加入黑名单。
目前不支持。
#### 2.1.5 数据删除
### 2.1.5 通用设计
以下是一些表设计中无具体业务意义可通用的字段。
#### 2.1.5.1 deleted
除极少数表,其他所有表都存在`deleted`字段,支持逻辑删除。
因此目前删除数据时,不会直接删除数据,而是修改`deleted`字段。
当然,数据库管理员可以连接到数据库直接删除数据,或者开发者
可以修改这里的逻辑采用物理删除。
所有表的数据在代码层面都不支持删除,除非数据库管理员连接到数据库删除数据。
#### 2.1.5.2 add_time
在访问层,数据库的删除操作
除极少数表,其他所有表都存在`add_time`字段,记录数据创建时间。
#### 2.1.5.3 version
如果开发者需要在访问表时采用乐观锁机制,则需要在表中设置`version`字段,
这个字段开发者不需要管理,而是由程序自动使用,来提高乐观锁机制。
具体使用方法可以参考`2.2.8 乐观锁`
## 2.2 litemall-db
litemall-db模块是一个普通的Spring Boot应用,基于mybatis技术提供开发者
访问数据库的功能。
此外,litemall-db最终是作为一个类库被其他模块所依赖使用,因此并不对外
直接服务,没有使用Spring MVC技术。
技术:
* Spring Boot 1.5.10
* MySQL
......@@ -212,8 +258,6 @@ litemall.sql数据库基于nideshop中的[nideshop.sql](https://github.com/tumob
* PageHelper
* Mybatis Generator
* Mybatis Generator非官方插件mybatis-generator-plugin
因为litemall-db是一个业务模块,并不对外直接服务,因此无需使用Spring MVC。
![](./pic2/2-2.png)
......@@ -284,6 +328,9 @@ litemall.sql数据库基于nideshop中的[nideshop.sql](https://github.com/tumob
如果基于一个新表创建新访问组件,请阅读下面章节2.2.6
关于mybatis generator的用法,可以参考:
https://blog.csdn.net/isea533/article/details/42102297
### 2.2.2 业务代码
基于2.2.1的代码,业务代码处理一些具体业务相关的操作,对其他模块提供具体的服务。
......@@ -377,8 +424,141 @@ litemall.sql数据库基于nideshop中的[nideshop.sql](https://github.com/tumob
}
```
### 2.2.7 逻辑删除
数据删除可以直接使用delete方法进行物理删除,也可以采用设置删除字段进行逻辑删除。
根据具体业务,也有可能部分数据可以物理删除,部分数据只能逻辑删除。
目前所有删除操作是逻辑删除,除了极少数表外,其他所有表的设置了`deleted 字段。
开发者可以自行修改代码进行真正的物理删除。
### 2.2.8 乐观锁
由于服务是多线程并发的,因此这带来了多线程同时操作数据库中同一数据的问题。
由于数据极少删除或者是逻辑删除,因此操作数据,可以简化成更新数据。
也就是说,需要解决多线程更新数据库同一数据的并发问题。
例如,下单操作中,用户A购买商品G的数量是1个,而用户B同一时间也购买商品G的
数量也是1个,那么如果没有很好地并发控制,有可能商品G的数量仅仅是减1,而不是
设想的2。
通常采用悲观锁或者乐观锁来处理并发更新问题,
本项目目前采用基于`version`字段的乐观锁机制。
原理是:
1. 每个表都存在version字段
2. 更新前,先查询数据,得到表的业务数据和version字段
3. 更新时,通过where条件查询当前version字段和数据库中当前version字段是否相同。
* 如果相同,说明数据没有改变则可以更新,数据更新同时version调整一个新值;
* 如果不相同,则说明数据改变了则更新失败,不能修改数据。
当然,这里好像也存在一个漏洞,3中所比较的数据库当前version字段的值有可能修改过
但是恰巧没有变。例如version加1再减1,那么查询时该值并没有变化。当然,如果version
是单调自增,则应该不存在这个问题。
具体技术细节如下:
1.
当然,由于采用乐观锁,这里也会带来另外一个问题:
数据库有可能更新失败,那么如何处理更新失败的情况?
目前的方法是在业务层多次尝试。
例如:
由于用户A和B同时更新同一商品数量,而用户A成功,B则失败。
此时B失败后会再次进行商品购买逻辑。
当然逻辑上这里仍然会存在再次和其他用户同时购买而失败的情况。
不过考虑到本项目设想的场景,因此可以采用。
开发者需要注意这个问题,可能需要采用其他技术来解决或避免。
### 2.2.9 mybatis增强框架
通过mybatis-generator已经自动生成了很多代码,而且具有一定的功能,
但是开发者仍然需要基于生成的代码写一些固定的CRUD代码。
目前发现已经有两个mybatis增强的框架可以进一步简化代码和功能增强:
* [mybatis-plus](https://github.com/baomidou/mybatis-plus)
* [Mapper](https://github.com/abel533/Mapper)
目前没有采用,以后可能会基于其中之一重构数据库访问代码。
开发者感兴趣的可以自行研究使用。
## 2.3 litemall-core
litemall-core模块是spring boot应用通用的代码,包括配置代码和util代码。
### 2.3.1 config
#### 2.3.1.1 CorsConfig
目前开发过程中,CORS配置是允许所有请求。
真正部署时,开发者需要做一些调整,来保证当前的服务只接受来自所设置域名的请求。
#### 2.3.1.2 GlobalExceptionHandler
如果系统内部产生了异常而开发者没有catch,那么异常的内容会发送到前端。
这里通过提供全局异常处理器,来处理所有开发者没有处理的异常,返回
“系统内部错误”之类的信息给前端从而达到保护系统的效果。
#### 2.3.1.3 JacksonConfig
Jackson做一些设置。
### 2.3.2 util
注意
> 这里的util代码不会涉及具体业务,例如litemall-db模块中存在一个
> OrderUtil类处理数据库中litemall_order表的一些转换工作。
#### 2.3.2.1 ResponseUtil
这里是用于设置response中body的内容格式。
如果是成功则是 :
```json
{
errno: 0,
errmsg: '成功',
data: XXX
}
```
如果失败则是:
```json
{
errno: 非0的XXX,
errmsg: XXX
}
```
#### 2.3.2.2 JacksonUtil
当请求时POST时,请求的json内容在body。
通常存在存在两种方式取出数据:
* 如果json内容正好对应一个POJO,那么在方法中使用POJO时,spring会自动解析填充数据;
* 或者开发者自己采用jackson或者其他json处理库手动解析数据。
这里JacksonUtil简化解析工作。这里代码有局限性,开发者请谨慎使用,或者熟悉Jackson
使用的开发者欢迎优化代码。
#### 2.3.2.3 CharUtil
生成固定长度的随机字母字符串或者随机数字字符串。
#### 2.3.2.4 bcypt
这里是用于对用户密码或者管理员密码加密存储。
bcypt代码本质上是spring里面的代码。
## 2.4 litemall-os-api
对象存储服务目前的目标是支持图片的上传下载。
......
......@@ -244,6 +244,63 @@
目前这里没有实现,仅列出。
### 3.1.17 定时任务
目前有些业务需要定时任务:
* 订单未付款超时自动取消订单
* 订单未确认超时自动确认订单
定时任务技术上采用Spring的任务机制,即`@EnableScheduling``@Scheduled`注解。
目前需要讨论存在的限制或者问题:
1. 定时任务带来的延时问题
定时任务是定时启动,而不是针对任务中具体的工作定时处理,因此会带来延时问题。
例如,订单未付款工作检测是基于半小时超时时间,但是因为订单是相隔半个小时才启动,
因此会导致实际最长一个小时才能检测订单超时。
当然,这个问题可能并不严重。
* 可以结合其他机制来减轻这个问题。例如订单未付款超时可以在用户查询自身订单时
也启动,从而提前完成检测工作,给用户的感觉也是最长半小时的超时时间。
* 这个延时是可以接收的,或者说定时任务中的工作是延时不敏感的。例如,订单未确认
虽然希望是七天确认,但是延时带来的八天也是可以接受的。
* 如果需要严格的时间管理,可能不应该采用定时任务机制。
2. 定时任务中数据库查询问题
目前这里的两个定时任务都是简单的查询数据库以后处理所有符合情况的订单。
理论上可能存在大量符合情况的订单,这样在定时任务处理大量工作可能不是很好。
但是,本项目的场景是小微型企业,因此设想的订单业务量不会很大,因此这里简化。
3. 分布式环境下相同定时任务问题
如果两台云主机都部署小商城后台服务,那么这里也会出现两个相同的定时任务。
虽然相同定时任务导致的并发问题可以通过锁机制解决,对系统实际业务不会造成影响,
但是相同定时任务同时存在仍然是不合理的,因此应该避免。可行做法是从小商场后台
模块中剥离这些定时任务形成一个独立任务模块,然后单独部署,从而保证分布式环境
下定时任务是唯一存在的。通常,这个任务模块是基于quartz技术。
但是目前本项目设想场景是小商场后台仅部署一台主机,同时系统中定时任务不是很多,
因此这里定时任务仍然是耦合在小商城后台服务模块中。因此开发者需要注意到这里
存在的潜在问题。
### 3.1.18 并发控制
参考`2.2.8 乐观锁`
当乐观锁更新失败时采用多次尝试方案。
### 3.1.19 事务管理
### 3.1.20 开发技巧
当小商城后台服务开发中因为测试或者debug可能需要经常性重启应用,此时
一旦重启,将导致小商场的小程序段的token失效,因此要求用户再次登录。
这里,介绍一个小技巧:
开发时,
## 3.2 litemall-wx
这里的代码基于[nideshop-mini-program](https://gitee.com/tumobi/nideshop-mini-program),但是做了一定的修改:
......
......@@ -32,14 +32,6 @@ public class Application {
### 6.1.4 vue-element-admin跟新
目前的vue-element-admin基于element 2.0.8, 因此element的很多修复没有跟新。
### 6.1.5 事务管理
目前没有事务管理,因此如果直接把项目用于正式运行中,可能会存在数据不一致等问题。
### 6.1.6 小程序登录设计
个人觉得目前nideshop-mini-program里的登录设计内部实现不是很合理。
### 6.1.n 代码重构
技术不断迭代开发中,应该在业务基本完成和功能基本完善以后,
......@@ -51,10 +43,6 @@ public class Application {
目前微信支付模块因缺乏支付权限而不能开发。
### 6.2.2 任务日程模块
部分业务需要引入任务管理服务,例如订单下单以后一个小时未支付则自动失效关闭。
### 6.2.3 监控管理
项目运行的整个运行过程应该需要监控管理
......@@ -106,4 +94,14 @@ public class Application {
目前的关键字是管理员设置,然后用户的搜索时匹配关键字,因此需要专业的推荐系统。
### 6.3.6 Spring Boot 2.0迁移(可选)
\ No newline at end of file
Apache Solor
### 6.3.7 Spring Boot 2.0
### 6.3.8 Spring Cloud
### 6.3.8 定时任务模块
### 6.3.9 单点登录模块
### 6.3.10 消息队列
\ No newline at end of file
user www-data;
worker_processes auto;
pid /run/nginx.pid;
events {
worker_connections 768;
# multi_accept on;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# SSL Settings
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
gzip_disable "msie6";
# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
##
# Virtual Host Configs
##
server {
listen 443;
server_name www.example.com;
ssl on;
ssl_certificate /etc/nginx/1_www.example.com_bundle.crt;
ssl_certificate_key /etc/nginx/2_www.example.com.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
location ^~ /os {
proxy_pass http://localhost:8081;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ^~ /wx {
proxy_pass http://localhost:8082;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ^~ /admin {
proxy_pass http://localhost:8083;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location / {
root /home/ubuntu/deploy/litemall-admin/dist;
index index.html index.htm;
}
}
server {
listen 80;
server_name www.example.com;
rewrite https://$server_name$request_uri? permanent;
}
#include /etc/nginx/conf.d/*.conf;
#include /etc/nginx/sites-enabled/*;
}
#mail {
# # See sample authentication script at:
# # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
#
# # auth_http localhost/auth.php;
# # pop3_capabilities "TOP" "USER";
# # imap_capabilities "IMAP4rev1" "UIDPLUS";
#
# server {
# listen localhost:110;
# protocol pop3;
# proxy on;
# }
#
# server {
# listen localhost:143;
# protocol imap;
# proxy on;
# }
#}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment