前端组件、页面布局、表单组件、#form:*、Beetl

引言

前端CSS框架选用BootStrap和AdminLTE作为管理框架为基础,JS库仍然采用jQuery为核心框架,前端视图采用目前比较流行简单的Beetl模板引擎,取消了之前的JSP视图,为了减少耦合,并将所有视图文件分布到各个工程模块的资源目录下(如:/modules/core/src/main/resources/views/),JeeSite4.x对Beetl做了一个强化,主要包括如下几点:

  • 常用函数库,如:字符串工具类,集合工具类,映射转换工具类,配置工具类,权限用户工具类等;
  • 封装常用表单控件参考Spring MVC的form标签,实现更便捷的输入框、下拉框、单选、复选等,自动进行数据绑定;
  • 封装常用表单组件,如:多级树结构选择组件,列表选择组件,文件上传组件,验证码生成组件等等;
  • 封装常用JS类库,如:动态加载,对话框,消息框,加载框,JS模板,Ajax,格式化,动态Tab等等;
  • 封装JS数据表格组件DataGrid,分页,排序,多表头,分组,子表,冻结,小计,合计,编辑行,树表表格等;
  • 提供丰富例子,如:Box盒子、表单布局、栅格布局、图表等等 更多资料:beetl 官方文档

模板语言界定符选择

Beetl模板语言类似JS语言和习俗,只需要将Beetl语言放入定界符号里即可,JeeSite使用jsp标准定界符<% %>来作为模板语言的定界符,一方同比较容易被理解,并明确是后端运行的语法,另一方面冲突少,比较好界定边界

举例一个通用布局的页面

  1. <% layout('/layouts/default.html', {title: '菜单管理', libs: ['validate'], bodyClass: ''}){ %>
  2. <div class="main-content">
  3. <div class="box box-main">
  4. <div class="box-header with-border">
  5. <div class="box-title">
  6. <i class="fa icon-book-open"></i> 菜单管理
  7. </div>
  8. <div class="box-tools pull-right">
  9. <button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>
  10. </div>
  11. </div>
  12. <div class="box-body">
  13. </div>
  14. <div class="box-footer">
  15. </div>
  16. </div>
  17. </div>
  18. <% } %>

调用默认布局 /layouts/default.html,自动引入页面头部和尾部内容,通过参数设置要加载的css和js类库,参数如下:

title参数: 设置页面的标题名字

libs参数: 设置页面要引入的css和js类库,支持类库如下:

默认引入:layer、select2、WdatePicker

  • zTree:树结构控件
  • tabPage:动态页签插件
  • dataGrid:数据表格组件
  • validate:表单验证组件
  • inputmask:表单格式化工具
  • fileupload:文件上传插件
  • ueditor:富文本编辑器控件 bodyClass参数: 设置body的class属性值

定义常用函数库

常用工具类导入

