Saiku嵌入页面plugin=true效果自定义实现(二十七)
Saiku嵌入页面使用 自定义实现 Plugin=true 效果
saiku嵌入页面plugin=true时数据不显示(plugin=false或者不设定plugin的值时数据显示正常)这个问题困扰了我好久好久呀.... 最近想着先处理问题吧,手动来实现一下类似的效果。
Saiku可以通过iframe将url嵌入页面使用,正常情况下是这样子的
http://10.22.33.44:8080/?username=admin&password=123&plugin=true&mode=view#query/open//KPI/ss.saiku
plugin的值为true/false
>> true: 以插件的形式展示,会隐藏菜单栏
>> false: 不以插件的形式展示,会带出工具栏
mode的值为 view/table
>>view 会带出导出excel那一栏工具按钮信息
>>table 只显示table数据,没有工具栏信息
我部署在本地的saiku能正常使用以上方法嵌入页面使用,但是不知道为什么 部署在公司的saiku使用plugin=true时显示不了... plugin=false的时候显示正常 无奈这又很影响使用,所以就自己改了一下源码,手动控制一些菜单栏以及工具栏的显示了
【debug了很久,没找到原因,后期会继续跟进此问题的,暂时先手工控制来处理此问题~】
实现思路:
嵌入url中添加一个参数 embedFlag,参数值我指定为 hideToolbar
然后在Saiku的Query.js文件的run方法中获取embedFlag参数值并且判断参数值是否为 hideToolbar。 如果是就添加控制菜单栏以及工具栏显示的js代码,如果不是就正常往下执行。
主要添加代码:
//add embed flag,when the parameter embedFlag equals hideToolbar,hide the toolbar. 20190508
var paramsURI = Saiku.URLParams.paramsURI(); //get the param from url
if(paramsURI.embedFlag != undefined && paramsURI.embedFlag == "hideToolbar"){
Saiku.toolbar.remove();//hide toolbar
$('#header').remove(); //hide tabs
$('#new_icon').remove(); //hide open query button
$('#fullscreen_icon').remove(); //hide fullscreen_icon button
}
由于plugin=true嵌入后没有数据显示,所以这里就不设定plugin参数了。
嵌入url: http://10.22.33.44:8080/?username=admin&password=123&mode=view#query/open//KPI/demo1_1.saiku
隐藏之前的效果:
在url上添加自定义的参数信息 embedFlag=hideToolbar
嵌入url: http://10.22.33.44:8080/?username=admin&password=123&mode=view&embedFlag=hideToolbar#query/open//KPI/demo1_1.saiku
隐藏之后的效果:
其实就是两个点
1.在Query.js文件中run方法里面添加此段代码:
//add embed flag,when the parameter embedFlag equals hideToolbar,hide the toolbar. 20190508
var paramsURI = Saiku.URLParams.paramsURI(); //get the param from url
if(paramsURI.embedFlag != undefined && paramsURI.embedFlag == "hideToolbar"){
Saiku.toolbar.remove();//hide toolbar
$('#header').remove(); //hide tabs
$('#new_icon').remove(); //hide open query button
$('#fullscreen_icon').remove(); //hide fullscreen_icon button
}
2.在url中添加此参数信息:
embedFlag=hideToolbar
ps: 查询按钮 以及 全屏按钮是否需要隐藏可根据自己的需要选择注释哦! (我这里显示的按钮比较少 是因为我注释掉了一些目前用不到的按钮信息,避免造成用户视觉混乱~)
隐藏按钮也比较简单啦, 谷歌浏览器 inspect 一下,然后找到对应的 id ,获取元素然后调用remove方法就可以啦~
例如 我们想隐藏导出excel按钮
1.inspect 看到对应的id为 export_xls_icon
2. 在Query.js run方法里面添加 $('#export_xls_icon').remove(); //hide export xls button 即可
最后提供完整的Query.js文件(修改后的)
Query.js
/*
* Copyright 2012 OSBI Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ /**
* Workspace query
*/
var Query = Backbone.Model.extend({ formatter: Settings.CELLSET_FORMATTER,
properties: null, /*初始化方法*/
initialize: function(args, options) {
if(args != null && args != undefined && args != "" && args.flag == "resultForstatisdate"){ this.get_all_statisdate(args);
}else{
// Save cube
_.extend(this, options); // Bind `this`
_.bindAll(this, "run"); // Generate a unique query id
this.uuid = 'xxxxxxxx-xxxx-xxxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g,
function (c) {
var r = Math.random() * 16 | 0,
v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
}).toUpperCase(); this.model = _.extend({ name: this.uuid }, SaikuOlapQueryTemplate);
if (args.cube) {
this.model.cube = args.cube;
}
this.helper = new SaikuOlapQueryHelper(this); // Initialize properties, action handler, and result handler
this.action = new QueryAction({}, { query: this });
this.result = new Result({ limit: Settings.RESULT_LIMIT }, { query: this });
this.scenario = new QueryScenario({}, { query: this }); // A flag to tell who changed selection members
this.updatedSelectionFromModal = false;
}
}, parse: function(response) {
// Assign id so Backbone knows to PUT instead of POST
this.id = this.uuid;
if (response.name) {
this.id = response.name;
this.uuid = response.name;
}
this.model = _.extend(this.model, response);
this.model.properties = _.extend({}, Settings.QUERY_PROPERTIES, this.model.properties);
}, setProperty: function(key, value) {
this.model.properties[key] = value;
}, getProperty: function(key) {
return this.model.properties[key];
}, syncSelectionsModalAndUpdateParameters: function() {
if (this.updatedSelectionFromModal) {
var mParameters = this.helper.model().parameters;
for (var mKey in mParameters) {
var mVal = mParameters[mKey];
var selections = this.helper.getSelectionsForParameter(mKey); mVal = selections.map(function(sel) { return sel.caption; }).join();
mParameters[mKey] = mVal;
}
} else {
var mParameters = this.helper.model().parameters;
for (var mKey in mParameters) {
var mVal = mParameters[mKey];
var mLevel = this.helper.getLevelForParameter(mKey);
var selections = this.helper.getSelectionsForParameter(mKey); if (mVal !== null && mVal !== undefined) {
this.helper.setSelectionsForParameter(mKey, _.filter(selections, function(sel) {
var containsParam = false;
_.each(mVal.split(','), function (v) {
if (sel.caption === v) {
containsParam = true;
return false;
}
});
return containsParam;
}));
}
}
} this.updatedSelectionFromModal = false;
}, /*执行查询的方法*/
run: function(force, mdx) { //add embed flag,when the parameter embedFlag equals hideToolbar,hide the toolbar. 20190508
var paramsURI = Saiku.URLParams.paramsURI(); //get the param from url
if(paramsURI.embedFlag != undefined && paramsURI.embedFlag == "hideToolbar"){
Saiku.toolbar.remove();//hide toolbar
$('#header').remove(); //hide tabs
$('#new_icon').remove(); //hide open query button
$('#fullscreen_icon').remove(); //hide fullscreen_icon button
} this.syncSelectionsModalAndUpdateParameters(); var self = this;
// Check for automatic execution
Saiku.ui.unblock();
if (typeof this.model.properties != "undefined" && this.model.properties['saiku.olap.query.automatic_execution'] === false &&
(force === false || force === undefined || force === null)) {
return;
}
this.workspace.unblock(); $(this.workspace.el).find(".workspace_results_info").empty();
this.workspace.trigger('query:run');
this.result.result = null;
var validated = false;
var errorMessage = '<span class="i18n">Query Validation failed!</span>'; var exModel = this.helper.model(); //針對Summary數據做出更改 當行數據為空的時候 也需要展示出來
var cubename = exModel.cube.name ;
if(cubename == "SummaryKPI_2018_ext" ||cubename == "SummaryKPI_2019_ext" ||cubename == "SummaryKPI_2019_Dynamic" ) {
exModel.queryModel.axes.ROWS.nonEmpty=false;//設置行數據為空的時候也顯示數據! 20190425 for summaryKPI Data
}else{
exModel.queryModel.axes.ROWS.nonEmpty=true;
}
for(var k in this.attributes) {
var att = this.attributes[k];
if(k.substring(0,5)==="PARAM"){
var p = k.substring(5, k.length);
exModel.parameters[p] = att;
} }
if (exModel.queryType == "OLAP") {
if (exModel.type == "QUERYMODEL") {
var columnsOk = Object.keys(exModel.queryModel.axes.COLUMNS.hierarchies).length > 0;
var rowsOk = Object.keys(exModel.queryModel.axes.ROWS.hierarchies).length > 0;
var detailsOk = exModel.queryModel.details.axis == 'COLUMNS' && exModel.queryModel.details.measures.length > 0;
if (!rowsOk || !columnsOk || !detailsOk) {
errorMessage = "";
}
if (!columnsOk && !detailsOk) {
errorMessage += '<span class="i18n">You need to include at least one measure or a level on columns for a valid query.</span>';
}
if(!rowsOk) {
errorMessage += '<span class="i18n">You need to include at least one level on rows for a valid query.</span>'; }
if ( (columnsOk || detailsOk) && rowsOk) {
validated = true;
} } else if (exModel.type == "MDX") {
validated = (exModel.mdx && exModel.mdx.length > 0);
if (!validated) {
errorMessage = '<span class="i18n">You need to enter some MDX statement to execute.</span>';
}
}
}
if (!validated) {
this.workspace.table.clearOut();
$(this.workspace.processing).html(errorMessage).show();
this.workspace.adjust();
Saiku.i18n.translate();
return;
} // Run it
this.workspace.table.clearOut();
$(this.workspace.processing).html('<span class="processing_image"> </span> <span class="i18n">Running query...</span> [ <a class="cancel i18n" href="#cancel">Cancel</a> ]').show();
this.workspace.adjust();
this.workspace.trigger('query:fetch');
Saiku.i18n.translate();
var message = '<span class="processing_image"> </span> <span class="i18n">Running query...</span> [ <a class="cancel i18n" href="#cancel">Cancel</a> ]';
this.workspace.block(message);
/*
TODO: i wonder if we should clean up the model (name and captions etc.)
delete this.model.queryModel.axes['FILTER'].name;
*/ /**根据ROWS中的statisdate字段过滤!*/
//根據用戶輸入的開始日期與結束日期查詢範圍數據
/*
var dimensionArr = exModel.queryModel.axes.ROWS.hierarchies; //取出行信息中的所有维度信息 dimension,用一个数组接收
var statisdateFlag = "no";
for(var i=0;i<dimensionArr.length;i++){
//判断维度信息中是否有statisdate这个时间维度(这是固定的)
if(dimensionArr[i]!=null && ((dimensionArr[i].dimension == "statisdate")||(dimensionArr[i].levels.statisdate != null)) ){
var paramsURI = Saiku.URLParams.paramsURI(); //get the param from url
//判断参数是否为空
if(paramsURI.startdate != null && paramsURI.startdate != undefined && paramsURI.startdate != ""&&
paramsURI.enddate != null && paramsURI.enddate != undefined && paramsURI.enddate != ""){
statisdateFlag = "yes";
this.startdateThis=null;
this.enddateThis=null;
var key="statisdateSpec";
(new SelectionsModal({
key: key,
exModel: exModel,
result: this.result,
workspace: this.workspace
})); }
}
}
*/ /**根据Fliter中的statisdate字段过滤!*/
var dimensionArr = exModel.queryModel.axes.FILTER.hierarchies; //取出FILTER信息中的所有维度信息 dimension,用一个数组接收
var statisdateFlag = "no";
for(var i=0;i<dimensionArr.length;i++){
//判断维度信息中是否有statisdate这个时间维度(这是固定的)
if(dimensionArr[i]!=null && ((dimensionArr[i].dimension == "statisdate")||(dimensionArr[i].levels.statisdate != null)) ){
var paramsURI = Saiku.URLParams.paramsURI(); //get the param from url
//判断参数是否为空
if(paramsURI.startdate != null && paramsURI.startdate != undefined && paramsURI.startdate != ""&&
paramsURI.enddate != null && paramsURI.enddate != undefined && paramsURI.enddate != ""){
statisdateFlag = "yes";
this.startdateThis=null;
this.enddateThis=null;
var key="statisdateSpec";
(new SelectionsModal({
key: key,
exModel: exModel,
result: this.result,
workspace: this.workspace
})); }
}
} //根据入参是否有statisdate字段来判断是否执行以下查询
if(statisdateFlag == 'no'){
this.result.save({},{ contentType: "application/json", data: JSON.stringify(exModel), error: function() {
Saiku.ui.unblock();
var errorMessage = '<span class="i18n">Error executing query. Please check the server logs or contact your administrator!</span>';
self.workspace.table.clearOut();
$(self.workspace.processing).html(errorMessage).show();
self.workspace.adjust();
Saiku.i18n.translate();
} });
}
}, //得到返回的所有statisdate參數信息
get_all_statisdate: function(args){
var response = args.response;
this.result = args.result;
//var exModel = args.exModel;
var statisdateArr= new Array();
for(var i=0;i<response.length;i++){
statisdateArr[i]=response[i].name;
}
//this.helper = new SaikuOlapQueryHelper(this);
var exModel = args.exModel;
var paramsURI = Saiku.URLParams.paramsURI(); //get the param from url
var startdate=null;
var enddate=null;
if(this.startdateThis != null){
startdate=this.dateToStr(this.startdateThis); //获取修正后的开始日期
}else{
startdate=paramsURI.startdate;//开始日期(参数中的)
} if(this.enddateThis != null){
enddate=this.dateToStr(this.enddateThis); //获取修正后的结束日期
}else{
enddate=paramsURI.enddate;//结束日期(参数中的)
} //startdate = this.dateToStr(startdate); // 日期格式化
//enddate = this.dateToStr(enddate); // 日期格式化
if(statisdateArr.indexOf(startdate) > -1){// 这里是判断开始日期是否属于statisdateArr if(statisdateArr.indexOf(enddate) > -1){// 这里是判断结束日期是否属于statisdateArr //var dimensionArr = exModel.queryModel.axes.ROWS.hierarchies; //根据ROWS
var dimensionArr = exModel.queryModel.axes.FILTER.hierarchies; //根据Filter
for(var i=0;i<dimensionArr.length;i++){
if(dimensionArr[i]!=null && (dimensionArr[i].dimension == "statisdate" || dimensionArr[i].levels.statisdate != null ) ){
//更改level下的mdx表达式(使用開始日期與結束日期來控制過濾數據)
dimensionArr[i].levels.statisdate.mdx="[statisdate].[statisdate].[statisdate].["+startdate+"]:[statisdate].[statisdate].[statisdate].["+enddate+"]";
//需要清除之前默認展示本週數據的過濾腳本信息
//exModel.queryModel.axes.ROWS.filters=[];//在ROWS中定义了过滤表达式时,清除此表达式
exModel.queryModel.axes.FILTER.filters=[];//在Filter中定义了过滤表达式时,清除此表达式
}
} this.result.save({},{ contentType: "application/json", data: JSON.stringify(exModel), error: function() {
Saiku.ui.unblock();
var errorMessage = '<span class="i18n">Error executing query. Please check the server logs or contact your administrator!</span>';
self.workspace.table.clearOut();
$(self.workspace.processing).html(errorMessage).show();
self.workspace.adjust();
Saiku.i18n.translate();
} });
}else{//结束日期不存在时:如果结束日期大于开始日期,将结束日期往前减一天 var tmpStartdate = this.strToDate(startdate);//StringToDate方法不存在
var tmpEnddate = this.strToDate(enddate); if(tmpEnddate>=tmpStartdate){
tmpEnddate = tmpEnddate.valueOf();
tmpEnddate = tmpEnddate - 1*24*60*60*1000;
tmpEnddate = new Date(tmpEnddate); //这里改变paramURL中的结束日期参数值,然后回调当前函数 get_all_statisdate
this.enddateThis=tmpEnddate;
this.get_all_statisdate(args); }else{ //否则的话直接执行查询,直接无数据返回 var dimensionArr = exModel.queryModel.axes.FILTER.hierarchies;
for(var i=0;i<dimensionArr.length;i++){
if(dimensionArr[i]!=null && (dimensionArr[i].dimension == "statisdate" || dimensionArr[i].levels.statisdate != null ) ){
enddate = this.dateToStr(tmpStartdate)
//更改level下的mdx表达式(使用開始日期與結束日期來控制過濾數據)
dimensionArr[i].levels.statisdate.mdx="[statisdate].[statisdate].[statisdate].["+enddate+"]:[statisdate].[statisdate].[statisdate].["+enddate+"]";
//需要清除之前默認展示本週數據的過濾腳本信息
//exModel.queryModel.axes.ROWS.filters=[];//在ROWS中定义了过滤表达式时,清除此表达式
exModel.queryModel.axes.FILTER.filters=[];//在Filter中定义了过滤表达式时,清除此表达式 }
} this.result.save({},{ contentType: "application/json", data: JSON.stringify(exModel), error: function() {
Saiku.ui.unblock();
var errorMessage = '<span class="i18n">Error executing query. Please check the server logs or contact your administrator!</span>';
self.workspace.table.clearOut();
$(self.workspace.processing).html(errorMessage).show();
self.workspace.adjust();
Saiku.i18n.translate();
} }); }
}
}else{ //开始日期不存在时: 如果开始日期小于结束日期,将开始日期往后加一天 var tmpStartdate = this.strToDate(startdate);
var tmpEnddate = this.strToDate(enddate);
if(tmpStartdate<=tmpEnddate){
tmpStartdate = tmpStartdate.valueOf();
tmpStartdate = tmpStartdate + 1*24*60*60*1000;
tmpStartdate = new Date(tmpStartdate); //这里改变paramURL中的结束日期参数值,然后回调当前函数get_all_statisdate
this.startdateThis=tmpStartdate;
this.get_all_statisdate(args);
}else{ //否则的话直接执行查询,直接无数据返回 var dimensionArr = exModel.queryModel.axes.FILTER.hierarchies;
for(var i=0;i<dimensionArr.length;i++){
if(dimensionArr[i]!=null && (dimensionArr[i].dimension == "statisdate" || dimensionArr[i].levels.statisdate != null ) ){
startdate = this.dateToStr(tmpEnddate)
//更改level下的mdx表达式(使用開始日期與結束日期來控制過濾數據)
dimensionArr[i].levels.statisdate.mdx="[statisdate].[statisdate].[statisdate].["+startdate+"]:[statisdate].[statisdate].[statisdate].["+startdate+"]";
//需要清除之前默認展示本週數據的過濾腳本信息
//exModel.queryModel.axes.ROWS.filters=[];//在ROWS中定义了过滤表达式时,清除此表达式
exModel.queryModel.axes.FILTER.filters=[];//在Filter中定义了过滤表达式时,清除此表达式
}
} this.result.save({},{ contentType: "application/json", data: JSON.stringify(exModel), error: function() {
Saiku.ui.unblock();
var errorMessage = '<span class="i18n">Error executing query. Please check the server logs or contact your administrator!</span>';
self.workspace.table.clearOut();
$(self.workspace.processing).html(errorMessage).show();
self.workspace.adjust();
Saiku.i18n.translate();
} }); }
}
}, /*將string類型的數據轉換為date類型*/
strToDate: function(strDate){
strDate = strDate.toLocaleString();
strDate = strDate.substring(-1,10);
var convert = Date.parse(strDate);
var tmpdate = new Date(convert);
return tmpdate;
}, /*将Date类型转换为String类型 格式为:2019-03-03*/
dateToStr: function(dateStr){
//dateStr = this.strToDate(dateStr);
var tmpYear= dateStr.getFullYear();
var tmpMonth = dateStr.getMonth()+1;
var tmpDay = dateStr.getDate();
if(tmpMonth < 10){ tmpMonth = "0"+tmpMonth;}
if(tmpDay < 10){ tmpDay = "0"+tmpDay;}
var tmpdate = tmpYear+"-"+tmpMonth+"-"+tmpDay;
return tmpdate;
}, enrich: function() {
var self = this;
this.workspace.query.action.post("/../enrich", {
contentType: "application/json",
data: JSON.stringify(self.model),
async: false,
success: function(response, model) {
self.model = model;
}
});
}, url: function() {
return "api/query/" + encodeURI(this.uuid);
}
/**
get_statisdate_members: function() {
var path = "/result/metadata/hierarchies/%5Bstatisdate%5D.%5Bstatisdate%5D/levels/statisdate"; * gett isn't a typo, although someone should probably rename that method to avoid confusion. this.workspace.query.action.gett(path, {
success: this.fetch_statisdate_members,
error: function() {
alert("error");
},
data: {result: true, searchlimit: 30000 }});
}, 得到獲取statisdate字段的結果信息然後處理
fetch_statisdate_members: function(model, response) { if (response && response.length > 0) {
alert("Fetch_statisdate_member++++++++++++"+response);
} }, */
});
Saiku嵌入页面plugin=true效果自定义实现(二十七)的更多相关文章
- Saiku使用iframe嵌入页面访问地址配置化(二十八)--DWR的基本使用
Saiku使用iframe嵌入页面使用时ip与端口配置化(二十八)--DWR的基本使用 DWR(Direct Web Remoting)是一个用于改善web页面与Java类交互的远程服务器端Ajax开 ...
- Saiku嵌入系统使用时传参数访问saiku(十六)
Saiku嵌入系统使用时传参数访问saiku Saiku通过iframe嵌入其他系统使用时,我们可以设定参数信息,然后根据url中参数对结果进行筛选哦. 这里我们实现的是根据日期字段进行范围查询,UR ...
- IFrame 根据嵌入页面自动调节大小
很多人估计会遇到这样的情况,在IFrame嵌入某些页面,总会出现滚动条,那么有没方法,可以让IFrame随着嵌入页面的内容大小自动调节大小而不出现滚动条呢?答案是肯定的,经过查找,本人发现用Ifram ...
- Saiku控制页面展示的数据过长自动换行(二十四)
Saiku控制页面展示的数据过长自动换行 目前用到saiku来展示数据,发现数据文本过长也不会自动换行,然而用户那边又需要换行(会好看些),所以就来改一改源码啦 首先我们使用谷歌浏览器 inspect ...
- 手机QQ访问时,html页面在QQ中自定义预览和自定义分享
手机QQ访问时,html页面在QQ中自定义预览和自定义分享 有一天,产品说要做个自定义预览和分享功能,于是很快在微信上实现了,可是不知道在QQ上怎么实现,查看了很多网站,最后才找到了解决方案,于是想和 ...
- 移动页面div居中效果代码
在线查看效果:http://hovertree.com/texiao/mobile/4.htm 可用手机浏览器查看 以下为HTML文件: <!DOCTYPE html> <html& ...
- ScrollMagic – 酷毙了!超炫的页面滚动交互效果
ScrollMagic 是一款 jQuery 插件,它让你可以像使用进度条一样使用滚动条.如果你想在特定的滚动位置开始一个动画,并且让动画同步滚动条的动作,或者把元素粘在一个特定的滚动位置,那么这款插 ...
- Space.js – HTML 驱动的页面 3D 滚动效果
为了让我们的信息能够有效地沟通,我们需要创建用户和我们的媒体之间的强有力的联系.今天我们就来探讨在网络上呈现故事的新方法,并为此创造了一个开源和免费使用的 JavaScript 库称为 space.j ...
- iframe嵌入页面不能全部展示
在嵌入页面不能全部展示的问题中,可以通过js改变iframe的高度 html部分代码: <iframe src="#" name="i" id=" ...
随机推荐
- MySQL5.6与MySQL5.7安装的区别
一.MySQL5.6与MySQL5.7安装的区别 1.cmake的时候加入了boost 下载boost.org 2.初始化时 cd /application/mysql/bin/mysql 使用mys ...
- MySQL数据库~~~~~查询行(文件的内容)
1. 单表查询 语法 select distinct 字段 from 库名.表名 where 条件 group by 字段 # 分组 having 筛选 # 过滤 order by 字段 # 排序 l ...
- sql server编写脚本求解第1天1分钱之后每天两倍持续一个月的等比数列问题
一.问题 问题1 场景:如果你未来的丈母娘要求你,第1天给她1分钱,第2天给2分钱,第3天给4分钱,以此类推,每天给前一天的2倍,给1个月(按30天)算就行.问:第30天给多少钱,总共给多少钱? 问题 ...
- DynamicList
DynamicList设计要点——类模板 申请连续空间作为顺序存储空间 动态设置顺序存储空间的大小 保证重置顺序存储空间时的异常安全性 DynamicList设计要点——函数异常安全的概念 不泄露任何 ...
- 淘宝爬取图片和url
刚开始爬取了 百度图片和搜狗图片 但是图片不是很多,随后继续爬取淘宝图片,但是淘宝反爬比较厉害 之前的方法不能用 记录可行的 淘宝爬取 利用selenium爬取 https://cloud.tence ...
- 朝花夕拾《精通CSS》一、HTML & CSS 的基础
一.背景 翻出我4年前看的<精通CSS>一书,可惜当初没有整理读书笔记的习惯,最近又很少写前端,遂很多东西.知识点遗忘了,恰且现在 css 也有些变化和进步,遂一起打包整理,输出成几篇 b ...
- Spark家族:Win10系统下搭建Scala开发环境
一.Scala环境基础 Scala对Java相关的类,接口进行了包装,所以依赖Jvm环境. Jdk 1.8 scala 依赖 scala 2.11 安装版本 idea 2017.3 开发工具 二.配置 ...
- java 与 iOS 平台概念比较
java oc/swift jvm iphone jre runtime? jdk ios SDK spring xcode 生成的应用模版 服务器(tomcat) 系统的事件调度派发部分 class ...
- Selenium(十五):unittest单元测试框架(一) 初识unittest
1. 认识unittest 什么是单元测试?单元测试负责对最小的软件设计单元(模块)进行验证,它使用软件设计文档中对模块的描述作为指南,对重要的程序分支进行测试以发现模块中的错误.在python语言下 ...
- Go 自定义类型来实现枚举类型限制
今天使用iota 发现一个问题.定义别名类型的时候 调用函数报错.废话不多说,我们看一段示例(关于iota的用法这里就不介绍了,手册介绍滴比较详细): package main import &quo ...