您的位置:首页 > 大数据 > 人工智能

saiku - 访问saiku首页的时候前后台处理流程

2015-10-21 12:10 435 查看
这篇文章讲述:
项目启动后,首次访问SAIKU的登录页,前后台分别做了什么处理

(1) 访问的到底是什么页面?

浏览器输入:localhost:8080 啪一回车
根据web访问的尿性,访问的是 index.jsp 或者 index.html

先看看 index.jsp ,没什么内容

<%@ taglib prefix="authz" uri="http://www.springframework.org/security/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Pentaho BI Platform</title>
<META HTTP-EQUIV="refresh" CONTENT="0;URL=./serverdocs">
</head>
<body>
</body>
</html>

<meta http-equiv="refresh" content="0; url=">
表示:经过一段时间转到另外某个页面
这里0表示没有延时,直接跳转到后面的URL;把0改成1,则延时1秒后跳转。
这就是为什么有的人访问localhost:8080会跳转到localhost:8080/saiku/serverdocs的原因

再看看 index.html

代码太多,你需要知道一点:配置中引入了所有需要的JS和CSS(除了一些需要动态加载的JS和CSS)
因为不管访问什么请求,地址栏都是localhost:8080没变过,得知所有的接口调用都是ajax异步请求
因此,所有需要的JS和CSS必然都是在index.html中引入包含了

目前迫切关注这几个引入:
<script src="js/jquery/jquery.min.js" type="text/javascript"></script>//基本JS
<script type="text/javascript" src="js/backbone/backbone.js"></script>//框架JS

//Saiku 重要的JS
<script type="text/javascript" src="js/saiku/Settings.js"></script>//saiku基本配置->源码
<script type="text/javascript" src="js/saiku/Saiku.js"></script>//初始化saiku基本信息
<script type="text/javascript" src="js/saiku/models/Plugin.js"></script>//访问接口动态获取JS插件
<script type="text/javascript" src="js/saiku/models/Settings.js"></script>//访问接口动态获取CSS插件
<script type="text/javascript" src="js/saiku/adapters/SaikuServer.js"></script>//URL请求交互处理
<script type="text/javascript" src="js/saiku/models/Session.js"></script>//用户状态信息操作类
<script type="text/javascript" src="js/saiku/views/LoginForm.js"></script>//创建用户登录窗口

结论:index.html


(2) 首页,你在初始化自己的时候,都干哈了好事?

Saiku.js 跳了出来 ,他说:在全部的js中,哥们儿我有唯一的一个

$(function(){
//页面初始化加载代码于此
});

我在这里面做了以下的好事,我按顺序说了啊

1、先判断是不是作为BI的PLUGIN存在,如果不是,那我可是一个独立的系统,是需要登录的哟,是就算了撒

2、显然我是被独立了,那我就开始初始化加载吧

3、我第一件事就是要构造一个获取动态JS的接口 URL :/saiku/rest/saiku/info

4、接下来当然是要访问这个接口啦

|——失败后我不做任何处理,反正我破罐子破摔了
|——成功后嘿嘿【接口处理代码和返回的JS列表看最后】

5、我再去构造一个获取动态CSS的接口 URL:/saiku/rest/saiku/info/ui-settings

6、接下来当然还是要访问这个接口啦

|——这么说吧,我如果成功success了,我要做以下的事:
|——加载所有的JS[plugins.size次异步请求]
|——加载所有的CSS[css.size次异步请求]
|——如果我不小心失败error
|——我就只能加载所有的JS[plugins.size次异步请求]啦,你总不能要求我加载获取失败的CSS吧

|——可是不管我是成功还是失败,我要做的事就必须做完,这些事我必做的:

1)创建Session对象
Saiku.session = new Session({}, {username: Settings.USERNAME,password: Settings.PASSWORD});

在创建的时候会调用check_session方法通过构造/saiku/rest/saiku/session并访问该接口去获取用户session信息
如果用户session信息为空就创建new LoginForm()登录页
否则调用load_session方法构建首页空间 - new SessionWorkspace()
|-其实是访问/saiku/rest/saiku/用户帐号/discover接口获取数据源,成功后返回的connectionsList
|-成功后调用process_datasources方法 传入返回的 connectionsList 作为参数
|- 根据 connectionsList 执行 prefetch_dimensions 预加载Cube ->  _.delay(this.prefetch_dimensions, 20);