以下工具类可通过@类型快速调用,如:${@Global.getConfig(‘key’)}

  • Global:全局配置类,全局常量,读取属性文件参数值等
  • EncodeUtils:封装各种格式的编码解码工具类,HEX、Base64、HTML、URL、XSS过滤、SQL过滤等
  • ListUtils:List常用工具类,继承Apache的ListUtils,New工具、快速提取属性值、类型转换等
  • MapUtils:Map常用工具类,继承Apache的MapUtils,New工具、Map与Bean互转等
  • SetUtils:Set常用工具类,继承Apache的SetUtils,New工具等
  • IdGenerate:封装各种生成唯一性ID算法的工具类,生成LongUUID,StringUUID,Code生成等
  • ByteUtils:字节转换工具
  • DateUtils:日期工具类,继承Apache的DateUtils
  • NumberUtils:BigDecimal工具类,继承Apache的NumberUtils类
  • ObjectUtils:对象操作工具类,继承Apache的ObjectUtils类
  • StringUtils:字符串工具类,继承Apache的StringUtils类
  • TimeUtils:时间计算工具类,xx天xx时xx分xx秒,刚刚,xx秒,xx分钟,xx小时前、xx天前
  • WorkDayUtils:工作日计算工具类,计算日期直接的工作日等
  • BeanMapper:简单封装Dozer,对象数据映射
  • JaxbMapper:Jaxb实现XML与Java Object的转换
  • JsonMapper:简单封装Jackson,实现Json与Java Object的转换
  • ClassUtils:Class扫描工具类,根据接口查询类,根据继承查询类等
  • ReflectUtils:反射工具类,方便进行getter/setter方法, 访问私有变量, 调用私有方法
  • ModuleUtils:模块工具类,方便获取系统模块信息,例如 ${@ModuleUtils.getModule(‘core’)}
  • DictUtils:字典工具类,例如 ${@DictUtils.getDictListJson(‘sys_menu_type’)}
  • UserUtils:用户工具类,方便获取进行用户及相关信息,例如 ${@UserUtils.getUser()}
  • EmpUtils:员工工具类,获取当前用户员工信息、所在部门、公司,${@EmpUtils.getEmployee()}
  • RoleUtils:角色工具类,判断当前或某用户是否包含某角色,${@RoleUtils.hasUserRole(‘user’,’role’)} 以下是Beetl函数及扩展函数

  • date:返回一个java.util.Date类型的变量,如 date() 返回一个当前时间(对应java的java.util.Date); ${date( “2011-1-1” , “yyyy-MM-dd” )} 返回指定日期

  • print:打印一个对象 print(user.name);
  • println:打印一个对象以及回车换行符号,回车换号符号使用的是模板本身的,而不是本地系统的.如果仅仅打印一个换行符,则直接调用println() 即可
  • nvl:函数nvl,如果对象为null,则返回第二个参数,否则,返回自己 nvl(user,”不存在”)
  • isEmpty:判断变量或者表达式是否为空,变量不存在,变量为null,变量是空字符串,变量是空集合,变量是空数组,此函数都将返回true
  • isNotEmpty:同上,判断对象是否不为空
  • has:变量名为参数,判断是否存在此全局变量,如 has(userList),类似于1.x版本的exist(“userList”),但不需要输入引号了
  • assert:如果表达式为false,则抛出异常
  • trim:截取数字或者日期,返回字符,如trim(12.456,2)返回”12.45”,trim(date,’yyyyy’)返回”2017”
  • trunc:截取数字,保留指定的小数位,如trunc(12.456,2) 输出是12.45.不推荐使用,因为处理float有问题,兼容原因保留了
  • decode:一个简化的if else 结构,如 decode(a,1,”a=1”,2,”a=2”,”不知道了”)},如果a是1,这decode输出”a=1”,如果a是2,则输出”a==2”, 如果是其他值,则输出”不知道了”
  • debug:在控制台输出debug指定的对象以及所在模板文件以及模板中的行数,如debug(1),则输出1 [在3行@/org/beetl/core/lab/hello.txt],也可以输出多个,如debug(“hi”,a),则输出hi,a=123,[在3行@/org/beetl/core/lab/hello.txt]
  • range:接收三个参数,初始值,结束值,还有步增(可以不需要,则默认为1),返回一个Iterator,常用于循环中,如for(var i in range(1,5)) {print(i)},将依次打印1234.
  • flush:强制io输出。
  • pageCtx:仅仅在web开发中,设置一个变量,然后可以在页面渲染过程中,调用此api获取,如pageCtx(“title”,”用户添加页面”),在其后任何地方,可以pageCtx(“title”) 获取该变量
  • cookie:返回指定的cookie对象 ,如var userCook = cookie(“user”), allCookies = cookie();
  • isBlank:判断对象是否是一个空字符串,${isBlank(‘str’)}
  • isNotBlank:判断对象是否不是一个空字符串,${isBlank(‘str’)}
  • toJson:将对象转Json字符串,${toJson(Object)}
  • fromJson:将Json字符串转换为对象,${fromJson(Object)}
  • hasPermi:判断是否有改权限;单个权限验证:${hasPermi(‘sys:user:edit’)};多个AND关系:${hasPermi(‘sys:user:view,sys:user:edit’, ‘and’)}; 多个OR关系:${hasPermi(‘sys:user:view,sys:user:edit’, ‘or’)}
  • cookie:获取cookie值,${cookie(name, isRemove)}
  • lang: 获取当前国际化语言名称,例如:lang(),返回:zh_CN、en、等
  • text: 获取当前国际化代码译文,例如:text(‘中国’),当前语言英文状态下,返回:China;支持格式化参数,如:text(‘第{0}天’, 3) 数据类型格式化

日期格式化:

  1. Today is ${date,dateFormat='yyyy-MM-dd'}
  2. Today is ${date,dateFormat}
  3. 如果date为日期类型可简写:
  4. ${date,'yyyy-MM-dd'}

数值格式化:

  1. Salary is ${salary,numberFormat='##.##'}

基本表单控件应用(类似 Spring MVC 表单标签)

form 表单标签

  1. 生成一个form标签,支持指定model属性,类似SpringMVC的<form:form modelAttribute=""/>标签的属性,自动给表单内的控件绑定属性值
  2. <#form:form id="inputForm" model="${user}" action="${ctx}/sys/user" method="POST" class="form-horizontal">
  3. 表单内容
  4. </#form:form>
  5. 支持上传文件:
  6. <#form:form id="inputForm" model="${user}" action="${ctx}/sys/user" method="POST" enctype="multipart/form-data" class="form-horizontal">
  7. 表单内容
  8. </#form:form>

控件属性:

  1. var p = {
  2. // 标签参数
  3. id: id!, // 表单ID
  4. model: model!, // 绑定Model对象,例如:${user!}
  5. action: action!, // 表单请求地址
  6. method: method!, // 请求方法,默认 post
  7. enctype: enctype!, // 发送之前进行数据编码,上传文件时指定:multipart/form-data
  8. };

input 输入框标签

  1. 自动绑定form:form上指定的model下的userName属性,类似SpringMVC的<form:input path=""/>标签的属性
  2. <#form:input path="userName" maxlength="100" class="form-control required "/>
  3. 日期格式化:
  4. <#form:input path="createDate" dataFormat="date" class="form-control required "/>
  5. 数值格式化:
  6. <#form:input path="createDate" dataFormat="number" class="form-control required "/>
  7. 自定义格式化:
  8. <#form:input name="createDate" value="${@DateUtils.formatDate(user.createDate,'yyyyMMdd')}" class="form-control required "/>
  9. 不自动绑定,把 path 改为 name 就可以:
  10. <#form:input name="createDate" value="${user.createDate}" class="form-control required "/>

