JeeSite 框架学习笔记

JeeSite 框架学习笔记

目录

一、全局配置

1. 获取 Resource资源实际路径 DefaultResourceLoader

示例:

// 获取 Resource资源实际路径
 ResourceLoader resourceLoader = new DefaultResourceLoader();
 System.out.println(resourceLoader.getResource("classpath:static/font/").getURI());

在这里插入图片描述

参考链接:
java web获取配置文件路径.
java web获取配置文件路径_绝对路径、相对路径.

2. 配置前端 js css

配置前端 js css:

// resources\views\include\jslibs.html
// resources\views\include\csslibs.html

二、JAVA 处理 Word 和 打印

1. JAVA 处理 Word

参考链接:
Java多种方式动态生成doc文档.
POI设置 word文本下划线样式及文字底纹.

2. JAVA 打印

参考链接:
使用Java调用打印机进行打印(JPG、PDF和Word三种文件格式).
Java jacob调用打印机打印word文档.

3. Word转图片

// 测试:从本地读取word保存图片到本地 
File fWord = new File("d:\\test.docx");
InputStream inStream = new FileInputStream(fWord);

List<BufferedImage> tempImg = WordAspose.wordToImg(inStream);
BufferedImage mergeImage = WordAspose.mergeImage(false, tempImg);

ImageIO.write(mergeImage, "jpg", new File("D:\\1.jpg"));

4. 前端 js 打印页面

// 打印选项设置 
// 注意:如果写成 magin: 0mm; 可能会不起作用
// 此方法不适用IE内核的浏览器,IE 使用 pagesetup_null()
<style media="print">
	@page {
		margin-bottom: 0mm;
		margin-top: 0mm
	}
	/*@page {*/
	/*	size: auto;  !* auto is the initial value *!*/
	/*	margin: 0mm; !* this affects the margin in the printer settings *!*/
	/*}*/
	.noprint {display: none;}
</style>

// 页面打印
function doPrint() {
	let bdhtml = window.document.body.innerHTML;

	// 设置打印页面内容
	window.document.body.innerHTML = bdhtml;
	if (getExplorer() == "IE") {
		pagesetup_null();
	}

	window.print();
}

// 获取浏览器类型
function getExplorer() {
	let explorer = window.navigator.userAgent;
	//ie   
	if (explorer.indexOf("MSIE") >= 0) {
		return "IE";
	}
	//firefox   
	else if (explorer.indexOf("Firefox") >= 0) {
		return "Firefox";
	}
	//Chrome  
	else if (explorer.indexOf("Chrome") >= 0) {
		return "Chrome";
	}
	//Opera  
	else if (explorer.indexOf("Opera") >= 0) {
		return "Opera";
	}
	//Safari  
	else if (explorer.indexOf("Safari") >= 0) {
		return "Safari";
	}
}

// 设置去除页眉页脚
function pagesetup_null() {
	let hkey_root, hkey_path, hkey_key;
	hkey_root = "HKEY_CURRENT_USER";
	hkey_path = "\\Software\\Microsoft\\Internet Explorer\\PageSetup\\";
	try {
		let RegWsh = new ActiveXObject("WScript.Shell");
		hkey_key = "header";
		RegWsh.RegWrite(hkey_root + hkey_path + hkey_key, "");
		hkey_key = "footer";
		RegWsh.RegWrite(hkey_root + hkey_path + hkey_key, "");
	} catch (e) {
	}
}

打印页面中特定内容:

// 需要打印的页面内容
<div class="">
	<!--startprint-->
	<img src="${ctx}/management/v1/minio/file/view?path=${outBarnCertQuery.outCertPicUrl}">
	<!--endprint-->
</div>
			
// 指定部分内容打印
function doPrint() {
	let bdhtml = window.document.body.innerHTML;

	// 用于截断字符串的内容,截取到指定的图片内容了
	let sprnstr = "<!--startprint-->";
	let eprnstr = "<!--endprint-->";
	let prnhtml = bdhtml.substr(bdhtml.indexOf(sprnstr) + 17);
	prnhtml = prnhtml.substring(0, prnhtml.indexOf(eprnstr));
//       let printContent = $("#printConent")[0].innerHTML; //利用jquery获取打印内容;
//       window.document.body.innerHTML = printContent;

	// 设置打印页面内容
	window.document.body.innerHTML = prnhtml;
	if (getExplorer() == "IE") {
		pagesetup_null();
	}

	window.print();

	// 还原原有页面内容
	window.document.body.innerHTML = bdhtml;
}

参考链接:
window.print():去除页眉页脚及网址.

三、Form 页面

1. 单列页面

a) label 和控件在一行

// 全部用 col-xs-*
<div class="row">
	<div class="col-xs-12">
		<div class="form-group">
			<label class="control-label col-xs-2" title="">
				<span class="required ">*</span> ${text('编码')}<i class="fa icon-question hide"></i></label>
			<div class="col-xs-10">
				<#form:input path="code" maxlength="30" class="form-control required"/>
			</div>
		</div>
	</div>
</div>

b) 底部按钮与编辑框右对齐

