# 3 litemall小商城

技术：

* 小商城前端，即litemall-wx模块
  * 微信小程序
* 小商城后端，即litemall-wx-api模块
  * Spring Boot 1.5.10
  * Spring MVC
  * [weixin-java-tools](https://gitee.com/binary/weixin-java-tools)


目前发现需要完善的：

* 支付功能
* 优惠券功能
* 商品搜索
* 进一步区分商品和货品的关系
* 地址优化，目前每一次点击都会请求后台，应该缓存已有的数据
* 商品数量和规格中，如果货品数量不足，则显示不能点击的效果
* 商品好评计算与显示

## 3.1 litemall-wx-api

### 3.1.1 业务

#### 3.1.1.1 运费计算

订单费用小于88时，则需要运费8元；
否则运费0元。

目前运费8元是写在后台代码中，未来可能允许设置管理员设置其他值；
或者采用更加符合实际情况的运费计算方式。

### 3.1.2 安全

#### 3.1.2.1 Token

用户登录成功以后，后端会返回`token`，之后用户的请求都会携带token。

目前token的失效和跟新机制没有涉及。

#### 3.1.2.2 CROS

如果litemall-admin-api不配置CROS，则Spring Boot会失败。
但是，这里litemall-wx-api没有配置CROS，Spring Boot却不会报错，需要进一步研究。

#### 3.1.2.3 账号密码加盐

如果是微信登录，那么无需账号和密码。

而如果用户采用了账号和密码的形式登录，那么后端需要把用户密码加盐。

#### 3.1.2.4 限制登录

如果采用账号密码登录，那么登录失败一定次数，应该限制登录。

进一步地，如果项目启用了短信功能，应该短信提醒用户，防止他人登录。

目前这里没有实现，仅列出。

### 3.1.3 支付

准备采用weixin-java-tools工具简化微信支付代码的开发。
由于需要商户相关信息，目前没有开发。

## 3.2 litemall-wx

这里的代码基于[nideshop-mini-program](https://gitee.com/tumobi/nideshop-mini-program)，但是做了一定的修改：

* 数据属性名称调整，原项目中数据属性名称是下划线法命名（例如goods_id），而这里采用骆驼式命名法（例如goodsId），因此代码中需要进行相应调整；
* 代码清理重构，删除了一些目前不必要的文件，梳理一些逻辑功能；
* BUG修补，修改了一些错误；
* 功能完善拓展，例如商品立即购买功能、商品评价功能；

具体变化可以采用工具进行对比。

注意
> 目前litemall-wx项目代码基于nideshop-mini-program的commit版本[acbf6276eb27abc6a48887cddd223d7261f0088e](https://github.com/tumobi/nideshop-mini-program/commit/acbf6276eb27abc6a48887cddd223d7261f0088e)。由于改动变化较大，因此之后litemall-wx将独立开发，nideshop-mini-program的跟新不一定会合并到litemall-wx中。

### 3.2.1 业务API切换

业务API存放在`config/api.js`。

但是可以发现这样的代码：

```
// 本机开发时使用
var WxApiRoot = 'http://localhost:8082/wx/';
// 局域网测试使用
// var WxApiRoot = 'http://192.168.0.101:8082/wx/';
// 云平台部署时使用
//  var WxApiRoot = 'http://122.152.206.172:8082/wx/';
```

也就是说这里存在三种类型的API服务地址，这里是考虑到开发存在三种情况：

1. 本机开发时，localhost是当前开发机的地址；
2. 手机预览时，192.168.0.101是开发机的IP地址；
3. 当后台部署在云主机中时，122.152.206.172是云主机的IP地址；
4. 此外，更最重要的是，如果小程序正式部署时，这里的地址必须是域名，
而不能是IP地址。

因此，开发阶段用户可以按照具体情况切换1，2或3的选项。

### 3.2.2 登录

按照官方文档，开发者采用`wx.login`方法即可实现登录操作；
然而，由于`wx.login`只能返回临时登录凭证`code`，从服务器也只能返回对应的sessionId,
因此虽然已经可以视作登录，但是在小程序中不能显示有意义的登录状态，
因此实际很多小程序是继续采用`wx.getUserInfo`来进一步请求用户信息。

因此本模块中，用户的登录状态也是由`wx.login`和`wx.getUserInfo`组成。

#### 3.2.2.1 登录检测

用户可以采用`user.checkLogin`来检查是否`已登录`，而其检测逻辑是：

1. 可以从storage获取`userInfo`和`token`
2. 同时`wx.checkSession`也成功。

但是如果每次都使用`checkLogin`可能也不太好，因此目前机制是：
1. 应用启动时就检测一次，如果登录则设置app.globalData.hasLogin为已登录状态;
之后，其他页面只要查看这个状态即可知道目前是否已登录；
2. 此外，如果后台token过期返回401代码时，则及时清除过期的登录状态信息；
而用户登录失败时则app.globalData.hasLogin为未登录状态。

注意：
> 这里的逻辑可能有点乱。。。，但是目前实际效果看没有问题。

#### 3.2.2.2 登录时机

登录请求用户信息的时机存在两种设计：

1. 一种是小程序加载时，即申请用户信息，这种实现较简单；
2. 另外一种是小程序加载时不需要，但是小程序用户需要真正用户信息时才申请用户信息，
而这种实现较复杂。

目前采用第二张实现，可以分成两种情况：

* 用户主动登录

  用户主动登录，指的是`我的`页面中用户没有登录显示`点击登录`的效果。

* 用户被动登录

  用户被动登录，指的是用户想购买商品或者需要用户登录才能操作的行为，
  此时因为向服务器请求时token没有设置，因此服务器拒绝用户的请求，同时返回`401`业务代码。
 
  目前需要检测用户登录的页面有:
   
   * 购物车
   * 我的主页

讨论:
> 对于第二张情况，原nideshop-mini-program项目是采取一种自动登录的方式。
> 这里则采用跳转登录页面的方式。

#### 3.2.2.3 登录操作

如前面讨论，这里的登录操作实际包含两个操作`wx.login`和`wx.getUserInfo`。
用户可以采用`user.loginByWeixin`来进行登录操作。

按照官网文档，用户登录前应该检测以下，来避免频繁无意义的登录操作，
因此较合适的做法如下所示:

```
    user.checkLogin().catch(() => {

      user.loginByWeixin().then(res => {
        this.setData({
          userInfo: res.data.userInfo,
        });
      }).catch((err) => {
        util.showErrorToast('登录失败');
      });

    });
```

#### 3.2.2.4 登录拒绝授权

还存在一个问题，当用户登录时，会出现"微信授权"的对话框。
如果用户选择”拒绝“，那么之后用户的登录操作总是失败的。

目前的做法是，用户拒绝授权后，如果再次登录，则：
1. 弹出对话框，请求用户授权
2. 如果用户仍然拒绝，则返回
3. 如果用户接受授权，则弹出系统权限配置页面，等待用户给与授权。

### 3.2.3 立即购买和放入购物车

### 3.2.3 

### 3.2.4 storage使用

本模块中采用storage来存储一些数据，以及组件间进行通信。

#### 3.2.4.1 userInfo和token

#### 3.2.4.2 cartId

#### 3.2.4.3 addressId