控件属性:

  1. var p = {
  2. // 标签参数
  3. id: id!, // 元素ID,如果不填写,则与name相同
  4. path: path!, // 绑定form上model中属性的值
  5. name: name!, // 元素名称,不填写
  6. value: value!, // 元素值
  7. defaultValue: defaultValue!,// 默认值 v4.1.5
  8. type: type!'text', // 元素的类型,默认text
  9. dataFormat: dataFormat!'', // 数据格式化,支持如下值:
  10. // date: 日期;默认值设置:defaultValue="${date()}"
  11. // yyyy: 年;默认值设置:defaultValue="${date('2019','yyyy')}"
  12. // yyyy-MM: 年月;
  13. // datetime: 日期时间;
  14. // datetime2: 日期时间,带秒;
  15. // number: 数值类型,保留2位小数,默认值设置:defaultValue="${0}"
  16. // 自定义格式化 path="field" 替换为:name="field" value="${model.field,格式化类型}"
  17. };

select 下拉框标签

  1. 根据字典类型设置下拉数据:
  2. <#form:select path="userType" dictType="sys_user_type" class="form-control required " />
  3. 增加一个空白选项:
  4. <#form:select path="roleType" dictType="sys_role_type" blankOption="true" class="form-control " />
  5. <#form:select path="roleType" dictType="sys_role_type" blankOption="true" blankOptionLabel="请选择" class="form-control " />
  6. 多选下拉列表:
  7. <#form:select path="roleType" dictType="sys_role_type" multiple="true" class="form-control " />
  8. 手动设置下拉框值,类似SrpingMVC的<form:options items="" itemLabel="" itemValue=""/>标签的属性:
  9. <#form:select path="moduleCodes" items="${moduleList}" itemLabel="moduleName" itemValue="moduleCode" class="form-control required" />

控件属性:

  1. var p = {
  2. // 标签参数
  3. id: id!, // 元素ID,如果不填写,则与name相同
  4. path: path!, // 绑定form上model中属性的值
  5. name: name!, // 元素名称,不填写
  6. value: value!, // 元素值
  7. defaultValue: defaultValue!,// 默认值 v4.1.5
  8. dictType: dictType!, // 字典类型,从字典里获取,自动设置items、itemLabel、itemValue
  9. items: items![], // 列表数据,可接受对象集合,如:List<DictData>
  10. itemLabel: itemLabel!'', // 指定列表数据中的什么属性名作为option的标签名
  11. itemValue: itemValue!'', // 指定列表数据中的什么属性名作为option的value值
  12. multiple: multiple!'false', // 是否为多选框
  13. blankOption: @ObjectUtils.toBoolean(blankOption!false), // 是否默认有个空白选择项目
  14. blankOptionLabel: blankOptionLabel!'&nbsp;', // 给空白选择项目设置一个标签,如:请选择、全部
  15. };

radio 单选框标签

  1. 类似<#form:select/>标签的使用方法
  2. <#form:radio path="menuType" dictType="sys_menu_type" class="form-control required" />

控件属性:

  1. var p = {
  2. // 标签参数
  3. id: id!, // 元素ID,如果不填写,则与name相同
  4. path: path!, // 绑定form上model中属性的值
  5. name: name!, // 元素名称,不填写
  6. value: value!, // 元素值
  7. defaultValue: defaultValue!,// 默认值 v4.1.5
  8. dictType: dictType!, // 字典类型,从字典里获取,自动设置items、itemLabel、itemValue
  9. items: items!([]), // 列表数据,可接受对象集合,如:List<DictData>
  10. itemLabel: itemLabel!'', // 指定列表数据中的什么属性名作为option的标签名
  11. itemValue: itemValue!'', // 指定列表数据中的什么属性名作为option的value值
  12. };

checkbox 复选框标签

  1. 类似<#form:select/>标签的使用方法,后台接受moduleCodes为字符串,选择多个自动使用“,”分隔,相比SpringMVC必须是List方便的多
  2. <#form:checkbox path="moduleCodes" items="${moduleList}" itemLabel="moduleName" itemValue="moduleCode" class="form-control required" />
  3. 生成一个复选框按钮,后台接受replaceFileGlobal.YESGlobal.NO值:
  4. <#form:checkbox path="replaceFile" label="是否替换现有文件" class="form-control"/>

控件属性:

  1. var p = {
  2. // 标签参数
  3. id: id!, // 元素ID,如果不填写,则与name相同
  4. path: path!, // 绑定form上model中属性的值
  5. name: name!, // 元素名称,不填写
  6. value: value!, // 元素值
  7. defaultValue: defaultValue!,// 默认值 v4.1.5
  8. dictType: dictType!'', // 字典类型,从字典里获取,自动设置items、itemLabel、itemValue
  9. items: items!([]), // 列表数据,可接受对象集合,如:List<DictData>
  10. itemLabel: itemLabel!'', // 指定列表数据中的什么属性名作为option的标签名
  11. itemValue: itemValue!'', // 指定列表数据中的什么属性名作为option的value值
  12. label: label!, // 只有一个复选按钮的情况下设置
  13. };

textarea 文本域标签

  1. <#form:textarea path="remarks" rows="3" maxlength="200" class="form-control"/>