// 使用 pull-right,再用 pr 或 mr 调节
<div class="row pr10">
	<div class="pull-right mr5">
		<button type="submit" class="btn btn-sm btn-primary" id="btnSubmit"><i class="fa fa-check"></i> ${text('保 存')}</button>;
		<button type="button" class="btn btn-sm btn-default" id="btnCancel" onclick="closeCurrentLayer()"><i class="fa fa-reply-all"></i> ${text('关 闭')}</button>
	</div>
</div>

2. 参数控制

a) 参数模板控制


// controller
@RequiresPermissions("management:baseinfo:enterprise:view")
@RequestMapping(value = "form")
public String form(Enterprise enterprise, Model model) {
	enterprise.setIsEnabled(1L);
	if (StringUtils.isBlank(enterprise.getEnterpriseId())) {
		model.addAttribute("operation", "0");
	} else {
		model.addAttribute("operation", "1");
	}

	model.addAttribute("enterprise", enterprise);
	return "modules/management/baseinfo/mgtEnterprise/enterpriseForm";
}

// form.html
<div class="col-xs-9">
	<% if(operation != "0"){ %>
		<#form:input path="creditCode" readonly="true"  maxlength="20" class="form-control required"/>
	<% }else{ %>
		<#form:input path="creditCode" maxlength="20" onblur="checkCreditCode()" class="form-control required"/>
	<% } %>
</div>

b) 利用实体的 isNewRecord 判断

${text(storageInPlan.isNewRecord ? '新增入库计划' : '编辑入库计划')}

<% if(storageInPlan.isNewRecord){ %>
	<div class="form-unit">${text('基本信息')}</div>
<% } %>

3. select 控件 和 input 控件同一行无法对齐

a) select 控件 和 input 控件同一行无法对齐
在这里插入图片描述


// 1. 在 select 控件 和 input 控件外再包一层 div.col-xs-12 ,再微调一下 margin 和 padding
<div class="col-xs-12">
	<div class="col-xs-6">
		<div class="form-group" style="margin-left: -30px;">
			<label class="control-label col-xs-4" title="">
				<span class="required ">*</span> ${text('是否有劳动能力')}<i class="fa icon-question hide"></i></label>
			<div class="col-xs-8">
				<% if (formType == "1"){ %>
				<#form:input name="isLaborAbility" value="${regUnemployment.isLaborAbility == 0 ? '否' : '是'}" class="form-control" disabled="true"/>
				<% } else { %>
				<#form:select path="isLaborAbility" dictType="sys_yes_no" blankOption="true" blankOptionLabel="请选择" class="form-control"/>
				<% } %>
			</div>
		</div>
	</div>
	<div class="col-xs-6">
		<div class="form-group" style="margin-left: -8px;">
			<label class="control-label col-xs-4" title="">
				<span class="required hide">*</span> ${text('专业技能证件')}<i class="fa icon-question hide"></i></label>
			<div class="col-xs-8 pr0">
				<#form:input path="skillCertName" maxlength="64" class="form-control"/>
			</div>
		</div>
	</div>
</div>

// 2. 设置 Select 控件的高度与 Input 控件一样
<div class="col-xs-6">
	<div class="form-group">
		<label class="control-label col-xs-4" title="">
			<span class="required ">*</span> ${text('业务类型')}<i class="fa icon-question hide"></i></label>
		<div class="col-xs-8" style="height: 30px">
			<#form:select path="clsInoutReasonId" items="${clsInoutReasonList!}" itemLabel="nameAbbr" itemValue="code" blankOption="true" data-placeholder="请选择" class="form-control required"/>
		</div>
	</div>
</div>

4. input 控件

a) input 控件中显示数组元素


// form
<div class="form-group">
	<label class="control-label col-xs-4" title="">
		<span class="required ">*</span> ${text('致残类型')}<i class="fa icon-question hide"></i></label>
	<div class="col-xs-8">
		<% var cripItems = ["其他", "视力残疾", "听力残疾", "言语残疾", "力残疾", "肢体残疾", "精神残疾", "多重残疾"]; %>
		<% if (formType == "1"){ %>
		<#form:input name="typeCrip" value="${cripItems[regDisabler.typeCrip]}" class="form-control required" disabled="true"/>
		<% } else { %>
		<#form:select path="typeCrip" dictType="crip_type" blankOption="true" blankOptionLabel="请选择" class="form-control required"/>
		<% } %>
	</div>
</div>

b) input 控件中显示字典中的值


// form
<div class="form-group">
	<label class="control-label col-xs-3" title="">
		<span class="required ">*</span> ${text('建筑用途')}<i class="fa icon-question hide"></i></label>
	<div class="col-xs-9">
		<% if (formType != "1"){ %>
		<#form:select path="houseUsage" dictType="HOUSE_USAGE" blankOption="true" blankOptionLabel="请选择" class="form-control"/>
		<% } else { %>
		<% var tempHouseUsage2 = "商住两用"; %>
		<% var tempHouseUsage3 = @DictUtils.getDictListJson('HOUSE_USAGE'); %>
		<% var tempHouseUsage = @DictUtils.getDictLabel('msg_inner_content_level', '1', '普通'); %>
		// 注意: @DictUtils.getDictLabel 的第二个参数是String类型,传入整型会报错
		<#form:input name="houseUsage" value="${@DictUtils.getDictLabel('HOUSE_USAGE', resDoorAddr.houseUsage, ' ')}" class="form-control" disabled="true"/>
		<% } %>
	</div>
