信托学习笔记

后端Datacenter, CRM, 账户服务管那些数据

DC/CRM可以理解为一个东西,都是crmbase那个数据库。
账户服务是单独的库,主要目的是支持手机号登录,以前只支持证件号登录
账户服务将手机号和证件号做关联,在不改变原结构的基础上,支持通过手机号进行登录。

反向代理

在浏览器上伪装成向本机IP的appServer发送请求
实际上是给远程服务器发送的请求,解决跨域的问题.
config.json中配置appBaseUrl,即接口服务地址,如果这里用相对域名/trustgateway,那么请求发送给的就是192.168.114.6:3000/trustgateway
project.json中proxy里面的配置key是/trustgateway,应该是当请求的地址匹配192.168.114.6:3000/trustgateway时,实际请求的是后面配的192.168.114.6:8080/trustgateway
在使用mock地址时,因为appBaseUrl和proxy不匹配,所以proxy并没有生效,但是mock服务器response header返回了access-control-allow-origin:192.168.114.6:3000,所以没有跨域报错.

//config.json
  "appBaseUrl": "/trustgateway/",

//project.json
  "pluginConfig": {
  	"proxy": {
  		"/trustgateway": "http://192.168.114.6:8080/" //此处为真实服务器地址
  	}
  }

TOMCAT 开发环境(业务网关)服务器

war包放在webapps里,跑tomcat时会自动解压生成项目文件夹
WEB-INF/classes/config
appServerConfig.properties //appServer基础配置
appControlConfig.properties //如果部分配置在app写死,如果要修改app需要重新打包,所以将配置环境迁移至业务网关,app通过请求接口获取配置
privateConfig.properties //客户个性化配置
WEB-INF/classes/application.properties //app.registry.address (注册中心地址,业务网关CRM等通过RPC协议统一注册到注册中心)

改端口
conf/server.xml
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8"/>

Tomcat产生logs
/logs

war包产生logs
/bin/logs

Nginx host前端app并反向代理连接开发环境服务器

``
开发环境的实现
/usr/local/nginx
server {
listen 8801;
server_name 10.20.146.48 ;
# 主页/, 打开的是/home/nginx/html5文件夹里的build出来的web app
location / {
root /home/nginx;
# try_files $uri $uri/ /index.html;
index index.html;
}
# 二级域名/trustgateway, 反向代理到开发环境服务器
location /trustgateway {
proxy_pass http://10.20.146.48:8094/trustgateway/;

            #为nginx配置的一些配置项,以此获取真实的访问地址
            proxy_set_header Host $Host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Port $Server_port;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
    }

}

/home/nginx/html5
该文件夹下为build出来的web app
``

项目地址配置 (反向代理)

config.json appBaseUrl 指定了请求接口的服务器地址
信托项目为 /trustgateway/, 即发送req请求时,请求的地址为localhost:xxxx/trustygateway/
在浏览器上伪装成向本机IP的appServer发送请求
pluginConfig中指定了需要代理的真实服务器地址
即伪装成对本机IP(同域)的appServer发送请求,实际上请求的是"http://10.20.xx.xx:xxxx/"远程服务器
"pluginConfig": {
"proxy": {
"/trustgateway": "http://10.20.xx.xx:xxxx/"
}
}

常用数据库表格

``
--短信验证码
select * from tsms_send order by L_serialno desc

--字典表
select * from tdictionary

--系统参数表
select * from tsysparameter

--潜在用户表(只注册没有开过户的账号)
select * from tunregister

--真实用户表
select * from tcustomerinfo

-- 行情表
select * from tfundday

OCI库配置
配置-首选项-链接-OCI库-配置成文件夹下的oci.dll
``

andriod studio