钻取层级
var connection = this.connections[i];
var catalog = connection.catalogs[j];
var schema = catalog.schemas[k];
var cube = schema.cubes[l];

var key = connection.name + "/" + catalog.name + "/" +
((schema.name === "" || schema.name === null) ? "null" : schema.name) +
"/" + encodeURIComponent(cube.name);

this.cube[key] = new Cube({ key: key });

if (Settings.DIMENSION_PREFETCH === true) {
this.cube[key].fetch();
}
|- 最后新建Workspace或者直接打开查询  -> Saiku.tabs.add(new Workspace());

2)创建Toolbar对象
Saiku.toolbar = new Toolbar();


(3) 动态获取JS

1、关键代码 - InfoResource.getAvailablePlugins()

filepath配置在saiku-beans的这个bean里面

<bean id="platformBean" class="org.saiku.service.PlatformUtilsService">
  <property name="path" value="../webapps/saiku/js/saiku/plugins/"/>
</bean>





2、动态加载的JS如下



(4) $(function(){}); 源码详细分析

if (! Settings.BIPLUGIN) {//Settings.BIPLUGIN 在settings.js中配置为false

//执行页面初始化加载
$(document).ready(function () {

//这个JS对象在js/saiku/models/Plugin.js里面定义
//完成后构建了访问的url:/saiku/rest/saiku/info
/* js/saiku/models/Plugin.js
var PluginCollection = Backbone.Collection.extend({
model: Plugin,
url: 'info'
});
*/
var plugins = new PluginCollection();

//接着,执行 backbone 的 fetch 方法就去访问了这个rest服务 /saiku/rest/saiku/info
plugins.fetch({
//调用成功。返回各个模块的plugin.js的路径
success: function () {

//这个JS对象在js/saiku/models/Settings.js里面定义
//完成后构建了访问的url:/saiku/rest/saiku/info/ui-settings
/* js/saiku/models/Settings.js
var SettingsOverrideCollection = Backbone.Collection.extend({
model: SettingsOverride,
url: 'info/ui-settings'
});
*/
var settingsoverride = new SettingsOverrideCollection();

//接着执行 backbone 的 fetch 方法就去访问了这个rest服务 /saiku/rest/saiku/info/ui-settings
settingsoverride.fetch({

//调用成功。返回一个全局css文件
//加载第一个接口返回的JS和第二个接口返回的CSS
//并根据创建Session对象的状态去决定到登录页还是首页
//创建Toolbar工具栏
success: function () {
var i = plugins.size();
var j = 0;

//遍历第一个rest返回的plugin.js,逐个去异步获取
plugins.each(function (log) {
j = j + 1;
if (log.attributes.path != "js/saiku/plugins/I18n/plugin.js") {
jQuery.ajax({
async:false,
type:'GET',
url:log.attributes.path,
data:null,
success:function(){
//JS全部遍历完毕后,再遍历第二个接口获取到的CSS
if (j == i) {

var k = settingsoverride.size();
var l = 0;
settingsoverride.each(function (log) {
l = l + 1;

for (var key in log.attributes) {
Settings[key] = log.attributes[key];
}
if(Settings.CSS != undefined){
Saiku.loadCSS(Settings.CSS, null)
}

//CSS全部遍历完毕后,创建一个Session:js/saiku/models/Session.js
//创建session会调用初始化方法,从而调用check_session方法
/**
check_session: function() {
if (this.sessionid === null || this.username === null || this.password === null) {
var that = this;
this.clear();
//在这里会调用本页面的url 构造的接口是/saiki/rest/saiku/session
//调用成功后调用process_session
/**
url: function() {return "session";}
**/
this.fetch({ success: this.process_session, error: this.brute_force });
} else {
this.username = encodeURIComponent(options.username);
this.load_session();
}
},
**/

/**
process_session: function(model, response) {
if ((response === null || response.sessionid == null)) {
// Open form and retrieve credentials
Saiku.ui.unblock();
if (Settings.DEMO) {
this.form = new DemoLoginForm({ session: this });
} else {

//第一次访问肯定没有用户信息
//所以就创建一个LoginForm了
//至此就完成了首页初次访问登录框的加载
this.form = new LoginForm({ session: this });
}
this.form.render().open();
} else {
this.sessionid = response.sessionid;
this.roles = response.roles;
this.isAdmin = response.isadmin;
this.username = encodeURIComponent(response.username);
this.language = response.language;
if (typeof this.language != "undefined" && this.language != Saiku.i18n.locale) {
Saiku.i18n.locale = this.language;
Saiku.i18n.automatic_i18n();
}
this.load_session();
}

return this;
},
**/

//再创建工具栏对象:js/saiku/views/Toolbar.js
if (k == l) {
Saiku.session = new Session({}, {
username: Settings.USERNAME,
password: Settings.PASSWORD
});

Saiku.toolbar = new Toolbar();
}
});

}
},
dataType:'script'
});
}
else{
if (j == i) {

var k = settingsoverride.size();
var l = 0;
settingsoverride.each(function (log) {
l = l + 1;

for (var key in log.attributes) {
Settings[key] = log.attributes[key];
}
if(Settings.CSS != undefined){
Saiku.loadCSS(Settings.CSS, null)
}
if (k == l) {
Saiku.session = new Session({}, {
username: Settings.USERNAME,
password: Settings.PASSWORD
});

Saiku.toolbar = new Toolbar();
}
});

}
}

});

},

//如果ui-settings访问失败,只加载第一个接口返回的JS
//并根据创建Session对象的状态去决定到登录页还是首页
//创建Toolbar工具栏
error: function () {
var i = plugins.size();
var j = 0;
plugins.each(function (log) {
j = j + 1;
if (log.attributes.path != "js/saiku/plugins/I18n/plugin.js") {
jQuery.ajax({
async:false,
type:'GET',
url:log.attributes.path,
data:null,
success: function(){
if (j == i) {
if(Settings.CSS != undefined){
Saiku.loadCSS(Settings.CSS, null)
}
Saiku.session = new Session({}, {
username: Settings.USERNAME,
password: Settings.PASSWORD
});

Saiku.toolbar = new Toolbar();
}
},
dataType:'script'
});
}
else{
if (j == i) {

if(Settings.CSS != undefined){
Saiku.loadCSS(Settings.CSS, null)
}
Saiku.session = new Session({}, {
username: Settings.USERNAME,
password: Settings.PASSWORD
});

Saiku.toolbar = new Toolbar();

}
}
});

}
});
}
});
});
}


