mirror of
https://gitee.com/ShopeX/ECShopX
synced 2026-08-10 05:16:04 +08:00
8
docs/docs/deploy_prepare_appoint.md
Normal file
8
docs/docs/deploy_prepare_appoint.md
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
url: deploy_prepare_appoint
|
||||
---
|
||||
|
||||
# 约定
|
||||
|
||||
- 部署文档以源源客官方平台作为例子, 域名为: yuanyuanke.cn
|
||||
-
|
||||
44
docs/docs/deploy_prepare_domain.md
Normal file
44
docs/docs/deploy_prepare_domain.md
Normal file
@@ -0,0 +1,44 @@
|
||||
---
|
||||
url: deploy_prepare_domain
|
||||
---
|
||||
|
||||
# 域名
|
||||
|
||||
<a name="ff8ccd26"></a>
|
||||
## SSL证书
|
||||
> ssl证书, 对网站传输的数据可以进行SSL加密,包括用户名,密码等等,防止窃取和篡改。并且网站安装SSL证书后,在浏览器地址栏可以显示一个安全锁,告诉用户你的网站是安全的。SSL证书是数字证书的一种,类似于驾驶证、护照和营业执照的电子副本。因为配置在服务器上,也称为SSL服务器证书。
|
||||
|
||||
|
||||
|
||||
|
||||
> **ECShopX需要购买通配型ssl证书(泛域名型ssl证书).
|
||||
|
||||
**
|
||||
|
||||
<a name="f9439f4a"></a>
|
||||
## 域名规划域名规划
|
||||
|
||||
为了表述方便, 以域名_b.yuanyuanke.cn_做例子.
|
||||
|
||||
- https://b.yuanyuanke.cn api/商家后台域名
|
||||
- https://h5.yuanyuanke.cn h5访问域名
|
||||
- https://pc.yuanyuanke.cn pc访问域名
|
||||
- https://b-import-cdn.yuanyuanke.cn 上传文件cdn域名
|
||||
- https://b-cdn.yuanyuanke.cn 后台前端的相关 css js 资源cdn域名
|
||||
- https://b-img-cdn.yuanyuanke.cn 图片cdn域名
|
||||
|
||||
<a name="FAQ"></a>
|
||||
## FAQ
|
||||
|
||||
- 为什么必须要使用SSL证书
|
||||
<br />其一SSL证书作为电商领域保证客户信息安全的重要手段. 其二微信小程序 公众号 苹果商店等对于安全性的要求越来越高, 微信小程序是必须SSL才可以, 其它场景也陆续增加限制. 其三, C端用户对于安全的意识也越来越强, 有些客户对于没有小锁头的电商网站有抵触.
|
||||
- 是否可以选择免费的SSL?
|
||||
<br />尽量避免使用免费的SSL, 免费的SSL通常不支持**通配符型SSL证书**/**泛域名SSL证书**, 本文档相关部署以支持_通配符型SSL证书_为准.
|
||||
- 对于收费的SSL证书应该如何选择?
|
||||
- 云盾证书服务
|
||||
- SSL去哪里买?
|
||||
<br />主流的云供应商都有, 阿里的云盾
|
||||
|
||||
<a name="bKVjD"></a>
|
||||
##
|
||||
|
||||
35
docs/docs/deploy_prepare_domain_record.md
Normal file
35
docs/docs/deploy_prepare_domain_record.md
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
url: deploy_prepare_domain_record
|
||||
---
|
||||
|
||||
# 域名备案
|
||||
|
||||
根据 《互联网信息服务管理办法》 以及 《非经营性互联网信息服务备案管理办法》 ,国家对非经营性互联网信息服务实行备案制度,对经营性互联网信息服务实行许可制度。未取得许可或者未履行备案手续的,不得从事互联网信息服务。即所有对中国大陆提供服务的网站都必须先进行 ICP 备案,才可开通服务。阿里云ICP代备案系统为您提供申请备案、修改注销备案信息、认领备案等功能。
|
||||
|
||||
> **如果由商派提供采购阿里云服务器, 可以选用我们的备案服务.**<br />
|
||||
|
||||
|
||||
<a name="61fe3c73"></a>
|
||||
## 阿里云备案
|
||||
|
||||
[阿里云备案](https://beian.aliyun.com)
|
||||
|
||||
<a name="eebf8b79"></a>
|
||||
## 腾讯云备案
|
||||
|
||||
[腾讯云备案](https://cloud.tencent.com/product/ba)
|
||||
|
||||
<a name="a2e173ea"></a>
|
||||
## 微软云(中国)
|
||||
|
||||
[微软云备案](https://www.azure.cn/zh-cn/support/icp/icp-new/)
|
||||
|
||||
<a name="50cca03c"></a>
|
||||
## 华为云备案
|
||||
|
||||
[华为云备案](https://support.huaweicloud.com/pi-icp/zh-cn_topic_0115820080.html)
|
||||
|
||||
<a name="faf6cf75"></a>
|
||||
## 网易云备案
|
||||
|
||||
[网易云备案](https://www.163yun.com/help/documents/15588222030344192)
|
||||
256
docs/docs/deploy_prepare_implementation.md
Normal file
256
docs/docs/deploy_prepare_implementation.md
Normal file
@@ -0,0 +1,256 @@
|
||||
---
|
||||
url: deploy_prepare_implementation
|
||||
---
|
||||
|
||||
# ECShopX初始化
|
||||
|
||||
> **本文档引自ECShopX操作手册. 前半部分为数据初始化及上线前准备工作, 因此罗列在此处.**
|
||||
>
|
||||
|
||||
> **目前本文档仅有Word版, 如需要可向售后人员索要.**
|
||||
|
||||
<a name="OobJ2"></a>
|
||||
### 开通EcshopX
|
||||
|
||||
|
||||
<a name="7t47E"></a>
|
||||
### 注册开放平台以及创建第三方平台
|
||||
|
||||
|
||||
<a name="ee3c7775"></a>
|
||||
### 申请服务号并且认证
|
||||
> 不能是订阅号
|
||||
|
||||
|
||||
|
||||
<a name="C0hNt"></a>
|
||||
### 申请小程序并且认证
|
||||
> 可以通过服务号快速申请小程序,这样可以避免主体不一致带来的麻烦
|
||||
|
||||
|
||||
|
||||
<a name="JgdDj"></a>
|
||||
### 申请微信支付
|
||||
> 小程序支付、JSAPI支付、h5支付
|
||||
> 按您的业务需求申请,如果只有小程序则只需要开通小程序支付即可
|
||||
|
||||
|
||||
|
||||
> 在接入微信支付过程中,会出现APPID、MCH_ID、公众平台、开放平台、商户平台等概念,下面仅从微信支付的角度来做简单分析:
|
||||
>
|
||||
|
||||
> 
|
||||
|
||||
>
|
||||
|
||||
|
||||
> **● 公众平台([mp.weixin.qq.com](https://mp.weixin.qq.com/)):**注册、配置服务号、订阅号、小程序的入口,注册成功后系统就会下发一个与之一一对应的APPID(其中订阅号的APPID不支持申请和使用微信支付)。
|
||||
|
||||
>
|
||||
|
||||
|
||||
> **● 商户平台([ pay.weixin.qq.com](https://pay.weixin.qq.com/)):**微信支付业务管理中心,商户可以在商户平台进行所有支付业务相关操作,例如退款、下载对账单、查询订单、提现、账号绑定、API证书下载、API密钥设置、查看证书序列号等操作。
|
||||
|
||||
>
|
||||
|
||||
|
||||
> **● 开放平台([open.weixin.qq.com](https://open.weixin.qq.com/)):**注册、配置APP移动应用、网站应用的入口,注册成功后系统就会下发一个与之一一对应的APPID。
|
||||
|
||||
>
|
||||
|
||||
|
||||
> **● APPID:**在公众平台或开放平台申请注册之后由平台下发,在支付接口中通常作为配置参数,必须上传。
|
||||
|
||||
>
|
||||
|
||||
|
||||
> **● MCH_ID:**在公众平台、开放平台申请微信支付成功后由微信支付下发,或者直接在商户平台注册也可获得MCH_ID,在支付接口中通常作为配置参数,必须上传。
|
||||
|
||||
>
|
||||
|
||||
|
||||
> 注意: 支付接口要求APPID与MCH_ID必须有绑定关系,在商户平台注册获得的MCH_ID需要在【商户平台—>产品中心—>APPID授权管理】菜单下与APPID进行绑定后方可使用。
|
||||
|
||||
<a name="f88sS"></a>
|
||||
###
|
||||
<a name="UlRPA"></a>
|
||||
### ECShopX授权绑定服务号
|
||||
> 管理员才能授权
|
||||
|
||||
|
||||
|
||||
<a name="MhZNP"></a>
|
||||
### ECShopX授权绑定小程序
|
||||
> 管理员才能授权
|
||||
|
||||
<br />
|
||||
<a name="rX3lg"></a>
|
||||
### 小程序模板开发
|
||||
> 与开发普通小程序一致,开发者在开发工具上开发好相关的业务逻辑之后,在项目页卡中提交预览即可以在微信中查看小程序的真实表现。
|
||||
|
||||
> 有所不同的是,第三方平台小程序的提交上传是上传至该第三方平台的 open 帐号下的模板草稿箱中,该平台的管理员需要自行对该模板进行相应的设置,更多请参考 [开放平台的文档](https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1489144594_DhNoV&token=&lang=zh_CN) 。
|
||||
|
||||
<a name="dv3WC"></a>
|
||||
### 上架小程序须知
|
||||
> 第三方平台帮助旗下已授权的小程序进行代码管理时,需先开发完成小程序模板,再将小程序模板部署到旗下小程序帐号中,具体流程如下:
|
||||
|
||||
> **第一步:绑定开发小程序**
|
||||
|
||||
> (1)第三方平台的开发人员需先到微信公众平台(mp.weixin.qq.com)申请一个普通的小程序并完善小程序的头像、昵称、简介、服务类目等信息。
|
||||
|
||||
> (2)进入微信开放平台,在第三方平台详情中,将该小程序添加为**开发小程序**。
|
||||
|
||||
> **注意:** 绑定为开发小程序后,该小程序的在开发工具中上传,代码会直接上传到开放平台,不会上传到公众平台。
|
||||
|
||||
> **第二步:小程序模板的开发和上传**
|
||||
|
||||
> 使用开发小程序的开发者微信号登录[微信开发者工具](https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html),开发者工具中按照正常的小程序开发流程进行代码开发和调试。开发完成后,在开发工具中点击上传。使用详见:[**第三方平台代开发小程序**](https://developers.weixin.qq.com/miniprogram/dev/devtools/ext.html)
|
||||
|
||||
> **第三步:添加到小程序模板库,获得模板 ID**
|
||||
|
||||
> 从开发者工具中上传的代码,会先存在草稿箱中,每个开发小程序只保留最新一份上传记录。开发者可将草稿箱中的代码添加到小程序模板库中,小程序模板库中的模板不会被覆盖。最多可以有200个代码模板,添加后可以获得模板 ID(TemplateID)。
|
||||
|
||||
> **第四步:调用接口,为旗下授权的小程序部署代码**
|
||||
|
||||
> 具体接口详见“代码管理”文档中的接口。
|
||||
|
||||
> **重点提示:**
|
||||
|
||||
> 小程序授权托管之后,只能使用第三方平台的在微信开放平台登记的服务器地址。所以第三方平台在帮助旗下公众号发布代码之前,需先把服务器地址设置到小程序的服务器地址中,设置接口详见“修改服务器地址”文档中的接口。
|
||||
|
||||
<!--
|
||||
|
||||
<a name="ccf3d27d"></a>
|
||||
## 微信支付配置
|
||||
|
||||
|
||||
<a name="0aeca07a"></a>
|
||||
## 基础设置
|
||||
|
||||
|
||||
<a name="818c8a91"></a>
|
||||
### 新增运费模版
|
||||
|
||||
|
||||
<a name="5782b6ea"></a>
|
||||
### 商品管理
|
||||
|
||||
|
||||
<a name="b56f8d93"></a>
|
||||
#### 新增商品品牌
|
||||
|
||||
|
||||
<a name="8dca0e3f"></a>
|
||||
#### 新增商品规格
|
||||
|
||||
|
||||
<a name="8686bbbf"></a>
|
||||
#### 商品参数
|
||||
|
||||
|
||||
<a name="7b40f744"></a>
|
||||
#### 商品主目录
|
||||
|
||||
|
||||
<a name="aa3736f4"></a>
|
||||
##### 商品类目关联规格、参数
|
||||
|
||||
|
||||
<a name="ea4da67d"></a>
|
||||
##### 关联规格
|
||||
|
||||
|
||||
<a name="804a1f6b"></a>
|
||||
##### 关联参数
|
||||
|
||||
|
||||
<a name="41be0e36"></a>
|
||||
#### 新增商品分类
|
||||
|
||||
|
||||
<a name="23b8e6c3"></a>
|
||||
#### 商品录入
|
||||
|
||||
|
||||
<a name="b944dbc4"></a>
|
||||
#### 商品会员价
|
||||
|
||||
|
||||
<a name="ba7290ac"></a>
|
||||
#### 批量处理
|
||||
|
||||
|
||||
<a name="f2827c2c"></a>
|
||||
## 会员卡
|
||||
|
||||
|
||||
<a name="7b1bd4f7"></a>
|
||||
### 普通等级
|
||||
|
||||
|
||||
<a name="27cbae87"></a>
|
||||
### 付费等级
|
||||
|
||||
|
||||
<a name="21352a1f"></a>
|
||||
### 付费等级会员卡延期
|
||||
|
||||
|
||||
<a name="e9cc0a19"></a>
|
||||
### 会员导出
|
||||
|
||||
|
||||
<a name="2f36359e"></a>
|
||||
## 优惠券
|
||||
|
||||
|
||||
<a name="9268f91e"></a>
|
||||
### 折扣券
|
||||
|
||||
|
||||
<a name="607c87ab"></a>
|
||||
### 代金券
|
||||
|
||||
|
||||
<a name="8bc752db"></a>
|
||||
### 兑换券
|
||||
|
||||
|
||||
<a name="b017e964"></a>
|
||||
## 会员营销
|
||||
|
||||
|
||||
<a name="3cc026e1"></a>
|
||||
### 会员标签
|
||||
|
||||
|
||||
<a name="dfa3625e"></a>
|
||||
### 群发优惠券
|
||||
|
||||
|
||||
<a name="43e10b7a"></a>
|
||||
### 群发短信
|
||||
|
||||
|
||||
<a name="66833906"></a>
|
||||
### 新客营销
|
||||
|
||||
|
||||
<a name="91fa9bc1"></a>
|
||||
#### 赠送优惠券
|
||||
|
||||
|
||||
<a name="811077e4"></a>
|
||||
#### 赠送付费会员卡
|
||||
|
||||
|
||||
<a name="1f53fac2"></a>
|
||||
#### 赠送积分
|
||||
|
||||
|
||||
<a name="57605093"></a>
|
||||
## 商城小程序模版装修
|
||||
|
||||
|
||||
<a name="95456b09"></a>
|
||||
## 客服设置 -->
|
||||
7
docs/docs/deploy_prepare_lbs.md
Normal file
7
docs/docs/deploy_prepare_lbs.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
url: deploy_prepare_lbs
|
||||
---
|
||||
|
||||
# 腾讯位置服务
|
||||
|
||||
[接入步骤](https://lbs.qq.com/guides/startup.html)
|
||||
17
docs/docs/deploy_prepare_license.md
Normal file
17
docs/docs/deploy_prepare_license.md
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
url: deploy_prepare_license
|
||||
---
|
||||
|
||||
# 域名备案
|
||||
|
||||
如果由商派提供采购阿里云服务器, 可以选用我们的备案服务.
|
||||
|
||||
<a name="61fe3c73"></a>
|
||||
## 阿里云备案
|
||||
|
||||
[阿里云备案](https://beian.aliyun.com)
|
||||
|
||||
<a name="eebf8b79"></a>
|
||||
## 腾讯云备案
|
||||
|
||||
[腾讯云备案](https://cloud.tencent.com/product/ba)
|
||||
168
docs/docs/deploy_prepare_open_weixin.md
Normal file
168
docs/docs/deploy_prepare_open_weixin.md
Normal file
@@ -0,0 +1,168 @@
|
||||
---
|
||||
url: deploy_prepare_open_weixin
|
||||
---
|
||||
|
||||
# 微信开放平台第三方平台申请
|
||||
|
||||
<a name="b66b8eaa"></a>
|
||||
## 注册微信开放平台账号
|
||||
|
||||
<br />[注册微信平台注册](https://open.weixin.qq.com/cgi-bin/readtemplate?t=regist/regist_tmpl&lang=zh_CN)<br />
|
||||
|
||||
<a name="d7b8487d"></a>
|
||||
## 开发者资质认证
|
||||
|
||||
<br />[第三方平台申请流程](https://open.weixin.qq.com/cgi-bin/frame?t=home/wx_plugin_tmpl&lang=zh_CN)<br />
|
||||
<br /><br />
|
||||
<br />点击_`开发者资质认证`_, 并进行认证.<br />
|
||||
|
||||
> 开发者资质认证介绍
|
||||
> 微信开放平台帐号的开发者资质认证提供更安全、更严格的真实性认证、也能够更好的保护企业及用户的合法权益<br />开发者资质认证通过后,微信开放平台帐号下的应用,将获得微信登录、智能接口、第三方平台开发等高级能力<br />审核费用:中国大陆地区:300元,非中国大陆地区:99美元
|
||||
|
||||
|
||||
<br />认证时间大概2-3天, 已微信实际认证时间为准<br />
|
||||
|
||||
<a name="bcce70b7"></a>
|
||||
## 创建第三方平台
|
||||
|
||||
<br />管理中心->第三方平台<br />
|
||||
<br /><br />
|
||||
<br />点击_`创建第三方平台`_<br />
|
||||
|
||||
<a name="a2890803"></a>
|
||||
## 输入基本信息
|
||||
|
||||
<br />平台类型选择_**`平台型服务商`**_<br />
|
||||
<br /><br />
|
||||
|
||||
<a name="b17be281"></a>
|
||||
## 选择权限
|
||||
|
||||
<br />公众号权限<br />
|
||||
<br /><br /><br />
|
||||
<br />小程序权限<br />
|
||||
<br /><br />
|
||||
|
||||
<a name="eeac4e56"></a>
|
||||
## 填写开发资料
|
||||
|
||||
<br />为了表述方便, 下文将以主域名_yuanyuanke.cn_为例。实际部署时根据您的域名进行修改,并且您的域名是要https的。<br />
|
||||
|
||||
<a name="A3eVR"></a>
|
||||
#### 授权流程相关
|
||||
|
||||
|
||||
- 登录授权的发起页域名:_ b.yuanyuanke.cn_
|
||||
|
||||
|
||||
|
||||
> 必须从本域名内网页跳转到登录授权页,才可完成登录授权。无需填写`https://等域名协议前缀`。
|
||||
|
||||
|
||||
|
||||
- 授权测试公众号列表: gh_************
|
||||
|
||||
|
||||
|
||||
> 在全网发布之前,仅该列表内公众号才可进行授权(包含测试小程序),以便测试。请填写公众号的原始ID(可在公众平台网站的公众号设置页找到),最多10个,以英文“;”隔开。
|
||||
|
||||
|
||||
|
||||
- 授权事件接收URL: _b.yuanyuanke.cn/wechatAuth/events_
|
||||
|
||||
|
||||
|
||||
> 用于接收取消授权通知、授权成功通知、授权更新通知,也用于接收ticket,ticket是验证平台方的重要凭据。
|
||||
> 并且选择https协议头。
|
||||
|
||||
|
||||
|
||||
<a name="QGqHD"></a>
|
||||
#### 授权后实现业务
|
||||
|
||||
|
||||
- 消息校验Token: qwn2891ktj024
|
||||
|
||||
|
||||
|
||||
> 开发者在代替公众号或小程序接收到消息时,用此Token来校验消息。可以自定义。
|
||||
> **消息校验Token前后, 绝不能有空格**
|
||||
|
||||
|
||||
|
||||
- 消息加解密Key: sklfjkfgeiawwwqvn65997wlj01ndnfoqoe8x2k0nck
|
||||
|
||||
|
||||
|
||||
> 在代替公众号或小程序收发消息过程中使用。必须是长度为43位的字符串,只能是字母和数字。可以自定义。
|
||||
> **消息加解密Key前后, 绝不能有空格. 长度必须43位<br />**
|
||||
|
||||
|
||||
|
||||
- 消息与事件接收URL: _b.yuanyuanke.cn/wechatAuth/callback/$APPID$_
|
||||
|
||||
|
||||
|
||||
> 通过该URL接收公众号或小程序消息和事件推送,该参数按规则填写(需包含/$APPID$,如www.abc.com/$APPID$/callback),实际接收消息时$APPID$将被替换为公众号或小程序AppId。
|
||||
|
||||
|
||||
|
||||
- 公众号开发域名: _b.yuanyuanke.cn_
|
||||
|
||||
|
||||
|
||||
> 第三方平台在代公众号做网页授权、调用JS SDK等网页开发工作时所用的域名,以;隔开。为了满足开发者管理需要,符合以下要求的下级域名也将生效:$APPID$.wx.abc.com($APPID$为公众号的AppID的替换符)<br />请**下载校验文件**,并将文件放置在域名根目录下,例如wx.qq.com,并确保可以访问该文件。<br />每月可提交修改申请3次,本月有3次机会。不需要填写https协议头。
|
||||
|
||||
|
||||
|
||||
- 小程序服务器域名: _b.yuanyuanke.cn;b-websocket.yuanyuanke.cn;mmbiz.qpic.cn;wx.qlogo.cn;b-img-cdn.yuanyuanke.cn;up.qiniup.com;up-z1.qiniup.com;up-z2.qiniup.com;up-na0.qiniup.com;up-as0.qiniup.com;thirdwx.qlogo.cn_
|
||||
|
||||
|
||||
|
||||
> 第三方平台旗下授权的小程序,只可配置本平台服务器域名列表中的域名,以;隔开。<br />每月可提交修改申请3次,本月有2次机会。
|
||||
|
||||
|
||||
|
||||
> **需要访问的小程序服务器域名, 同时需要后端接口b.yuanyuanke.cn 和 websocket服务: b-websocket.yuanyuanke.cn。这里主要就是您的网站域名,其他还有图片相关域名(七牛,阿里OSS的相关域名,原始域名或者cdn域名),websocket域名(如果用到),微信官方素材域名**
|
||||
|
||||
|
||||
|
||||
- 小程序业务域名: **无需填写**
|
||||
|
||||
|
||||
|
||||
> 请**下载校验文件**,并将文件放置在域名根目录下,例如wx.qq.com,并确保可以访问该文件。<br />每月可提交修改申请3次,本月有3次机会
|
||||
|
||||
|
||||
|
||||
<a name="VVMkM"></a>
|
||||
#### 其他
|
||||
|
||||
|
||||
- 白名单IP地址列表: 47.115.75.92;
|
||||
|
||||
|
||||
|
||||
> 仅当开发者IP地址在该列表中时,才被允许调用相关接口。最多填写100个IP地址,以英文“;”隔开。
|
||||
|
||||
|
||||
|
||||
> **服务器出口ip地址, 如果是vpc. 否则访问微信接口会被拒**
|
||||
|
||||
**
|
||||
<a name="z2igl"></a>
|
||||
#### 开发资料综合截图
|
||||
<br />
|
||||
|
||||
<a name="19401cf2"></a>
|
||||
## 获取APPSECRET
|
||||
|
||||
<br />获取appsecret(微信开放平台管理中心的第三方平台详情页中的AppID和AppSecret)。<br />示例:<br />
|
||||
<a name="7e548143"></a>
|
||||
## 绑定开发者小程序
|
||||
|
||||
<br />微信开放平台管理中心的**第三方平台详情页**的**开发配置**里添加开发小程序。<br />同时在对应的小程序**添加开发者**。<br />**建议开发小程序和您的实际授权小程序用同一个**,避免一些异常问题。<br />示例:<br />
|
||||
<a name="c07f7d53"></a>
|
||||
## 开放平台绑定小程序
|
||||
|
||||
<br />微信开放平台管理中心的小程序中去绑定小程序。用于保证unionid一致。<br />
|
||||
64
docs/docs/deploy_prepare_qiniu.md
Normal file
64
docs/docs/deploy_prepare_qiniu.md
Normal file
@@ -0,0 +1,64 @@
|
||||
---
|
||||
url: deploy_prepare_qiniu
|
||||
---
|
||||
|
||||
# 七牛
|
||||
|
||||
<a name="b59c9e0f"></a>
|
||||
## 概念
|
||||
|
||||
<a name="cdn"></a>
|
||||
### cdn
|
||||
|
||||
> CDN的全称是Content Delivery Network,即内容分发网络。CDN是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。CDN的关键技术主要有内容存储和分发技术。
|
||||
|
||||
|
||||
<a name="9e236b4b"></a>
|
||||
### 开放存储服务 OSS
|
||||
|
||||
> 开放存储服务(OpenStorageService,简称OSS),是云对外提供的海量,安全,低成本,高可靠的云存储服务。用户可以通过简单的API(REST方式的接口),在任何时间、任何地点、任何互联网设备上进行数据上传和下载 保存js, ccs, 图片等静态资源
|
||||
|
||||
|
||||
<a name="3deda530"></a>
|
||||
### 七牛云
|
||||
|
||||
[七牛云](https://www.qiniu.com)
|
||||
|
||||
> 七牛云是国内领先的企业级公有云服务商,致力于打造以数据为核心的场景化PaaS服务。围绕富媒体场景,七牛先后推出了对象存储,融合CDN加速,数据通用处理,内容反垃圾服务,以及直播云服务等。目前,七牛云已经在为 50多万家企业提供服务, 亲历互联网创新创业发展的同时,也深入理解传统企业转型过程中的云服务需求场景,推出了有针对性的一系列行业解决方案
|
||||
|
||||
|
||||
<a name="f947a646"></a>
|
||||
## 创建存储空间
|
||||
|
||||
<a name="espier-vue"></a>
|
||||
### espier-vue
|
||||
|
||||
用来存储前端的 css js 及静态图片等
|
||||
|
||||
- 存储空间(bucket): espier-vue
|
||||
- 融合 CDN 加速域名: [https://b-cdn.yuanyuanke.cn](https://b-cdn.yuanyuanke.cn)
|
||||
- 访问控制: 公开空间
|
||||
|
||||
<a name="espier-import-files"></a>
|
||||
### espier-import-files
|
||||
|
||||
用来存储系统导入 导出的相关数据
|
||||
|
||||
- 存储空间(bucket): espier-import-files
|
||||
- 融合 CDN 加速域名: [https://b-import-cdn.yuanyuanke.cn](https://b-import-cdn.yuanyuanke.cn)
|
||||
- 访问控制: 私有空间
|
||||
|
||||
<a name="espier-images"></a>
|
||||
### espier-images
|
||||
|
||||
用来存储商品图片, video等资源
|
||||
|
||||
- 存储空间(bucket): espier-images
|
||||
- 融合 CDN 加速域名: [https://b-img-cdn.yuanyuanke.cn](https://b-img-cdn.yuanyuanke.cn)
|
||||
- 访问控制: 公开空间
|
||||
|
||||
<a name="FAQ"></a>
|
||||
## FAQ
|
||||
|
||||
- 怎么获取或者找到 Access Key 和 Secret Key
|
||||
<br />[怎么获取或者找到 Access Key 和 Secret Key](https://developer.qiniu.com/af/kb/1479/how-to-access-or-locate-the-access-key-and-secret-key)
|
||||
14
docs/docs/deploy_prepare_readme.md
Normal file
14
docs/docs/deploy_prepare_readme.md
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
url: deploy_prepare_readme
|
||||
---
|
||||
|
||||
# README.md
|
||||
|
||||
---
|
||||
|
||||
|
||||
<a name="fb3745ce"></a>
|
||||
## description: Shortcut keys allows an easy and quick method for navigating or editing con
|
||||
|
||||
<a name="88210852"></a>
|
||||
# 准备工作
|
||||
120
docs/docs/deploy_prepare_solution.md
Normal file
120
docs/docs/deploy_prepare_solution.md
Normal file
@@ -0,0 +1,120 @@
|
||||
---
|
||||
url: deploy_prepare_solution
|
||||
---
|
||||
|
||||
# 服务器方案
|
||||
|
||||
<a name="4c5c2fdb"></a>
|
||||
## 独立部署服务器方案
|
||||
|
||||

|
||||
|
||||
- 角色定义
|
||||
- 负载均衡: Load Balance
|
||||
- Web服务:<br />
|
||||
API服务
|
||||
- 队列:<br />
|
||||
可使用redis/rabbitmq
|
||||
- scheduler:<br />
|
||||
定时任务, 例如凌晨1点产生统计任务, 加入队列.
|
||||
- job:<br />
|
||||
处理队列中的任务
|
||||
- neo4j:<br />
|
||||
图数据库
|
||||
- redis:<br />
|
||||
Key-Value数据库
|
||||
- OSS:<br />
|
||||
对象存储, 存储文件/图片/视频
|
||||
- CDN:<br />
|
||||
CDN的全称是Content Delivery Network,即内容分发网络
|
||||
|
||||
<a name="86e79fca"></a>
|
||||
### 声明
|
||||
|
||||
- 本文方案所指皆为以阿里云, 其它云方方案可以此为基准.
|
||||
- 数据库建议使用RDS. 如果不使用RDS, 请做好备份方案, 以免误操作造成数据丢失.
|
||||
|
||||
<a name="03b54f13"></a>
|
||||
### 入门级方案
|
||||
|
||||
- ECS1台 4核8g 100g高速硬盘<br />
|
||||
部署 redis/neo4j/ecshopX(web/Job/scheduler)
|
||||
- RDS 2核4g
|
||||
- 七牛云 cdn 及 图片
|
||||
|
||||
方案简描述:
|
||||
|
||||
```
|
||||
入门级方案, 不考虑高可用, 仅作为业务刚刚开始, 初始量级不大的情况下.
|
||||
```
|
||||
|
||||
<a name="70c4464b"></a>
|
||||
### 标准方案
|
||||
|
||||

|
||||
|
||||
- 负载均衡
|
||||
- ECS3台 4核8g 100g高速硬盘
|
||||
- Web服务: ecs*2
|
||||
- 定时任务/job/redis/neo4j ecs*1
|
||||
- RDS: 2核4g
|
||||
|
||||
方案简描述:
|
||||
|
||||
```
|
||||
优点
|
||||
Web端提供两台服务器做负载均衡, 保证高可用. 队列任务分开部署, 将可异步处理的业务从前端业务中剥离, 后端的任务处理不影响API业务正常的相应. 一旦业务发生瓶颈, 可以方便增加Web机的数量, 提高RDS的配置. 以快速相应业务.
|
||||
|
||||
缺点
|
||||
任务机上部署了过多的服务, 当任务服务器负载过重时, 快速扩展不易.
|
||||
```
|
||||
|
||||
<a name="72c5a326"></a>
|
||||
### 进阶方案(根据业务侧重点调整方案配置)
|
||||
|
||||
- 负载均衡
|
||||
- ecs 4核8g 40g ssd硬盘 * 6
|
||||
- Web: ecs * 3
|
||||
- Job: ecs * 2
|
||||
- Scheduler/redis/neo4j: ecs * 1
|
||||
- RDS 2核4g 100g * 1 集群版 便于扩展主从
|
||||
- 七牛云 cdn 及 图片
|
||||
- 日志服务
|
||||
|
||||
<a name="422d97da"></a>
|
||||
### Kubernetes方案
|
||||
|
||||

|
||||
|
||||
- kubernetes 主节点: ecs 2核4g * 3
|
||||
- kubernetes node 工作节点: ecs 4核8g * 3
|
||||
- RDS 2核4g 100g * 1 集群版 便于扩展主从
|
||||
|
||||
<a name="fc9f6ae1"></a>
|
||||
## 私有云方案(kubernetes)
|
||||
|
||||
服务器托管在商派集群. 使用kubernetes集群方案.
|
||||
|
||||
<a name="f33c8e41"></a>
|
||||
### 入门方案(默认)
|
||||
|
||||
- 共享负载均衡
|
||||
- 5核5g 容器资源
|
||||
- RDS 2核4g 100g * 1
|
||||
- 七牛云 cdn 及 图片
|
||||
|
||||
<a name="70c4464b-1"></a>
|
||||
### 标准方案
|
||||
|
||||
- 独享负载均衡
|
||||
- ECS 4核8g 100g高速硬盘 * 2 (独享)
|
||||
- RDS 2核4g
|
||||
- 七牛云 cdn 及 图片
|
||||
|
||||
<a name="72c5a326-1"></a>
|
||||
### 进阶方案(根据业务侧重点调整方案配置)
|
||||
|
||||
- 独享负载均衡
|
||||
- ECS 4核8g 100g高速硬盘 * 6 (独享)
|
||||
- RDS 2核4g 100g * 1 集群版 便于扩展主从
|
||||
- 七牛云 cdn 及 图片
|
||||
77
docs/docs/deploy_prepare_wxa.md
Normal file
77
docs/docs/deploy_prepare_wxa.md
Normal file
@@ -0,0 +1,77 @@
|
||||
---
|
||||
url: deploy_prepare_wxa
|
||||
---
|
||||
|
||||
# 小程序
|
||||
|
||||
> **本文档引自ECShopX操作手册. 前半部分为数据初始化及上线前准备工作, 因此罗列在此处.**<br />
|
||||
|
||||
|
||||
|
||||
> **需确认好小程序的**_**管理员**_**。****后续很多其它操作员的操作都需要管理员微信扫码。例如添加开发者,小程序授权等**
|
||||
|
||||
|
||||
|
||||
<a name="Gz6C1"></a>
|
||||
#### 申请小程序
|
||||
|
||||
|
||||
> [https://kf.qq.com/faq/170109iQBJ3Q170109JbQfiu.html](https://kf.qq.com/faq/170109iQBJ3Q170109JbQfiu.html)
|
||||
>
|
||||
|
||||
> 如果您有服务号,建议直接从服务号后台走快速注册并认证小程序,避免主体搞错的情况发生
|
||||
> 
|
||||
|
||||
<a name="PWa57"></a>
|
||||
####
|
||||
<a name="DDDy1"></a>
|
||||
#### 小程序认证
|
||||
|
||||
|
||||
> [https://kf.qq.com/faq/170109F7ZVzq170109MnQRNN.html](https://kf.qq.com/faq/170109F7ZVzq170109MnQRNN.html)
|
||||
|
||||
<a name="UYJzk"></a>
|
||||
####
|
||||
<a name="hqkyd"></a>
|
||||
#### 添加开发者或者体验者
|
||||
|
||||
|
||||
> 登录小程序后。开发的时候都是在小程序开发者工具中进行开发,所以必须要开发者权限才能运行。体验成员则可以看小程序体验版。
|
||||
> 
|
||||
|
||||
|
||||
|
||||
<a name="R0WSY"></a>
|
||||
#### 获取小程序的APPID(小程序ID),原始ID
|
||||
|
||||
|
||||
> - 登录小程序后,点 _设置->基本设置_
|
||||
>
|
||||
__
|
||||
> - 拉到页面底部
|
||||
>
|
||||

|
||||
|
||||
|
||||
|
||||
<a name="rX3lg"></a>
|
||||
### 小程序模板开发
|
||||
> 与开发普通小程序一致,开发者在开发工具上开发好相关的业务逻辑之后,在项目页卡中提交预览即可以在微信中查看小程序的真实表现。
|
||||
> 有所不同的是,第三方平台小程序的提交上传是上传至该第三方平台的 open 帐号下的模板草稿箱中,该平台的管理员需要自行对该模板进行相应的设置,更多请参考 [开放平台的文档](https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1489144594_DhNoV&token=&lang=zh_CN) 。
|
||||
|
||||
<a name="dv3WC"></a>
|
||||
### 上架小程序须知
|
||||
> 第三方平台帮助旗下已授权的小程序进行代码管理时,需先开发完成小程序模板,再将小程序模板部署到旗下小程序帐号中,具体流程如下:
|
||||
> **第一步:绑定开发小程序**
|
||||
> (1)第三方平台的开发人员需先到微信公众平台(mp.weixin.qq.com)申请一个普通的小程序并完善小程序的头像、昵称、简介、服务类目等信息。
|
||||
> (2)进入微信开放平台,在第三方平台详情中,将该小程序添加为**开发小程序**。
|
||||
> **注意:** 绑定为开发小程序后,该小程序的在开发工具中上传,代码会直接上传到开放平台,不会上传到公众平台。
|
||||
> **第二步:小程序模板的开发和上传**
|
||||
> 使用开发小程序的开发者微信号登录[微信开发者工具](https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html),开发者工具中按照正常的小程序开发流程进行代码开发和调试。开发完成后,在开发工具中点击上传。使用详见:[**第三方平台代开发小程序**](https://developers.weixin.qq.com/miniprogram/dev/devtools/ext.html)
|
||||
> **第三步:添加到小程序模板库,获得模板 ID**
|
||||
> 从开发者工具中上传的代码,会先存在草稿箱中,每个开发小程序只保留最新一份上传记录。开发者可将草稿箱中的代码添加到小程序模板库中,小程序模板库中的模板不会被覆盖。最多可以有200个代码模板,添加后可以获得模板 ID(TemplateID)。
|
||||
> **第四步:调用接口,为旗下授权的小程序部署代码**
|
||||
> 具体接口详见“代码管理”文档中的接口。
|
||||
> **重点提示:**
|
||||
> 小程序授权托管之后,只能使用第三方平台的在微信开放平台登记的服务器地址。所以第三方平台在帮助旗下公众号发布代码之前,需先把服务器地址设置到小程序的服务器地址中,设置接口详见“修改服务器地址”文档中的接口。
|
||||
|
||||
6
docs/docs/dicucx.md
Normal file
6
docs/docs/dicucx.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
url: dicucx
|
||||
---
|
||||
|
||||
# php的readme
|
||||
|
||||
1343
docs/docs/el5sfv.md
Normal file
1343
docs/docs/el5sfv.md
Normal file
File diff suppressed because it is too large
Load Diff
21
docs/docs/fe4lti.md
Normal file
21
docs/docs/fe4lti.md
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
url: fe4lti
|
||||
---
|
||||
|
||||
# 架构说明
|
||||
|
||||
|
||||
|
||||
<a name="cTwYb"></a>
|
||||
## 软件架构
|
||||
后端开发语言:PHP 8.2<br />后端技术框架:采用 Lumen 开源框架开发,引入dingo作为接口管理,采用更符合大型项目的 Doctrine ORM 替换系统自带 ORM<br />前端开发语言:HTML5/CSS3/ES6/小程序开发框架<br />前端开发框架:VueJS,Taro<br />数据库:支持 MySQL/MariaDB/SqlServer等数据库<br />队列:支持 Redis/RabbitMQ/数据库 等方案,默认采用 Redis<br />缓存:支持 Redis/filesystem/memcached,默认采用 Redis<br />CDN/OSS:支持阿里云/七牛云<br />图形数据库:Neo4j(可选)<br />日志搜集:ELK/Sentry
|
||||
<a name="SoaeN"></a>
|
||||
## 数据处理能力
|
||||
支持 MySQL 读写分离模式,支持阿里云PolarDB。<br />在 5 机集群下支持 2000 每秒并发,其中订单占比 1%,且根据实际业务需求扩容<br />采用多级缓存机制,可以有效保证API响应时间在 2S 以内<br />系统具备按照终端,店铺,门店等权限控制<br />
|
||||
|
||||
<a name="igNAZ"></a>
|
||||
## 稳定性
|
||||
系统支持集群模式部署,可按照 web/schedule/worker 等不同角色部署,可有效保证系统高可用<br />支持阿里云 K8S 部署,可以通过HPA实现 POD 自动扩容,可有效保证在突发流量下,系统的高可用<br />采用事件机制,可以异步处理耗时业务逻辑,保证实时业务稳定性<br />采用多级缓存机制,nginx+memcache/php+redis 方式,在redis数据库宕机是,可由 nginx 缓存来替代,保证系统高可用。
|
||||
<a name="Qk1if"></a>
|
||||
## 持续集成
|
||||
系统采用 PHP 开发,支持二次开发<br />具备完善的开发环境(docker-compose)和测试环境构建脚本,可以快速搭建环境<br />采用基于 GitLab-CI/K8S/Helm/Helmfile 的持续集成方案
|
||||
51
docs/docs/fiytfx.md
Normal file
51
docs/docs/fiytfx.md
Normal file
@@ -0,0 +1,51 @@
|
||||
---
|
||||
url: fiytfx
|
||||
---
|
||||
|
||||
# 阿里云
|
||||
|
||||
进入 [https://oss.console.aliyun.com/bucket](https://oss.console.aliyun.com/bucket) 创建bucket。<br />
|
||||
|
||||
<a name="h29pS"></a>
|
||||
## 创建 espier-image 和 espier-vue(公共读)
|
||||
|
||||
|
||||
<a name="UTQO7"></a>
|
||||
### 一、创建 Bucket
|
||||
<br />
|
||||
|
||||
<a name="tNULn"></a>
|
||||
### 二、填写详细信息
|
||||
|
||||
<br /><br />
|
||||
|
||||
<a name="Zv52U"></a>
|
||||
### 三、进入详情页面配置
|
||||
|
||||
<br /><br />
|
||||
|
||||
<a name="jUZQ5"></a>
|
||||
### 四、创建跨域规则
|
||||
|
||||
<br /><br />
|
||||
<br />创建完成如下:<br />
|
||||
<br /><br />
|
||||
|
||||
<a name="Ytp9Z"></a>
|
||||
### 五、配置 CDN
|
||||
进入 cdn 管理界面 [https://cdn.console.aliyun.com/domain/list](https://cdn.console.aliyun.com/domain/list)<br />
|
||||
<br />
|
||||
<a name="k69o2"></a>
|
||||
### 六、域名解析
|
||||
CDN添加完成后,会在域名管理界面生成相应的CNAME,然后在域名解析后台添加相应的解析<br /><br />
|
||||
|
||||
<a name="ZHeb0"></a>
|
||||
## 创建 espier-import-files (私有)
|
||||
<a name="2nG6V"></a>
|
||||
### 一、创建
|
||||
<br />
|
||||
|
||||
> 私有存储不需要配置 cdn 和跨域
|
||||
|
||||
|
||||
|
||||
339
docs/docs/framework_architecture-repository.md
Normal file
339
docs/docs/framework_architecture-repository.md
Normal file
@@ -0,0 +1,339 @@
|
||||
---
|
||||
url: framework_architecture-repository
|
||||
---
|
||||
|
||||
# Repository
|
||||
|
||||
> **使用 Repository 辅助 Model**<br />
|
||||
|
||||
|
||||
若将数据库逻辑都写在 model,会造成 model 的肥大而难以维护,基于 SOLID 原则,我们应该使用 Repository 模式辅助 model,将相关的数据库逻辑封装在不同的 repository,方便中大型项目的维护。
|
||||
|
||||
<a name="c101406b"></a>
|
||||
## 数据库逻辑
|
||||
|
||||
在 CRUD 中,CUD 比较稳定,但 R 的部分则千变万化,大部分的数据库逻辑都在描述R 的部分,若将数据库逻辑写在 controller 或 model 都不适当,会造成 controller 与 model 肥大,造成日后难以维护。
|
||||
|
||||
<a name="Model"></a>
|
||||
## Model
|
||||
|
||||
如果使用 Eloquent ORM 来实现 Repository 模式,需要修改 model 不要包含数据库逻辑,仅保留以下部分:
|
||||
|
||||
- Property : 如$table,$fillable…等。
|
||||
- Mutator: 包括 mutator 與 accessor。
|
||||
- Method : relation 類的 method,如使用 hasMany() 與 belongsTo()。
|
||||
|
||||
简化后的Eloquent 的 model 类我们可以称之为`Eloquent Class`,由于继承了`Illuminate\Database\Eloquent\Model` 类,所以`Eloquent Class`仍然有很多方法可以操作数据库。
|
||||
|
||||
Eloquent Class 代码结构如下:
|
||||
|
||||
```php
|
||||
namespace MyBlog;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
/**
|
||||
* MyBlog\User
|
||||
*
|
||||
*/
|
||||
class User extends Model {
|
||||
|
||||
/**
|
||||
* The database table used by the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'users';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['name', 'email', 'password'];
|
||||
|
||||
/**
|
||||
* The attributes excluded from the model's JSON form.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $hidden = ['password', 'remember_token'];
|
||||
}
|
||||
```
|
||||
|
||||
而在 ECShopX 中,由于我们采用了 Doctrine ORM,其自带Repository模式。在 Doctrine ORM 中也有简化的 model 类: `Entity Class`。
|
||||
|
||||
相比 `Eloquent Class` `Entity Class` 更简单,其只包含 `protected` 或 `private`的属性和`getter` 和 `setter` 方法(在 JAVA 中,这种对象成为值对象)。
|
||||
|
||||
Entity Class 代码结构如下:
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace MyBlog;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="users")
|
||||
*/
|
||||
class User
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue
|
||||
*/
|
||||
protected $id;
|
||||
/**
|
||||
* @ORM\Column(type="string")
|
||||
*/
|
||||
protected $name;
|
||||
/**
|
||||
* @ORM\Column(type="string")
|
||||
*/
|
||||
protected $email;
|
||||
/**
|
||||
* @ORM\Column(type="string")
|
||||
*/
|
||||
protected $password;
|
||||
/**
|
||||
* @ORM\Column(type="string")
|
||||
*/
|
||||
protected $remember_token;
|
||||
// .. (other code getter setter )
|
||||
}
|
||||
```
|
||||
|
||||
<a name="Repository"></a>
|
||||
## Repository
|
||||
|
||||
初学者常会在 controller 直接调用 model 写数据库逻辑:
|
||||
|
||||
```php
|
||||
public function index()
|
||||
{
|
||||
$users = User::where('age', '>', 20)
|
||||
->orderBy('age')
|
||||
->get();
|
||||
|
||||
return view('users.index', compact('users'));
|
||||
}
|
||||
```
|
||||
|
||||
数据库逻辑是`获取 20 岁以上的用户`。
|
||||
|
||||
在中大型项目中,会有几个问题 :
|
||||
|
||||
- 将数据库逻辑写在 controller,造成 controller 的肥大难以维护。
|
||||
- 违反 SOLID 的单一职责原则 : 数据库逻辑不应该写在 controller。
|
||||
- controller 直接相依于model,使得我们无法对 controller 做单元测试。
|
||||
|
||||
比较好的方式是使用 repository :
|
||||
|
||||
- 将 model 依赖注入到 repository。
|
||||
- 将数据库逻辑写在 repository。
|
||||
- 将 repository 依赖注入到 service。
|
||||
|
||||
以此原则,我们看下,采用 Eloquent ORM 如何使用 Repository 模式。
|
||||
|
||||
UserRepository.php
|
||||
|
||||
```php
|
||||
namespace MyBlog\Repositories;
|
||||
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use MyBlog\User;
|
||||
|
||||
class UserRepository
|
||||
{
|
||||
/** @var User 注入的User model */
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* UserRepository constructor.
|
||||
* @param User $user
|
||||
*/
|
||||
public function __construct(User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回年龄大于$age的用户
|
||||
* @param integer $age
|
||||
* @return Collection
|
||||
*/
|
||||
public function getAgeLargerThan($age)
|
||||
{
|
||||
return $this->user
|
||||
->where('age', '>', $age)
|
||||
->orderBy('age')
|
||||
->get();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
第 8 行
|
||||
|
||||
```php
|
||||
/** @var User 注入的User model */
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* UserRepository constructor.
|
||||
* @param User $user
|
||||
*/
|
||||
public function __construct(User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
```
|
||||
|
||||
将依赖的 User model 依赖注入到 UserRepository。
|
||||
|
||||
UserController.php
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests;
|
||||
use MyBlog\Repositories\UserRepository;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
/** @var UserRepository 注入的UserRepository */
|
||||
protected $userRepository;
|
||||
|
||||
/**
|
||||
* UserController constructor.
|
||||
*
|
||||
* @param UserRepository $userRepository
|
||||
*/
|
||||
public function __construct(UserRepository $userRepository)
|
||||
{
|
||||
$this->userRepository = $userRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$users = $this->userRepository
|
||||
->getAgeLargerThan(20);
|
||||
|
||||
return view('users.index', compact('users'));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
将依赖的 UserRepository 依赖注入到 UserController。
|
||||
|
||||
26行
|
||||
|
||||
```php
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$users = $this->userRepository
|
||||
->getAgeLargerThan(20);
|
||||
|
||||
return view('users.index', compact('users'));
|
||||
}
|
||||
```
|
||||
|
||||
从原本直接依赖 User model,改成依赖注入的 UserRepository。
|
||||
|
||||
改用这种写法,有几个优点:
|
||||
|
||||
- 将数据库逻辑写在存储库中,解决控制器肥大问题。
|
||||
- 符合SOLID的单一职责原则:数据库逻辑写在repository,没写在controller。
|
||||
- 符合SOLID的依赖转换原则:controller 并非直接相依于存储库,而是将存储库依赖注入进controller。
|
||||
|
||||
>
|
||||
|
||||
**实际上建议repository仅依赖注入于service,而不要直接注入在controller,本范例因为还没介绍到servie模式,以便简化起见,所以直接注入于controller**。<br />
|
||||
<br />
|
||||
|
||||
>
|
||||
|
||||
**是否该建立存储库接口?**<br />
|
||||
|
||||
|
||||
理论上使用依赖注入时,应该使用接口,不过接口目的在于通过抽象化,方便在后期更换接口的具体实现,以便让程序达到开放封闭的要求,但是实际上要更换存储库的机会不高,除非你有更换资料库的需求,如从MySQL抽换到MongoDB,此时就该建立存储库接口。
|
||||
|
||||
不过由于我们使用了依赖注入,将来要从类改成interface也很方便,只要在构造方法的类型提示改成interface即可,维护成本很低,所以在此大可使用的存储库类,用接口反而会造成设计过度,等真正需求来时再重构成接口即可。
|
||||
|
||||
采用 Doctrine ORM 如何使用 Repository 模式。
|
||||
|
||||
由于 Doctrine ORM 自带 Repository 模式,所以直接使用即可。
|
||||
|
||||
UserRepository.php
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
namespace App\Repositories;
|
||||
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
class UserRepository extends EntityRepository {
|
||||
|
||||
/**
|
||||
* 返回年龄大于$age的用户
|
||||
* @param integer $age
|
||||
* @return Collection
|
||||
*/
|
||||
public function getAgeLargerThan($age)
|
||||
{
|
||||
return $this->user
|
||||
->where('age', '>', $age)
|
||||
->orderBy('age')
|
||||
->get();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
UserController.php
|
||||
|
||||
```php
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests;
|
||||
use MyBlog\Repositories\UserRepository;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
/** @var UserRepository 注入的UserRepository */
|
||||
protected $userRepository;
|
||||
|
||||
/**
|
||||
* UserController constructor.
|
||||
*
|
||||
* @param UserRepository $userRepository
|
||||
*/
|
||||
public function __construct(UserRepository $userRepository)
|
||||
{
|
||||
$this->userRepository = $userRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$users = $this->userRepository
|
||||
->getAgeLargerThan(20);
|
||||
|
||||
return view('users.index', compact('users'));
|
||||
}
|
||||
}
|
||||
```
|
||||
308
docs/docs/framework_architecture-service.md
Normal file
308
docs/docs/framework_architecture-service.md
Normal file
@@ -0,0 +1,308 @@
|
||||
---
|
||||
url: framework_architecture-service
|
||||
---
|
||||
|
||||
# Service
|
||||
|
||||
>
|
||||
|
||||
**使用 Service 辅助 Controller**<br />
|
||||
|
||||
|
||||
若将商业逻辑都写在 controller,会造成 controller 肥大而难以维护,基于SOLID原则,我们应该使用 Service 模式辅助 controller,将相关的商业逻辑封装在不同的 service,方便中大型项目的维护。
|
||||
|
||||
<a name="f86fc3d0"></a>
|
||||
## 商业逻辑
|
||||
|
||||
商业逻辑中,常见的如 :
|
||||
|
||||
- 牵涉到外部行为 : 如发送Email,使用外部API…。
|
||||
- 使用PHP写的逻辑 : 如促销规则计算、订单创建等。
|
||||
|
||||
若将商业逻辑写在 controller,会造成 controller 肥大,日后难以维护。
|
||||
|
||||
<a name="Service"></a>
|
||||
## Service
|
||||
|
||||
牵涉到外部行为
|
||||
|
||||
如发`送Email`,初学者常会在 controller 直接调用 `Mail::queue()`:
|
||||
|
||||
```php
|
||||
public function store(Request $request)
|
||||
{
|
||||
Mail::queue('email.index', $request->all(), function (Message $message) {
|
||||
$message->sender(env('MAIL_USERNAME'));
|
||||
$message->subject(env('MAIL_SUBJECT'));
|
||||
$message->to(env('MAIL_TO_ADDR'));
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
> Mail::queue()只有一行可能无感,但很多外部服务需要一连串 API,甚至还要有 try/catch 处理。
|
||||
|
||||
|
||||
在中大型项目,会有几个问题 :
|
||||
|
||||
- 将牵涉到外部行为的商业逻辑写在 controller,造成 controller 的肥大难以维护。
|
||||
- 违反 SOLID 的单一职责原则 : 外部行为不应该写在 controller。
|
||||
- controller 直接相依于外部行为,使得我们无法对 controller 做单元测试。
|
||||
|
||||
比较好的方式是使用 service :
|
||||
|
||||
- 将外部行为注入到 service。
|
||||
- 在 service 使用外部行为。
|
||||
- 将 service 注入到 controller。
|
||||
|
||||
EmailService.php
|
||||
|
||||
```php
|
||||
namespace App\Services;
|
||||
|
||||
use Illuminate\Mail\Mailer;
|
||||
use Illuminate\Mail\Message;
|
||||
|
||||
class EmailService
|
||||
{
|
||||
/** @var Mailer */
|
||||
private $mail;
|
||||
|
||||
/**
|
||||
* EmailService constructor.
|
||||
* 将依赖的 Mailer 注入到 EmailService。
|
||||
* @param Mailer $mail
|
||||
*/
|
||||
public function __construct(Mailer $mail)
|
||||
{
|
||||
$this->mail = $mail;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送Email
|
||||
* 将发送 Email 的商业逻辑写在 send()。
|
||||
* 不是使用 Mail facade,而是使用注入的 $this->mail。
|
||||
* @param array $request
|
||||
*/
|
||||
public function send(array $request)
|
||||
{
|
||||
$this->mail->queue('email.index', $request, function (Message $message) {
|
||||
$message->sender(env('MAIL_USERNAME'));
|
||||
$message->subject(env('MAIL_SUBJECT'));
|
||||
$message->to(env('MAIL_TO_ADDR'));
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
UserController.php
|
||||
|
||||
```php
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests;
|
||||
use Illuminate\Http\Request;
|
||||
use MyBlog\Services\EmailService;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
/** @var EmailService */
|
||||
protected $emailService;
|
||||
|
||||
/**
|
||||
* UserController constructor.
|
||||
* @param EmailService $emailService
|
||||
*/
|
||||
public function __construct(EmailService $emailService)
|
||||
{
|
||||
//将依赖的 EmailService 注入到 UserController。
|
||||
$this->emailService = $emailService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
//从原本直接依赖于 Mail facade,改成相依于注入的 EmailService。
|
||||
$this->emailService->send($request->all());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
>
|
||||
|
||||
**改用这种写法,有几个优点 :**<br />
|
||||
|
||||
|
||||
- 将外部行为写在 service,解决 controller 肥大问题。
|
||||
- 符合 SOLID 的单一职责原则 : 外部行为写在 service,没写在 controller。
|
||||
- 符合 SOLID 的依赖反转原则 : controller 并非直接相依于 service,而是将 service 依赖注入进 controller。
|
||||
|
||||
使用 PHP 写的逻辑:
|
||||
|
||||
如根据购买的件数,有不同的折扣,初学者常会在 controller 直接写 if...else 逻辑。
|
||||
|
||||
```php
|
||||
public function store(Request $request)
|
||||
{
|
||||
$qty = $request->input('qty');
|
||||
|
||||
$price = 500;
|
||||
|
||||
if ($qty == 1) {
|
||||
$discount = 1.0;
|
||||
} elseif ($qty == 2) {
|
||||
$discount = 0.9;
|
||||
} elseif ($qty == 3) {
|
||||
$discount = 0.8;
|
||||
} else {
|
||||
$discount = 0.7;
|
||||
}
|
||||
|
||||
$total = $price * $qty * $discount;
|
||||
|
||||
echo($total);
|
||||
}
|
||||
```
|
||||
|
||||
在中大型项目,会有几个问题 :
|
||||
|
||||
- 将 PHP 写的商业逻辑直接写在 controller,造成 controller 的肥大难以维护。
|
||||
- 违反 SOLID的 单一职责原则 : 商业逻辑不应该写在 controller。
|
||||
- 违反SOLID的单一职责原则: 若未来想要改变折扣与加总的算法,都需要改到此method,也就是说,此method 同时包含了计算折扣与计算加总的职责,因此违反SOLID 的单一职责原则。
|
||||
- 直接写在 controller 的逻辑无法被其他 controller 使用。
|
||||
|
||||
比较好的方式是使用 service。
|
||||
|
||||
- 将依赖的类注入到 service。
|
||||
- 在 service 写 PHP逻辑使用相依物件。
|
||||
- 将 service 注入到 controller。
|
||||
|
||||
OrderService.php
|
||||
|
||||
```php
|
||||
namespace App\Services;
|
||||
|
||||
class OrderService
|
||||
{
|
||||
/**
|
||||
* 計算折扣
|
||||
* @param int $qty
|
||||
* @return float
|
||||
*/
|
||||
//为了符合 SOLID 的单一职责原则,将计算折扣独立成 getDiscount(),将PHP写的判断逻辑写在里面。
|
||||
public function getDiscount($qty)
|
||||
{
|
||||
if ($qty == 1) {
|
||||
return 1.0;
|
||||
} elseif ($qty == 2) {
|
||||
return 0.9;
|
||||
} elseif ($qty == 3) {
|
||||
return 0.8;
|
||||
} else {
|
||||
return 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算最后价格
|
||||
* @param integer $qty
|
||||
* @param float $discount
|
||||
* @return float
|
||||
*/
|
||||
//为了符合 SOLID 的单一职责原则,将计算加总独立成 getTotal(),将PHP写的计算逻辑写在里面。
|
||||
public function getTotal($qty, $discount)
|
||||
{
|
||||
return 500 * $qty * $discount;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
OrderController.php
|
||||
|
||||
```php
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests;
|
||||
use App\MyBlog\Services\OrderService;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class OrderController extends Controller
|
||||
{
|
||||
/** @var OrderService */
|
||||
protected $orderService;
|
||||
|
||||
/**
|
||||
* OrderController constructor.
|
||||
* @param OrderService $orderService
|
||||
*/
|
||||
public function __construct(OrderService $orderService)
|
||||
{
|
||||
//将依赖的 OrderService 注入到 UserController。
|
||||
$this->orderService = $orderService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$qty = $request->input('qty');
|
||||
//将原本的 if...else 逻辑改成调用 OrderService,
|
||||
//controller 变得非常干净,也达到了controller 接收 HTTP request,调用其他 class 的责任。
|
||||
$discount = $this->orderService->getDiscount($qty);
|
||||
$total = $this->orderService->getTotal($qty, $discount);
|
||||
|
||||
echo($total);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
::: info
|
||||
改用这种写法,有几个优点 :
|
||||
:::
|
||||
|
||||
- 将PHP写的商业逻辑写在 service,解决 controller 肥大问题。
|
||||
- 符合 SOLID 的单一职责原则 : 商业逻辑写在 service,没写在 controller。
|
||||
- 符合 SOLID 的单一职责原则 : 计算折扣与计算加总价分开在不同 method,且归属于 OrderService,而非 OrderController。
|
||||
- 符合 SOLID 的依赖反转原则 : controller 并非直接相依于 service,而是将 service依赖注入进 controller。
|
||||
- 其他 controller 也可以重复使用此段商业逻辑。
|
||||
|
||||
<a name="Controller"></a>
|
||||
## Controller
|
||||
|
||||
涉及到外部行为
|
||||
|
||||
```php
|
||||
public function store(Request $request)
|
||||
{
|
||||
$this->emailService->send($request->all());
|
||||
}
|
||||
```
|
||||
|
||||
使用 PHP 写的逻辑
|
||||
|
||||
```php
|
||||
public function store(Request $request)
|
||||
{
|
||||
$qty = $request->input('qty');
|
||||
|
||||
$discount = $this->orderService->getDiscount($qty);
|
||||
$total = $this->orderService->getTotal($qty, $discount);
|
||||
|
||||
echo($total);
|
||||
}
|
||||
```
|
||||
|
||||
若使用了 service 辅助 controller,再搭配依赖注入与 service container,则 controller 就非常干净,能专心处理`接收HTTP request,调用其他class`的职责了。
|
||||
|
||||
<a name="Conclusion"></a>
|
||||
## Conclusion
|
||||
|
||||
- 实际上会有很多 service,须自行依照 SOLID 原则去判断是否该建立 service。
|
||||
- Service 使得商业逻辑从 controller 中解放,不仅更容易维护、更容易扩展、更容易重复使用,且更容易测试。
|
||||
109
docs/docs/framework_architecture.md
Normal file
109
docs/docs/framework_architecture.md
Normal file
@@ -0,0 +1,109 @@
|
||||
---
|
||||
url: framework_architecture
|
||||
---
|
||||
|
||||
# 中大型项目架构
|
||||
|
||||
Laravel 的初学者分为两种:
|
||||
|
||||
- 一种是乖乖的将程序在写 MVC 架构内,这将导致 Controller 和 Model 非常臃肿,日后代码很难维护。
|
||||
- 一种是不知道将程序写在哪一个Class内而犹豫不决。
|
||||
|
||||
本文整理出最适合 Laravel 的中大型项目架构,兼具易维护、易扩展、易复用和易测试的特点。
|
||||
|
||||
<a name="910dfdc0"></a>
|
||||
## Controller 过于肥大
|
||||
|
||||
受RoR的影响,初学者常认为 MVC 架构就是 Model,View,Controller:
|
||||
|
||||
- Model 就是数据库。
|
||||
- Controller 负责与 HTTP 通信,调用 Model 与 View。
|
||||
- View 就是 HTML。
|
||||
|
||||
假如按照此定义,以下需求应该写在哪里呢?
|
||||
|
||||
1.发送 Email,使用外部 API。
|
||||
|
||||
2.使用 PHP 写的逻辑。
|
||||
|
||||
3.依需求将显示格式作转换。
|
||||
|
||||
4.依需求是否显示某些资料。
|
||||
|
||||
5.依需求显示不同资料。
|
||||
|
||||
其中1, 2 属于商业逻辑,而3, 4, 5 属于显示逻辑,若依照一般人对 MVC 的定义,Model 是数据库,而 View 是HTML,以上这些需求都不能写在Model 与View,只能勉强写在Controller。
|
||||
|
||||
因此初学者开始将大量程序写在 Controller,造成 Controller 的肥大难以维护。
|
||||
|
||||
<a name="d0cd5997"></a>
|
||||
## Model 过于肥大
|
||||
|
||||
>
|
||||
|
||||
**既然逻辑写在 Controller 不方便维护,那我将逻辑都写在 Model 就好了?**<br />
|
||||
<br />
|
||||
|
||||
当你将逻辑从 Controller 搬到 Model 后,虽然 Controller 变瘦了,但却肥了 Model,Model 从原本只处理数据库逻辑,现在变成还要负担商业逻辑与显示逻辑,结果更惨。
|
||||
|
||||
Model 代表数据库吗?把它想成是 Eloquent class就好,数据库逻辑应该写在 repository 里,这也是为什么 Laravel(Lumen) 已经没有 Models目录,Eloquent class 仅仅是放在 app 根目录下而已。
|
||||
|
||||
<a name="4b968317"></a>
|
||||
## 中大型项目架构
|
||||
|
||||
那我们该怎么写呢?别将我们的思维局限在 MVC 内 :
|
||||
|
||||
- Model : 仅当成 Eloquent class。
|
||||
- Repository : 辅助 Model,处理数据库逻辑,然后注入到 service。
|
||||
- Service : 辅助 Controller,处理商业逻辑,然后注入到 Controller。
|
||||
- Controller : 接收 HTTP request,调用其他 service。
|
||||
- Presenter : 处理显示逻辑,然后注入到 View。
|
||||
- View : 使用 blade 将资料 binding 到 HTML。
|
||||
|
||||
其中蓝色为原本的 MVC,而紫色为本文要介绍的的重点 : Repository 模式,Service 模式与 Presenter 模式。
|
||||
|
||||

|
||||
|
||||
> 箭头表示物件依赖注入的方向。
|
||||
|
||||
|
||||
我们可以发现 MVC 架构还在,由于 SOLID 的单一职责原则与依赖反转原则 :
|
||||
|
||||
- 我们将数据库逻辑从 Model 分离出来,由 repository 辅助 Model,将 Model 依赖注入进 repository。
|
||||
- 我们将商业逻辑从 Controller 分离出来,由 service 辅助 Controller,将 service 依赖注入进 Controller。
|
||||
- 我们将显示逻辑从 View 分离出来,由 presenter 辅助 View,将 presenter 依赖注入进 View。
|
||||
|
||||
建立目录在 src 的 Bundle 目录下建立 Repositories,Services 与 Presenters 目录。
|
||||
|
||||
别害怕在 Laravel 预设目录以外建立的其他目录,根据 SOLID 的单一职责原则,class 功能越多,责任也越多,因此越违反单一职责原则。
|
||||
|
||||
所以你应该将你的程序分割成更小的部分,每个部分都有它专属的功能,而不是一个 class 功能包山包海,也就是所谓的`万能类`。
|
||||
|
||||
所以整个项目不应该只有 MVC 三个部分,放手根据你的需求建立适当的目录,并将适当的 class 放到该目录下,只要我们的class 有namespace 帮我们分类即可。
|
||||
|
||||
<a name="Repository"></a>
|
||||
## Repository
|
||||
|
||||
由于篇幅的关系,将 repository 独立成专文讨论,请参考[如何使用 Repository 模式](framework_architecture-repository) ?
|
||||
|
||||
<a name="Service"></a>
|
||||
## Service
|
||||
|
||||
由于篇幅的关系,将 service 独立成专文讨论,请参考如何使用 Service 模式?
|
||||
|
||||
<a name="93b824b5"></a>
|
||||
## 单元测试
|
||||
|
||||
由于现在Model、View、Controller 的依赖都已经拆开,也都使用依赖注入,因此每个部分都可以单独的做单元测试,如要测试service,就将repository 加以 mock,也可以将其他 service 加以 mock。
|
||||
|
||||
<a name="54bbba80"></a>
|
||||
## 结论
|
||||
|
||||
本文谈到的架构只是开始,你可以依照实际需求增加更多的目录与 class,当你发现你的 MVC 违反 SOLID原则时,就大胆的将 class 从 MVC 拆开重构,然后依照以下手法 :
|
||||
|
||||
- 建立新的 class 或 interface。
|
||||
- 将依赖类依赖注入到 class。
|
||||
- 在 class 内处理他的职责。
|
||||
- 将 class 或 interface 注入到 Controller 或 View。
|
||||
|
||||
最后搭配单元测试,测试重构后的架构是否与原来的需求结果相同。
|
||||
Reference in New Issue
Block a user