JeeSite 框架学习笔记

目录

  • JeeSite 框架学习笔记
    • 一、全局配置
      • 1. 获取 Resource资源实际路径 DefaultResourceLoader
      • 2. 配置前端 js css
    • 二、JAVA 处理 Word 和 打印
      • 1. JAVA 处理 Word
      • 2. JAVA 打印
      • 3. Word转图片
      • 4. 前端 js 打印页面
    • 三、Form 页面
      • 1. 单列页面
      • 2. 参数控制
      • 3. select 控件 和 input 控件同一行无法对齐
      • 4. input 控件
      • 5. jQuery Validate自定义验证
      • 6. textarea 禁止自定义大小
      • 7. 图片路径获取
      • 8. div onresize事件
      • 9. 去掉 comboTree的图标
      • 10. jQuery validator
      • 11. 输入范围在 {0} 到 {1} 之间的数值
      • 12. 强行将字段更新为 null
      • 13. 传到后端的值中多了逗号 ","
      • 14. 刷新 list 页面
    • 四、DataGrid
      • 1. 禁止拖拽表格列头
      • 2. 多次表头出现多出一列
      • 3. action 图标对齐
      • 4. 最小高度设置 options.gridMinMeight
      • 5. 下载文件处理
    • 五、jQuery 应用
      • 1. 属性选择器处理按钮
      • 2. SELECT 控件操作
      • 3. ajax 请求数据
    • 六、IDEA 配置
      • 1. 手动加的 lib 加入到 git
      • 2. 快速查找和定位文件位置
      • 3. run application报错
      • 4. DashBoard/ Services不显示端口号
      • 5. 底部显示 service 窗口
      • 6. 快捷键
    • 七、修改 JeeSite内置页面
      • 1. 修改登录页面
    • 八、权限配置
      • 1. 无需登录直接访问 url
    • 九、Beetl
      • 1. 注意点
    • 十、不同窗口之间交互
    • 十一、使用经验总结:
      • 1. 查看表单中的控件禁用:
      • 2. ajax 请求:
      • 3. DataGrid 中 Action 按钮操作方式
      • 4. js.getCurrentTabPage 打开新页面窗口回调
      • 5. 文本中加入汉字空格
      • n. temp
    • 十二、JavaScript 操作DOM:
      • 1. 向 document中手动添加 style:
    • 十三、调试技巧:
      • 1. 跟踪前端底层代码:
    • 十四、DataGrid:
      • 1. 同一页面根据 url 参数不同显示内容不同:
    • 十五、自动生成:
      • 1. 新增/修改 表单 自动生成 详设文档:

一、全局配置

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;//ieif (explorer.indexOf("MSIE") >= 0) {return "IE";}//firefoxelse if (explorer.indexOf("Firefox") >= 0) {return "Firefox";}//Chromeelse if (explorer.indexOf("Chrome") >= 0) {return "Chrome";}//Operaelse if (explorer.indexOf("Opera") >= 0) {return "Opera";}//Safarielse 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").contentWindowupdateDataGrid(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);}});