(5) Settings.js源码

var Settings = {
VERSION: "Saiku-${version}",
BIPLUGIN: false,
BIPLUGIN5: false,
BASE_URL: window.location.origin,
TOMCAT_WEBAPP: "/saiku",
REST_MOUNT_POINT: "/rest/saiku/",
DIMENSION_PREFETCH: true,
DIMENSION_SHOW_ALL: true,
DIMENSION_SHOW_REDUCED: false,
ERROR_LOGGING: false,
I18N_LOCALE: "en",
// number of erroneous ajax calls in a row before UI cant recover
ERROR_TOLERANCE: 3,
QUERY_PROPERTIES: {
'saiku.olap.query.automatic_execution': true,
'saiku.olap.query.nonempty': true,
'saiku.olap.query.nonempty.rows': true,
'saiku.olap.query.nonempty.columns': true,
'saiku.ui.render.mode' : 'table',
'saiku.olap.query.filter' : true,
'saiku.olap.result.formatter' : "flattened"
},
TABLE_LAZY: true,          // Turn lazy loading off / on
TABLE_LAZY_SIZE: 1000,     // Initial number of items to be rendered
TABLE_LAZY_LOAD_ITEMS: 20,       // Additional item per scroll
TABLE_LAZY_LOAD_TIME: 20,  // throttling call of lazy loading items
/* Valid values for CELLSET_FORMATTER:
* 1) flattened
* 2) flat
*/
CELLSET_FORMATTER: "flattened",
// limits the number of rows in the result
// 0 - no limit
RESULT_LIMIT: 0,
MEMBERS_FROM_RESULT: true,
MEMBERS_LIMIT: 3000,
MEMBERS_SEARCH_LIMIT: 75,
ALLOW_IMPORT_EXPORT: false,
ALLOW_PARAMETERS: true,
PLUGINS: [
"Chart"
],
DEFAULT_VIEW_STATE: 'view', // could be 'edit' as well
DEMO: false,
TELEMETRY_SERVER: 'http://telemetry.analytical-labs.com:7000',
LOCALSTORAGE_EXPIRATION: 10 * 60 * 60 * 1000 /* 10 hours, in ms */,
UPGRADE: true,
EVALUATION_PANEL_LOGIN: true,
QUERY_OVERWRITE_WARNING: true,
MAPS: true,
MAPS_TYPE: 'OSM' // OSM || GMAPS
};

