From bef1e8fd50bf5fee3511b819884c01b1d9566ec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=90=E6=B0=B8=E5=B7=9D?= Date: Fri, 26 Jun 2026 13:44:58 +0000 Subject: [PATCH] update docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 唐永川 --- docs/docs/deploy_prepare_appoint.md | 8 + docs/docs/deploy_prepare_domain.md | 44 + docs/docs/deploy_prepare_domain_record.md | 35 + docs/docs/deploy_prepare_implementation.md | 256 ++++ docs/docs/deploy_prepare_lbs.md | 7 + docs/docs/deploy_prepare_license.md | 17 + docs/docs/deploy_prepare_open_weixin.md | 168 +++ docs/docs/deploy_prepare_qiniu.md | 64 + docs/docs/deploy_prepare_readme.md | 14 + docs/docs/deploy_prepare_solution.md | 120 ++ docs/docs/deploy_prepare_wxa.md | 77 + docs/docs/dicucx.md | 6 + docs/docs/el5sfv.md | 1343 +++++++++++++++++ docs/docs/fe4lti.md | 21 + docs/docs/fiytfx.md | 51 + .../docs/framework_architecture-repository.md | 339 +++++ docs/docs/framework_architecture-service.md | 308 ++++ docs/docs/framework_architecture.md | 109 ++ 18 files changed, 2987 insertions(+) create mode 100644 docs/docs/deploy_prepare_appoint.md create mode 100644 docs/docs/deploy_prepare_domain.md create mode 100644 docs/docs/deploy_prepare_domain_record.md create mode 100644 docs/docs/deploy_prepare_implementation.md create mode 100644 docs/docs/deploy_prepare_lbs.md create mode 100644 docs/docs/deploy_prepare_license.md create mode 100644 docs/docs/deploy_prepare_open_weixin.md create mode 100644 docs/docs/deploy_prepare_qiniu.md create mode 100644 docs/docs/deploy_prepare_readme.md create mode 100644 docs/docs/deploy_prepare_solution.md create mode 100644 docs/docs/deploy_prepare_wxa.md create mode 100644 docs/docs/dicucx.md create mode 100644 docs/docs/el5sfv.md create mode 100644 docs/docs/fe4lti.md create mode 100644 docs/docs/fiytfx.md create mode 100644 docs/docs/framework_architecture-repository.md create mode 100644 docs/docs/framework_architecture-service.md create mode 100644 docs/docs/framework_architecture.md diff --git a/docs/docs/deploy_prepare_appoint.md b/docs/docs/deploy_prepare_appoint.md new file mode 100644 index 0000000..26853b5 --- /dev/null +++ b/docs/docs/deploy_prepare_appoint.md @@ -0,0 +1,8 @@ +--- +url: deploy_prepare_appoint +--- + +# 约定 + +- 部署文档以源源客官方平台作为例子, 域名为: yuanyuanke.cn +- diff --git a/docs/docs/deploy_prepare_domain.md b/docs/docs/deploy_prepare_domain.md new file mode 100644 index 0000000..099a7dc --- /dev/null +++ b/docs/docs/deploy_prepare_domain.md @@ -0,0 +1,44 @@ +--- +url: deploy_prepare_domain +--- + +# 域名 + + +## SSL证书 +> ssl证书, 对网站传输的数据可以进行SSL加密,包括用户名,密码等等,防止窃取和篡改。并且网站安装SSL证书后,在浏览器地址栏可以显示一个安全锁,告诉用户你的网站是安全的。SSL证书是数字证书的一种,类似于驾驶证、护照和营业执照的电子副本。因为配置在服务器上,也称为SSL服务器证书。 + + + + +> **ECShopX需要购买通配型ssl证书(泛域名型ssl证书). + +** + + +## 域名规划域名规划 + +为了表述方便, 以域名_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域名 + + +## FAQ + +- 为什么必须要使用SSL证书 +
其一SSL证书作为电商领域保证客户信息安全的重要手段. 其二微信小程序 公众号 苹果商店等对于安全性的要求越来越高, 微信小程序是必须SSL才可以, 其它场景也陆续增加限制. 其三, C端用户对于安全的意识也越来越强, 有些客户对于没有小锁头的电商网站有抵触. +- 是否可以选择免费的SSL? +
尽量避免使用免费的SSL, 免费的SSL通常不支持**通配符型SSL证书**/**泛域名SSL证书**, 本文档相关部署以支持_通配符型SSL证书_为准. +- 对于收费的SSL证书应该如何选择? +- 云盾证书服务 +- SSL去哪里买? +
主流的云供应商都有, 阿里的云盾 + + +## + diff --git a/docs/docs/deploy_prepare_domain_record.md b/docs/docs/deploy_prepare_domain_record.md new file mode 100644 index 0000000..480eecd --- /dev/null +++ b/docs/docs/deploy_prepare_domain_record.md @@ -0,0 +1,35 @@ +--- +url: deploy_prepare_domain_record +--- + +# 域名备案 + +根据 《互联网信息服务管理办法》 以及 《非经营性互联网信息服务备案管理办法》 ,国家对非经营性互联网信息服务实行备案制度,对经营性互联网信息服务实行许可制度。未取得许可或者未履行备案手续的,不得从事互联网信息服务。即所有对中国大陆提供服务的网站都必须先进行 ICP 备案,才可开通服务。阿里云ICP代备案系统为您提供申请备案、修改注销备案信息、认领备案等功能。 + +> **如果由商派提供采购阿里云服务器, 可以选用我们的备案服务.**
+ + + +## 阿里云备案 + +[阿里云备案](https://beian.aliyun.com) + + +## 腾讯云备案 + +[腾讯云备案](https://cloud.tencent.com/product/ba) + + +## 微软云(中国) + +[微软云备案](https://www.azure.cn/zh-cn/support/icp/icp-new/) + + +## 华为云备案 + +[华为云备案](https://support.huaweicloud.com/pi-icp/zh-cn_topic_0115820080.html) + + +## 网易云备案 + +[网易云备案](https://www.163yun.com/help/documents/15588222030344192) diff --git a/docs/docs/deploy_prepare_implementation.md b/docs/docs/deploy_prepare_implementation.md new file mode 100644 index 0000000..71a6abe --- /dev/null +++ b/docs/docs/deploy_prepare_implementation.md @@ -0,0 +1,256 @@ +--- +url: deploy_prepare_implementation +--- + +# ECShopX初始化 + +> **本文档引自ECShopX操作手册. 前半部分为数据初始化及上线前准备工作, 因此罗列在此处.** +> + +> **目前本文档仅有Word版, 如需要可向售后人员索要.** + + +### 开通EcshopX + + + +### 注册开放平台以及创建第三方平台 + + + +### 申请服务号并且认证 +> 不能是订阅号 + + + + +### 申请小程序并且认证 +> 可以通过服务号快速申请小程序,这样可以避免主体不一致带来的麻烦 + + + + +### 申请微信支付 +> 小程序支付、JSAPI支付、h5支付 +> 按您的业务需求申请,如果只有小程序则只需要开通小程序支付即可 + + + +> 在接入微信支付过程中,会出现APPID、MCH_ID、公众平台、开放平台、商户平台等概念,下面仅从微信支付的角度来做简单分析: +> + +> ![](../assets/1599795958725-a6092948-c05e-43af-adac-56b41a67bae4.png) + +> + + +> **● 公众平台([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进行绑定后方可使用。 + + +### + +### ECShopX授权绑定服务号 +> 管理员才能授权 + + + + +### ECShopX授权绑定小程序 +> 管理员才能授权 + +
+ +### 小程序模板开发 +> 与开发普通小程序一致,开发者在开发工具上开发好相关的业务逻辑之后,在项目页卡中提交预览即可以在微信中查看小程序的真实表现。 + +> 有所不同的是,第三方平台小程序的提交上传是上传至该第三方平台的 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) 。 + + +### 上架小程序须知 +> 第三方平台帮助旗下已授权的小程序进行代码管理时,需先开发完成小程序模板,再将小程序模板部署到旗下小程序帐号中,具体流程如下: + +> **第一步:绑定开发小程序** + +> (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)。 + +> **第四步:调用接口,为旗下授权的小程序部署代码** + +> 具体接口详见“代码管理”文档中的接口。 + +> **重点提示:** + +> 小程序授权托管之后,只能使用第三方平台的在微信开放平台登记的服务器地址。所以第三方平台在帮助旗下公众号发布代码之前,需先把服务器地址设置到小程序的服务器地址中,设置接口详见“修改服务器地址”文档中的接口。 + + diff --git a/docs/docs/deploy_prepare_lbs.md b/docs/docs/deploy_prepare_lbs.md new file mode 100644 index 0000000..cab0db5 --- /dev/null +++ b/docs/docs/deploy_prepare_lbs.md @@ -0,0 +1,7 @@ +--- +url: deploy_prepare_lbs +--- + +# 腾讯位置服务 + +[接入步骤](https://lbs.qq.com/guides/startup.html) diff --git a/docs/docs/deploy_prepare_license.md b/docs/docs/deploy_prepare_license.md new file mode 100644 index 0000000..0ef0a76 --- /dev/null +++ b/docs/docs/deploy_prepare_license.md @@ -0,0 +1,17 @@ +--- +url: deploy_prepare_license +--- + +# 域名备案 + +如果由商派提供采购阿里云服务器, 可以选用我们的备案服务. + + +## 阿里云备案 + +[阿里云备案](https://beian.aliyun.com) + + +## 腾讯云备案 + +[腾讯云备案](https://cloud.tencent.com/product/ba) diff --git a/docs/docs/deploy_prepare_open_weixin.md b/docs/docs/deploy_prepare_open_weixin.md new file mode 100644 index 0000000..273a53b --- /dev/null +++ b/docs/docs/deploy_prepare_open_weixin.md @@ -0,0 +1,168 @@ +--- +url: deploy_prepare_open_weixin +--- + +# 微信开放平台第三方平台申请 + + +## 注册微信开放平台账号 + +
[注册微信平台注册](https://open.weixin.qq.com/cgi-bin/readtemplate?t=regist/regist_tmpl&lang=zh_CN)
+ + +## 开发者资质认证 + +
[第三方平台申请流程](https://open.weixin.qq.com/cgi-bin/frame?t=home/wx_plugin_tmpl&lang=zh_CN)
+
![open_weixin_flow.png](../assets/1584343626626-7d4018ea-489a-4240-b918-e59057c13c7b.png)
+
点击_`开发者资质认证`_, 并进行认证.
+ +> 开发者资质认证介绍 +> 微信开放平台帐号的开发者资质认证提供更安全、更严格的真实性认证、也能够更好的保护企业及用户的合法权益
开发者资质认证通过后,微信开放平台帐号下的应用,将获得微信登录、智能接口、第三方平台开发等高级能力
审核费用:中国大陆地区:300元,非中国大陆地区:99美元 + + +
认证时间大概2-3天, 已微信实际认证时间为准
+ + +## 创建第三方平台 + +
管理中心->第三方平台
+
![open_third_platform.png](../assets/1584343649169-0b36319a-545c-4150-855b-7fd915ecd521.png)
+
点击_`创建第三方平台`_
+ + +## 输入基本信息 + +
平台类型选择_**`平台型服务商`**_
+
![open_third_platform_create_1.png](../assets/1584343669051-3bc5c06e-af75-4353-941f-0dd327ba05ce.png)
+ + +## 选择权限 + +
公众号权限
+
![open_third_platform_create_2_1.png](../assets/1584343692332-dd5950e1-5f56-46b7-ba67-1413dd763bb1.png)
![open_third_platform_create_2_2.png](../assets/1584343704222-2b3df860-3813-4fc5-9c5c-3d300b33bbf5.png)
+
小程序权限
+
![image.png](../assets/1599635273983-376e0426-6436-4e17-a429-89fceca249b5.png)
+ + +## 填写开发资料 + +
为了表述方便, 下文将以主域名_yuanyuanke.cn_为例。实际部署时根据您的域名进行修改,并且您的域名是要https的。
+ + +#### 授权流程相关 + + +- 登录授权的发起页域名:_ b.yuanyuanke.cn_ + + + +> 必须从本域名内网页跳转到登录授权页,才可完成登录授权。无需填写`https://等域名协议前缀`。 + + + +- 授权测试公众号列表: gh_************ + + + +> 在全网发布之前,仅该列表内公众号才可进行授权(包含测试小程序),以便测试。请填写公众号的原始ID(可在公众平台网站的公众号设置页找到),最多10个,以英文“;”隔开。 + + + +- 授权事件接收URL: _b.yuanyuanke.cn/wechatAuth/events_ + + + +> 用于接收取消授权通知、授权成功通知、授权更新通知,也用于接收ticket,ticket是验证平台方的重要凭据。 +> 并且选择https协议头。 + + + + +#### 授权后实现业务 + + +- 消息校验Token: qwn2891ktj024 + + + +> 开发者在代替公众号或小程序接收到消息时,用此Token来校验消息。可以自定义。 +> **消息校验Token前后, 绝不能有空格** + + + +- 消息加解密Key: sklfjkfgeiawwwqvn65997wlj01ndnfoqoe8x2k0nck + + + +> 在代替公众号或小程序收发消息过程中使用。必须是长度为43位的字符串,只能是字母和数字。可以自定义。 +> **消息加解密Key前后, 绝不能有空格. 长度必须43位
** + + + +- 消息与事件接收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的替换符)
请**下载校验文件**,并将文件放置在域名根目录下,例如wx.qq.com,并确保可以访问该文件。
每月可提交修改申请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_ + + + +> 第三方平台旗下授权的小程序,只可配置本平台服务器域名列表中的域名,以;隔开。
每月可提交修改申请3次,本月有2次机会。 + + + +> **需要访问的小程序服务器域名, 同时需要后端接口b.yuanyuanke.cn 和 websocket服务: b-websocket.yuanyuanke.cn。这里主要就是您的网站域名,其他还有图片相关域名(七牛,阿里OSS的相关域名,原始域名或者cdn域名),websocket域名(如果用到),微信官方素材域名** + + + +- 小程序业务域名: **无需填写** + + + +> 请**下载校验文件**,并将文件放置在域名根目录下,例如wx.qq.com,并确保可以访问该文件。
每月可提交修改申请3次,本月有3次机会 + + + + +#### 其他 + + +- 白名单IP地址列表: 47.115.75.92; + + + +> 仅当开发者IP地址在该列表中时,才被允许调用相关接口。最多填写100个IP地址,以英文“;”隔开。 + + + +> **服务器出口ip地址, 如果是vpc. 否则访问微信接口会被拒** + +** + +#### 开发资料综合截图 +![image.png](../assets/1599634362838-5ff39c5c-ea0a-418a-b73d-0a0c62c7ce03.png)
+ + +## 获取APPSECRET + +
获取appsecret(微信开放平台管理中心的第三方平台详情页中的AppID和AppSecret)。
示例:
![image.png](../assets/1599635790626-92d05a28-49a6-475a-9e69-fc003032e51b.png) + +## 绑定开发者小程序 + +
微信开放平台管理中心的**第三方平台详情页**的**开发配置**里添加开发小程序。
同时在对应的小程序**添加开发者**。
**建议开发小程序和您的实际授权小程序用同一个**,避免一些异常问题。
示例:
![image.png](../assets/1599634524957-1d5f3f64-c7b8-4d03-af9c-5b9c10729448.png) + +## 开放平台绑定小程序 + +
微信开放平台管理中心的小程序中去绑定小程序。用于保证unionid一致。
![image.png](../assets/1599634689598-ab320e8e-d646-4371-adbb-f1725d5d146b.png) diff --git a/docs/docs/deploy_prepare_qiniu.md b/docs/docs/deploy_prepare_qiniu.md new file mode 100644 index 0000000..c59f6ac --- /dev/null +++ b/docs/docs/deploy_prepare_qiniu.md @@ -0,0 +1,64 @@ +--- +url: deploy_prepare_qiniu +--- + +# 七牛 + + +## 概念 + + +### cdn + +> CDN的全称是Content Delivery Network,即内容分发网络。CDN是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。CDN的关键技术主要有内容存储和分发技术。 + + + +### 开放存储服务 OSS + +> 开放存储服务(OpenStorageService,简称OSS),是云对外提供的海量,安全,低成本,高可靠的云存储服务。用户可以通过简单的API(REST方式的接口),在任何时间、任何地点、任何互联网设备上进行数据上传和下载 保存js, ccs, 图片等静态资源 + + + +### 七牛云 + +[七牛云](https://www.qiniu.com) + +> 七牛云是国内领先的企业级公有云服务商,致力于打造以数据为核心的场景化PaaS服务。围绕富媒体场景,七牛先后推出了对象存储,融合CDN加速,数据通用处理,内容反垃圾服务,以及直播云服务等。目前,七牛云已经在为 50多万家企业提供服务, 亲历互联网创新创业发展的同时,也深入理解传统企业转型过程中的云服务需求场景,推出了有针对性的一系列行业解决方案 + + + +## 创建存储空间 + + +### espier-vue + +用来存储前端的 css js 及静态图片等 + +- 存储空间(bucket): espier-vue +- 融合 CDN 加速域名: [https://b-cdn.yuanyuanke.cn](https://b-cdn.yuanyuanke.cn) +- 访问控制:  公开空间 + + +### espier-import-files + +用来存储系统导入 导出的相关数据 + +- 存储空间(bucket): espier-import-files +- 融合 CDN 加速域名: [https://b-import-cdn.yuanyuanke.cn](https://b-import-cdn.yuanyuanke.cn) +- 访问控制:  私有空间 + + +### espier-images + +用来存储商品图片, video等资源 + +- 存储空间(bucket): espier-images +- 融合 CDN 加速域名: [https://b-img-cdn.yuanyuanke.cn](https://b-img-cdn.yuanyuanke.cn) +- 访问控制:  公开空间 + + +## FAQ + +- 怎么获取或者找到 Access Key 和 Secret Key +
[怎么获取或者找到 Access Key 和 Secret Key](https://developer.qiniu.com/af/kb/1479/how-to-access-or-locate-the-access-key-and-secret-key) diff --git a/docs/docs/deploy_prepare_readme.md b/docs/docs/deploy_prepare_readme.md new file mode 100644 index 0000000..414c4da --- /dev/null +++ b/docs/docs/deploy_prepare_readme.md @@ -0,0 +1,14 @@ +--- +url: deploy_prepare_readme +--- + +# README.md + +--- + + + +## description: Shortcut keys allows an easy and quick method for navigating or editing con + + +# 准备工作 diff --git a/docs/docs/deploy_prepare_solution.md b/docs/docs/deploy_prepare_solution.md new file mode 100644 index 0000000..f4a11ed --- /dev/null +++ b/docs/docs/deploy_prepare_solution.md @@ -0,0 +1,120 @@ +--- +url: deploy_prepare_solution +--- + +# 服务器方案 + + +## 独立部署服务器方案 + +![deploy.jpg](../assets/1584344156612-d48bb04b-5f44-49e7-8cd4-941abc03a9be.jpeg) + +- 角色定义 + - 负载均衡: Load Balance + - Web服务:
+API服务 + - 队列:
+可使用redis/rabbitmq + - scheduler:
+定时任务, 例如凌晨1点产生统计任务, 加入队列. + - job:
+处理队列中的任务 + - neo4j:
+图数据库 + - redis:
+Key-Value数据库 + - OSS:
+对象存储, 存储文件/图片/视频 + - CDN:
+CDN的全称是Content Delivery Network,即内容分发网络 + + +### 声明 + +- 本文方案所指皆为以阿里云, 其它云方方案可以此为基准. +- 数据库建议使用RDS. 如果不使用RDS, 请做好备份方案, 以免误操作造成数据丢失. + + +### 入门级方案 + +- ECS1台 4核8g 100g高速硬盘
+部署 redis/neo4j/ecshopX(web/Job/scheduler) +- RDS 2核4g +- 七牛云 cdn 及 图片 + +方案简描述: + +``` +入门级方案, 不考虑高可用, 仅作为业务刚刚开始, 初始量级不大的情况下. +``` + + +### 标准方案 + +![deploy_3.jpg](../assets/1584344192904-4878b26e-b21c-46e0-9d55-bbfcc50106e4.jpeg) + +- 负载均衡 +- ECS3台 4核8g 100g高速硬盘 + - Web服务: ecs*2 + - 定时任务/job/redis/neo4j ecs*1 +- RDS: 2核4g + +方案简描述: + +``` +优点 +Web端提供两台服务器做负载均衡, 保证高可用. 队列任务分开部署, 将可异步处理的业务从前端业务中剥离, 后端的任务处理不影响API业务正常的相应. 一旦业务发生瓶颈, 可以方便增加Web机的数量, 提高RDS的配置. 以快速相应业务. + +缺点 +任务机上部署了过多的服务, 当任务服务器负载过重时, 快速扩展不易. +``` + + +### 进阶方案(根据业务侧重点调整方案配置) + +- 负载均衡 +- ecs 4核8g 40g ssd硬盘 * 6 + - Web: ecs * 3 + - Job: ecs * 2 + - Scheduler/redis/neo4j: ecs * 1 +- RDS 2核4g 100g * 1 集群版 便于扩展主从 +- 七牛云 cdn 及 图片 +- 日志服务 + + +### Kubernetes方案 + +![kubernetes_deploy.jpg](../assets/1584344218270-4d439a3a-4baa-48c9-957c-7c3df981f546.jpeg) + +- kubernetes 主节点: ecs 2核4g * 3 +- kubernetes node 工作节点: ecs 4核8g * 3 +- RDS 2核4g 100g * 1 集群版 便于扩展主从 + + +## 私有云方案(kubernetes) + +服务器托管在商派集群. 使用kubernetes集群方案. + + +### 入门方案(默认) + +- 共享负载均衡 +- 5核5g 容器资源 +- RDS 2核4g 100g * 1 +- 七牛云 cdn 及 图片 + + +### 标准方案 + +- 独享负载均衡 +- ECS 4核8g 100g高速硬盘 * 2 (独享) +- RDS 2核4g +- 七牛云 cdn 及 图片 + + +### 进阶方案(根据业务侧重点调整方案配置) + +- 独享负载均衡 +- ECS 4核8g 100g高速硬盘 * 6 (独享) +- RDS 2核4g 100g * 1 集群版 便于扩展主从 +- 七牛云 cdn 及 图片 diff --git a/docs/docs/deploy_prepare_wxa.md b/docs/docs/deploy_prepare_wxa.md new file mode 100644 index 0000000..c759a9d --- /dev/null +++ b/docs/docs/deploy_prepare_wxa.md @@ -0,0 +1,77 @@ +--- +url: deploy_prepare_wxa +--- + +# 小程序 + +> **本文档引自ECShopX操作手册. 前半部分为数据初始化及上线前准备工作, 因此罗列在此处.**
+ + + +> **需确认好小程序的**_**管理员**_**。****后续很多其它操作员的操作都需要管理员微信扫码。例如添加开发者,小程序授权等** + + + + +#### 申请小程序 + + +> [https://kf.qq.com/faq/170109iQBJ3Q170109JbQfiu.html](https://kf.qq.com/faq/170109iQBJ3Q170109JbQfiu.html) +> + +> 如果您有服务号,建议直接从服务号后台走快速注册并认证小程序,避免主体搞错的情况发生 +> ![image.png](../assets/1599637547874-89d12ef5-e2a2-45c1-8cb1-057cf523d291.png) + + +#### + +#### 小程序认证 + + +> [https://kf.qq.com/faq/170109F7ZVzq170109MnQRNN.html](https://kf.qq.com/faq/170109F7ZVzq170109MnQRNN.html) + + +#### + +#### 添加开发者或者体验者 + + +> 登录小程序后。开发的时候都是在小程序开发者工具中进行开发,所以必须要开发者权限才能运行。体验成员则可以看小程序体验版。 +> ![image.png](../assets/1599636099208-c2abcc21-fd52-4706-a6b6-4a567cf50da5.png) + + + + +#### 获取小程序的APPID(小程序ID),原始ID + + +> - 登录小程序后,点 _设置->基本设置_ +> +_![image.png](../assets/1599636771216-5703d789-921f-46d3-9479-d64efd3817df.png)_ +> - 拉到页面底部 +> +![image.png](../assets/1599636892509-a7648d02-e44e-47b0-a056-8690548be4fd.png) + + + + +### 小程序模板开发 +> 与开发普通小程序一致,开发者在开发工具上开发好相关的业务逻辑之后,在项目页卡中提交预览即可以在微信中查看小程序的真实表现。 +> 有所不同的是,第三方平台小程序的提交上传是上传至该第三方平台的 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) 。 + + +### 上架小程序须知 +> 第三方平台帮助旗下已授权的小程序进行代码管理时,需先开发完成小程序模板,再将小程序模板部署到旗下小程序帐号中,具体流程如下: +> **第一步:绑定开发小程序** +> (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)。 +> **第四步:调用接口,为旗下授权的小程序部署代码** +> 具体接口详见“代码管理”文档中的接口。 +> **重点提示:** +> 小程序授权托管之后,只能使用第三方平台的在微信开放平台登记的服务器地址。所以第三方平台在帮助旗下公众号发布代码之前,需先把服务器地址设置到小程序的服务器地址中,设置接口详见“修改服务器地址”文档中的接口。 + diff --git a/docs/docs/dicucx.md b/docs/docs/dicucx.md new file mode 100644 index 0000000..df43383 --- /dev/null +++ b/docs/docs/dicucx.md @@ -0,0 +1,6 @@ +--- +url: dicucx +--- + +# php的readme + diff --git a/docs/docs/el5sfv.md b/docs/docs/el5sfv.md new file mode 100644 index 0000000..ad15be5 --- /dev/null +++ b/docs/docs/el5sfv.md @@ -0,0 +1,1343 @@ +--- +url: el5sfv +--- + +# 单机部署方案 + + +## 约定 + + +- 操作系统:Centos 7.x x64 +- 域名: 文档内域名规划参见 [系统部署/准备/域名](deploy_prepare_domain) +- 操作权限: root + + + + +## 服务清单 + + +- supervisorctl > 3.0 +- neo4j 3.5.x +- mysql 5.7 +- nginx + php-fpm +- npm > 6.0 +- redis ~ 4.x +- php 7.2 + + + + +## 基础服务部署 + + + +### 调整时间 + + +``` +timedatectl set-timezone Asia/Shanghai +``` + + + +### 安装sudo + + +``` +yum install sudo +``` + + + +### 安装PHP + + +```bash +yum -y install epel-release +yum install http://rpms.remirepo.net/enterprise/remi-release-7.rpm +yum install yum-utils +yum-config-manager --enable remi-php72 + +yum install php72 \ + php72-php-gd \ + php72-php-json \ + php72-php-mbstring \ + php72-php-mysqlnd \ + php72-php-xml \ + php72-php-opcache \ + php72-php-bcmath \ + php72-php-pecl-swoole \ + php72-php-pecl-mongodb \ + php72-php-pecl-zip \ + php72-php-pecl-redis4 \ + php72-php-pcntl \ + php72-php-pecl-apcu + +ln /opt/remi/php72/root/usr/bin/php /usr/bin/php +``` + +
验证
+ +``` +php --version +php --modules +``` + + + +### 安装composer + + +``` +curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin --filename=composer +/usr/bin/composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/ +``` + + + +### 安装supervisor + +
版本基于3.0
+
安装supervisor
+ +``` +yum install -y epel-release +yum install -y supervisor +``` + +
开启supervisorctl
+ +``` +systemctl enable supervisord.service +``` + + + +### 创建用户和组 + + +``` +groupadd www +useradd --shell /sbin/nologin -g www www +``` + + + +### 安装php-fpm + +
安装php-fpm
+ +``` +yum install php72-php-fpm +``` + +
开启php-fpm
+ +``` +systemctl enable php72-php-fpm.service +``` + +
修改用户权限, 将用户和组从apache 改为www
+ +``` +/etc/opt/remi/php72/php-fpm.d/www.conf +``` + + +``` +user = www +group = www +``` + + + +### 安装npm + + +1. 添加**Node.js** **Yum**仓库``` +curl -sL https://rpm.nodesource.com/setup_12.x | bash - +``` + +2. 安装**Node.js**``` +yum install -y nodejs +``` + +3. 检查**Node.js**和**NPM**版本``` +node -v + +v12.6.0 +Also, check the version of npm. + +npm -v + +6.9.0 +``` + + + +
参考: [How To Install Latest Nodejs on CentOS/RHEL 7/6](https://tecadmin.net/install-latest-nodejs-and-npm-on-centos/)
+ + +### 安装nginx + +
安装nginx
+ +```bash +yum install nginx +``` + +
开启nginx
+ +```bash +systemctl enable nginx.service +``` + + + +### 安装crontabs +> 如果已经安装,请忽略 + + + +```bash +yum install crontabs +``` + + +```bash +systemctl enable crond.service +``` + + +```bash +systemctl start crond.service +``` + + + +### 安装redis +> 如果使用阿里云的redis,安装请忽略 + +安装redis
+ +```bash +yum install -y redis +``` + +
开启redis
+ +```bash +yum enable redis +``` + +
修改配置文件**/etc/redis.conf**
+ +```bash +# requirepass foobared +requirepass #指定密码为 redis1234 +``` + +
启动redis
+ +```bash +systemctl start redis +``` + +
测试
+ +```bash +redis-cli -h 127.0.0.1 -a redis1234 +keys * +``` + + + +### 安装neo4j + + +1. 导入签名并且添加neo4j的源到本地centos源中 +```bash +rpm --import https://debian.neo4j.org/neotechnology.gpg.key +cat < /etc/yum.repos.d/neo4j.repo +[neo4j] +name=Neo4j RPM Repository +baseurl=https://yum.neo4j.org/stable +enabled=1 +gpgcheck=1 +EOF +``` + + +2. 安装neo4j
+ - 用**root**权限安装neo4j社区版 +```bash +yum install neo4j-3.5.7 +``` + +
+ +3. 运行以下命令会返回已安装的Neo4j的版本: + +```bash +rpm -qa | grep neo4j +``` + + + +3. 修改默认**密码
**生产环境使用时需要修改初始密码, 否则会安装使用时报错.**
** +```bash +# neo4j-admin set-initial-password +neo4j-admin set-initial-password neo4j1234 +``` + + + +3. 启动neo4j +```bash +systemctl start neo4j +``` + +### 安装mysql + + +> **如果使用云方提供的RDS, 请忽略安装** + +添加mysql7的源到本地centos源中
+ +``` +yum install -y https://dev.mysql.com/get/mysql57-community-release-el7-9.noarch.rpm +``` + +
安装mysql
+ +``` +yum install -y mysql-server +``` + +
修改配置文件**/etc/my.conf**(配置位置取决于安装方式) + +** +> **如果使用阿里云的RDS可以忽略此步骤**
+ + + +``` +sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' +``` + +
开启mysql
+ +``` +systemctl enable mysqld +``` + +
启动mysql
+ +``` +systemctl start mysqld +``` + +
在安装过程中,为MySQL**root**用户生成一个临时密码
+ +``` +grep 'temporary password' /var/log/mysqld.log +``` + +
输出:
+ +``` +2016-12-01T00:22:31.416107Z 1 [Note] A temporary password is generated for root@localhost: mqRfBU_3Xk>r +``` + +
请记录下密码, 在此例里中为**mqRfBU_3Xk>r**
+ +``` +mysql_secure_installation +``` + +
会提示你输入默认的**root**密码, 输入好后, 会被要求改掉密码.
+
输出
+ +``` +The existing password for the user account root has expired. Please set a new password. + +New password: +``` + +
输入一个新的12个字符的密码,该密码至少包含一个大写字母、一个小写字母、一个数字和一个特殊字符。在提示时重新输入.
+
在此例中设置为, **Wka25ijklmng0ada-x**
+
您将收到关于新密码强度的反馈,然后您将立即被提示再次更改密码.
+
输出
+ +``` +Estimated strength of the password: 100 +Change the password for root ? (Press y|Y for Yes, any other key for No) : +``` + +
我们将按下**Y**,然后进入所有后续问题,以便删除匿名用户、禁止远程根登录、删除测试数据库并访问它,并重新加载特权表.
+
命令行连接**mysql**
+ +``` +mysql -uroot -p"Wka25ijklmng0ada-x" +``` + +
创建应用数据库 +> 请使用编码 utf8mb4 + + + +``` +CREATE DATABASE espier_bloated CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +``` + +
参考: [How To Install MySQL on CentOS 7](https://www.digitalocean.com/community/tutorials/how-to-install-mysql-on-centos-7)
+ + +## 系统应用部署 + +
部署几部分
+ +> 系统是前后端分离的。所以分为商家端(VUE开发,后台管理页面),API端(PHP开发,提供api服务) + + + + +### 配置授权 + +
安装swoole-loader,用于解密。下载地址如果变化,请自行验证一下
+
确认PHP扩展目录
+ +``` +# php -r 'phpinfo();' | grep -i '^extension_dir' + +extension_dir => /opt/remi/php72/root/usr/lib64/php/modules => /opt/remi/php72/root/usr/lib64/php/modules +``` + +
本例中为**/opt/remi/php72/root/usr/lib64/php/modules**
+ +```bash +curl https://business.swoole.com/static/loader2.0.0/swoole_loader72.so > /opt/remi/php72/root/usr/lib64/php/modules/swoole_loader72.so +``` + +
php扩展配置文件位置
+ +``` +# php -r 'phpinfo();' | grep -i 'Scan this dir for additional' + +Scan this dir for additional .ini files => /etc/opt/remi/php72/php.d +``` + +
设置授权 +> 注意配置license的正确位置, 默认license.zl在代码包(espier-bloated)根目录下 + +``` +{ \ + echo "extension=swoole_loader72.so"; \ + echo "swoole_license_files=/var/www/html/license.zl"; \ +} > /etc/opt/remi/php72/php.d/60-swoole_loader.ini +``` + +
重启fpm
+ +``` +systemctl enable php72-php-fpm.service +``` + + + +### 部署API服务(php) + + + +#### 配置 + +
后端代码
+ +``` +mkdir -p /var/www/espier-bloated +chown -R www:www /var/www/espier-bloated +``` + +
放置代码到**/var/www/espier-bloated**目录中
+
修改配置**.env**, 拷贝**.env.production**文件做为模版.
+ +1. 配置数据库``` +DB_HOST=127.0.0.1 +DB_PORT=3306 +DB_DATABASE=espier_bloated +DB_USERNAME=root +DB_PASSWORD=Wka25ijklmng0ada-x +``` + + + +1. 配置REDIS```bash +# REDIS配置 +REDIS_CLIENT=predis +REDIS_HOST= +# 必须要设置密码 +REDIS_PASSWORD=redis1234 +REDIS_PORT=6379 +``` + +1. 配置队列```bash +QUEUE_DRIVER=redis +``` + +1. 配置neo4j``` +NEO4J_DEFAULT_PROTOCOL=bolt +NEO4J_DEFAULT_HOST=127.0.0.1 +NEO4J_DEFAULT_PORT=7687 +NEO4J_DEFAULT_USERNAME=neo4j +NEO4J_DEFAULT_PASSWORD=neo4j1234 +``` + +1. 配置缓存```bash +CACHE_DRIVER=redis +``` + +1. 配置七牛
[如何获取Access Key和Secret Key](https://developer.qiniu.com/af/kb/1479/how-to-access-or-locate-the-access-key-and-secret-key)
```bash +# 图片CDN域名 +QINIU_IMAGE_DOMAIN=b-img-cdn.yuanyuanke.cn +# 图片bucket +QINIU_IMAGE_NAME=espier-images +# 导入导出文件CDN域名 +QINIU__FILE_DOMAIN=https://b-import-cdn.yuanyuanke.cn +导入导出bucket +QINIU_FILE_NAME=espier-import-files +# 七牛Access Key +QINIU_ACCESS_KEY= +# 七牛Secret Key +QINIU_SECRET_KEY= +``` + +1. 配置阿里OSS选七牛就不用配了 +```bash +# OSS配置 +## OSS密钥配置 +OSS_ACCESS_KEY= +OSS_SECRET_KEY= +## OSS文件配置 +### 不通地区域名不一样,文件类的不需要cdn +OSS_FILE_ENDPOINT=https://oss-cn-shanghai.aliyuncs.com +OSS_FILE_BUCKET=oss-cdn +OSS_FILE_IS_CNAME=false +## OSS图片配置 +OSS_IMAGE_ENDPOINT=https://oss-cn-shanghai.aliyuncs.com +OSS_IMAGE_BUCKET=oss-cdn +### 是否开启cdn +OSS_IMAGE_IS_CNAME=false +### 图片cdn,开启cdn则该配置必填 +OSS_IMAGE_DOMAIN= +## OSS视频配置 +OSS_VIDEO_ENDPOINT=https://oss-cn-shanghai.aliyuncs.com +OSS_VIDEO_BUCKET=oss-cdn +OSS_VIDEO_IS_CNAME=flase +### 视频cdn,开启cdn则该配置必填 +OSS_VIDEO_DOMAIN= +``` + + +8. 配置微信开放平台第三方平台相关配置 +```bash +# 微信开放平台对应第三方平台APPID +WECHAT_APPID= +# 微信开放平台对应第三方平台APPSECRET +WECHAT_SECRET= +# 微信开放平台对应第三方平台 消息校验Token +WECHAT_TOKEN= +# 微信开放平台对应第三方平台 消息加解密Key +WECHAT_AES_KEY= +WECHAT_DEBUG=true +``` +9.配置商城小程序模版
模版ID, 需要添加到小程序模版库,获得模版ID, 参考:[开发者平台小程序模板](https://developers.weixin.qq.com/community/develop/doc/000c6c3524cff06575466ccd35ec00)
     +```bash +# 微商城小程序配置 +## 微信模板id +YYKWEISHOP_TEMPLATE_ID=1 +## 微信模板id(小程序支持直播,一般可不填) +YYKWEISHOP_TEMPLATE_ID_2=1 +## 小程序自定义版本 +YYKWEISHOP_VERSION=v1.0.0 +## request合法域名,逗号分割 +YYKWEISHOP_REQUESTDOMAIN=https://b.test.cn +## socket合法域名,逗号分割 +YYKWEISHOP_WSREQUESTDOMAIN=wss://b-websocket.test.cn +## uploadFile合法域名,逗号分割,七牛,根据自己实际情况填 +YYKWEISHOP_UPLOADDOMAIN=https://up.qiniup.com,https://up-as0.qiniup.com,https://up-na0.qiniup.com,https://up-z1.qiniup.com,https://up-z2.qiniup.com +## uploadFile合法域名,逗号分割,阿里OSS,根据自己实际情况填 +#YYKWEISHOP_UPLOADDOMAIN=https://oss-cn-hangzhou.aliyuncs.com +## downloadFile合法域名,逗号分割,七牛,根据自己实际情况填 +YYKWEISHOP_DOWNLOADDOMAIN=https://mmbiz.qpic.cn,https://wx.qlogo.cn,https://up.qiniup.com,https://up-as0.qiniup.com,https://up-na0.qiniup.com,https://up-z1.qiniup.com,https://up-z2.qiniup.com +## downloadFile合法域名,逗号分割,阿里OSS,根据自己实际情况填 +#YYKWEISHOP_DOWNLOADDOMAIN=https://mmbiz.qpic.cn,https://wx.qlogo.cn,https://oss-cn-hangzhou.aliyuncs.com +## 业务域名,逗号分割 +YYKWEISHOP_WEBVIEWDOMAIN= +``` +10.配置腾讯位置服务
腾讯位置服务需要申请账号配置KEY, KEY对接口的访问是有配额的, 配额内是免费的.
在[腾讯位置服务Key管理](https://lbs.qq.com/console/mykey.html?console=mykey), 可以查询到Key, 并且可以查询到配额.
为了开发环境方便, 提供只为开发环境公用的免费KEY. 因为是公共的, 无法保证一定可用 +```bash +QQMAP_KEY=PSPBZ-KQ5CW-CSGRF-ON2S4-K2HQJ-XEBQG +``` + +11. 配置支付通知接口 +```bash +WECHAT_PAYMENT_NOTIFY=https://b.yuanyuanke.cn/wechatAuth/wxpay/notify +``` + +12. 生成api密钥 +```bash +php artisan jwt:secret +``` + +13. 修改业务版本 + +standard:标准连锁版,后台界面有“店铺”菜单
platform:平台版,后台界面有“商家”菜单,并且有独立的店铺后台 +```bash +# 系统版本,standard|platform +PRODUCT_MODEL=standard +``` + +
完整的例子
+ +```bash +# 标识应用环境, 本地环境设置为local,生产环境为production +APP_ENV=production +# 调试模式, 正式环境可以关闭(true,false) +APP_DEBUG=true +# 时区不要修改 +APP_TIMEZONE=PRC + +# 数据库相关配置 +## DB_CONNECTION默认不需要改 +DB_CONNECTION=default +DB_HOST= +DB_PORT=3306 +DB_DATABASE= +DB_USERNAME= +DB_PASSWORD= + +# REDIS配置 +REDIS_CLIENT=predis +REDIS_HOST= +REDIS_PASSWORD=redis1234 +REDIS_PORT=6379 + +# 数据库主从配置 +#DB_DRIVER=master_slave +#DB_MASTER={"user":"root","password":"123455","host":"localhost","dbname":"ecx"} +#DB_SLAVES=[{"user":"root","password":"123455","host":"localhost2","dbname":"ecx"},{"user":"root","password":"123455","host":"localhost3","dbname":"ecx"}] + +# 缓存驱动, 默认使用redis +CACHE_DRIVER=redis +# 队列驱动, 默认使用redis +QUEUE_DRIVER=redis + +# 文件存储。oss或者qiniu +DISK_DRIVER=qiniu + +# 七牛相关配置 +## 七牛密钥配置 +QINIU_ACCESS_KEY= +QINIU_SECRET_KEY= +## 七牛图片配置 +QINIU_IMAGE_DOMAIN= +QINIU_IMAGE_NAME=espier-image +QINIU_IMAGE_REGION=z2 +## 七牛视频配置 +QINIU_VIDEO_DOMAIN= +QINIU_VIDEO_NAME=espier-videos +QINIU_VIDEO_REGION=z2 +## 七牛文件配置 +QINIU__FILE_DOMAIN= +QINIU_FILE_NAME=espier-file + +# OSS配置 +## OSS密钥配置 +OSS_ACCESS_KEY= +OSS_SECRET_KEY= +## OSS文件配置 +### 不通地区域名不一样,文件类的不需要cdn +OSS_FILE_ENDPOINT=https://oss-cn-shanghai.aliyuncs.com +OSS_FILE_BUCKET=oss-cdn +OSS_FILE_IS_CNAME=false +## OSS图片配置 +OSS_IMAGE_ENDPOINT=https://oss-cn-shanghai.aliyuncs.com +OSS_IMAGE_BUCKET=oss-cdn +### 是否开启cdn +OSS_IMAGE_IS_CNAME=false +### 图片cdn,开启cdn则该配置必填 +OSS_IMAGE_DOMAIN= +## OSS视频配置 +OSS_VIDEO_ENDPOINT=https://oss-cn-shanghai.aliyuncs.com +OSS_VIDEO_BUCKET=oss-cdn +OSS_VIDEO_IS_CNAME=flase +### 视频cdn,开启cdn则该配置必填 +OSS_VIDEO_DOMAIN= + +# JWT 相关配置, 通过php artisan jwt:secret生成密钥,线上务必修改 +JWT_SECRET=ker4H1Gp4TsddddWJMaB2SMA8Zsh3drv +JWT_TTL=7200 +JWT_REFRESH_TTL=20160 + +# 微信第三方平台配置。本地开发环境不配置, 会影响到调用微信的相关页面, 整体不影响后台开发。 +## 第三方平台APPID +WECHAT_APPID= +## 第三方平台SECRET +WECHAT_SECRET= +## 消息校验Token +WECHAT_TOKEN= +## 消息加解密Key +WECHAT_AES_KEY= +## 开启微信接口debug模式 +WECHAT_DEBUG=true + +# 微信支付通知回调地址 +WECHAT_PAYMENT_NOTIFY=https://域名/wechatAuth/wxpay/notify + +# 支付宝配置 +ALIPAY_PAYMENT_NOTIFY= +ALIPAY_PAYMENT_RETURN= +ALIPAY_PAYMENT_RETURN_PC= +ALIPAY_PAYMENT_RETURN_H5= +ALIPAY_MODE=normal + +# SWOOLE 配置 +SERVER_HOST=0.0.0.0 +SERVER_PORT=9058 + +# 好像没用 +SERVER_OPTIONS_USER=www-data +SERVER_OPTIONS_GROUP=www-data +SERVER_OPTIONS_DAEMONIZE=false +SERVER_OPTIONS_WORKER_NUM=4 + +# dingo api标准配置, 根据实际场景进行配置,token需要修改 +API_PREFIX=api +API_NAME="Espier API" +API_STANDARDS_TREE=vnd +API_STRICT=false +API_DEBUG=false +API_VERSION=v1 +API_SUBTYPE=espier +API_CONDITIONAL_REQUEST=false +API_TOKEN=Os6Bass1oT5vig2Yod0yiT8dU0as5cIn + +# RABBITMQ配置 +RABBITMQ_HOST= +RABBITMQ_PORT=5672 +RABBITMQ_VHOST=/ +RABBITMQ_LOGIN=guest +RABBITMQ_PASSWORD= +RABBITMQ_QUEUE=default +RABBITMQ_EXCHANGE_DECLARE=true +RABBITMQ_QUEUE_DECLARE_BIND=true +RABBITMQ_QUEUE_PASSIVE=false +RABBITMQ_QUEUE_DURABLE=true +RABBITMQ_QUEUE_EXCLUSIVE=false +RABBITMQ_QUEUE_AUTODELETE=false +RABBITMQ_EXCHANGE_NAME=sweetheart +RABBITMQ_EXCHANGE_TYPE=direct +RABBITMQ_EXCHANGE_PASSIVE=false +RABBITMQ_EXCHANGE_DURABLE=true +RABBITMQ_EXCHANGE_AUTODELETE=false +RABBITMQ_ERROR_SLEEP=false + +# NEO4J配置 +NEO4J_DEFAULT_PROTOCOL=http +NEO4J_DEFAULT_HOST=127.0.0.1 +NEO4J_DEFAULT_PORT=7474 +NEO4J_DEFAULT_USERNAME=neo4j +NEO4J_DEFAULT_PASSWORD= + +#默认小程序模板名称 +DEFAULT_WEISHOP_TEMP=yykweishop + +# 微商城小程序配置 +## 微信模板id +YYKWEISHOP_TEMPLATE_ID=1 +## 微信模板id(小程序支持直播,一般可不填) +YYKWEISHOP_TEMPLATE_ID_2=1 +## 小程序自定义版本 +YYKWEISHOP_VERSION=v1.0.0 +## request合法域名,逗号分割 +YYKWEISHOP_REQUESTDOMAIN=https://b.test.cn +## socket合法域名,逗号分割 +YYKWEISHOP_WSREQUESTDOMAIN=wss://b-websocket.test.cn +## uploadFile合法域名,逗号分割,七牛,根据自己实际情况填 +YYKWEISHOP_UPLOADDOMAIN=https://up.qiniup.com,https://up-as0.qiniup.com,https://up-na0.qiniup.com,https://up-z1.qiniup.com,https://up-z2.qiniup.com +## uploadFile合法域名,逗号分割,阿里OSS,根据自己实际情况填 +#YYKWEISHOP_UPLOADDOMAIN=https://oss-cn-hangzhou.aliyuncs.com +## downloadFile合法域名,逗号分割,七牛,根据自己实际情况填 +YYKWEISHOP_DOWNLOADDOMAIN=https://mmbiz.qpic.cn,https://wx.qlogo.cn,https://up.qiniup.com,https://up-as0.qiniup.com,https://up-na0.qiniup.com,https://up-z1.qiniup.com,https://up-z2.qiniup.com +## downloadFile合法域名,逗号分割,阿里OSS,根据自己实际情况填 +#YYKWEISHOP_DOWNLOADDOMAIN=https://mmbiz.qpic.cn,https://wx.qlogo.cn,https://oss-cn-hangzhou.aliyuncs.com +## 业务域名,逗号分割 +YYKWEISHOP_WEBVIEWDOMAIN= + +# 核销小程序配置,没有这个业务不需要填 +YYKZS_APPID= +YYKZS_APP_SECRET= + +# websocket配置 +WEBSOCKET_SERVER_PORT=9051 +WEBSOCKET_SERVER_HOST=域名 +TIPS_WS_URI=https://域名/ws:9051 +TIPS_WS_KEY= + +# sentry配置,报错收集 +SENTRY_LARAVEL_DSN= + +# 分销配置 +BROKERAGE_URI= +BROKERAGE_URI_ITEM= + +# OMS配置 +OMS_TOKEN= +OMS_API_URL= +ERP_GY_TOKEN= + +# 默认地址模板 +ADDRESS_TEMPLATE_ID= + +# 日志删除时间 +DEL_OPERATOR_LOGS_DATE= +# 是否saas +SYSTEM_IS_SAAS=false +# 主company_id,单账户,不是saas的配置 +SYSTEM_COMPANYS_ID=1 +# 设置系统主要的企业id,用于pc和h5 +SYSTEM_MAIN_COMPANYS_ID=1 + +# 是否使用系统菜单,false则是固定菜单,true则更新storage/static/目录下的菜单 +USE_SYSTEM_MENU=true +# 系统版本,starndard|platform +PRODUCT_MODEL=standard + +# 对接saas ERP的配置信息 +STORE_KEY=59887c5ceec36fa1a9d9a72c6cdf3741 +CERTI_BASE_URL=https://您的域名/ +# 矩阵关系绑定API +MATRIX_REALTION_URL=https://iframe.shopex.cn/? +# 矩阵API +MATRIX_API_URL=http://matrix.ecos.shopex.cn/sync +VERIFY_APP_ID=ecos.ecshopx + +# 腾讯地图接口KEY, 建议根据项目进行申请 +QQMAP_KEY=PSPBZ-KQ5CW-CSGRF-ON2S4-K2HQJ-XEBQG +# 腾讯地图配置 +TENCENT_LBS_KEY= +TENCENT_LBS_SECERT_KEY= + +# 是否需要服务号,false则需要自己绑定到开放平台 +WX_OPEN_THIRD=true +# 是否需要第三方平台 +WXA_NEED_OPEN_PLATFORM=true + +# 内部rpc,不用管 +RPCCALL_DRIVER=dingo + +# prism配置,默认不用动 +PRISM_URL=http://openapi.shopex.cn/api +PRISM_KEY=a4dyatls +PRISM_SECRET=xescyjbdmzox75cfybab + +# license配置,不用管 +LICENSE_PRODUCTION_URL=http://service.ec-os.net/api/yyk/register +LICENSE_PRODUCT=yyk + +# 文档生成配置 +SWAGGER_STORAGE_DIR=apidocs +SWAGGER_DOCS_ROUTER=api-doc +SWAGGER_API_HOST= +SWAGGER_API_BASE_PATH=/index.php/api + +# 发票链接 +FAPIAO_HANGXIN_API_URL= + +# pc端扫码登录 +PC_WXCODE_LOGIN= + +# H5地址 +H5_BASE_URL= + +``` + + + +#### 安装 + +
安装composer扩展包
+ +``` +cd /var/www/espier-blaoted +composer install +``` + +
数据库迁移
+ +``` +cd /var/www/espier-blaoted +./artisan doctrine:migrations:migrate +``` + + + +### 部署商家端(vue) + +
商家端代码
+
代码build好后build目录里的文件直接copy至此目录
+ +1. 创建项目目录``` +mkdir -p /var/www/espier-retail-manage +``` + +1. 放置代码
通常会通过git的方式进行部署及更新 + +根据业务选择版本。standard:标准版,有“店铺”菜单。platform:平台版,有“商家”菜单
修改**app/config/test.env.js**```bash +module.exports = { + IS_SAAS: '"true"', + PRODUCT_MODEL: '"standard"',// standard:标准版;platform:平台版 + NODE_ENV: '"testing"', + BASE_API: '"https://b.yuanyuanke.cn/api"',// 请求的api基础地质 + //WXIMG_URL: '"https://b.yuanyuanke.cn/image/"', + WXIMG_URL: '""', + WXAUTHCALL_Url: '"https://b.yuanyuanke.cn/"' // 微信授权回调域名,最后的斜杠别忘记了 +} +``` + +3. 安装npm包 +```bash +cd /var/www/espier-retail-manage/app + +npm install +``` + +3. 代码编译目录
**/var/www/espier-retail-manage/app/config/index.js**``` +assetsRoot: path.resolve(__dirname, '../test'), +``` +
编译后的文件在**/var/www/espier-retail-manage/app/test**下 +3. 代码编译``` +npm run build-test +``` + +7. 更改权限``` +chown -R www:www /var/www/espier-retail-manage +``` + + + + + +### 配置nginx + +
修改/etc/nginx/nginx.conf, 将权限nginx 改为www
+ +``` +use www; +``` + +
创建项目nginx配置 +> 以下是通过反向代理的形式配置的服务,您也可以自己按照自己需要配置,只要vue能访问到php就ok了 + +``` +vim /etc/nginx/conf.d/espier.conf +``` + +
需要配置ssl证书, 在下边配置的所有**配置ssl**处。 +```bash +server +{ + listen 443; + # 配置ssl + + server_name b.yuanyuanke.cn; + + location /api/ { + access_log /var/log/nginx/espier-bloated.log; + proxy_pass http://localhost:8080; + } + + location /wechatAuth/ { + access_log /var/log/nginx/espier-wechatauth.log; + proxy_pass http://localhost:8080; + } + + location / { + proxy_pass http://localhost:8081; + } +} + +# 配置API服务(espier-bloated) +server { + + listen 8080; + listen [::]:8080; + + server_name localhost; + root /var/www/espier-bloated/public; + index index.php index.html index.htm; + + location / { + try_files $uri $uri/ /index.php$is_args$args; + } + + location ~ \.php$ { + add_header Access-Control-Allow-Origin '*' always; + add_header Access-Control-Allow-Headers "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With"; + add_header Access-Control-Expose-Headers "Authorization"; + add_header Access-Control-Allow-Methods "DELETE, GET, HEAD, POST, PUT, OPTIONS, TRACE, PATCH"; + + if ($request_method = OPTIONS ) { + return 200; + } + + fastcgi_pass localhost:9000; + fastcgi_read_timeout 150; + fastcgi_index index.php; + fastcgi_buffers 16 16k; + fastcgi_buffer_size 32k; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + include fastcgi_params; + } + + location ~ /\.ht { + deny all; + } +} + +# 配置商家端(espier-retail-manage) +# pc端配置,h5配置可以参考这个进行修改 +server { + listen 8081; + listen [::]:8081; + + server_name localhost; + + location / { + root /var/www/espier-retail-manage/app/test; + index index.html index.htm; + try_files $uri $uri/ /index.html =404; + } + + location /wximage/ { + set $hostx ""; + set $addrs ""; + if ( $uri ~ "^/wximage/http./+([^/]+)/(.+)$") { + set $hostx $1; + set $addrs $2; + } + resolver 8.8.8.8; + proxy_pass http://$hostx/$addrs; + proxy_set_header referer "http://read.html5.qq.com/image"; + } +} + +配置websocket服务 +server +{ + listen 443; + + # 配置ssl + + server_name b-websocket.yuanyuanke.cn; + + location / { + proxy_pass http://localhost:9051/; + + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } +} +``` + + + +### 配置定时任务 + + +``` +crontab -e +``` + + +```json +* * * * * sudo -E -u www php /var/www/espier-bloated/artisan schedule:run >> /var/log/espier-cront.log 2>&1 +``` + + + +### 配置队列服务 + +
修改队列配置
+ +``` +vim /etc/supervisord.d/super-queue.ini +``` + + +```bash +[program:bloated-queue-default] +command=/var/www/espier-bloated/artisan queue:work --queue=default --delay=3 --memory=128 --timeout=30 --sleep=1 --tries=3 +stdout_logfile=/var/www/espier-bloated/storage/logs/supervisor-bloated-queue-default.log +redirect_stderr=true +process_name=%(program_name)s_%(process_num)02d +autostart=true +autorestart=true +numprocs=1 +user=www +startsecs=3 +startretries=100000 + +[program:bloated-queue-slow] +command=/var/www/espier-bloated/artisan queue:work --queue=slow --delay=3 --memory=128 --timeout=1800 --sleep=1 --tries=3 +stdout_logfile=/var/www/espier-bloated/storage/logs/supervisor-bloated-queue-slow.log +redirect_stderr=true +process_name=%(program_name)s_%(process_num)02d +redirect_stderr=true +autostart=true +autorestart=true +numprocs=1 +user=www +startsecs=3 +startretries=100000 + +[program:bloated-queue-sms] +command=/var/www/espier-bloated/artisan queue:work --queue=sms --delay=3 --memory=128 --timeout=1800 --sleep=1 --tries=3 +stdout_logfile=/var/www/espier-bloated/storage/logs/supervisor-bloated-queue-sms.log +redirect_stderr=true +process_name=%(program_name)s_%(process_num)02d +redirect_stderr=true +autostart=true +autorestart=true +numprocs=1 +user=www +startsecs=3 +startretries=100000 +``` + + + +### 配置websocket服务 + +
配置websocket
+ +``` +vim /etc/supervisord.d/super-websocket.ini +``` + + +```bash +[program:websocket] +command=/var/www/espier-bloated/artisan websocket:start +stdout_logfile=/var/www/espier-bloated/storage/logs/supervisor-websocket.log +redirect_stderr=true +autostart=true +autorestart=true +numprocs=1 +user=www +startsecs=3 +startretries=100000 +``` + + + +### 小程序编译打包 + +- .env文件配置信息 + + + +```json + { + "APP_BASE_URL": "接口访问地址", + "APP_WEBSOCKET": "websocket访问地址", + "APP_COMPANY_ID": "企业id", + "APP_PLATFORM": "打包平台,standard为标准版, platform为平台版", + "APP_CUSTOM_SERVER": "域名地址,H5支付回调使用", + "APP_HOME_PAGE": "首页访问路径", + "APP_MAP_KEY": "H5 腾讯地图使用key", + "APP_MAP_NAME": "H5 使用地图name" + } +``` + + +- ext.json文件配置 + + + +```json +{ + "extEnable": true, + "extAppid": "第三方平台绑定的开发小程序id,一般建议与小程序appid相同", + "ext": { + "company_id": "企业id", + "appid": "小程序id", + "wxa_name": "通用小程序" + } +} +``` + + +- npm打包指令 + + + +```bash +# 如遇初始化下载时间过长或者network timeout,可更换npm镜像源 +# npm更换淘宝镜像,使用此命令后,npm指令关键词改为(cnpm),例如:npm i 改为 cnpm i +# 更换命令:npm install -g cnpm --registry=https://registry.npm.taobao.org + +# npm初始化安装 +npm i + +# 小程序本地开发编译 +npm run dev:weapp + +# 小程序生产打包 +npm run build:weapp + +# ----------目前小程序包与H5分离,小程序包暂不支持打包H5,请注意区分----------------- + +# H5本地开发编译 +npm run dev:h5 + +# H5生产打包 +npm run build:h5 +``` + + +- 注意事项 +> - 关于小程序预览,dev:weapp本地开发编译模式下因为主包过大无法上传预览,需要使用build:weapp打包后选择小程序开发工具中的详情->本地设置->上传代码时自动压缩混淆 +> - 如果不需要直播插件请在app.js找到_live-player-plugin代码块将其注释掉_ +> - 目前小程序包与H5分离,小程序包暂不支持打包H5,请注意区分 + + +##
+ +### H5编译打包 +> 只支持H5打包 + + + +- .env文件配置 + + + +```javascript +//小程序id +APP_ID="小程序id" +//首页路径 +APP_HOME_PAGE="首页路径" +//企业ID +APP_COMPANY_ID="企业ID" +//api访问地址 +APP_API_BASE_URL="api访问地址" +//域名地址 +APP_HOME_URL="h5访问域名地址" +//websocket访问地址 +APP_WEBSOCKET_URL="websocket访问地址" +//cdn地址 +APP_PUBLIC_PATH="cdn地址" +//cdn地址 +CDN_QINIU_BUCKET="七牛cdn地址BUCKET" +CDN_QINIU_PATH=h5/ +// 平台判断(standard 标准版 platform平台版) +APP_PLATFORM="版本参数" +//地图key +APP_MAP_KEY="腾讯地图key" +//地图name +APP_MAP_NAME="腾讯地图名称" +``` + + +- cdn配置 +> package.json文件配置 + + + +```javascript +"cdn": { + "publicPath": "*host*", + "bucket": "***", + "path": "h5/" +} +``` + + +- 打包发布 + + + +```bash +# 如遇初始化下载时间过长或者network timeout,可更换npm镜像源 +# npm更换淘宝镜像,使用此命令后,npm指令关键词改为(cnpm),例如:npm i 改为 cnpm i +# 更换命令:npm install -g cnpm --registry=https://registry.npm.taobao.org + +# npm初始化安装 +npm i + +# H5本地开发编译 +npm run dev:h5 + +# H5生产打包 +npm run build:h5 + +# ----------目前小程序包与H5分离,H5包暂不支持打包小程序包,请注意区分----------------- +# 小程序本地开发编译 +npm run dev:weapp + +# 小程序生产打包 +npm run build:weapp +``` + + +- 美洽客服配置 + + + +> 如果配置了美洽客服将客户的美洽配置文件放置在打包生成的/dist/h5中与index.html同级 +> + +> 美洽客服配置文件需要客户登录自己的美洽客服平台访问[https://app.meiqia.com/chatlink](https://app.meiqia.com/chatlink) 生成文件下载下来 + + + +- 关于@shopex/sp-mui-app无法安装处理 + + + +```bash +# 配置npm镜像源 +npm config set registry http://registry.npm.ishopex.cn +``` + +## + +## 服务启动 + +
启动队列任务, websocket服务
+ +```bash +systemctl start supervisord.service +``` + +
启动nginx
+ +``` +systemctl start nginx.service +``` + +
启动php-fpm
+ +``` +systemctl start php72-php-fpm.service +``` + + diff --git a/docs/docs/fe4lti.md b/docs/docs/fe4lti.md new file mode 100644 index 0000000..1bfe6ec --- /dev/null +++ b/docs/docs/fe4lti.md @@ -0,0 +1,21 @@ +--- +url: fe4lti +--- + +# 架构说明 + + + + +## 软件架构 +后端开发语言:PHP 8.2
后端技术框架:采用 Lumen 开源框架开发,引入dingo作为接口管理,采用更符合大型项目的 Doctrine ORM 替换系统自带 ORM
前端开发语言:HTML5/CSS3/ES6/小程序开发框架
前端开发框架:VueJS,Taro
数据库:支持 MySQL/MariaDB/SqlServer等数据库
队列:支持 Redis/RabbitMQ/数据库 等方案,默认采用 Redis
缓存:支持 Redis/filesystem/memcached,默认采用 Redis
CDN/OSS:支持阿里云/七牛云
图形数据库:Neo4j(可选)
日志搜集:ELK/Sentry + +## 数据处理能力 +支持 MySQL 读写分离模式,支持阿里云PolarDB。
在 5 机集群下支持 2000 每秒并发,其中订单占比 1%,且根据实际业务需求扩容
采用多级缓存机制,可以有效保证API响应时间在 2S 以内
系统具备按照终端,店铺,门店等权限控制
+ + +## 稳定性 +系统支持集群模式部署,可按照 web/schedule/worker 等不同角色部署,可有效保证系统高可用
支持阿里云 K8S 部署,可以通过HPA实现 POD 自动扩容,可有效保证在突发流量下,系统的高可用
采用事件机制,可以异步处理耗时业务逻辑,保证实时业务稳定性
采用多级缓存机制,nginx+memcache/php+redis 方式,在redis数据库宕机是,可由 nginx 缓存来替代,保证系统高可用。 + +## 持续集成 +系统采用 PHP 开发,支持二次开发
具备完善的开发环境(docker-compose)和测试环境构建脚本,可以快速搭建环境
采用基于 GitLab-CI/K8S/Helm/Helmfile 的持续集成方案 diff --git a/docs/docs/fiytfx.md b/docs/docs/fiytfx.md new file mode 100644 index 0000000..87e6e3b --- /dev/null +++ b/docs/docs/fiytfx.md @@ -0,0 +1,51 @@ +--- +url: fiytfx +--- + +# 阿里云 + +进入 [https://oss.console.aliyun.com/bucket](https://oss.console.aliyun.com/bucket) 创建bucket。
+ + +## 创建 espier-image 和 espier-vue(公共读) + + + +### 一、创建 Bucket +![image.png](../assets/1584441196616-99d22e5b-b0a0-4571-aa7e-45ee632284cd.png)
+ + +### 二、填写详细信息 + +
![image.png](../assets/1584441319048-6c6a3e75-bba8-495a-aed9-3d14aaed031e.png)
+ + +### 三、进入详情页面配置 + +
![image.png](../assets/1584441452079-64e680e1-a70a-4e52-b715-ac5d78a8f08f.png)
+ + +### 四、创建跨域规则 + +
![image.png](../assets/1584441540025-4d88ba3c-d65c-43d0-8997-170fdb7e18fc.png)
+
创建完成如下:
+
![image.png](../assets/1584441567872-a8004b67-9ef7-43d1-b155-291656df2a5e.png)
+ + +### 五、配置 CDN +进入 cdn 管理界面 [https://cdn.console.aliyun.com/domain/list](https://cdn.console.aliyun.com/domain/list)
+
![image.png](../assets/1584441906864-3f87ef16-b4c2-40ee-a941-229fc417bd72.png) + +### 六、域名解析 +CDN添加完成后,会在域名管理界面生成相应的CNAME,然后在域名解析后台添加相应的解析
![图片.png](../assets/1590482695375-bb8fce09-dd9b-4702-8f84-1c93a926fdc8.png)
+ + +## 创建 espier-import-files (私有) + +### 一、创建 +![image.png](../assets/1584442028777-2124d276-52a2-4b24-9a92-2afd4081c3e0.png)
+ +> 私有存储不需要配置 cdn 和跨域 + + + diff --git a/docs/docs/framework_architecture-repository.md b/docs/docs/framework_architecture-repository.md new file mode 100644 index 0000000..8bb4c5c --- /dev/null +++ b/docs/docs/framework_architecture-repository.md @@ -0,0 +1,339 @@ +--- +url: framework_architecture-repository +--- + +# Repository + +> **使用 Repository 辅助 Model**
+ + +若将数据库逻辑都写在 model,会造成 model 的肥大而难以维护,基于 SOLID 原则,我们应该使用 Repository 模式辅助 model,将相关的数据库逻辑封装在不同的 repository,方便中大型项目的维护。 + + +## 数据库逻辑 + +在 CRUD 中,CUD 比较稳定,但 R 的部分则千变万化,大部分的数据库逻辑都在描述R 的部分,若将数据库逻辑写在 controller 或 model 都不适当,会造成 controller 与 model 肥大,造成日后难以维护。 + + +## 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 + +## 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 +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**。
+
+ +> + +**是否该建立存储库接口?**
+ + +理论上使用依赖注入时,应该使用接口,不过接口目的在于通过抽象化,方便在后期更换接口的具体实现,以便让程序达到开放封闭的要求,但是实际上要更换存储库的机会不高,除非你有更换资料库的需求,如从MySQL抽换到MongoDB,此时就该建立存储库接口。 + +不过由于我们使用了依赖注入,将来要从类改成interface也很方便,只要在构造方法的类型提示改成interface即可,维护成本很低,所以在此大可使用的存储库类,用接口反而会造成设计过度,等真正需求来时再重构成接口即可。 + +采用 Doctrine ORM 如何使用 Repository 模式。 + +由于 Doctrine ORM 自带 Repository 模式,所以直接使用即可。 + +UserRepository.php + +```php +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')); + } +} +``` diff --git a/docs/docs/framework_architecture-service.md b/docs/docs/framework_architecture-service.md new file mode 100644 index 0000000..fb89853 --- /dev/null +++ b/docs/docs/framework_architecture-service.md @@ -0,0 +1,308 @@ +--- +url: framework_architecture-service +--- + +# Service + +> + +**使用 Service 辅助 Controller**
+ + +若将商业逻辑都写在 controller,会造成 controller 肥大而难以维护,基于SOLID原则,我们应该使用 Service 模式辅助 controller,将相关的商业逻辑封装在不同的 service,方便中大型项目的维护。 + + +## 商业逻辑 + +商业逻辑中,常见的如 : + +- 牵涉到外部行为 : 如发送Email,使用外部API…。 +- 使用PHP写的逻辑 : 如促销规则计算、订单创建等。 + +若将商业逻辑写在 controller,会造成 controller 肥大,日后难以维护。 + + +## 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()); + } +} +``` + +> + +**改用这种写法,有几个优点 :**
+ + +- 将外部行为写在 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 也可以重复使用此段商业逻辑。 + + +## 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`的职责了。 + + +## Conclusion + +- 实际上会有很多 service,须自行依照 SOLID 原则去判断是否该建立 service。 +- Service 使得商业逻辑从 controller 中解放,不仅更容易维护、更容易扩展、更容易重复使用,且更容易测试。 diff --git a/docs/docs/framework_architecture.md b/docs/docs/framework_architecture.md new file mode 100644 index 0000000..47f7911 --- /dev/null +++ b/docs/docs/framework_architecture.md @@ -0,0 +1,109 @@ +--- +url: framework_architecture +--- + +# 中大型项目架构 + +Laravel 的初学者分为两种: + +- 一种是乖乖的将程序在写 MVC 架构内,这将导致 Controller 和 Model 非常臃肿,日后代码很难维护。 +- 一种是不知道将程序写在哪一个Class内而犹豫不决。 + +本文整理出最适合 Laravel 的中大型项目架构,兼具易维护、易扩展、易复用和易测试的特点。 + + +## 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 的肥大难以维护。 + + +## Model 过于肥大 + +> + +**既然逻辑写在 Controller 不方便维护,那我将逻辑都写在 Model 就好了?**
+
+ +当你将逻辑从 Controller 搬到 Model 后,虽然 Controller 变瘦了,但却肥了 Model,Model 从原本只处理数据库逻辑,现在变成还要负担商业逻辑与显示逻辑,结果更惨。 + +Model 代表数据库吗?把它想成是 Eloquent class就好,数据库逻辑应该写在 repository 里,这也是为什么 Laravel(Lumen) 已经没有 Models目录,Eloquent class 仅仅是放在 app 根目录下而已。 + + +## 中大型项目架构 + +那我们该怎么写呢?别将我们的思维局限在 MVC 内 : + +- Model : 仅当成 Eloquent class。 +- Repository : 辅助 Model,处理数据库逻辑,然后注入到 service。 +- Service : 辅助 Controller,处理商业逻辑,然后注入到 Controller。 +- Controller : 接收 HTTP request,调用其他 service。 +- Presenter : 处理显示逻辑,然后注入到 View。 +- View : 使用 blade 将资料 binding 到 HTML。 + +其中蓝色为原本的 MVC,而紫色为本文要介绍的的重点 : Repository 模式,Service 模式与 Presenter 模式。 + +![arch002.svg](../assets/1584351898106-8e924cd5-0904-4bf5-a50b-d48b44bbd0c4.svg) + +> 箭头表示物件依赖注入的方向。 + + +我们可以发现 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 帮我们分类即可。 + + +## Repository + +由于篇幅的关系,将 repository 独立成专文讨论,请参考[如何使用 Repository 模式](framework_architecture-repository) ? + + +## Service + +由于篇幅的关系,将 service 独立成专文讨论,请参考如何使用 Service 模式? + + +## 单元测试 + +由于现在Model、View、Controller 的依赖都已经拆开,也都使用依赖注入,因此每个部分都可以单独的做单元测试,如要测试service,就将repository 加以 mock,也可以将其他 service 加以 mock。 + + +## 结论 + +本文谈到的架构只是开始,你可以依照实际需求增加更多的目录与 class,当你发现你的 MVC 违反 SOLID原则时,就大胆的将 class 从 MVC 拆开重构,然后依照以下手法 : + +- 建立新的 class 或 interface。 +- 将依赖类依赖注入到 class。 +- 在 class 内处理他的职责。 +- 将 class 或 interface 注入到 Controller 或 View。 + +最后搭配单元测试,测试重构后的架构是否与原来的需求结果相同。