Browse Source

更新文档

Junling Bu 7 years ago
parent
commit
a75015ea46
4 changed files with 312 additions and 74 deletions
  1. 45 24
      doc/admin.md
  2. BIN
      doc/pic2/2-2.png
  3. 222 28
      doc/platform.md
  4. 45 22
      doc/wxmall.md

+ 45 - 24
doc/admin.md

@@ -2,7 +2,7 @@
 
 项目技术架构:
 
-* 后台管理前端,即litemall-admin模块
+* 管理后台前端,即litemall-admin模块
   * vue
   * vuex
   * vue-router
@@ -10,7 +10,7 @@
   * element
   * vue-element-admin 3.9.3
   * 其他,见package.json
-* 后台管理后端, 即litemall-admin-api模块
+* 管理后台后端, 即litemall-admin-api模块
   * Spring Boot 2.x
   * Spring MVC
 
@@ -82,28 +82,44 @@
 
 #### 4.1.8.1 Token
 
-用户登录成功以后,后端会返回`token`,之后用户的请求都会携带token。
-
-目前token的失效和更新机制没有涉及。
-
-#### 4.1.8.2 CROS
-
-如果litemall-admin-api不配置CROS,则Spring Boot会失败。
-
-#### 4.1.8.3 账号密码加盐
+管理员登录成功以后,后端会返回token,之后管理员的请求都会携带token。
+
+见AdminWebMvcConfiguration类、LoginAdmin和LoginAdminHandlerMethodArgumentResolver类。
+
+管理后台后端服务每次请求都会检测是否存在HTTP头部域`X-Litemall-Admin-Token`。
+如果存在,则内部查询转换成LoginAdmin,然后作为请求参数。
+如果不存在,则作为null请求参数。
+
+而具体的后端服务controller中,则可以利用LoginAdmin来检查。
+
+例如管理员地址服务中:
+```
+@RestController
+@RequestMapping("/admin/address")
+@Validated
+public class AdminAddressController {
+    @GetMapping("/list")
+    public Object list(@LoginAdmin Integer adminId,
+                       Integer userId, String name,
+                       @RequestParam(defaultValue = "1") Integer page,
+                       @RequestParam(defaultValue = "10") Integer limit,
+                       @Sort @RequestParam(defaultValue = "add_time") String sort,
+                       @Order @RequestParam(defaultValue = "desc") String order) {
+        if (adminId == null) {
+            return ResponseUtil.unlogin();
+        }
+        
+        ...
+    }
+```
+如果检测`adminId`是null,则返回错误信息“管理员未登录”。
+
+#### 4.1.8.2 账号密码加盐
 
 如果是微信登录,那么无需账号和密码。
 
 而如果用户采用了账号和密码的形式登录,那么后端需要把用户密码加盐。
 
-#### 4.1.8.4 限制登录
-
-如果采用账号密码登录,那么登录失败一定次数,应该限制登录。
-
-进一步地,如果项目启用了短信功能,应该短信提醒用户,防止他人登录。
-
-目前这里没有实现,仅列出。
-
 ### 4.1.9 定时任务
 
 AdminOrderController类存在以下三个方法,其实是三个定时任务:
@@ -115,15 +131,20 @@ AdminOrderController类存在以下三个方法,其实是三个定时任务:
 > 虽然定时任务放在AdminOrderController类中,但是可能这里不是很合适,
 > 以后需要调整或者完善。
 
-### 4.1.10 事务管理
-
-
 ## 4.2 litemall-admin
 