将build好的web app放到android\src\main\assets\www中,andriod应用就可以本地访问页面(即lightdist里的js文件)
src/main/assets/gmu/main.gmu的gmu://jsnative#home是懒加载,类似vue router里的异步import。等同于为先import app.native.js,然后再import lightdist/index-home.native.js
main.gmu(tab菜单的配置) 是否预加载,菜单的title、路径、是否需要登录,导航栏和菜单配色
jsnative.gmu(tab页的配置) 菜单栏页面的配置(pageid,startPage,navigationbar)
因为其他页面的跳转都是走hsopen(然后通过传参来控制页面样式,比如navbartype来控制是否显示navbar),tab页的切换不走hsopen控制不了,所以在原生jsnative这里来配置tab页的样式。
记得修改config.json 这里配置appBaseUrl为真实服务器地址(有些原生的地方,比如启动的时候也会用到服务器)

热更新

通过采用服务器文件而不是本地文件,服务器文件更新时APP对应的文件也会自动更新。
jsnative.gmu:

"inputParams":{
    // 原先,等于用的是lightdist/index-home.native.js,每次更新都需要重新打包
    "startPage":"app.native.js#/home"
    // 现在,重新编译服务器页面更新后,APP的home页面也跟着更新
    "startPage":"http://192.168.137.237:3000/app.native.js#/home"
},

jsnative.gmu只对菜单页面进行了配置,那非tab页面要怎么热更新呢?
注:非tab页面是打包在tab页面下的,所以只需要将菜单页面全部改用服务器文件即可。

@xxx对应的是src/main/res/values/xxx
@string/app_name:
src/main/res/values/string.xml
昆仑信托

@string/safe_welcome_info:
safe_operation\src\main\res\values\strings.xml
欢迎您

com.hundsun.xxx 对应的是rc/main/java/com/hundsun/xxx
com.hundsun.fzfb.SetGetureActivity:
src/main/java/com/hundsun/fzfb/SetGetureActivity.java

生命钩子

aftershow实际上是在mounted中加入的(light对mounted进行了改写)。根据mode,可能比mounted先执行,或者比mounted后执行。信托中,不要用aftershow,在created中通过this.$query去查询传参。

Broadcast

原生下用的是weex的BroadcastChannel注册,H5下用的是eventList
receive时将callback根据key值(事件名)注册到eventList里,当send触发时,将eventList里对应key的callback依一运行。

Keep-alive

Index.vue -> keep-alive中:include="cacheViewList"指定哪些页面会被keep alive. include匹配首先检查组件自身的 name 选项
比如supplement-bank.vue里,我们定义的是

export default {
    name: 'supplement-bank' //this.$options.name
}

所以我们在setCacheView时,要确保传进去的view名称和上面name保持一致

$.setCacheView(this.$options.name, true)
$.setCacheView("supplement-bank", false)

在plugin.js router beforeRouteEnter时,router会判断如果to.meta.cache(即index.html中view的cache属性)是true,则调用setCacheView将to页面缓存

setCacheView在index.vue重写了,定义为如果cache为true且cacheviewlist里没有,会把该页加入在keep-alive里的cacheviewlist

在plugin.js router beforeRouteLeave时,如果from的cache是true,然后to页面的cacheview不包含from,会取消from页的缓存。这里判断了this.$options.name是否存在,所以如果要清from页缓存,需要给from组件定义name

// from.vue
export default {
    name: 'supplement-bank' //this.$options.name
}

或者是to的cache是true,然后from页面的cacheview不包含to,取消to页的缓存。这里判断了to.meta.viewname是否存在,所以如果要清to页缓存,需要给to页指定viewname属性

// index.html
<view id="bankcard/supplement-bank" cache="true" viewname="supplement-bank" parent="index" async="true" chunkname="add-bank"/>

交易记录/注册/忘记密码/买入/卖出/新增银行卡/活动记录/积分购买礼物这些页面被缓存了,其他页面不被缓存(即重新进入时会重新加载)

markRequest $.storage.getOrRequest

我们会发现有些页面(比如trust-list)没有keep alive,但是再次进入时没有再次请求接口,这是怎么回事呢?其实是$.storage.getOrRequest做了一层判断,getOrRequest(saveKey: String, request: Function, opts);如果storage里有saveKey对应的数据,则从storage中获取数据;如果storage里没有,则调用request函数