控件属性:

  1. var p = {
  2. // 标签参数
  3. id: id!, // 元素ID,如果不填写,则与name相同
  4. path: path!, // 绑定form上model中属性的值
  5. name: name!, // 元素名称,不填写
  6. value: value!, // 元素值
  7. defaultValue: defaultValue!,// 默认值 v4.1.5
  8. };

hidden 隐藏域标签

  1. <#form:hidden path="menuCode" />

控件属性:

  1. var p = {
  2. // 标签参数
  3. id: id!, // 元素ID,如果不填写,则与name相同
  4. path: path!, // 绑定form上model中属性的值
  5. name: name!, // 元素名称,不填写
  6. value: value!, // 元素值
  7. defaultValue: defaultValue!,// 默认值 v4.1.5
  8. type: type!'hidden', // 元素的类型,默认hidden
  9. };

高级表单组件封装应用

treeselect 树结构选择

封装layer+zTree实现树结构选择组件,使用场景如:部门选择,行政区划选择,栏目列表选择等

  1. <#form:treeselect id="parent" title="上级菜单"
  2. path="parent.id" labelPath="parent.menuNameOrig"
  3. url="${ctx}/sys/menu/treeData?excludeCode=${menu.menuCode}&sysCode=${menu.sysCode}&isShowNameOrig=true"
  4. class="" allowClear="true" canSelectRoot="true" canSelectParent="true"/>

组件属性:

  1. var p = {
  2. // 标签参数
  3. id: id!, // 元素ID
  4. path: path!, // 绑定form上model中属性的值
  5. name: name!, // 隐藏域名称
  6. value: value!, // 隐藏域值
  7. defaultValue: defaultValue!,// 隐藏域默认值 v4.1.5
  8. labelPath: labelPath!, // 绑定form上model中属性的值
  9. labelName: labelName!, // 标签框名称
  10. labelValue: labelValue!, // 标签框值
  11. defaultLabel: defaultLabel!,// 标签框默认值 v4.1.5
  12. class: class!'', // 标签框的CSS类名
  13. placeholder: placeholder!, // 标签框的预期值的提示信息
  14. dataMsgRequired: thisTag.attrs['data-msg-required'], // 必填错误提示信息
  15. btnClass: btnClass!, // 标签框后面的按钮CSS类名
  16. title: title!text('选项选择'), // 对话框标题
  17. boxWidth: boxWidth!300, // 对话框宽度,默认300像素
  18. boxHeight: boxHeight!400, // 对话框高度,默认400像素
  19. url: url!, // 树结构,数据源地址 [{id, pid, name}]
  20. readonly: @ObjectUtils.toBoolean(readonly!false), // 是否只读模式
  21. allowInput: @ObjectUtils.toBoolean(allowInput!false), // 是否允许label框输入
  22. allowClear: @ObjectUtils.toBoolean(allowClear!true), // 是否允许清空选择内容
  23. checkbox: @ObjectUtils.toBoolean(checkbox!false), // 是否显示复选框,是否支持多选,如果设置canSelectParent=true则返回父节点数据
  24. chkboxType: chkboxType!'', // 复选框级联选择规则 v4.0.6,默认:{'Y':'ps','N':'ps'}
  25. expandLevel: @ObjectUtils.toInteger(expandLevel!(-1)), // 默认展开层次级别(默认:如果有1个根节点,则展开一级节点,否则不展开)
  26. canSelectRoot: @ObjectUtils.toBoolean(canSelectRoot!false), // 可以选择跟节点
  27. canSelectParent: @ObjectUtils.toBoolean(canSelectParent!false), // 可以选择父级节点
  28. isReturnValue: isReturnValue!'false', // 是否返回树结构的value值,而不是返回id(默认id)
  29. returnFullName: @ObjectUtils.toBoolean(returnFullName!false), // 是否返回全路径,包含所有上级信息,以 returnFullNameSplit 参数分隔
  30. returnFullNameSplit: returnFullNameSplit!'/', // 是否返回全路径,的分隔符,默认“/”
  31. checkFuncName: checkFuncName!'treeselectCheck', // 可自定义验证方法的函数名 v4.1.5
  32. callbackFuncName: callbackFuncName!'treeselectCallback', // 可自定义回调方法的函数名 v4.1.0
  33. };

JS回调事件:

  1. /**
  2. * 选择前调用,数据验证函数,返回false代表验证失败
  3. * @param id 标签的id
  4. * @param node 验证的数据
  5. * @return true 验证成功,false 验证失败
  6. */
  7. function treeselectCheck(id, nodes){
  8. if (id == 'parent'){
  9. log(nodes); // 选择的节点数据
  10. }
  11. return true;
  12. }
  13. /**
  14. * 选择回调方法
  15. * @param id 标签的id
  16. * @param act 动作事件:ok、clear、cancel
  17. * @param index layer的索引号
  18. * @param layero layer内容的jQuery对象
  19. * @param nodes 当前选择的树节点数组
  20. */
  21. function treeselectCallback(id, act, index, layero, nodes){
  22. if (id == 'parent' && (act == 'ok' || act == 'clear')){
  23. var win = layero.iframeWindow();
  24. log(win); // 选择框内容的window对象
  25. log(act); // 回调活动事件(ok、clear、cancel)
  26. log(index); // layer的index
  27. log(layero); // layer实例对象
  28. log(selectData); // 选择的节点数据
  29. log(nodes); // 选择的节点数据
  30. }
  31. }