/**
* Extend settings with query parameters
*/
Settings.GET = function () {
var qs = document.location.search;
qs = qs.split("+").join(" ");
var params = {},
tokens,
re = /[?&]?([^=]+)=([^&]*)/g;

tokens = re.exec(qs);
while (tokens) {
var value = decodeURIComponent(tokens[2]);
if (! isNaN(value)) value = parseInt(value);
if (value === "true") value = true;
if (value === "false") value = false;
if(decodeURIComponent(tokens[1].toUpperCase()).substring(0,5)==="PARAM"){
params["PARAM"+decodeURIComponent(tokens[1]).substring(5,decodeURIComponent(tokens[1]).length)] = value;
}
else{
params[decodeURIComponent(tokens[1]).toUpperCase()] = value;
}

tokens = re.exec(qs);
}

return params;
}();
_.extend(Settings, Settings.GET);

Settings.PARAMS = (function() {
var p = {};
for (var key in Settings) {
if (key.match("^PARAM")=="PARAM") {
p[key] = Settings[key];
}
}
return p;
}());

Settings.REST_URL = Settings.TOMCAT_WEBAPP + Settings.REST_MOUNT_POINT;

// lets assume we dont need a min width/height for table mode
if (Settings.MODE == "table") {
Settings.DIMENSION_PREFETCH = false;
$('body, html').css('min-height',0);
$('body, html').css('min-width',0);

}
if (Settings.BIPLUGIN5) {
Settings.BIPLUGIN = true;
}

Settings.INITIAL_QUERY = false;
if (document.location.hash) {
var hash = document.location.hash;
if (hash.length > 11 && hash.substring(1, 11) == "query/open") {
Settings.INITIAL_QUERY = true;
}
}

Settings.MONDRIAN_LOCALES = {
"English": "en_US",
"Dutch": "nl_BE",
"French": "fr_FR"
};

/**
* < IE9 doesn't support Array.indexOf
*/
if (!Array.prototype.indexOf)
{
Array.prototype.indexOf = function(elt /*, from*/)
{
var len = this.length >>> 0;

var from = Number(arguments[1]) || 0;
from = (from < 0) ? Math.ceil(from) : Math.floor(from);
if (from < 0)
from += len;

for (; from < len; from++)
{
if (from in this &&
this[from] === elt)
return from;
}
return -1;
};
}

var tagsToReplace = {
'&': '&',
'<': '<',
'>': '>'
};

function replaceTag(tag) {
return tagsToReplace[tag] || tag;
}

function safe_tags_replace(str) {
return str.replace(/[&<>]/g, replaceTag);
}

if ($.blockUI) {
$.blockUI.defaults.css = {};
$.blockUI.defaults.overlayCSS = {};
$.blockUI.defaults.blockMsgClass = 'processing';
$.blockUI.defaults.fadeOut = 0;
$.blockUI.defaults.fadeIn = 0;
$.blockUI.defaults.ignoreIfBlocked = false;

}

if (window.location.hostname && (window.location.hostname == "try.meteorite.bi" )) {
Settings.USERNAME = "admin";
Settings.PASSWORD = "admin";
Settings.DEMO = true;
Settings.UPGRADE = false;
}

var isIE = (function(){
var undef, v = 3;

var dav = navigator.appVersion;

if(dav.indexOf('MSIE') != -1) {
v  = parseFloat(dav.split('MSIE ')[1]);
return v> 4 ? v : false;
}
return false;

}());

var isFF = (function(userAgent) {
'use strict';

return !!userAgent.match(/Firefox/);
}(navigator.userAgent));

var isMobile = (function(userAgent) {
'use strict';

return !!userAgent.match(/android|webos|ip(hone|ad|od)|opera (mini|mobi|tablet)|iemobile|windows.+(phone|touch)|mobile|fennec|kindle (Fire)|Silk|maemo|blackberry|playbook|bb10\; (touch|kbd)|Symbian(OS)|Ubuntu Touch/i);
}(navigator.userAgent));
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: