常见编程示例
常见编程示例
按钮的权限控制
页面使用securityCheck标签
#if($securityCheck.hasPermission("user:configInfo:add"))
<a class="btn btn-success" onclick="jQuery.operate.add()" shiro:hasPermission="system:config:add">
<i class="fa fa-plus"></i> 新增
</a>
#endcontroller使用securityCheck注解
@SecurityChecker("user:configInfo:add")
public String addPre(ModelMap model , String id) {
if(StringUtils.isNotBlank(id)) {表格内的按钮权限控制
var editFlag = $securityCheck.hasPermission("user:configInfo:edit");
{
title: '操作',
align: 'center',
formatter: function(value, row, index) {
var actions = [];
actions.push('<a class="btn btn-success btn-xs ' + editFlag + '" href="#" onclick="jQuery.operate.edit(\'' + row.id + '\')"><i class="fa fa-edit"></i>编辑</a> ');
return actions.join('');
}
}字段有效性校验
数据字典的使用
系统中默认集成了数据字典.
页面查询
使用enumTag,通过和velocity语法结合,直接在页面上渲染下拉选项.
<li>
状态:<select name="visible" >
<option value="">所有</option>
#foreach($item in $enumTag.getEnumsByType("COMMON_BOOL"))
<option value="$item.value" #if($item.value.equals($edit.configType))seleced#end>$item.text</option>
#end
</select>
</li>表格内枚举翻译
后台数据返回各种枚举数字,在表格内,将枚举数字转换为名称.
var datas = $enumTag.getEnumsJsonByType("COMMON_BOOL");
{
field: 'status',
title: '状态',
align: 'center',
formatter: function(value, row, index) {
return jQuery.table.selectDictLabel(datas, value);
}
}java代码使用枚举
提高代码的可读性,又不声明java的enum类
loginforInfo.setLogType(Enums.getInstance().getEnumsValueByCode("LOG_TYPE", "LOG_TYPE_IN"));id转name的特别方法
//接口声明
public List<UserInfoVO> selectUserVOListByPage(UserInfoQueryModel user, PageInfo<UserInfoVO> page);
//controller中的调用情况
SSOUser ssoUser = SSOClientUtils.getInstance().findCurrentUser();
// 非超级管理员,限定默认查询当前用户所在机构下及其下级下的用户
if (!SSOClientUtils.getInstance().isAdmin() && user.getDeptCode() == null) {
user.setDeptCode(new String[] {ssoUser.getCurrentDept().getDeptCode()});
}
//这边page里面返回的是接口里面声明的UserInfoVO对象
userService.selectUserVOListByPage(user, page);
//调用数据翻译,把租户号翻译为对应的租户记录
List<Map> list = DataTranslateUtils.translate(page.getData(), "tenantCode", "tenant", new TenantTranslateCallback());
page.setData(list);
//输出页面
return new ApiBaseResponse<PageInfo>( RetStatusEnum.SUCCESS,Constants.API_RESPONSE_SUCCESS_CODE,
Constants.API_RESPONSE_SUCCESS_MESSAGE, page);页面使用数据,展示租户名称,这边结合velocity,实现了租户号的动态展示,如果在admin用户下会展示租户号,如果不是在admin用户下访问,则不会展示租户号.
#if($userTag.isAdmin() && $serverProperty.findProperty("mutiable.tenant","false") == "true")
{
field: 'tenant.tenantName',
title: '租户号'
},
#end详细请看user-app中的UserInfoController和view/user-app/userInfo/list.vm
奇特的导出实现
导出按钮
前端实现
<a class="btn btn-warning" onclick="jQuery.table.exportExcel()">
<i class="fa fa-download"></i> 导出
</a>后台实现
复用查询实现,使用Exporter注解
@Exporter(code="OpLog")
public @ResponseBody ApiBaseResponse<PageInfo<OperLogInfo>> search(ModelMap model , OperLogQuery query , PageInfo<OperLogInfo> pageInfo){
if(pageInfo == null){
pageInfo = new PageInfo<OperLogInfo>();
}配置导出模板
注解中的OpLog指向的是导出模板中的ExportRegister的key
请注意在这个导出模板中,特别配置了com.istock.base.hyperExport.ExportTranslateCallback,把查询出来的operName转化为operUser.
<bean name="loginNameTranslate" class="com.istock.union.user.translate.LoginNameTranslateCallback"></bean>
<bean name="opLogTemplate" class="com.istock.base.hyperExport.ExportTemplate">
<property name="fileName" value="opLog"></property>
<property name="limit" value="20"></property>
<property name="translateCallback">
<list>
<bean class="com.istock.base.hyperExport.ExportTranslateCallback">
<property name="orgiFiledName" value="operName"></property>
<property name="newFiledname" value="operUser"></property>
<property name="callback" ref="loginNameTranslate"></property>
</bean>
</list>
</property>
<property name="itemList">
<list>
<bean class="com.istock.base.hyperExport.ExportTemplateItem">
<property name="fieldName" value="id"></property>
<property name="name" value="id"></property>
</bean>
<bean class="com.istock.base.hyperExport.ExportTemplateItem">
<property name="fieldName" value="menuName"></property>
<property name="name" value="菜单名"></property>
</bean>
<bean class="com.istock.base.hyperExport.ExportTemplateItem">
<property name="fieldName" value="functionName"></property>
<property name="name" value="功能名"></property>
</bean>
<bean class="com.istock.base.hyperExport.ExportTemplateItem">
<property name="fieldName" value="method"></property>
<property name="name" value="方法"></property>
</bean>
<bean class="com.istock.base.hyperExport.ExportTemplateItem">
<property name="fieldName" value="operName"></property>
<property name="name" value="操作人"></property>
</bean>
<bean class="com.istock.base.hyperExport.ExportTemplateItem">
<property name="fieldName" value="status"></property>
<property name="name" value="操作结果"></property>
<property name="dicName" value="COMMON_STATUS"></property>
</bean>
<bean class="com.istock.base.hyperExport.ExportTemplateItem">
<property name="fieldName" value="operUser.sex"></property>
<property name="name" value="性别"></property>
<property name="dicName" value="COMMON_SEX"></property>
</bean>
<bean class="com.istock.base.hyperExport.ExportTemplateItem">
<property name="fieldName" value="operUser.email"></property>
<property name="name" value="邮箱"></property>
</bean>
</list>
</property>
</bean>
<bean name="ExportRegister" class="com.istock.base.export.ExportRegister" factory-method="getInstance">
<property name="templateMap">
<map>
<entry key="OpLog" value-ref="opLogTemplate">
</entry>
</map>
</property>
</bean>详细请参考 OpLogController , view/user-app/opLog/list.vm和export-template.xml
登录用户敏感的机构树
随着登录用户不一样,而出现不一样的机构选择树,只能看到当前登录用户所属机构及其子机构.
查询用机构树
主要体现在,租户不能选,机构可以多选,不存在上下级机构级联,参考用户查询页面的机构树选择
//机构树控件的坑
<li>
<div class="form-group" style="width:345px">
<label class="col-sm-4 control-label" style="width:auto">机构:</label>
<div class="col-sm-8">
<div id="selectDept"></div>
</div>
</div>
</li>
//使用velocity,直接渲染treeData
jQuery("#selectDept").TreePicker({
name:"deptCode",
mode:"multi",
data:$treeData
});controller中的使用
List<Map<String , Object>> deptList = deptService.queryDeptTreeData(user.getTenantNo(), user.getCurrentDept() != null ?user.getCurrentDept().getDeptCode():null
, SSOClientUtils.getInstance().isAdmin() , false);
model.put("treeData", JSON.toJSONString(deptList));编辑用机构树

主要体现在,租户不可选,机构都是单选,参考用户编辑界面的所属机构
//机构树控件的坑
<div class="form-group">
<label class="col-sm-3 control-label"><span class="required-icon">*</span>组织机构:</label>
<div id="deptTreeId" class="col-sm-8 deptTree">
</div>
</div>
//使用velocity,直接渲染treeData
jQuery(function() {
jQuery("#deptTreeId").TreePicker({
name:"deptCode",
mode:"single",
data:$treeData,
onselect:function(node){
jQuery("#tenantCode").val(node[0].tenantCode);
//changeDept(node[0].tenantCode);
}
});
});controller中的使用
SSOUser user = SSOClientUtils.getInstance().findCurrentUser();
List<Map<String , Object>> deptList = deptService.queryDeptTreeData(user.getTenantNo(), user.getCurrentDept() != null ?user.getCurrentDept().getDeptCode():null
, SSOClientUtils.getInstance().isAdmin(),false);
model.put("treeData", JSON.toJSONString(deptList));编辑用机构树2

主要体现在,租户可选,租户和机构都是单选,参考组织编辑页面的上级机构
//机构树控件的坑
<div id="parent" class="form-group">
<input type="hidden" name="tenantCode" id="tenantCode">
<input type="hidden" name="parentId" id="parentId">
<label class="col-sm-3 control-label ">上级组织:</label>
<div class="col-sm-8">
<div id="selectDept"></div>
</div>
</div>
//使用velocity,直接渲染treeData
jQuery("#selectDept").TreePicker({
name:"selectDept",
mode:"single",
data:$treeData,
onselect:function(node){
jQuery("#tenantCode").val(node[0].tenantCode);
jQuery("#parentId").val("");
if(node[0].nodeType == "dept"){
jQuery("#parentId").val(node[0].id);
}else{
jQuery("#parentId").val("0");
}
}
});controller中的使用
//给定页面能够选择的组织机构树
SSOUser user = SSOClientUtils.getInstance().findCurrentUser();
List<Map<String , Object>> deptList = deptService.queryDeptTreeData(user.getTenantNo(), user.getCurrentDept() != null ?user.getCurrentDept().getDeptCode():null
, SSOClientUtils.getInstance().isAdmin(),true);
model.put("treeData", JSON.toJSONString(deptList));下拉多选
//用户编辑页面的角色字段,注意select中的multiple="multiple"
<div class="form-group">
<label class="col-sm-3 control-label">角色:</label>
<div class="col-sm-8 roleTree" >
<select id="roleTreeId" class="form-control m-b" multiple="multiple" name="roleIds">
#foreach($item in $roles)
<option value="$item.id" #if($item.selected)selected#end>$item.roleName</option>
#end
</select>
</div>
</div>//controller中,使用数组接受前端页面的多选参数
@OperLog(functionName="修改",menuName="用户管理")
public ApiBaseResponse<Boolean> editSave(UserInfo user , String[] roleIds) {
String rspCode = Constants.API_RESPONSE_SUCCESS_CODE;
RetStatusEnum rspStatus = RetStatusEnum.SUCCESS;下拉ajax多选
//使用noselect2,系统不会把select组件自动使用select2渲染
<div class="form-group" id="userSelect">
<label class="col-sm-4 control-label"><span class="required-icon">*</span>用户选择:</label>
<div class="col-sm-8">
<input type="hidden" name="userParamStr" />
<select name="userParam" id="userParam" class="form-control m-b noselect2" multiple="multiple">
#foreach($item in $selectUserList)
<option value="$item.userId" selected>$item.userName ( $item.loginName ) </option>
#end
</select>
</div>
</div>//自己使用js,将空间userParam渲染为select2控件,并且允许输入搜索条件,变更option,并多选
jQuery("#userParam").select2({
allowClear: true, //选中之后,可手动点击删除
placeholder: "输入搜索...",
multiple: true,
minimumInputLength: 1,
ajax: {
url: function (params) {
return jQuery.common.transferUrl(prefix + "/queryUserList.do");
},
delay: 250,
method:"post",
data: function (params) {
return {
"userName": params.term, // search term
"current": params.page||1
}
},
dataType: 'json',
processResults: function (data, params) {
params.page = params.page || 1;
jQuery(data.result).each(function(i,n){
//必须要有id和text属性,否则select2会报错
n.text = n.userName+" ( "+n.loginName+" ) ";
n.id = n.userId;
});
return {
results: data.result,
pagination: {
more: params.page < data.totalPage
}
};
},
cache:true
}
,escapeMarkup: function (markup) { return markup; },
});//后台接受搜索条件,过滤并分页,展示option数据
@RequestMapping("queryUserList")
public @ResponseBody ApiBaseResponse<List<SSOUser>> queryUserList(String userName , PageInfo page){
List<SSOUser> userList = flowAuthService.findAllUserList(userName , page);
return new ApiBaseResponse<List<SSOUser>>(RetStatusEnum.SUCCESS ,ApiBaseResponse.DEFAULT_RESPONSE_CODE_SUCCESS, ApiBaseResponse.DEFAULT_RESPONSE_MESSAGE_SUCCESS, userList);
}两个层级的属性配置
使用properties文件的配置
应用中,使用properties文件的配置,我们使用spring加载配置文件,properties中的配置,一般代表系统级别的配置,不允许随便修改,修改一般需要重启.
我们也可以使用下面的方式,静态的调用到properties文件内的属性值.
PropertyStaticLoader.getInstance().findProperty("passwd.expire", "90")如果在页面,我们可以使用PropertyTag调用到properties配置文件的值
$serverProperty.findProperty("mutiable.tenant","false")使用DB的配置
在DB中,有一张表SYS_CONFIG_INFO表,里面也可以存储K-V配置.DB中的配置,存储在缓存里,每次通过页面修改配置,都会刷新缓存,再次访问就能获得配置值的变更.
在java程序中,可以这么访问DB的配置项
Configs.getInstance().findByKey("配置Key");在页面上,我们也可以使用tag,访问DB的配置项
$configTag.findByKey("配置Key")