中间有过改动的地方,想想还是留着之前的,记录一下这个思考、变化的过程
哇~终于到写博客的时候了
行为分析:分析什么(用户的行为)
前端是angular,借助其自带的指令收集用户行为;
后端借助ELK:存到elasticsearch中借助kibana强大的图形展示 以图表方式展示分析的结果;
思路:
1、分为二部分:整个系统为一个实体,具体网页 为一个实体,其实还有一个局部区域的实体,但是交接的时候三个对他们来说有点绕,那索性去一个好辣
2、进入时开始收集数据,离开区域时调用后端方法保存数据,单击时获取单击的相关信息;
如:进入系统界面时收集进入时数据、及浏览器的一些信息(给实体),离开或退出时(准备用组件销毁钩子)收集离开的相关信息;网页和区域同样的道理;
关于离开时调用后端,之前计划离开整个系统时一起提交到后端,但是跨指令我new实体,你知道,之前的数据就没有了,(⊙o⊙)…我可能陷里面了,目前没有找到更好的方法,欢迎大家多提宝贵意见;
前端:
大致思路如下
//定义一个指令:gatherComponentData;指令和组件是一样的道理
@Directive({
selector: '[gatherComponentData]'
})
//考虑到后端地址可能会变,所以需要@input给指令传递后端的url以方便调用,这样改的话成本比较小
@Input('gatherComponentData') behaviorActionUrl: string;
这些三个指令是一样的,下面多少有一些差异,但是都差不多:
//界面加载完成之后 给webContent实体赋值,并存储一部分数据到localstoage中,系统界面销毁时存储到后端
ngAfterViewInit() {
let webContent = {
webEnterTime: new Date(),
browserLanguage: navigator.language || "en-*",
browserColorDepth: screen.colorDepth.toString() + "像素/英寸",
browserWidth: document.documentElement.scrollWidth.toString() || document.body.scrollWidth.toString() || screen.width.toString(),
browserHeight: document.documentElement.scrollHeight.toString() || document.body.scrollHeight.toString() || screen.height.toString(),
browserPlatform: navigator.platform || "",
browserCookieEnabled: navigator.cookieEnabled.toString(),
browserName: navigator.userAgent
}
this.localStorage.setObject('webContent', webContent);
};
/**
* 监听 了点击事件,target是点击的目标:90%是监听对象
*/
@HostListener('click', ['$event.target'])
onMouseclick(btn: HTMLElement) {
//模块名、网页名 根据id获取
// iconfont icon-9 iconfont icon-jiantouxia iconfont icon-jiantouxia
if (btn.id == "webPageId") {
this.webPageContent.webpageName = btn.innerText.trim();//网页名
localStorage.setItem("pageName", btn.innerText.trim());
} else if (btn.id == "webModuleId") {
this.webPageContent.webmoduleName = btn.innerText.trim();//网页所属模块名 需要添加
localStorage.setItem("moduleName", btn.innerText.trim());
} else {
this.webPageContent.webmenuName = btn.innerHTML.trim();//网页一级菜单名
localStorage.setItem("menuName", btn.innerText.trim());
}
};
根据上面的信息,我有一个判断,前端html界面上如果没有这个id的话是需要添加的,或者换成其他的如class也可以,目前是根据id存储到localstorage里面,方便网页指令、区域指令获取自己的网页名等
再展示一个离开事件吧:为了防止用户只是一划而过而收集到无效信息,对时间添加了一个判断:
/**
* 鼠标离开 整个组件的 事件
*/
@HostListener('mouseleave')
onMouseLeave() {
if (this.childDiv) {
//日期格式问题:后台实体内的日期是date类型,但是我如果转成字符串格式是正确的,在转成日期格式就又自动格式化了;停用
// var startDate = new Date();
// let startString = startDate.getFullYear() + '-' + (startDate.getMonth() + 1) + '-' + startDate.getDate() + ' ' + startDate.getHours() + ':' + startDate.getMinutes() + ':' + startDate.getSeconds();
this.enterDivMsg.leaveTime = new Date();//离开组件的时间
let staySecond: number = (this.enterDivMsg.leaveTime.getTime() - this.enterDivMsg.enterTime.getTime()) / 1000
if (staySecond > 1) {
//如果离开操作距离 进入操作 只隔 2s 则 此次离开事件不算
this.enterDivMsg.webpageName = localStorage.getItem("pageName") || " ";//网页名
this.enterDivMsg.webmoduleName = localStorage.getItem("moduleName") || " ";//网页所属模块名 需要添加
//传给后端网页数据
let body = JSON.stringify(this.enterDivMsg);
this.enterDivMsg = new WebPageContent();
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });//, options
let boolean: any = this.http.post(this.behaviorActionChildUrl, body)
.map(res => <any>res.json());
}
}
};
后端
后端用的是bboss连接的elasticsearch并存储:只是存储
bbossgroups是国内首款集AOP、MVC、持久化、JSP标签库、分布式RPC服务、分布式事件框架于一身的企业级JavaEE开发框架,在Apache License Version 2.0 许可协议下开源,后有介绍:
和solr差不多,es需要建立映射,映射很像给实体里的字段定义类型:基本类型
<property name="createUserActionIndice">
<![CDATA[{
"settings": {
"number_of_shards": 6,
"index.refresh_interval": "5s"
},
{
"mappings": {
"webContentComm": {
"properties": {
"userId": {
//字段
"type": "text"//类型
},
"userName": {
"type"