JeeSite 框架学习笔记相关推荐

  1. SpringMVC框架--学习笔记(下)

    接上篇:SpirngMVC框架--学习笔记(上):https://blog.csdn.net/a745233700/article/details/81038382 17.全局异常处理: 系统中异常包 ...

  2. SpringMVC框架--学习笔记(上)

    1.SpringMVC入门程序: (1)导入jar包:spring核心jar包.spring-webmvc整合Jar包 (2)配置前端控制器:web.xml文件中 <?xml version=& ...

  3. mybatis框架--学习笔记(下)

    上篇:mybatis框架--学习笔记(上):https://blog.csdn.net/a745233700/article/details/81034021 8.高级映射: (1)一对一查询: ①使 ...

  4. mybatis框架--学习笔记(上)

    使用JDBC操作数据库的问题总结: (1)数据库连接,使用时创建,不使用时立即释放,对数据库进行频繁连接开启和关闭,造成数据库资源浪费,影响数据库性能. 设想:使用数据库连接池管理数据库连接. (2) ...

  5. JavaSE中Map框架学习笔记

    前言:最近几天都在生病,退烧之后身体虚弱.头疼.在床上躺了几天,什么事情都干不了.接下来这段时间,要好好加快进度才好. 前面用了三篇文章的篇幅学习了Collection框架的相关内容,而Map框架相对 ...

  6. python表单提交的两种方式_Flask框架学习笔记之表单基础介绍与表单提交方式

    本文实例讲述了Flask框架学习笔记之表单基础介绍与表单提交方式.分享给大家供大家参考,具体如下: 表单介绍 表单是HTML页面中负责数据采集功能的部件.由表单标签,表单域和表单按钮组成.通过表单,将 ...

  7. php框架费尔康,GitHub - majixian/study-phalcon: phalcon(费尔康)框架学习笔记

    phalcon(费尔康)框架学习笔记 以实例程序invo为例(invo程序放在网站根目录下的invo文件夹里,推荐php版本>=5.4) 环境不支持伪静态网址时的配置 第一步: 在app\con ...

  8. [Spring+SpringMVC+Mybatis]框架学习笔记(四):Spring实现AOP

    上一章:[Spring+SpringMVC+Mybatis]框架学习笔记(三):Spring实现JDBC 下一章:[Spring+SpringMVC+Mybatis]框架学习笔记(五):SpringA ...

  9. Samza框架-----学习笔记

    Samza框架-----学习笔记 基本概念: 作业:是对一组输入流进行处理转化成输出流的程序. 分区: Samza的流数据单位既不是Storm中的元组,也不是Spark Streaming中的DStr ...

最新文章

  1. 优化营商环境建议个人_优化营商环境的几点建议(三)
  2. 6次课(相对和绝对路径、cd命令、创建和删除目录mkdir/rmdir、rm命令)
  3. Linux: grep命令
  4. 中学计算机老师 当领导可能性,求分享,当中学计算机老师带信息学奥赛是怎样的感受 - 信息科学技术学院(EECS)版 - 北大未名BBS...
  5. HTML5 兼容IE浏览器
  6. java ee junit_JavaEE——Junit
  7. ffmpeg windows版本交叉编译方法
  8. 【自动化测试】在做自动化测试之前你需要知道的
  9. 各类推荐算法图表详解
  10. Assetbundle coustomerScripts
  11. 深入剖析Redis主从复制
  12. EasyAr聚焦模式
  13. 将WinPE安装至硬盘
  14. 计算机网络第七版笔记--第一章
  15. 怎样用c语言编程解多元方程组,求用C#编程实现:求一个多元一次方程组解
  16. [机器学习笔记] 什么是经验风险?什么是结构风险?
  17. mysql重启后应用也要重启_数据库重启后应用也必须重启
  18. AcWing算法基础课 第一讲小结(持续更新中)
  19. 【Three.js:3D模型】常用建模软件
  20. 北航计算机学院的博士待遇,北航博士毕业留校让人寒心的工资

热门文章

  1. <audio>播放音频Chrome浏览器禁止自动播放问题 play() failed because the user didn‘t interact with the document first
  2. PX4实战之旅(三):通过OFFBOARD模式控制无人机自主飞行
  3. Nagios配置文件介绍
  4. 解读苹果新财报:iPhone销量回暖实现逆增长,苹果再唱高歌?
  5. excel-文本函数
  6. code128 java_如何使用Code128字体将文本转换为code128条形码
  7. gulp-前端打包工具
  8. java安装界面 问号_win7系统打开软件安装界面全部都是问号的解决方法
  9. DirectUI浅谈
  10. 抖音上纸短情长音符用计算机打de,抖音纸短情长怎么录-抖音纸短情长怎么制作-PC6教学视频...