</div>

在这里插入图片描述
c) input 控件中自定义格式化


<#form:input name="field" value="${@DateUtils.formatDate(model.field,'yyyyMMdd')}" class="form-control "/>
<#form:input name="field" value="${@NumberUtils.formatNumber(model.field,'0.0')}" class="form-control "/>

d) input 控件中显示单位


<div class="form-group">
	<label class="control-label col-xs-4" title="">
		<span class="required hide">*</span> 应急资金投入:<i class="fa icon-question hide"></i></label>
	<div class="col-xs-8">
		<#form:input path="yjzjtr" maxlength="14" class="form-control digits"/>
		<span style="position: absolute; top: 0; right: 15px; display: table-cell; white-space: nowrap; padding: 5px 10px;"></span>
	</div>
</div>

在这里插入图片描述

5. jQuery Validate自定义验证


// 注册验证方法
$(function(){
	// 身份证号码验证
	$.validator.addMethod("isIdCardNo", function(value, element) {
		return this.optional(element) || (checkIdcard(value) == 'ok');
	}, "请输入正确的身份证号码");
});

$("#inputForm").validate({
	// 定义验证规则
	rules: {
	 	// householderIdnum : 控件ID
	 	// isIdCardNo 验证方法名,[]: 参数列表(此处为空)
		householderIdnum: {isIdCardNo:[]}
	},
	submitHandler: function (form) {
		js.ajaxSubmitForm($(form), function (data) {
			js.showMessage(data.message);
			if (data.result == Global.TRUE) {
				parent.refreshList();
				closeCurrentLayer();
			}
		}, "json");
	}
});

6. textarea 禁止自定义大小

// 添加 style="resize: none;"
<#form:textarea path="spYj" rows="8" maxlength="200" style="resize: none;" class="form-control"/>

7. 图片路径获取

// ${ctxStatic} 对应 resources/static 路径
// ${ctx}
// box-sizing: border-box 盒子模型:height = margin + padding + content;
<div id="alarmImageDiv" style="width: 100%; border: #e7e7e7 solid 1px; padding: 10px; box-sizing: border-box;" >
    <img id="alarmImageBox" style="width: 100%;" src="${ctxStatic}/images/videoAlarm/personIn.png" alt="">
</div>

8. div onresize事件

// 在监控的过程中发现每次改变浏览器窗口的时候 onresize 事件都会触发两次(产生 的原因貌似比较复杂,网上没有定论,发现在最大化浏览器的时候,浏览器也会闪一下,有两次窗口大小的改变)。
// 解决方法: setTimeout()
// 解决触发两次的情况,实际浏览器的 resize 事件可能会触发 n 次,持续时间并不一定是 100 毫秒,例如用户拖动浏览器的边框,以下代码会执行多次 callback 事件;
$(function () {
    window.onresize = function () {
        var target = this;
        if (target.resizeFlag) {
            clearTimeout(target.resizeFlag);
        }

        target.resizeFlag = setTimeout(function() {
            resizeWidget();
            target.resizeFlag = null;
        }, 800);
    }
});

// gridData 控件调整大小有延时,设置一定的时间间隔才能获取到最新的宽高
function resizeWidget() {
    $('#alarmImageDiv').height($('#gbox_dataGrid').height() - 20);
}

9. 去掉 comboTree的图标

<style>
	/*去掉 comboTree的图标*/
	.tree-folder{ width: 0px !important; }
	.tree-file{ width: 0px !important; }
</style>

10. jQuery validator

a) validate 表单提交前二次验证数据的合法性

// 验证数据的合法性,不合法 return false;
$("#inputForm").validate({
	submitHandler: function(form){
		let zzValue = $("#zz").val();
		if (zzValue == "" || zzValue == "请选择") {
			js.alert("请选择组长", {icon: 7});
			console.log(zzValue);
			return false;
		}
		let zgbmValue = $("#zgbmCombo").val();
		if (zgbmValue == "" || zgbmValue == "请选择") {
			js.alert("请选择主管部门", {icon: 7});
			console.log(zgbmValue);
			return false;
		}
		$('#zgbmdm').attr('disabled', false);

		js.ajaxSubmitForm($(form), function(data){
			js.showMessage(data.message);
			if(data.result == Global.TRUE){
				js.getCurrentTabPage(function(window){
					window.refresh()
					closeCurrentLayer()
				},false);
			}
		}, "json");
	}
});

b) 添加自定义校验

// 中文字两个字节
jQuery.validator.addMethod("byteRangeLength", function(value, element, param) {
    var length = value.length;
    for(var i = 0; i < value.length; i++){
        if(value.charCodeAt(i) > 127){
            length++;
        }
    }
  return this.optional(element) || ( length >= param[0] && length <= param[1] );   
}, $.validator.format("请确保输入的值在{0}-{1}个字节之间(一个中文字算2个字节)"));

// 实用工具:用参数代替模板中的 {n}。
jQuery.format(template,argument,argumentN...)

// 邮政编码验证   
jQuery.validator.addMethod("isZipCode", function(value, element) {   
    var tel = /^[0-9]{6}$/;
    return this.optional(element) || (tel.test(value));
}, "请正确填写您的邮政编码");

// 固话和手机号码验证
$.validator.addMethod("telOrMobile", function(value, element) {
	var tel = /^(((\d{3,4}-?)?[0-9]{7,8})|(1(3|4|5|6|7|8|9)\d{9}))$/g;
	return this.optional(element) || (tel.test(value));
}, $.validator.messages.phone);

11. 输入范围在 {0} 到 {1} 之间的数值

// 输入范围在 0 到 9999.999999 之间的数值;
<#form:input path="safetyReserve" maxlength="11" type="number" min="0" max="9999.999999" style="width:173px" class="form-control required number"/>

12. 强行将字段更新为 null

// 增加 isUpdateForce = true
@Column(name="parent_id", attrName="parentId", label="父节点", comment="父节点", isUpdateForce = true),

13. 传到后端的值中多了逗号 “,”

// 问题原因: 表单中存在重名的控件

14. 刷新 list 页面

// 1. 通过 iframe 的name 属性获取对应的 window对象
<iframe id="storageInPlanListIframe" name="storageInPlanListIframe" class="ui-layout-content p0 b0 " src="${ctx}/plan/storageInPlan/list"></iframe>
js.getCurrentTabPage(function(contentWindow){
	try {
		contentWindow.storageInPlanListIframe.refresh();
	} catch (e) {
		console.log("reloadList error: ", e);
	}
});

// 2. 
js.getCurrentTabPage(function (contentWindow){
	let dom = contentWindow.document.getElementById("mainIframe").contentWindow
	updateDataGrid(dom.$("#dataGrid"),data.data);
});

// 3.
js.closeCurrentTabPage(function(contentWindow){
	contentWindow[0].$('#dataGrid').dataGrid('refresh');
	closeCurrentLayer();
});

四、DataGrid

1. 禁止拖拽表格列头


// 初始化DataGrid对象
$('#dataGrid').dataGrid({
	searchForm: $("#searchForm"),
	showRownum: false,   // 是否显示行号
	frozenCols: true,    // 禁止拖拽表格列头
	sortableColumn: false,    // 是否允许列排序
	columnModel: []
	});

2. 多次表头出现多出一列

在这里插入图片描述


// 1. 设置 css 强调把多出的一列高度设置为 0
<style>
	/*.jqg-first-row-header {display: none !important;}*/
	.ui-jqgrid-hbox tr {height: 0px !important;} 
</style>

// 初始化DataGrid对象
$('#dataGrid').dataGrid({
	searchForm: $("#searchForm"),
	columnModel: [],
	// 2. 设置多级表头
	groupHeaders: {
		twoLevel:[
			{startColumnName: 'dateUnemp', numberOfColumns: 8, titleText: '失业信息'},
			{startColumnName: 'isReEmp', numberOfColumns: 8, titleText: '再就业信息'}
		]
	},
	});

3. action 图标对齐


// 新增一个隐藏的图标
actions.push('<a href="javascript:0" title="${text(' ')}" style="visibility: hidden;"><i class="fa fa-eye"></i></a>&nbsp;');

4. 最小高度设置 options.gridMinMeight

统一上下结构列表的样式:

  1. 上下结构的列表页, 下方Pannel高度统一:
    带分页控件的,高度350px,
    不带分页控件的,高度300px
  2. 下方Panel内,dataGrid设置属性 gridMinMeight: 150

// 统一上下结构列表的样式
// 1. 布局 south__size: '350'
$('body').layout({
    south__size: '350',
    south__closable: false,
    south__onresize: function () {
        // 调整iframe的高度
        var height = $("#parent").height();
        $('#emerPersonFrame').height(height - 32);
    }
});

// 2. Datagrid 最小高度设置: gridMinMeight: 150
// 初始化DataGrid对象
$('#dataGrid').dataGrid({
	searchForm: $("#searchForm"),
	showRownum: false, // 列排序
	resizable: true, // 列宽固定
	shrinkToFit: true,
	sortableColumn: false,
	gridMinMeight: 150,
	columnModel: [
		{header:'<span class="col-align-left">人员姓名</span>', name:'xm', index:'a.xm', width:150, align:"left"},
	],
	// 加载成功后执行事件
	ajaxSuccess: function(data){
		
	}
});

5. 下载文件处理

// dataGrid
actions.push('<a οnclick="downloadFile('+"'"+row.emerDealArchivesId+"'"+');" title="${text('下载资料')}"><i class="fa fa-download"></i></a>&nbsp;');

// javascript
function downloadFile(emerDealArchivesId) {
	js.ajaxSubmitForm($('#searchForm'), {
		url:'${ctx}/biz/emer_deal/emerDealArchives/downFile?emerDealArchivesId='+emerDealArchivesId,
		callback:function (data){
			// 失败提示
			if(data.result == Global.FALSE){
				js.showMessage(data.message);
			}
		},
		downloadFile:true
	});
}

五、jQuery 应用

1. 属性选择器处理按钮


//刷新按钮触发事件
function refresh(){
	$('button[type=submit]').click();
}

2. SELECT 控件操作


// 遍历所有选项
$('#parentCode option').each(function () {
	console.log($(this).val());
})