v-bind vs v-bind:attribute vs v-model vs sync 用一个父元素object设置多个子元素props

// binding an attribute
v-bind:attr="parentParam.attr"
// binding an object of attributes
v-bind="parentParam"
// binding an object of attributes and adding v-on update listener for each attribute
v-bind.sync="parentParam"
//v-model vs .sync
.sync

equivalent to
<comp :value="username" :age="userAge" @update:name="val => userName = val" @update:age="val => userAge = val" />

v-model

equivalent to
<comp :value="username" @input="val => username = val" />

Sync can bind multiple properties other than a single value property, uses @update rather than @input

Index.vue created的时候做了什么

  1. 自定义一些全局方法(loading,toast,showActionSheet,setCacheView)
  2. 启动逻辑
    2.1 如果是APP
    ->如果是home页;
    ->->如果APP首次启动(S_APP_LAUNCH为1,部分场景会导致index.vue被重新created了,我们只希望以下逻辑只执行一遍,所以需要做判断),$.trust.onAppLaunch清理缓存,checkpriagreement->PrivacyService.check检查隐私协议并弹窗->检查新手引导并弹窗
    ->->不管是不是首次启动,SafeOperation.firstPreVerify (检查指纹/手势登录:注册“下次打开APP(重启APP或进入后台时间过长导致重启)清空登录信息”,注册记录进入后台和进入前台时间,未登录则要求指纹/手势验证),queryAppConfigs(查询并储存网关配置的APP配置)
    ->任何页面;
    ->->如果是index页:监听登录广播并清空dialog(原因,其他页面在未登录时dialog提醒,登录后需要把之前这些dialog给清除掉,通过置0时间戳signal,为0时watch会dialog.show = false),开启enableTabCheckLogin(筛选出needLogin的tab页,tab切换时,检查该页是否属于needLogin tabs,需要且未登录则跳转LOGIN,否则正常路由)
    2.2 如果不是APP:
    queryAppConfigs,开启enableTabCheckLogin(功能描述详见2.1)
  3. 登录预检permission.checkAfterLogin
    web则在router.afterEach监听,APP则在Light.on('viewappear')监听,根据是否存在PRECHECK预检标签判断是否预检过,没有则callback运行步骤4,仅运行一次(运行后PRECHECK标签删除)
  4. 检查指纹手势登录SafeOperation.afterLoginVerify
    根据S_NOTIFYFPGL标签判断是否需要提示开启指纹手势登录,如果需要提示并且硬件支持&用户没有开启过(getSafeOperation&getSafeStatus),则setSafeOperation(开启指纹/手势弹窗及调用原生方法),结束后callback运行步骤5
  5. $.trust.checkInvestorStateAfterLogin检查投资者状态
    风险问卷是否过期,合格投资者是否过期,审核是否通过等,有异常根据actionType跳转不同页面

原生中启动的一些逻辑

配合上文步骤2的逻辑,原生启动时S_APP_LAUNCH置1,如果配置“下次启动清空登录信息”,则清空
Andriod下 WeexPlugins.java register:

如何正确获取设备高度

设备高度可以取weex.config.env

platform	String	Current running platform, could be "Android", "iOS" or "Web".
weexVersion	String	The version of Weex SDK.
appName         String	Mobile app name or browser name.
appVersion	String	The version of current app.
osName          String	The OS name, could be "Android" or "iOS".
osVersion	String	The version of current OS.
deviceModel	String	Mobile phone device model. (native only)
deviceWidth	Number	Screen resolution width.
deviceHeight	Number	Screen resolution height.

组件相对位置可以取weex.requireModule('dom').getComponentRect(this.$refs.component)

{
  result: true,
  size: {
    bottom: 60,
    height: 15,
    left: 0,
    right: 353,
    top: 45,
    width: 353
  }
}

weex在不同设备的缩放比scale是不一样的,所以取实际高度时需要除以scale
deviceHeight = deviceHeight / scale

Vue.filter & this.$options.filters