listselect 列表选择

  1. <#form:listselect id="empUserSelect" title="用户"
  2. url="${ctx}/sys/empUser/empUserSelect" allowClear="false"
  3. checkbox="false" itemCode="userCode" itemName="userName"/>

组件属性:

  1. var p = {
  2. // 标签参数
  3. id: id!, // 元素ID
  4. path: path!, // 绑定form上model中属性的值
  5. name: name!, // 隐藏域名称
  6. value: value!, // 隐藏域值
  7. defaultValue: defaultValue!,// 隐藏域默认值 v4.1.5
  8. labelPath: labelPath!, // 绑定form上model中属性的值
  9. labelName: labelName!, // 标签框名称
  10. labelValue: labelValue!, // 标签框值
  11. defaultLabel: defaultLabel!,// 标签框默认值 v4.1.5
  12. class: class!'', // 标签框的CSS类名
  13. placeholder: placeholder!, // 标签框的预期值的提示信息
  14. dataMsgRequired: thisTag.attrs['data-msg-required'], // 必填错误提示信息
  15. btnClass: btnClass!, // 标签框后面的按钮CSS类名
  16. title: title!'选项', // 对话框标题
  17. boxWidth: boxWidth!'$(top.window).width() - 100', // 对话框宽度
  18. boxHeight: boxHeight!'$(top.window).height() - 100', // 对话框高度
  19. url: url!, // 列表地址,参考EmpUserController的empUserSelect方法
  20. readonly: @ObjectUtils.toBoolean(readonly!false), // 是否只读模式
  21. allowInput: @ObjectUtils.toBoolean(allowInput!false), // 是否允许label框输入
  22. allowClear: @ObjectUtils.toBoolean(allowClear!true), // 是否允许清空选择内容
  23. checkbox: @ObjectUtils.toBoolean(checkbox!false), // 是否显示复选框,是否支持多选,如果设置canSelectParent=true则返回父节点数据
  24. itemCode: itemCode!, // 选择后结果集中的Code属性名,返回到隐藏域的值
  25. itemName: itemName!, // 选择后结果集中的Name属性名,返回到输入框的值
  26. getSelectDataFuncName: getSelectDataFuncName!'listselectGetSelectData', // 可自定义获取选择数据方法的函数名 v4.1.5
  27. callbackFuncName: callbackFuncName!'listselectCallback', // 可自定义回调方法的函数名 v4.1.5
  28. };

JS回调事件:

  1. /**
  2. * 选择前调用,数据验证函数,返回false代表验证失败
  3. * @param id 标签的id
  4. * @param selectData 当前选择列表的数据MAP
  5. * @return true 验证成功,false 验证失败
  6. */
  7. function listselectCheck(id, selectData){
  8. if (id == 'parent'){
  9. log(selectData); // 选择的节点数据
  10. }
  11. return true;
  12. }
  13. /**
  14. * 选择框回调方法
  15. * @param id 标签的id
  16. * @param act 动作事件:ok、cloear、cancel
  17. * @param index layer的索引号
  18. * @param layero layer内容的jQuery对象
  19. * @param selectData 当前选择列表的数据MAP
  20. */
  21. function listselectCallback(id, act, index, layero, selectData){
  22. if (id == 'parent' && (act == 'ok' || act == 'clear')){
  23. var win = layero.iframeWindow();
  24. log(win); // 选择框内容的window对象
  25. log(act); // 回调活动事件(ok、clear、cancel)
  26. log(index); // layer的index
  27. log(layero); // layer实例对象
  28. log(selectData); // 选择的节点数据
  29. }
  30. }
  31. /**
  32. * 列表数据回显调用方法
  33. * @param id 标签的id
  34. * @return selectData 当前选择列表的数据MAP
  35. */
  36. function listselectGetSelectData(id){
  37. var selectData = {};
  38. if (id == 'parent' && (act == 'ok' || act == 'clear')){
  39. selectData['主键字段值'] = {行数据};
  40. }
  41. return selectData;
  42. }

iconselect 图标选择

  1. <#form:iconselect path="menuIcon" class=""/>

组件属性:

  1. var p = {
  2. // 标签参数
  3. id: id!, // 元素ID,如果不填写,则与name相同
  4. path: path!, // 绑定form上model中属性的值
  5. name: name!, // 元素名称,不填写
  6. value: value!, // 元素值
  7. defaultValue: defaultValue!,// 默认值 v4.1.5
  8. class: class!'', // 隐藏域和标签框的CSS类名
  9. };

validcode 验证码

  1. <#form:validcode name="validCode" isRequired="true" isRemote="true" />

组件属性:

  1. var p = {
  2. id: id!name, // 验证码输入框ID
  3. name: name!, // 验证码输入框名称(必填)
  4. isRequired: @ObjectUtils.toBoolean(isRequired!true), // 是否必填,默认必填
  5. dataMsgRequired: thisTag.attrs['data-msg-required'], // 必填错误提示信息
  6. isRemote: @ObjectUtils.toBoolean(isRemote!true), // 是否支持实时远程验证
  7. dataMsgRemote: thisTag.attrs['data-msg-remote'], // 必填错误提示信息
  8. isLazy: @ObjectUtils.toBoolean(isLazy!false), // 是否懒加载验证码图片,原noRefresh参数
  9. isShowLabel: @ObjectUtils.toBoolean(isShowLabel!true), // 是否显示“验证码”标签,默认true(V4.0.5)
  10. };