// 默认选中项
$('#parentCode').val("654023101").select2();

// 打印选中选项
console.log($("#parentCode").find("option:selected").text());;


// data-ajax select 设置默认值 
<#form:select path="transport"
data-ajax--url="${ctx}/biz/inv_manager/inventoryOutEmergency/queryResCar"
data-ajax--delay="500"
blankOption="true" data-placeholder="请输入车牌号"
class="form-control"/>
                                
$('#transport').select2({data:[{id: data.numberCar, text: data.numberCar}]}).val(data.numberCar).select2();

3. ajax 请求数据

a) 415 错误


// 解决:
// 前端:
// contentType 与 data 都设置为JSON
// contentType: 'application/json; charset=UTF-8'
// JSON.stringify(data)
$.ajax({
	type: "post",
	async: false,
	url: "${ctx}/emer_manager/emerPlanEnact/saveSelectEmerEvent",
	contentType: 'application/json; charset=UTF-8',
	data: JSON.stringify(data),
	dataType: "json",
	success: function (msg) {
		console.log(msg);
	},
	error: function (obj) {
		js.alert('系统发生异常!');
	}
});

// 后台:
// 参数列表中加入@RequestBody注解

/**
 * 保存应急事件数据
 * url: "${ctx}/emer_manager/emerPlanEnact/saveSelectEmerEvent"
 * param: emerEventId
 * return: EmerPlan
 */
@RequiresPermissions("emer_manager:emerPlanEnact:edit")
@PostMapping(value = "saveSelectEmerEvent")
@ResponseBody
public String saveSelectEmerEvent(@RequestBody EmerEvent emerEvent) {
}