一般filter都是在template中以pipeline形式使用。当我们想在script中使用filter时,我们可以使用this.$options.filters(本地与全局定义Vue.filter或者mixin混入Vue.mixin({filters: {}})都可以使用),可以在component方法(methods, computed)和lifecycle方法(created,mounted)等场景使用。

filters: {
    imgSrc (path) {
        return  $.config.appBaseUrl + 'productFile/getFtpImg.json?filePath=' + encodeURIComponent(path)
    }
},
computed: {
    imageList () {
        return this.record.activity_picurl_detail.map((it) => ({ src: this.$options.filters.imgSrc(it) }))
    }
},

array 一些方法

array.map() 遍历生成新数组(对原数组的所有元素进行mutate,不能remove element,如果需要新数组除掉原数组的部分元素,考虑array.filter().map(),或者array.reduce(性能差点))

let newArray = array.map((item) => ({ value: item.name }));

array.find() 可以用来找array of objects

let obj = array.find( ({ name }) => name === 'abc' );

array.reduce() 遍历根据reducer方法累积,然后输出到initialValue里

//currentIndex, array和initialValue选填
arr.reduce(callback( accumulator, currentValue, currentIndex, array), initialValue)
//遍历array of objects
let obj = array.reduce( (accumulator, currentValue) => accumulator.concat(currentValue), []);

array.sort(compareFunction(a,b)) 也可用来sort array of objects

如果compareFunction(a,b) return > 0, sort b before a
array.sort((a, b) => a - b);

call, apply, bind

call和apply直接调用函数
call用,隔开参数 obj.myFun.call(db, '123', 'abc')
apply用array传参 obj.myFun.apply(db, ['123', 'abc'])
bind返回的是一个新函数,传参和call一样
var newFunction = obj.myFun.bind(db, '123', 'abc');
调用: obj.myFun.bind(db, '123', 'abc')();

通用拦截判断 permission.check

如果在页面跳转时报错或者跳转到了登录,且发现当前页面和目标页面都没有该逻辑判断,很有可能是在init.js改写的hsopen中发生的,这里判断了permission.check。

visitConfig 对一些页面的权限进行了限制:

比如:'^rewards/rewards-': 'PS' //PS代表个人
意思是rewards旗下页面只有个人权限可以访问,机构用户下,发现页面不展示积分商城rewards-market

checkRole 对用户状态进行了限制

调用checkCustInfo并对checkResult中的各个flag进行判断
比如:checkResult.hgflagNotExpired(HGNE 合格投资者未过期),过期则将对应的HGNE flag加入到checkPass里(checkPass.push('HGNE')),并返回error(checkPass, jsonResult);
init.js在permission.check返回error的情况下调用$.trust.checkInvestorState(),用于页面跳转时权限拦截,针对投资者状态,showDialog不同的提示,并hsopen跳转到对应认证或修改信息页面

SafeOperation.verify 未登录则指纹/面容/手势验证或跳转登录页

调用SafeOperation.verify 进行指纹/面容/手势等验证,如果没问题,则通过callNative调用相应的原生验证方法。如果没有开启指纹/面容认证或者认证失败了,会triggerLogout并直接hsopen到LOGIN页面或者next()回调,回调也会next到LOGIN页面
条件1:如果找到了visitConfig里该页面的role权限,但是检测到未登录状态
条件2:如果该页没有定role权限,页面路径是LOGIN(应对其他的check导致hsopen(LOGIN)的情况。比如我们在hsopen('blahblah')时check导致了hsopen(LOGIN),这时会进入条件2)

reporter.js 和环境信息管理系统

reporter.js重定义了 Vue.prototype.$throw。会调用handleError -> collectJsError -> $.http.post (最终post到环境信息管理系统)。不方便原生弹窗报错的话,可以用throw方法, 将报错信息post到环境信息管理系统方便查看。

post到这里

在http://192.168.70.249:9000/sensorslog 上查看

如何自己搭建
https://git01.hundsun.com/xiaqj19255/pem