fileupload 文件上传

  1. <% layout(... libs: ['fileupload'] ...}){ %>
  2. 1、文件上传:
  3. <#form:fileupload id="upload1" bizKey="${user.id}" bizType="user_upload1"
  4. uploadType="all" class="required" readonly="false"/>
  5. 后台代码:FileUploadUtils.saveFileUpload(user.getId(), "user_upload1");
  6. 2、图片上传:
  7. <#form:fileupload id="upload2" bizKey="${user.id}" bizType="user_upload2"
  8. uploadType="image" class="required" readonly="false"/>
  9. 后台代码:FileUploadUtils.saveFileUpload(user.getId(), "user_upload2");
  10. 3、返回路径:
  11. <#form:fileupload id="upload3" returnPath="true"
  12. filePathInputId="upload3Path" fileNameInputId="upload3Name"
  13. uploadType="image" readonly="false" maxUploadNum="3" isMini="false"/>
  14. <#form:input name="upload3Path" class="form-control"/>
  15. <#form:input name="upload3Name" class="form-control"/>
  16. 4、在线文件预览(增加 preview="weboffice" 属性):
  17. <#form:fileupload id="upload4" bizKey="${user.id}" bizType="user_upload4"
  18. uploadType="all" class="required" readonly="false" preview="weboffice"/>
  19. 5、支持指定文件查询地址,如 bizKey 右模糊查询数据,适应 parentBizKey 的场景(v4.1.5):
  20. <#form:fileupload id="upload5" bizKey="${entity.parentCode}_" bizType="upload5"
  21. uploadType="all" class="" readonly="true" preview="weboffice"
  22. serviceFileList="${ctxAdmin}/file/fileList?bizKeyIsLike=true"/>

注意:为什么没有保存 bizKey 和 bizType 值到后台,因为在上传文件的时候,新增的表单还没有生成主键,当你点击表单保存后,后台代码调用 FileUploadUtils.saveFileUpload 更新这两个值,才会真正建立文件和业务数据的关系。

若出现上传文件按钮点击无效的情况,可能是因为你的fileupload控件隐藏或控件的top位置改变造成的,你只需在显示隐藏控件后或onload事件后执行如下代码刷新按钮位置即可:

  1. if (typeof window.webuploaderRefresh == 'function'){
  2. window.webuploaderRefresh();
  3. }

举例:Bootstrap Tab 切换代码

  1. $(function(){
  2. $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
  3. if(typeof window.webuploaderRefresh == 'function'){
  4. window.webuploaderRefresh();
  5. }
  6. });
  7. });

组件属性:

  1. var p = {
  2. // 标签参数
  3. id: id!, // 元素ID
  4. bizKey: bizKey!, // 业务表的主键值(与附件关联的业务数据)
  5. bizType: bizType!, // 业务表的上传类型(全网唯一,推荐格式:实体名_上传类型,例如,文章图片:article_photo)
  6. returnPath: @ObjectUtils.toBoolean(returnPath!false), // 是否是返回文件路径到输入框(默认false),可将路径直接保存到某个字段里
  7. filePathInputId: filePathInputId!, // 设置文件URL存放的输入框的ID,当returnPath为true的时候,返回文件URL到这个输入框
  8. fileNameInputId: fileNameInputId!, // 设置文件名称存放的输入框的ID,当returnPath为true的时候,返回文件名称到这个输入框
  9. uploadType: uploadType!'', // 上传文件类型:all、file、image、media,若不设置,则自动根据上传文件后缀获取
  10. class: class!'', // 标签框的CSS类名,设置 required 加入必填验证
  11. readonly: @ObjectUtils.toBoolean(readonly!false), // 是否只读模式,只读模式下为查看模式,只允许下载
  12. allowSuffixes: allowSuffixes!'', // 允许上传的后缀,前台的限制,不能超越file.*AllowSuffixes的设置,例如:.jpg,.png,
  13. maxUploadNum: @ObjectUtils.toInteger(maxUploadNum!300), // 多文件下允许最多上传几个,默认300个,设置-1代表不限制
  14. cueWords: cueWords!'', // 提示语,默认:或将照片(文件)拖到这里,最多可选 maxUploadNum 张(个) v4.1.5
  15. imageMaxWidth: @ObjectUtils.toInteger(imageMaxWidth!1024), // 图片压缩,最大宽度(uploadType为image生效),设置-1代表不做任何处理
  16. imageMaxHeight: @ObjectUtils.toInteger(imageMaxHeight!768), // 图片压缩,最大宽度(uploadType为image生效),设置-1代表不做任何处理
  17. serviceUpload: serviceUpload!(ctxAdmin+'/file/upload'), // 上传文件后台服务 v4.1.5
  18. serviceDownload: serviceDownload!(ctxAdmin+'/file/download/'), // 下载文件后台服务 v4.1.5
  19. serviceFileList: serviceFileList!(ctxAdmin+'/file/fileList'), // 查询文件后台服务 v4.1.5
  20. extendParams: extendParams!'', // 提交的上传扩展参数,例如:n1:'v1',n2:'v2',后台接受:fileEntity.getFileUploadParams().getExtend() v4.1.3
  21. isLazy: @ObjectUtils.toBoolean(isLazy!false), // 设置为ture需要点击上传按钮才上传文件,否则选择后就直接上传
  22. isMini: @ObjectUtils.toBoolean(isMini!false), // 是否是精简上传窗口,无边距,无边框
  23. preview: preview!'', // 是否显示预览按钮,接受参数:weboffice
  24. };