-本介绍管理后台的前端模块。
+本章介绍管理后台的前端模块。
 
 litemall-admin模块的代码基于[vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
 
 ## 4.3 开发新组件
 
-这里介绍开发一个新的组件的流程。
+本章节介绍如何开发新的管理后台功能。
+
+### 4.3.1 管理后台前端页面
+
+### 4.3.2 前后端交互服务API
+
+### 4.3.3 管理后台后端服务
+
+### 4.3.4 数据库

BIN
doc/pic2/2-2.png


+ 222 - 28
doc/platform.md

@@ -7,6 +7,10 @@
 * litemall-db模块
 * litemall-all模块
 
+litemall-db模块提供数据库访问服务。
+
+litemall-core模块提供通用服务。
+
 litemall-all模块则只是一个包裹模块,几乎没有任何代码。该模块的作用是融合两个spring boot模块
 和litemall-admin模块静态文件到一个单独Spring Boot可执行jar包中。
 
@@ -313,7 +317,6 @@ litemall_region表保存了行政区域信息,包括省级、市级、县级
 
 所对应的后台服务方法是litemall-admin-api模块的`AdminOrderController.checkOrderUnpaid`
 
-
 注意:
 > 上述订单状态变化中具体的逻辑处理可以参考相应模块文档和模块代码。
 
@@ -369,7 +372,7 @@ litemall_region表保存了行政区域信息,包括省级、市级、县级
 
 #### 2.1.4.3 售后处理
 
-虽然这里用户有`退款`操作,但是目前不支持退货相关业务。
+目前不支持退货售后相关业务。
 
 #### 2.1.4.4 商品评价
 
@@ -405,14 +408,15 @@ litemall_region表保存了行政区域信息,包括省级、市级、县级
 
 ### 2.1.7 优惠券设计
 
+目前不支持。
+
 ### 2.1.8 系统配置设计
 
 系统配置表litemall_system保存系统的配置信息。
 
 这里需要注意的是,在Java代码层系统配置表只能执行更新操作,
-不能执行创建和删除操作。
-
-这里的系统配置数据都应该是开发者基于系统的配置情况在数据库中手动创建。
+不能执行创建和删除操作。也就是说,系统配置数据都应该是开发者
+基于系统的配置需求在数据库中手动创建。
 
 ### 2.1.9 存储对象设计
 
@@ -441,11 +445,11 @@ litemall_region表保存了行政区域信息,包括省级、市级、县级
 
 #### 2.1.10.3 update_time
 
-除极少数表,其他所有表都存在`add_time`字段,记录数据修改时间。
+除极少数表,其他所有表都存在`update_time`字段,记录数据修改时间。
 
 此外,此外开发者可以利用update_time来实现乐观锁更新机制。
 
-具体使用方法可以参考`2.2.8 乐观锁`
+具体使用方法可以参考`2.2.6 并发访问`
 
 ## 2.2 litemall-db
 
@@ -471,7 +475,7 @@ litemall-db模块是一个普通的Spring Boot应用,基于mybatis框架实现
   * generator生成代码
   * 非generator手动代码
 * 业务代码
-* mybatis支持代码
+* mybatis generator支持代码
 
 ### 2.2.1 mybatis数据库访问代码
 
@@ -481,10 +485,10 @@ mybatis数据库访问代码是指dao接口代码、dao数据库XML文件和doma
 * domain代码,则是保存数据库返回数据。
 
 此外,这里的数据库访问代码又进一步分成
-* generator生成代码,即基于mybatis generator相关插件自动生成上述三种代码或文件;
-* 非generator手动代码,则是需要开发者自己编写上述三种代码。
+* mybatis generator自动生成代码,即基于mybatis generator相关插件自动生成上述三种代码或文件;
+* 非mybatis generator手动代码,则是需要开发者自己编写上述三种代码。
 
-#### 2.2.1.1 generator生成代码
+#### 2.2.1.1 自动生成代码
 
 ![](./pic2/2-3.png)
 
@@ -542,9 +546,9 @@ mybatis数据库访问代码是指dao接口代码、dao数据库XML文件和doma
 
 关于mybatis generator的用法,可以自行查阅官网或文档。
 
-#### 2.2.1.2 非generator手动代码
+#### 2.2.1.2 手动代码
 
-虽然generator可以自动生产代码,帮助开发者简化开发工作,但是在涉及到多表操作或特殊数据库操作时,
+虽然mybatis generator可以自动生产代码,帮助开发者简化开发工作,但是在涉及到多表操作或特殊数据库操作时,
 仍然需要开发者自己手动编写基于mybatis框架的相关代码。
 
 具体如何基于mybatis框架编写代码,请开发者自己查找资料。
@@ -597,7 +601,34 @@ mybatis数据库访问代码是指dao接口代码、dao数据库XML文件和doma
 
 通常业务层代码在src文件夹`org.linlinjava.litemall.db.service` 包中。
 
-### 2.2.3 mybatis支持代码
+### 2.2.3 mybatis generator支持代码
+
+mybatis generator自动生成代码时,通过内置类型转换器自动把数据库类型转换成Java类。
+例如数据库类型`varchar`自动转化成`java.lang.String`。
+
+但是某些情况下,可以通过自定义TypeHandler的方式来采用自定义的类型转换器。
+开发者可以自行阅读相关资料了解。
+
+本项目中,为了简化数据表的设计,某些字段采用`varchar`来存储Json格式的数据。
+例如商品的图片列表可以直接采用`[url0, url1, ...]`来存储,而不需要设计一个专门商品图片表。
+
+这里通过自定义TypeHandler,可以实现Java的`String[]`和数据库类型`varchar`的自动转换。
+
+1. 实现JsonStringArrayTypeHandler类;
+2. 在mybatis generator配置文件中,配置需要的字段;
+    ```
+        <table tableName="litemall_goods">
+            <columnOverride column="gallery" javaType="java.lang.String[]"
+                            typeHandler="org.linlinjava.litemall.db.mybatis.JsonStringArrayTypeHandler"/>
+        </table>
+    ```
+3. 使用mybatis generator自动生成代码,可以看到LitemallGoods的gallery是`String[]`类型。
+
+目前只实现了两个自定义TypeHandler:
+* JsonStringArrayTypeHandler类,实现`String[]`和`varchar`的转换,保存的JSON数据格式是`[string0, string1, ...]`
+* JsonIntegerArrayTypeHandler类,实现`Integer[]`和`varchar`的转换,保存的JSON数据格式是`[integer0, integer1, ...]`
+
+如果开发者需要保存其他格式的JSON数据或者自定义格式的数据,请自行开发。
 
 ### 2.2.4 新服务组件
 
@@ -754,33 +785,35 @@ litemall-core模块是本项目通用的代码:
 * config
 
   通用配置,例如开启Spring Boot异步功能。
-  
-* express
 
-  物流服务,查询订单物流信息。
-  
-* notify
+* util
+
+  工具代码。
 
-  通知提醒功能,支持邮件通知、短信通知和微信通知。
-  
 * qcode
 
   本项目定制的分享二维码图片。
-
+  
 * storage
 
   存储功能,支持本地存储、腾讯云存储、阿里云存储和七牛云存储。
-  
-* validator
+      
+* notify
 
-  提供两个注解,帮助后端验证请求参数。
+  通知提醒功能,支持邮件通知、短信通知和微信通知。
+
+* express
+
+  物流服务,查询订单物流信息。
   
 * system
 
   通过litemall-db模块的数据库访问,读取本项目系统配置信息。
-  
-* util
 
+* validator
+
+  提供两个校验注解,帮助后端验证请求参数。
+  
 ### 2.3.1 config
 
 #### 2.3.1.1 CorsConfig
@@ -848,28 +881,189 @@ Jackson做一些设置。
 
 bcypt代码本质上是spring里面的代码。
 
+### 2.3.3 二维码
+
+见QCodeService类。
+
 ### 2.3.4 对象存储
 
 对象存储服务目前的目标是支持图片的上传下载。
 
+对象存储服务会自动读取配置配置,然后实例化服务。
+
+对象存储接口:
+```
+public interface Storage {
+    void store(InputStream inputStream, long contentLength, String contentType, String keyName);
+    Stream<Path> loadAll();
+    Path load(String keyName);
+    Resource loadAsResource(String keyName);
+    void delete(String keyName);
+    String generateUrl(String keyName);
+}
+```
+
 #### 2.3.4.1 本地存储服务
 
+见LocalStorage类。
+
 #### 2.3.4.2 腾讯云存储服务
 
+见TencentStorage类。
+
 #### 2.3.4.3 阿里云存储服务
 
+见AliyunStorage类。
+
+#### 2.3.4.4 七牛云存储服务
+
+见QiniuStorage类。
+
 ### 2.3.5 消息通知
 
+消息通知用于通知用户或者管理员。
+
+注意:
+> 目前这里实现比较粗糙,以后会完善细节。
+
 #### 2.3.5.1 邮件通知
 
+见NotifyService类的`notifyMail`方法。
+
 #### 2.3.5.2 短信通知
 
-#### 2.3.5.3 微信模板通知
+见NotifyService类的`notifySms`和`notifySmsTemplate`方法。
+
+而短信通知实现类见`TencentSmsSender`类。
+也就是目前仅支持腾讯云短信服务,其他短信服务不支持。
+此外,开发者必须先在腾讯云短信平台申请模板才能使用。
+
+#### 2.3.5.3 微信通知
+
+见NotifyService类的`notifySms`和`notifyWxTemplate`方法。
+而微信通知实现类见`WxTemplateSender`类。
+开发者必须在微信平台申请模板才能使用。
 
 ### 2.3.6 物流跟踪
 
+物流跟踪是基于第三方服务快鸟物流查询服务。
+开发者需要申请才能使用。
+
+见`ExpressService`类。
+
 ### 2.3.7 系统设置
 
+### 2.3.8 校验注解
+
+自定了两个校验注解,帮助开发者校验HTTP参数。
+
+#### 2.3.8.1 Order
+
+校验用户请求参数值只能是`desc`或者`asc`。
+
+注意,这里的Order不是订单的意思,而是排序的意思。
+
+1. 定义注解Order
+    ```
+    @Target({METHOD, FIELD, PARAMETER})
+    @Retention(RUNTIME)
+    @Documented
+    @Constraint(validatedBy = OrderValidator.class)
+    public @interface Order {
+        String message() default "排序类型不支持";
+        String[] accepts() default {"desc", "asc"};
+        Class<?>[] groups() default {};
+        Class<? extends Payload>[] payload() default {};
+    }
+    ```
+2. 实现OrderValidator
+    ```
+    public class OrderValidator implements ConstraintValidator<Order, String> {
+        private List<String> valueList;
+        @Override
+        public void initialize(Order order) {
+            valueList = new ArrayList<String>();
+            for (String val : order.accepts()) {
+                valueList.add(val.toUpperCase());
+            }
+        }
+        @Override
+        public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
+            if (!valueList.contains(s.toUpperCase())) {
+                return false;
+            }
+            return true;
+        }
+    }
+    ```
+3. 使用注解
+    ```
+    @RestController
+    @RequestMapping("/wx/topic")
+    @Validated
+    public class WxTopicController {
+        @GetMapping("list")
+        public Object list(@RequestParam(defaultValue = "1") Integer page,
+                       @RequestParam(defaultValue = "10") Integer size,
+                       @Sort @RequestParam(defaultValue = "add_time") String sort,
+                       @Order @RequestParam(defaultValue = "desc") String order) {
+         ...
+         }
+    ```
+    
+#### 2.3.8.2 Sort
+
+校验用户请求参数值只能是`add_time`或者`id`。
+
+1. 定义注解Sort
+    ```
+    @Target({METHOD, FIELD, PARAMETER})
+    @Retention(RUNTIME)
+    @Documented
+    @Constraint(validatedBy = SortValidator.class)
+    public @interface Sort {
+        String message() default "排序字段不支持";
+        String[] accepts() default {"add_time", "id"};
+        Class<?>[] groups() default {};
+        Class<? extends Payload>[] payload() default {};
+    }
+    ```
+2. 实现SortValidator
+    ```
+    public class SortValidator implements ConstraintValidator<Sort, String> {
+        private List<String> valueList;
+    
+        @Override
+        public void initialize(Sort sort) {
+            valueList = new ArrayList<String>();
+            for (String val : sort.accepts()) {
+                valueList.add(val.toUpperCase());
+            }
+        }
+    
+        @Override
+        public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
+            if (!valueList.contains(s.toUpperCase())) {
+                return false;
+            }
+            return true;
+        }
+    }
+    ```
+3. 使用注解
+    ```
+    @RestController
+    @RequestMapping("/wx/topic")
+    @Validated
+    public class WxTopicController {
+        @GetMapping("list")
+        public Object list(@RequestParam(defaultValue = "1") Integer page,
+                       @RequestParam(defaultValue = "10") Integer size,
+                       @Sort @RequestParam(defaultValue = "add_time") String sort,
+                       @Order @RequestParam(defaultValue = "desc") String order) {
+         ...
+         }
+    ```
 
 ## 2.4 litemall-all
 

+ 45 - 22
doc/wxmall.md

@@ -35,11 +35,13 @@
 
 ## 3.0 小商场环境
 
-开发者小商场开发环境以后,启动后台服务,小程序端可以
-显示数据和图片,但是微信登录会失败,因为appid不是
-开发者自己的,这里进一步介绍开发者需要设置的小商场环境。
+按照项目README文档中的“快速启动”一节,开发者可以快速启动小商场项目。
+但是小程序端只可以显示数据和图片,而微信登录会失败、微信支付也会失败,
+因为appid不是开发者自己的,
 
-### 3.0.1 微信小程序配置
+这里进一步介绍开发者需要设置的小商场环境。
+
+### 3.0.1 微信登录配置
 
 开发者在微信小程序官网申请以后,可以有app-id和app-secret信息。
 
@@ -62,7 +64,7 @@
 4. 建议开发者关闭当前项目或者直接关闭微信开发者工具,重新打开(因为此时litemall-wx模块的appid可能未更新)。
    编译运行,尝试微信登录
 
-### 3.0.2 微信商户支付配置
+### 3.0.2 微信支付配置
 
 开发者在微信商户平台申请以后,可以有app-id和app-secret信息。
 
@@ -77,11 +79,11 @@
     ```
 
     注意
-    > 1. notify-url是微信商户平台向小商场后台服务发送支付结果的地址。
+    > * notify-url是微信商户平台向小商场后台服务发送支付结果的地址。
     >    因此这就要求该地址是可访问的。
-    > 2. 目前小商场后台服务的默认request mapping是`/wx/order/pay-notify`(见WxOrderController类的payNotify),
+    > * 目前小商场后台服务的默认request mapping是`/wx/order/pay-notify`(见WxOrderController类的payNotify),
     >    因此notify-url应该设置的地址类似于`http://www.example.com/wx/order/pay-notify`
-    > 3. 当开发者真正上线后台服务时,强烈建议默认request mapping要重新命名,不能对外公开。
+    > * 当开发者真正上线后台服务时,强烈建议默认request mapping要重新命名,不能对外公开。
 
 2. 启动后台服务
 
@@ -90,9 +92,9 @@
 4. litemall-wx的api.js设置云主机的域名。
    编译运行,尝试微信支付。
    
-### 3.0.3 微信商户退款配置
+### 3.0.3 微信退款配置
 
-目前管理平台的退款功能需要进行维修商户退款配置
+目前管理平台的退款功能需要进行微信商户退款配置
 
 1. 从微信商户平台下载商户证书(或者叫做API证书),保存到合适位置,
    请阅读[文档](https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=4_3)
@@ -110,8 +112,8 @@
 注意:
 > 虽然这里管理后台退款接入了微信退款API,但是从安全角度考虑,**强烈建议**
 > 开发者删除管理后台微信退款代码,然后分成两个步骤实现管理员退款操作:
-> 1. 管理员登录微信平台进行退款操作;
-> 2. 管理员登陆管理后台点击退款按钮,进行订单退款状态变更和商品库存回库。
+> * 首先,管理员登录微信平台进行退款操作;
+> * 然后,管理员登陆管理后台点击退款按钮,进行订单退款状态变更和商品库存回库。
 
 ## 3.1 litemall-wx-api
 
@@ -182,13 +184,34 @@
 
 ### 3.1.16 安全
 
-### 3.1.16.1 开发技巧
+#### 3.1.16.1 Token
+
+用户登录成功以后,后端会返回`token`,之后用户请求都会携带token。
+
+见WxWebMvcConfiguration类、LoginUser和LoginUserHandlerMethodArgumentResolver类。
 
-当小商城后台服务开发中因为测试或者debug可能需要经常性重启应用,此时
-一旦重启,将导致小商场的小程序段的token失效,因此要求用户再次登录。
-这里,介绍一个小技巧:
-开发时,
+小商城后端服务每一次请求都会检测是否存在HTTP头部域`X-Litemall-Token`。
+如果存在,则内部查询转换成LoginUser,然后作为请求参数。
+如果不存在,则作为null请求参数。
 
+而具体的后端服务controller中,则可以利用LoginUser来检查。
+
+例如用户地址服务中:
+```
+@RestController
+@RequestMapping("/wx/address")
+@Validated
+public class WxAddressController {
+    @GetMapping("list")
+    public Object list(@LoginUser Integer userId) {
+        if (userId == null) {
+            return ResponseUtil.unlogin();
+        }
+        
+        ...
+    }
+```
+如果检测`userId`是null,则返回错误信息“用户未登录”。
 
 ## 3.2 litemall-wx
 
@@ -347,7 +370,7 @@ var WxApiRoot = 'http://localhost:8082/wx/';
         });
 ```
 
-### 3.2.4 storage使用
+### 3.2.4 storage
 
 litemall-wx模块采用storage来存储一些数据,以及支持组件间数据通信。
 
@@ -369,14 +392,14 @@ renard-wx是另外一个小程序前端,其后端API也是litemall-wx-api。
 1. 界面样式有所调整;
 2. 功能进一步简化。
 
-## 3.4 开发新功能
+## 3.4 开发新组件
 
 本章节介绍如何开发新的微信小程序功能。
 
-### 3.4.1 小商场页面开发
+### 3.4.1 小商场前端页面
 
-### 3.4.2 交互服务API设计
+### 3.4.2 前后端交互服务API
 
-### 3.4.3 后台服务开发
+### 3.4.3 小商场后端服务
 
 ### 3.4.4 数据库