@andrewwang
2017-03-19T22:49:28.000000Z
字数 10172
阅读 2064
方案
方式 | 默认信息要求 | 说明 |
---|---|---|
手机号注册 | 无 | |
app授权(微信QQ) | 无 | |
微信服务号授权 | 无 |
if (非平台方应用 && !外部跳转地址)
加iframe
如是登录情况下,从第4步开始流程,开始前需提醒用户需补充的信息。
登录注册页面:应用号,外部跳转地址(redirectUrl,外部发起的请求,无需页面头部和底部),内部跳转地址(url)
完善信息页面:同上。根据信息需求提示用户输入,已有的信息的不必显示。
授权注册,手机注册
完善信息
用户信息符合检查:登录状态除外
方式 | 手机号 | 说明 |
---|---|---|
手机号注册 | 有 | |
app授权(微信QQ) | 无 | |
微信服务号授权 | 无 |
代付单结构(BehalfPayOrder):请求方,代付方,代付金额,代付说明,请求方支付单,请求方订单号,代付方支付单,过期时间。
所需支持的表结构:请求方支付单(b),代付方支付单(p),代付单(df),请求方退款单(br),代付方退款单(pr)。
通过df能单向找到b和p,因为df是扩展功能。保证系统解耦。
- 发起代付:生成df(设置请求方订单号等)。
- 代付去支付:无操作
- 代付成功:生成b和p (状态都是支付成功),修改df(状态是完成, b和p的id)
- 代付退款:正常退款流程(生成br和pr,修改订单状态)。
- 发起后再自己支付:关闭df。
平台上每个服务都是个app。
app表结构:开发商(vendor),用户信息要求(userInfo),动态网址(isUrlDynamic),是否匿名,是否启用(isOn)。
开发商:开发商是平台的不用加iframe(平台开发的自带标准布局),其他都加iframe
用户信息要求:json格式。信息如mobile,idcard,address等。
每个app在使用前都会检查用户状态和信息要求。不符合则要完善。
广告项表结构:来源(custom, app),来源编号,网址,标题等
来源是custom,则使用广告项上的内容
来源是app,则用app的内容(如网址),广告项上的内容都无效。
后端接口:
app广告项的实现:返回应用号信息和应用url
app的动态网址获取:返回url
规则:分类_参数。例如:
实体:id是1000的活动,event_1000
搜索结果:s_news-lastIndex-1-10-keyword。s_news-1200-1-10-iphone,新闻搜索结果,起始点是id是1200的新闻,第一页,每页是10个,关键字是iphone
写:数据库
读:读缓存,没有读数据库(同时保存到缓存)
多用于搜索结果。更新的最小时间单位minTime(如5分钟),更新的最小条数minCount(如十条)。缓存有效期是最大时间单位(如1小时)
if(time < minTime)
refresh = false;
else if (count > minCount)
refresh = true;
// 其他情况下是缓存过期,会自动触发
所有的都是消息,通知是因用户交互产生的(下单,订阅)
推送是种信息传输方式,有短信,邮件,app,微信等
通知推送原则:
1. 推送渠道
1.1. 有来源渠道(推送回来源渠道),比如微信下单,微信通知。需业务记录渠道号(如订单记录渠道是微信)
1.2. 来源渠道没有时,推送到常用渠道(通过记录用户登录和日常使用,来获取)
3. 部分通知必须同时短信通知。如重要的,后续用户需要使用到的。
短信短地址的处理:
短地址对应的页面:有打开app、下载app、关注APP。
打开app时会将业务参数传入app,这样app打开时自动到了特定业务页面。
持久化:
每个消息有持久化模板,通过消息表持久化(用户编号,消息分类,已读,status,标题,内容,网址)
逻辑:
if(持久化) {
消息.标题 = format(持久化模板)
save 消息 to 消息表
}
分类 | 名称 | 编码 | 值 | 说明 | 前端行为 | 后端 | 业务处理 |
---|---|---|---|---|---|---|---|
系统 | 成功 | SUCCESS | 0 | 自定义 | N | ||
系统 | 繁忙 | BUSY | -1 | 系统异常 | ? | N | |
系统 | 失败 | FAIL | 1 | 各种错误原因 | 联系客服 | N | |
系统 | lock失败 | LOCK_FAIL | 2 | 资源锁定失败 | 系统繁忙,重新操作 | N | |
系统 | NEW操作频繁 | OPERATION_FAST | 3 | 操作太快了,在指定时间内(默认1秒)重复提交 | Y | ||
业务-通用 | 验证码错误 | CAPTCHA_ERROR | 300 | 自定义 | Y | ||
业务-通用 | NEW验证码发送频繁 | CAPTCHA_SEND_FAST | 301 | 自定义 | Y | ||
业务-通用 | NEW地址解析错误 | ADDRESS_PARSE_ERROR | 302 | Y | |||
业务-接口 | 数据不存在 | NOT_EXIST | 400 | 管理系统使用,RUD | 自定义 | Y | |
业务-接口 | 数据已存在 | EXIST | 401 | 管理系统使用,CREATE | 自定义 | Y | |
业务-接口 | 参数错误 | PARAM_ERROR | 410 | 比其他错误多一个错误参数编码(field) | ? | 错误参数编码(如bankCard),message(如为空/超过范围) | Y |
业务-接口 | 接口废弃 | DEPRECATED | 411 | 使用annotation实现 | 需升级app | N | |
业务-接口 | 已完成 | FINISHED | 412 | 请求已完成,属于重复提交。先lock,再判断重复。 | 已完成 | Y | |
业务-账户 | 登录失败 | LOGIN_FAIL | 500 | 自定义 | Y | ||
业务-账户 | 需登录 | NEED_LOGIN | 501 | 自定义 | N | ||
业务-账户 | 账户冻结 | ACCOUNT_FROZEN | 503 | 冻结警告 | 提供自定义提示信息 | Y | |
业务-账户 | 账号警告 | ACCOUNT_WARNING | 506 | 多次登录失败警告 | 提供自定义提示信息 | Y | |
业务-电商 | 没有地址 | NO_ADDRESS | 2001 | Y |
将提交内容的md5结果,作为资源锁定。
在锁定期间的后续重复请求自动返回无效。
通过消息队列完成
采用订阅模式:生产者发布消息,消费者订阅并处理
消息必须设置成持久化
业务-生产者:{Biz}Service,如TradeService。
业务-消费者:{Biz}Handler,如IncomeHandler。
框架-业务:EventDispatchService(事件分发,可不用消息队列),MsgDeliveryHandler(信息投递消费者)
框架-基础:MQService(消息队列服务)
{Biz}Service通过EventDispatchService发布消息
{Biz}Service提供指定日期范围内的业务消息
事件:如trade.finish
data(json格式):数据。
原则:如果db有值(如订单),则使用id或者code。无值(如日志)则保存完整数据。
实例:id和code二选一
{
event: 'trade.finish',
ver: '1',
time: 'yyyy-MM-dd HH:mm:ss'
data: {
id: 123456,
code: '123456'
}
}
事件:msg.delivery
data结构:
{
[{
type: 'SMS',
receivers: ['13916870669'],
tpl: {
code: 'tpl_23423423',
text: '',
params: {userName: '旺旺', expireSecond:'60'}
}
},
{
type: 'WX',
receivers: ['453rsfstslf3rwfsfs'],
tpl: {
code: 'tpl_wx322345364',
text: 'hello {userName}',
params: {userName: '旺旺', expireSecond:'60'}
}
}]
}
params支持扩展参数,比如阿里短信的默认前缀编码是ali_sms_prefix_code
如使用阿里短信,还需要配置默认签名,langya.sms.alibaba.prefix.default=阿里不知道啊
RabbitMQ
MQ资料
RabbitMQ三种Exchange模式
app支付流程
统一下单API
prepay(2b设计)解决方案
1. 2小时有效,如果支付时间少于2小时,可以存在订单上
2. 再次付款的解决方案
监控表结构:监控url,监控内容(没有内容则监控http200),监控状态(正常,异常,确定异常),异常次数,目标类型,目标编号
异常次数越多,查询间隔时间越长,超过次数则确定异常。
确定异常后,周期查询是否正常,正常则恢复正常。
恢复正常:重置异常次数
当监控确定异常或者恢复正常时,通知目标。
不管前端或者后端,版本定了后要发布。
特别是前端,需要发布一个uri存放特定版本,如/{codeName}/V。
每个js库有自身的版本号(config.js),如有更新,版本号+1。
项目也有自身的版本号(index.html),如有更新,版本号+1。
项目有版本信息(index.html的VERSION),会和版本号一起更新。
注意:项目只有在正式环境下时,文件才有缓存。
文件替换注意事项:强制全覆盖。
微信缓存解决(微信访问的第一个页面会做强制缓存,加随机数是无效的)
index.html页面上有个加载js文件,在js文件中加随机数加载其他js配置文件(确保本文件每次都被重新加载),至于其他js文件,如果没有版本更新,无需加载新的。
3种方案:
1. 路径签名,如图片网址
2. 特征取样签名,按照文件尺寸等间隔取16个点,合并点值,签名。参考
3. 全部内容签名,参考
最终文件签名:类型(p,t,a)/签名。如p/guid,a/guid。
系统环境(测试和正式)各自有域名和存储空间。定好后不能改变。
1. 存储空间使用规范
正式存储空间:静态文件(如logo,加载中等),正式的动态数据(如cms,广告等)
测试存储空间:测试的动态数据
2. 所有db内的url必须是绝对地址
通过公式计算结果
常用于收入计算,清分等
计算方:基于对象数据计算结果
业务方:提供对象数据,提供时间范围内符合要求的待计算业务对象列表
业务方发起计算请求,计算方计算结果
确保所有的业务对象都会处理
计算方周期发起请求给业务方,获取时间范围内符合要求的待计算业务对象列表,计算方重新计算
支持线性公式和阶梯式公式
公式有code,支持公式嵌套
不支持公式集
不支持实时公式更新
支持模拟计算:需提供所有的输入参数
第三方库有mvel、SpEL、Aviator,现采用SpEL。
公式调用要提供:公式编码和参数列表(类型,编码)
公式表:编码,名称,输入参数列表(json:编码code,名称name,数据类型type),公式
公式定义采用占位符参数形式。比如:
incoming1=#personCount * 1
incoming2=#saleFee * #percent
incoming=#fnCalcDecimal('incoming1', #root)+#fnCalcDecimal('incoming2', #root)
bonus=#fnCalcDecimal('incoming', #root) * 10%
total=#fnCalcDecimal('incoming', #root) + #fnCalcDecimal('bonus', #root)
#fnCalcDecimal('调用公式的编码', #root)
常规方法是直接计算点和点之间的距离。精准度高,但计算量大。
现按照10米一网格将网格中心和点的距离保存,如下一个信息处于本网格中,直接使用本距离。显示误差是10米。
如误差容忍度更高,可以将网格调整的更高。
- 二维环境,点位是否在区域里的判断方法:
用百度接口判断。GeoUtils示例,GeoUtils的API二维环境,点位在哪个区域里的判断方法:
和上面的区别是:上面是Y/N,这个是哪个区域。
也就是说这个是在未知情况下的判断。
- 人工从地图上标出区域边界线(参考画线/区域工具)
- 将标出的区域网格化(具体粒度待定,算法未定)
- 根据目标点位的坐标去查询所属网格,通过网格知道所在区域
- 获取坐标工具
- 获取中国行政区域的边界(最小到”区/县”)
API接口的安全级别
级别 | 机制 | 接口实例 | 说明 |
---|---|---|---|
无 | 无 | 获取商品明细 | |
普通 | 白名单,设置域名或者IP | 获取商品明细 | 黑客可以模拟攻击 |
高级 | 商户:商户授权 | 商户账单获取 | |
高级 | 用户:商户授权+用户令牌 | 订单获取 |
商户授权:
1. 存储位置
a. 后端(客户端被攻击成功也是临时的,提供前端暂时使用的令牌)
b. 前端(客户端被攻击成功就是永久获取)
2. 安全级别
a. 普通(key,可以存储在前端,如百度地图)
b. 高级(key+secret,只能存储在后端,如淘宝)
渠道的安全机制
渠道 | 采用机制 | 说明 |
---|---|---|
自有网站 | 普通安全级别 | |
第三方后端直连 | 高级安全级别,后端存储 | |
原生APP | 高级安全级别,前端存储 | 大部分app采用的方案,前端要确保秘钥安全 |
混合型APP | 高级安全级别,前端存储不安全啊??? | 调用原生函数实现签名? |
有些功能是长期测试功能,通过用户的测试级别定。
用户的测试级别有3级
级别 | 范围 | 说明 |
---|---|---|
1 | 测试部门 | |
2 | 公司内部 | |
3 | 公司外部 |
- 用户有功能版本列表(功能+AB版本),不同功能间的版本是独立的。
- 功能版本列表存放在本地,如cookie。
- 没有功能版本则使用功能前自动分配。
- 分流控制:等比例分配。如2个版本各是50%,5个版本各是20%。
- 每个功能版本都有其页面版本包(页面和逻辑)。通过用户版本自动加载不同的页面和逻辑。
- 测试完成后,可以全部使用选中的版本。
本质上是个功能的路由器,可重定向,可关闭。
每个功能都有发布级别,上下线
分流控制:可指定特定地域,用户级别等
每个发布控制点关联一个功能编码
功能的发布级别是可以管理配置的。支持手工调整和自动调整(如3天升一级)
用户选择随机性确保:功能编码做随机数种子。
级别 | 范围 | 说明 |
---|---|---|
1 | 测试人员 | |
2 | 公司内部 | 内测 |
3 | 1% | 外部小范围 |
4 | 5% | 外部大范围 |
5 | 100% | 发布 |
前端一次性下载(周期性更新):用户级别,功能级别(发布中的功能,不是全部功能)。
用户级别足够,则显示功能,否则隐藏。
老数据的处理方案:如无历史数据压力,推荐方案1
方案1:调整老结构成新结构
数据持久化的是新结构。
老接口做结构转换(新结构转换成老结构)
新接口按照新结构开发
方案2:新老接口同时兼容新老结构
新数据持久化的是新结构。
老接口兼容新老结构
新接口兼容新老结构
常规枚举:单选模式。
组合枚举:多选模式。值是2的倍数,可同时有多个枚举值。比如3就是选择了1和2。
enum Styles {
ShowBorder = 1, //是否显示边框
ShowCaption = 2, //是否显示标题
ShowToolbox = 4 //是否显示工具箱
}
keyValue持久化表(kv),有过期时间。
如有重复则重新生成key(可以不用锁,冲突概率忽略不计)。
if (key exist)
return false;
else
insert
短地址是keyvalue持久化的一种应用场景。
可使用t.cn之类的服务
因第三方短信服务商要检查链接的域名许可。所以只能使用自己的域名。
- 地址路径:域名/t/短地址编码
- 短地址编码:6位的字母数字
配置项:http://www.xyz.com/t/{0}
都在内存操作,不需要存储到文件系统。
导入:前端输入导入文件,后端直接在内存里用模板文件生成。模板文件在类启动时自动加载到内存。
导出:前端输入查询条件,后端获取数据,返回内存文件。
冗余说明:文件上传了,但最后没有用到,放弃了。
冗余实例:修改头像时,未保存的文章,草稿文章删除,文章删除。
七牛支持给每个文件附加数据
方案(未考虑删除):
1. 实时操作
1.1. 标识模式:文件先上传,文件标识成临时使用。在“保存”时标识成永久使用。
1.2. 数量模式:文件先上传,文件使用数是0。在“保存”时使用数+1。
缺陷:要精准使用数成本太高。
1.3. 临时目录模式:文件先上传到存储系统的临时目录,在“保存”时迁移到正式目录。
缺陷:迁移的同时需要修改文件url。用户需要重开编辑界面编辑(临时文件url已经无效)。
临时的打标签
2. 周期清理
列出所有使用到的存储文件,比对存储系统上的列表。清理差异。
缺陷:不适用于大型系统。
流程:TODO
1. 前端设置两个路径,前端/后端返回存储服务的路径清单。
2. 前端/后端比对路径差异,差异文件上传到存储服务。
3. 刷新存储服务的CDN。
列表:
lastindex确保结果唯一
新增:系统周期的自动更新到lastindex
修改:对象动态自动更新
删除:不管,会自动去除
搜索结果:
累计次数,无效之?
分组用于商品等,标签用于订单、活动等
属性 | 适用场景 | 例子 | 反例 |
---|---|---|---|
CreateTime | 关注时间的 | 订单 | 键值 |
Status | 有状态的,支持逻辑删除的 | 商品 | 公式 |
支持图片多选/单选,编辑
方案1:七牛组件
方案2:自建
app:前端调用原生选图编辑图。原生提交编辑后的图片本地路径到前端,前端上传到后端,后端处理后返回图片地网址给前端。
微信:用js组件
ios的预置第一页就是欢迎页
类型 | 说明 | 内容 | 数量 |
---|---|---|---|
引导页 | 安装后显示一次 | 功能介绍 | 2-3 |
欢迎页 | 每次显示 | 产品简介,文字类或者一个简单图片 | 1 |
广告页 | 广告需求才显示 | 0-1 |
产品页面:
类型 | 底栏按钮 | 后退按钮 |
---|---|---|
根页面 | 有 | 无 |
其他页面 | 无 | 有 |
深层次的页面,需要能退出到首页吗?
第三方应用页面(页面或者iframe):
类型 | 设备 | 底部按钮 | 后退按钮 | 退出按钮(第三方应用) |
---|---|---|---|---|
根页面 | Android | 无 | 无 | 有 |
其他页面 | Android | 无 | 无 | 有(点击后回应用首页) |
根页面 | iOS | 无 | 有 | 无 |
其他页面 | iOS | 无 | 有 | 有(点击后回应用首页) |
配置 | 类型 | 说明 |
---|---|---|
根页面 | bool | |
预置的后退页面 | string | |
保留状态 | bool | 当前页面所处位置记忆 |
后退发起的页面会自动从url列表清除
跳转到的页面,是需要不支持后退,底层支持情况如下:
1. app可控制后退(含内置浏览器),达到要求
2. 浏览器或者微信浏览器无法控制后退,不行
if (有预置的后退页面)
后退到预置的后退页面
else
后退到上个页面
浏览器的后退是无法控制,所以我们要能获悉它的后退。
获悉方法:通过自己创建的页面堆栈来辅助。如当前render页面是堆栈最后一个,就是后退。如果是ABA(B跳转到A),无法判断是后退还是跳转你。
需要记忆的页面:重点页面,列表页
模块(列表)容器记忆的方案(另外方案是记录可允许记忆的最大容器数量):
1. 每个模块板块都有容器列表
2. 容器输入参数:是否清除记忆
3. 容器定义参数:功能板块名称,容器名称,记忆方式(永久,临时,不记忆)
4. 明细页:记录变量“是否清除记忆”(如果来源页是其对应的列表页,则是true),变量作为参数传递到下个页面
5. 处理流程(render):
赋值当前功能板块
if (是否清除记忆)
删除当前容器的记忆
遍历容器列表
if (容器.记忆方式 == 临时)
if (容器.功能板块名称 != 当前功能板块)
删除容器的记忆
继续 render
if (容器.记忆方式 != 不记忆)
记忆当前容器
扫描结果是网址(为了支持微信扫描,必须是网址),方案有2个,推荐使用方案1。
方案1:
静态,如http://www.xyz.com/item/123456,http://www.xyz.com/event/123456
处理方式:
1. 微信处理:直接跳转
2. app处理:绝对匹配“http://www.xyz.com/”,前端处理参数,跳转到指定路由。
方案2:
动态,如http://www.xyz.com/scan?type=item&id=123456
处理方式:
1. 微信处理:前端处理参数
2. app处理:绝对匹配“http://www.xyz.com/scan”,前端处理参数。
http://www.xyz.com/scan?type=item&id=123456转换成
http://www.xyz.com/item/123456
http://www.xyz.com/event/123456
- 结构:省/直辖市 市 区/县 街道/镇 居委 社区
- 实例:上海市 上海市 黄浦区 南京东路街道 南东一居委 人民一村
浙江省 台州市 椒江区 路东街道 唐镇3居委 华唐新村- 省市区选择的联动逻辑:
“省/直辖市”选择后,如果选的是直辖市,“市”直接选中且不能修改。