WebUploader支持事件绑定,可用于回调。

  1. $(function(){
  2. var uploader = window.webuploader[0];
  3. uploader.on('all', function(type, file) {
  4. log(type)
  5. log(file)
  6. });
  7. });

手机端上传附件:如果你采用html5混合模式开发,你可解压 jeesite-framework.jar 并将 /static/webuploader 文件夹拷贝到你的手机端APP里面,可删掉 swf 和其它用不到的文件。然后在你的对应页面引入 webuploader.css、webuploader.extend.css、webuploader.extend.js、webuploader.js(v4.1.1下可引入webuploader.mobile.js)等文件,其它依赖文件也要引入,如:jquery-1.12.4.min.js、bootstrap.min.css、jeesite.js、jeesite_zh_CN.js。接下来,随便在PC后端beetl视图页面里加入如下代码:

  1. <#form:fileupload id="uploadImage" bizKey="当前业务主键"
  2. bizType="当前业务类型_image" uploadType="image"
  3. class="" readonly="false" isMini="true"/>

通过Chrome浏览器访问这个控制器视图,空白处右键“查看当前框架页面的源代码”,搜索 class="wup_container 拷贝该div和紧挨着下方的script标签内容到你的手机页面,修改对应fileupload接受参数即可。

若你是原生开发: 还请参照此控件自己实现上传UI即可,参照方法:浏览器 F12 打开 network 监控,监控请求路径及数据,共分为2次请求:

  • 第一次发送文件的MD5码(10M部分,不足10M取全部),后台返回result结果。
  • result为true,则代表已经上传过,并返回 fileUpload 数据,并放到 bizType 命名的隐藏域中。
  • result为false,则待办未上传过,还请你根据F12监控到的数据,需要你第二次发送上传文件请求。
  • 提交表单时,请将 bizType 隐藏域和 bizType__del 隐藏域提交到后台。(重要
  • 后台通过 FileUplandUtils 接受到该值并文件与当前表单主键建立关系。
  • 接口测试(可以导入Postman):https://gitee.com/thinkgem/jeesite4/attach_files/249363/download 如何将存储到阿里云OSS或七牛?继承 FileUploadServiceExtendSupport 类,并添加 @Service 注入到 SpringBean,举例如下:
  1. /**
  2. * 文件上传本地磁盘 v4.0.7+
  3. * @author ThinkGem
  4. * @version 2018年8月17日
  5. */
  6. @Service
  7. public class FileUploadServiceExtendImpl extends FileUploadServiceExtendSupport{
  8. /**
  9. * 验证文件是否真实的存在
  10. * @param fileEntity 文件实体信息
  11. * @return 文件存在true,不存在false
  12. */
  13. public boolean fileExists(FileEntity fileEntity){
  14. String path = fileEntity.getFileRealPath();
  15. File localFile = new File(path);
  16. return localFile.exists();
  17. }
  18. /**
  19. * 上传文件,首次上传文件都调用(保存到文件实体表之前调用)
  20. * @param fileEntity 文件实体信息
  21. * @param fileEntity.getFileRealPath() 文件实际磁盘路径
  22. * @exception 支持抛出 throw ServiceException("文件不符合要求") v4.1.5
  23. */
  24. public void uploadFile(FileEntity fileEntity){
  25. }
  26. /**
  27. * 保存上传文件信息,每次上传都调用(保存文件和用户关系数据之前调用)
  28. * @param fileUpload 文件上传信息,包括文件实体
  29. * @exception 支持抛出 throw ServiceException("文件不符合要求") v4.1.5
  30. */
  31. public void saveUploadFile(FileUpload fileUpload){
  32. }
  33. /**
  34. * 获取文件下载的URL地址
  35. * @param fileUpload 文件上传的信息,包括文件实体
  36. * @return 无文件下载地址,则返回null,方便后续处理
  37. */
  38. public String getFileUrl(FileUpload fileUpload){
  39. return fileUpload.getFileEntity().getFileUrl();
  40. }
  41. /**
  42. * 下载文件到浏览器
  43. * @param fileUpload 文件上传的信息
  44. * @param request 请求对象,可能断点续传用
  45. * @param response 响应对象,输出文件流使用
  46. * @return 如果不是文件流数据,也可返回文件的URL地址进行跳转,如果文件不存在返回404字符串
  47. */
  48. public String downFile(FileUpload fileUpload, HttpServletRequest request, HttpServletResponse response){
  49. FileEntity fileEntity = fileUpload.getFileEntity();
  50. File file = new File(fileEntity.getFileRealPath());
  51. if (file.exists()){
  52. FileUtils.downFile(file, request, response, fileUpload.getFileName());
  53. return null;
  54. }
  55. return "404";
  56. }
  57. }

imageclip 图片裁剪

  1. <img id="avatarImg" class="profile-user-img img-responsive img-circle"
  2. src="${@user.getAvatarUrl().replaceFirst('/ctxPath', ctxPath)}">
  3. <#form:imageclip name="imageBase64" btnText="修改头像" btnClass="btn-block"
  4. imageId="avatarImg" imageDefaultSrc="${ctxStatic+'/images/user1.jpg'}"
  5. circle="true"/>

后台代码:

  1. // 如果设置了头像,则保存头像
  2. if (StringUtils.isNotBlank(imageBase64)){
  3. if ("EMPTY".equals(imageBase64)){
  4. user.setAvatar(StringUtils.EMPTY);
  5. }else{
  6. String imageUrl = "avatar/"+user.getUserCode()
  7. +"."+FileUtils.getFileExtensionByImageBase64(imageBase64);
  8. String fileName = Global.getUserfilesBaseDir(imageUrl);
  9. FileUtils.writeToFileByImageBase64(fileName, imageBase64);
  10. user.setAvatar(Global.USERFILES_BASE_URL + imageUrl);
  11. }
  12. }

组件属性:

  1. var p = {
  2. // 标签参数
  3. id: id!, // 元素ID,如果不填写,则与name相同
  4. path: path!, // 绑定form上model中属性的值
  5. name: name!, // 元素名称,不填写
  6. value: value!, // 元素值
  7. defaultValue: defaultValue!,// 默认值 v4.1.5
  8. class: class!'', // 隐藏域的CSS类名
  9. btnText: btnText!text('选择图片'), // 按钮的名字
  10. btnClass: btnClass!'', // 按钮的CSS类名
  11. imageId: imageId!'', // 裁剪后base64返回到img的id
  12. imageDefaultSrc: imageDefaultSrc!'', // 图片默认地址,清除后使用地址
  13. circle: circle!'false', // 是否圆形图片
  14. };

ueditor 富文本在线编辑器

  1. <% layout(... libs: ['ueditor'] ...}){ %>
  2. <#form:ueditor name="text" maxlength="10000" height="200" class="required"
  3. simpleToolbars="false" readonly="false" outline="false"/>

组件属性:

  1. var p = {
  2. // 标签参数
  3. id: id!, // 元素ID,如果不填写,则与name相同
  4. path: path!, // 绑定form上model中属性的值
  5. name: name!, // 元素名称,不填写
  6. value: value!, // 元素值
  7. defaultValue: defaultValue!,// 默认值 v4.1.5
  8. class: class!'', // 标签框的CSS类名,设置 required 加入必填验证
  9. maxlength: maxlength!'', // 编辑器最大输入字数,为空代表无限制
  10. height: height!'200', // 编辑器的高度,默认200
  11. simpleToolbars: @ObjectUtils.toBoolean(simpleToolbars!false), // 是否是简单的工具条
  12. readonly: @ObjectUtils.toBoolean(readonly!false), // 是否只读模式
  13. outline: @ObjectUtils.toBoolean(outline!false), // 大纲视图
  14. options: options!'', // UE附加选项,逗号隔开。
  15. };

注意:如果需要将文件上传到其它文件服务,重写 jeesite-common 项目下的 StorageManager 类 uploadFileSuccess 方法即可。

表单内置验证 Class 名称

  1. (function ($) {
  2. $.extend($.validator.messages, {
  3. required: "必填信息",
  4. remote: "请修正该信息",
  5. email: "请输入正确格式的电子邮件",
  6. url: "请输入合法的网址",
  7. date: "请输入合法的日期",
  8. dateISO: "请输入合法的日期 (YYYY-MM-DD).",
  9. number: "请输入合法的数值",
  10. digits: "请输入一个正整数",
  11. equalTo: "请再次输入相同的值",
  12. maxlength: $.validator.format("最多可以输入 {0} 个字符"),
  13. minlength: $.validator.format("最少要输入 {0} 个字符"),
  14. rangelength: $.validator.format("请输入长度在 {0} 到 {1} 之间的字符串"),
  15. range: $.validator.format("请输入范围在 {0} 到 {1} 之间的数值"),
  16. max: $.validator.format("请输入不大于 {0} 的数值"),
  17. min: $.validator.format("请输入不小于 {0} 的数值"),
  18. errorMessage: "您填写的信息有误,请根据提示修正。",
  19. userName: "登录账号只能包括中文字、英文字母、数字和下划线",
  20. realName: "姓名只能为2-30个汉字",
  21. abc: "请输入字母数字或下划线",
  22. noEqualTo: "请再次输入不同的值",
  23. mobile: "请正确填写您的手机号码,只能是13,14,15,16,17,18,19号段",
  24. simplePhone: "请正确填写您的电话号码,固话为区号(3-4位)号码(7-9位)",
  25. phone: "请正确填写您的电话号码,固话为区号(3-4位)号码(7-9位),手机为13,14,15,16,17,18,19号段",
  26. zipCode: "请正确填写您的邮政编码",
  27. integer: "请输入一个整数",
  28. ipv4: "请输入一个有效的 IP v4 地址",
  29. ipv6: "请输入一个有效的 IP v6 地址",
  30. qq: "请正确填写您的QQ号码",
  31. idcard: "请输入正确的身份证号码(15-18位)"
  32. });
  33. }(jQuery));

扩展自定义验证:

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