参考链接:
415错误及解决方法.
[Resolved org.springframework.web.HttpMediaTypeNotSupportedException: Content type.

六、IDEA 配置

1. 手动加的 lib 加入到 git

// 问题描述:
[ERROR] Failed to execute goal on project jeesite-cloud-module-management: Could not resolve dependencies for project com.jeesite:jeesite-cloud-module-management:war:4.3.3-SNAPSHOT: Could not find artifact aspose.words:aspose-words:jar:15.8.0 at specified path /home/tfs-agent/_work/2/s/modules/management/management/src/main/webapp/WEB-INF/lib/aspose-words-15.8.0.jar

// 解决方案:
// 1. 打开 .gitignore
// 2. 在最后新增一行
!**/webapp/WEB-INF/lib/*.jar
 

在这里插入图片描述

在这里插入图片描述

2. 快速查找和定位文件位置

在这里插入图片描述

3. run application报错

a) 报错信息:Error running Application. Command line is too long. Shorten the command line via JAR manifest or via a classpath file and rerun.
在这里插入图片描述
解决:
方案一:
在这里插入图片描述
在这里插入图片描述
方案二:
全局设置

  1. 由于方案一是当前项目设置,其他项目打开又没有了,所以可以设置全局,点击File→New Projects Settings→Run Configuration Templates for New Projects

  2. 点击springboot项目,跟方案一的配置一样。
    在这里插入图片描述

参考链接:
IDEA报错Command line is too long.
IDEA报错Command line is too long.

4. DashBoard/ Services不显示端口号

解决方案:

打开启动项管理,把Enable JMX agent复选框选中,重新启动对应服务即可显示端口号。(IDEA 版本:2021.3.1)
在这里插入图片描述

5. 底部显示 service 窗口

a) View => Tool Windows => Service (快捷键: Alt + 8)
b) Service 窗口点 " + " 按钮 => Run Configuration Type +. Spring Boot

6. 快捷键

// 1. Surround with
CTRL+ALT+T
// eg. 
//region Description
//endregion

// 2. 生成变量
CTRL+ALT+V

七、修改 JeeSite内置页面

1. 修改登录页面

a) 禁止登录页面出现滚动条

// 以下配置会出现纵向滚动条 
/*.login-page {*/
/*	background-image: url(${ctxStatic}/themes/login/bg.png);*/
/*	background-size: 100% 100%;*/
/*	background-repeat: no-repeat;*/
/*	color: #FFFFFF;*/
/*}*/

.login-page {
	min-height: 500px;
	background-image: url(${ctxStatic}/themes/login/bg.png);
	background-position: center center;
	background-repeat: no-repeat;		
	/*background-attachment: fixed;*/   /* 底图固定:不随滚动条的滚动而滚动*/
	/*background-size: cover;*/
	overflow: hidden;    /* 设置禁止出现滚动条 */
}

八、权限配置

1. 无需登录直接访问 url

需求:通过 http://localhost:8980/js/a/track/home/homeIndex 就可以直接打开首页。
注意点:通过 nacos 配置对应模块下的 jeesite-cloud-module-track.yml


  # URI 权限过滤器定义(自定义添加参数时,请不要移除 ${adminPath}/** = user,否则会导致权限异常)
  # 提示:填写过滤规则,请注意先后顺序,从上到下,先匹配先受用规则,匹配成功后不再继续匹配。
  filterChainDefinitions: |
    # 过滤掉这些接口(anno表示可匿名使用,可以理解为匿名用户或游客,即不登录就可以访问这个接口)
    ${adminPath}/track/home/** = anon
    /inner/api/** = inner
    /api/** = user
    ${adminPath}/** = user

#  # URI 权限过滤器定义(以下参考,必须登录user可访问的地址和不需要登录anon可访问地址)
#  filterChainDefinitions: |
#    /ReportServer/** = user
#    ${adminPath}/file/** = anon
#    ${adminPath}/cms/* = anon
#    ${adminPath}/cms/site/select = anon
#    ${adminPath}/cms/site/* = anon
#    ${adminPath}/cms/category/treeData = anon
#    ${adminPath}/cms/category/* = anon
#    ${adminPath}/cms/article/* = anon
#    ${adminPath}/cms/link/* = anon
#    ${adminPath}/sys/corpAdmin/treeData = anon
#    ${adminPath}/${spring.application.name}/swagger/** = anon
#    ${adminPath}/** = user

案例:

// 1. Nacos 的 jeesite-cloud-module-management.yml 增加
#Shiro 相关配置
shiro:
  # URI 权限过滤器定义
  filterChainDefinitions: |
    ${adminPath}/management/inoutsupervise/outBarnCertQuery/** = anon
    /inner/api/** = inner
    /api/** = user
    ${adminPath}/** = user

// 2. Controller 增加映射
//	@RequiresPermissions("management:inoutsupervise:outBarnCertQuery:view") // 去掉权限
	@RequestMapping(value = {"mIndex", ""})
	public String mIndex(OutBarnCertQuery outBarnCertQuery, Model model) {
		model.addAttribute("outBarnCertQuery", outBarnCertQuery);
		return "modules/management/inoutsupervise/outBarnCert/mIndex";
	}

// 3. 访问方式
http://localhost:8980/js/a/management/inoutsupervise/outBarnCertQuery/mIndex

九、Beetl

1. 注意点

a) 需要知道Java集合,数组长度,统一用虚拟属性~size来表示


// 需要知道Java集合,数组长度,统一用虚拟属性~size来表示
var list=[1,2,3];
var size = list.~size

b) for-in循环


// 1.
<%
  for(user in userList){
    print(userLP.index);
    print(user.name);
  }
%>
//第三行代码 userLP是Beetl隐含定义的变量,是一个ILoopStatus实例,能在循环体内使用。其命名规范是item名称后加上LP,他提供了当前循环的信息,如

// - **userLP.index **当前的索引,从1开始
// - userLP.dataIndex 索引,从0开始
// - **userLP.size **集合的长度
// - userLP.first 是否是第一个
// - userLP.last 是否是最后一个
// - userLP.even 索引是否是偶数
// - userLP.odd 索引是否是奇数

// 2.
// 对于渲染逻辑更为常见的是经典的for循环语句
<%
var a = [1,2,3];
// a.~size 是集合的大小,beetl 中的虚拟属性
for(var i=0;i<a.~size;i++){
        print(a[i]);
}
%>

// 3.
// 不同于通常程序语言,如果没有进入循环体,则不需额外的处理,模板渲染逻辑更常见情况是如果没有进入循环体,还需要做点什么,因此,对于for循环来说,还有elsefor 用来表达如果循环体没有进入,则执行elsefor 后的语句
<%
var list = [];
for(item in list){

}elsefor{
  print("未有记录");
}
%>

c) 安全输出
模板中还有两种情况会导致模板输出异常

  • 有时候模板变量并不存在,这时候必须报错,如果简单忽略不输出(Velocity就是这样),很容易留坑
  • 模板变量为null,但输出的是此变量的一个属性,如 ${user.wife.name}
// 安全输出指示符号: !
// 可以在!后增加一个常量(字符串,数字类型等),或者另外一个变量,方法,本地调用,作为默认输出,譬如:
// 如果user为null,或者user.wife为null,或者user.wife.name为null,输出单身
${user.wife.name!"单身"}

// 表示如果user为null,或者user. birthday为null,输出 System.constants.DefaultBir
${user.birthday!@System.constants.DefaultBir}

d) 调用Java方法与属性

可以通过符号@来表明后面表达式调用是java风格,可以调用对象的方法,属性


${@user.getMaxFriend(“lucy”)}
${@user.maxFriend[0].getName()}
${@com.xxxx.constants.Order.getMaxNum()}
// 内部类(包括枚举)访问同java一样,如User类有个内部枚举类Gender,访问是User$Gender
${@com.xxxx.User$Gender.MAN}
<%
var max = @com.xxxx.constants.Order.MAX_NUM;
var c =1;
var d = @user.getWife(c).getName();
%>

十、不同窗口之间交互

a) 三层及以上窗口交互:通过当前 layer 向上一层 layer 传递数据,窗口层次关系如下图:
在这里插入图片描述


// 方案一:利用 parent.window 获取目标窗口
// 调试技巧,在 F12调试窗口的控制台中输入 parent查看,在目标中添加类似aaaPlanEmerForm的function方便确认是否是目标窗口
parent.window[0].aaaPlanEmerForm();

// 方案二:利用 parent.layer
var index = parent.layer.getFrameIndex("layui-layer-iframe1");
var body = parent.layer.getChildFrame('body', index);
body.children().find('#xzcy').val('小组成员赋值');   // 小组成员赋值

%>

b) 同一 Tab 下的不同 window 之间交互,窗口之间的关系如下图:
在这里插入图片描述


// 1:获取 currentTabWindow,保存各窗口引用
// xxx1.html
let currentTabWindow;
js.getCurrentTabPage(function (w) {
	// 将当前 window 保存到 currentTabWindow的属性中,这样就可以在同tab 的其他window中访问
	w.mainListWindow = window;
	currentTabWindow = w;
});

// xxx2.html
let currentTabWindow;
js.getCurrentTabPage(function (w) {
	w.listWindow = window;
	currentTabWindow = w;
});

// 2:利用 currentTabWindow 保存的窗口引用操作相应窗口
onSelectRow: function(id, isSelect, event) {
	let rowData =$('#dataGrid').dataGrid('getRowData', id);
	let mainListWindow = currentTabWindow.mainListWindow;
	let listWindow = currentTabWindow.listWindow;

	console.log("currentTabWindow = ", currentTabWindow);
	console.log("mainListWindow = ", mainListWindow);
	console.log("listWindow = ", listWindow);
},
%>

在这里插入图片描述

十一、使用经验总结:

1. 查看表单中的控件禁用:


// planEmerForm.html
$(function () {
	$('#isEnabled').select2({minimumResultsForSearch: -1});
	if ($('#zt').val() != "新的") {
		$('#inputForm *').attr('disabled', true);
		$('#btnSubmit').css('display', 'none');
		$('#btnCancel').attr('disabled', false);
		$('#zgbmCombo').combotree('disable');
	}
});

2. ajax 请求:

a) JQuery:

// 使用示例
$.ajax({
	type: "get",
	async: false,
	url: "${ctx}/biz/emerManager/emerPlan/getEmerPersonList",
	data: {
		'emerOrgId': emerOrgId
	},
	dataType: "json",
	success: function (msg) {
		console.log(msg);
	},
	error: function (obj) {
		js.alert('系统发生异常!');
	}
});

b) JeeSite:

/**
 * AJAX 提交
 * @param urlOrOpt 请求地址,或 AJAX 的选项(Opt为4.2.0新增)
 * @param data 请求参数
 * @param callback 请求 AJAX 后的回调方法
 * @param dataType 返回数据类型(默认JSON)
 * @param async 是否异步(默认true)
 * @param message 调用 js.loading(message) 的提示信息。
 * @usage js.ajaxSubmit('/js/a/index', function(data){ log(data) })
 * @usage js.ajaxSubmit('/js/a/index', {param: 1}, function(data){ log(data) })
 * @usage js.ajaxSubmit('/js/a/index', {param: 1}, function(data){ log(data) },
            'json', true, '正在获取数据...')
 * @usage js.ajaxSubmit({
			url: '/js/a/index', data: {id: '123', name: '456'}, 
			callback: function(data){ log(data) }, dataType: 'json',
			async: true, message: '正在获取数据...'});
 */
js.ajaxSubmit(urlOrOpt, data, callback, dataType, async, message);

3. DataGrid 中 Action 按钮操作方式


// <a> + href=url
actions.push('<a href="${ctx}/biz/emer_manager/emerEvent/delete?emerEventId='+row.emerEventId+'" class="btnList" title="${text('删除应急事件信息')}" data-confirm="${text('确认要删除该应急事件信息吗?')}"><i class="fa fa-trash-o"></i></a>&nbsp;');
// <a> + οnclick=fun()
actions.push('<a οnclick="addOrEditForm('+"'"+row.emerEventId+"'"+')" title="${text('编辑应急事件信息')}"><i class="fa fa-pencil"></i></a>&nbsp;');
// <a> + href=javascript:fun()
actions.push('<a href="javascript:lookForm('+ "'" + row.emerEventId + "'" + ')" title="${text('查看应急事件信息')}"><i class="fa fa-eye"></i></a>&nbsp;');

4. js.getCurrentTabPage 打开新页面窗口回调


// innerCallback 回调
// 获取百度点坐标
function getPoint(){
	var jd = $("#jd").val();
	var wd = $("#wd").val();
	var dtlAddress = $("#dtlAddress").val();
	var url = '${ctxPath}/biz/commonunit/baiduMapPoint';
	if(isDefine(jd) && isDefine(wd)){
		url = url+"?longitude="+jd+"&latitude="+wd+"&address="+dtlAddress;
	}
	js.getCurrentTabPage(function (contentWindow) {
		contentWindow.layer.open({
			type: 2,
			title: '获取经纬度及地址',
			maxmin: false,
			resize :false,
			scrollbar: false,
			area: ['1000px', '705px'],
			content: [url, 'no'],
			innerCallback: function(index, layero, data){
				if(typeof mapPointCallback == 'function'){
					mapPointCallback(data);
				}
				return true;
			}
		});
	});
}

5. 文本中加入汉字空格


// 英文空格: &nbsp;
// 汉字空格: &emsp;
<a href="#tabOther" aria-controls="tabOther" role="tab" data-toggle="tab">&emsp;其他&emsp;</a>

n. temp


// Hello world
console.log("Hello world!");

十二、JavaScript 操作DOM:

1. 向 document中手动添加 style:


// mobilizationCapability/index.vue
// document中 append sytle
var style = this.$refs.mapcontainer.contentWindow.document.createElement("style");
style.type = "text/css";
style.innerHTML =
  ".custom-popup { width: 100%; height: 100%; padding: 5px; color: white; font-size: 16px; text-align: left; } .custom-popup2 { width: 100%; height: 100%; padding: 5px; color: yellow; font-size: 14px; text-align: left; }";
this.$refs.mapcontainer.contentWindow.document
  .getElementsByTagName("head")
  .item(0)
  .appendChild(style);

// 使用
let pointid = this.mapEdit.addpoint(
  res,
  icon,
  {
    content: `<div class="custom-popup2"><div class="custom-popup">${res.ssqymc}</div><div>储备能力:200吨</div><div>储备物资:100吨</div><div>日生产能力:15吨</div><div>日加工能力:20吨</div><div>日配送能力:60吨</div><div>配送车辆数:5辆</div><div>响应能力:2小时</div></div>`,
  },
  )

在这里插入图片描述

十三、调试技巧:

1. 跟踪前端底层代码:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

十四、DataGrid:

1. 同一页面根据 url 参数不同显示内容不同:

// url 配置:
// 登记 url:/biz/inv_manager/inventoryIn/index
// 审核 url:/biz/inv_manager/inventoryIn/index?type=submit
// index 页面中:
<iframe id="inventoryInMainFrame" name="inventoryInMainFrame"
     class="ui-layout-content p0"
     src="${ctx}/biz/inv_manager/inventoryIn/list?type=${parameter.type}"
></iframe>
// DataGrid
{header:'${text(" ")}', name:'actions', width:('${parameter.type}' == 'submit' ? 58 : 102), align: 'right', fixed:true, sortable:false, title:false, frozen: true,formatter: function(val, obj, row, act){
   var actions = [];
   if(row.statusIo=="待入库"){
       //<% if(hasPermi('inv_manager:inventoryIn:edit') && parameter.type != 'submit'){ %>
           actions.push('<a href="javascript:addOrEditForm('+ "'" + row.ivyInoutDtlId + "'" + ')" title="${text("编辑日常入库信息")}"><i class="fa fa-pencil"></i></a>&nbsp;');
           actions.push('<a href="${ctx}/biz/inv_manager/inventoryIn/del?ivyInoutDtlId='+row.ivyInoutDtlId+'" class="btnList" title="${text("删除日常入库信息")}" data-confirm="${text("确认要删除该日常入库信息吗?")}"><i class="fa fa-trash-o"></i></a>&nbsp;');
           actions.push('<a href="javascript:chouyang('+ "'" + row.ivyInoutDtlId + "'" + ')" title="${text("生成样品")}"><i class="fa fa-bitbucket"></i></a>&nbsp;');
       //<% } %>
       //<% if(hasPermi('inv_manager:inventoryIn:check') && parameter.type == 'submit'){ %>
           actions.push('<a href="javascript:checkFileSample('+ "'" + row.ivyInoutDtlId + "'" + ')"  title="${text("提交日常入库信息")}"><i class="fa fa-check"></i></a>&nbsp;');
       //<% } %>
   }
   actions.push('<a href="javascript:viewForm('+ "'" + row.ivyInoutDtlId + "'"+')" title="${text("查看日常入库信息")}"><i class="fa fa-eye"></i></a>&nbsp;');

   return actions.join('');
}},

十五、自动生成:

1. 新增/修改 表单 自动生成 详设文档:


// 打印文档
$(document).ready(function(){

    var regArray = ['email', 'mobile', 'phone', 'contactPhone', 'simplePhone', 'zipCode', 'idcard'];
    var ctlList = [];

    $('#inputForm label').each(function () {
        ctlList.push({label: $(this).text().trim().replace('* ', '')});
    });

    // console.log(ctlList);

    var ctlList2 = [];
    $('#inputForm input, #inputForm select').each(function () {

        if ($(this).attr('type') != 'hidden') {
            var maxlength = $(this).attr('maxlength');
            var isReg = false;
            for (let i = 0; i < regArray.length; i++) {
                if ($(this).hasClass(regArray[i])) {
                    isReg = true;
                    break;
                }
            }

            var bSelectCtl = false;
            if ($(this).is('select')) {
                bSelectCtl = true;
            }
            if ($(this).attr('id') != 'cntUnitName' && $(this).attr('id') != 'weightUnitName') {
                ctlList2.push({id: $(this).attr('id'),
                    maxlength: (maxlength != undefined ? ',长度'+maxlength+'位':''),
                    required: ($(this).hasClass('required') ? '必填' : '选填'),
                    bSelectCtl: (bSelectCtl ? ',下拉列表' : ''),
                    isReg: (isReg ? ',使用正则校验':'')});
            }
        }
    });

    // console.log(ctlList2);

    if (ctlList.length != ctlList2.length) {
        console.log("两个数组长度不一样,请手工核验!");
    }

    for (let i = 0; i < ctlList.length; i++) {
        var output = i+1 + '. ' + ctlList[i].label + ctlList2[i].required + ctlList2[i].bSelectCtl + ctlList2[i].maxlength + ctlList2[i].isReg;
        if (i == ctlList.length-1) output = output + '。'
        else output = output + ';'
        console.log(output);
    }

});

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尹笑辉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值