@chenpbh
2018-10-31T02:45:53.000000Z
字数 10356
阅读 543
公共文档
版本 | 日期 | 人员 | 变更内容 |
---|---|---|---|
1.1 | 2017-08-02 | 陈鹏 | 版本初定义 |
1.2 | 2017-09-06 | 陈鹏 | 增加字典格式化 |
1.3 | 2017-11-22 | 陈鹏 | 增加名称格式化 |
1.4 | 2018-03-05 | 陈鹏 | 增加开发规范章节,介绍了权限控制、缓存处理、日志采集 |
1.6 | 2018-03-06 | 陈鹏 | 增加系统自动化工具章节 |
1.7 | 2018-04-10 | 陈鹏 | 增加导出文件的规范和流程 |
框架基于Spring Boot进行开发,目前主要使用了如下的相关组件:
需要注意几点:
在此与test_demo表为例,子系统名即为:test,相关类的目录规范如下
二次开发自定义编写的脚本,样式,还有引用的图片,必须按规定放在/resources/static/extend目录。引用的第三方前端组件,按规定放到/resources/static/frame目录
表名和字段名,统一采用小写+下划线,并且应该是有意义而且易于理解的,最好是能够表达字段含义的英文字母。
注意,所有的表和字段都必须填写相关注释。
base_user
,则表示基础子系统下的用户表。u
将对应mapper.xml中的aliasid
varchar(36)name
,长度视具体情况而定
框架支持生成搜索条件的注释,比如注释字段为用户名|action:search#lis
实体类需要继承TailBean类来实现混合模型(实体+Map)的特性。关于混合模型使用的规则,数据表字段直接在实体中定义,联表查询的字段,用map获取。
混合模型需要Mapper.xml的支持,需要配置resultMap
u.get("roleIds")
获取roleIds的值
序号 | 属性名 | 描述 | 是否必须 | 默认值 | 示例 |
---|---|---|---|---|---|
1 | name | select选择框名称 | 是 | 无 | status |
2 | ds | 数据源,dict:字典,sql:sql | 是 | 无 | sql |
3 | key | 键值,若ds=dict,key对应字典管理里的编码,或ds=sql,对应xml里的sqlid | 是 | 无 | base.RoleMapper.roles |
4 | value | 当前值 | 是 | ||
5 | verify | 验证规则名 | 否 |
如果ds=sql,那么sql应该固定返回val
和name
字段,比如select id as val,name as name from xxxx
示例
<div class="layui-form-item">
<label class="layui-form-label">状态</label>
<div class="layui-input-block">
<@core.select name="status" ds="dict" key="USER_STATE" value="1" />
</div>
</div>
序号 | 属性名 | 描述 | 是否必须 | 默认值 | 示例 |
---|---|---|---|---|---|
1 | name | radio名称 | 是 | 无 | status |
2 | ds | 数据源,dict:字典,sql:sql | 是 | 无 | sql |
3 | key | 键值,若ds=dict,key对应字典管理里的编码,或ds=sql,对应xml里的sqlid | 是 | 无 | base.RoleMapper.roles |
4 | value | 当前值 | 是 | ||
5 | verify | 验证规则名 | 否 |
如果ds=sql,那么sql应该固定返回val
和name
字段,比如select id as val,name as name from xxxx
序号 | 属性名 | 描述 | 是否必须 | 默认值 | 示例 |
---|---|---|---|---|---|
1 | name | checkbox名称 | 是 | 无 | status |
2 | ds | 数据源,dict:字典,sql:sql | 是 | 无 | sql |
3 | key | 键值,若ds=dict,key对应字典管理里的编码,或ds=sql,对应xml里的sqlid | 是 | 无 | base.RoleMapper.roles |
4 | value | 当前值,支持多个值,用逗号“,”分隔 | 是 | ||
5 | verify | 验证规则名 | 否 |
如果ds=sql,那么sql应该固定返回val
和name
字段,比如select id as val,name as name from xxxx
序号 | 属性名 | 描述 | 是否必须 | 默认值 | 示例 |
---|---|---|---|---|---|
1 | name | select选择框名称 | 是 | status | |
2 | value | 当前值,支持多个值 | 是 | 1,2 | |
3 | display | 显示文本 | 否 | 程序员,前端工程师 | |
4 | refer | 引用页面dom的ID,在页面为隐藏域,开发人员不需要手动增加隐藏域 | 是 | roleIds | |
5 | key | sql,对应xml里的sqlid | 是 | base.RoleMapper.roles | |
6 | args | 附加参数 | 是 | k1:v1,k2:v2 | |
7 | title | 标题 | 是 | 请选择角色 | |
8 | width | 长度,单位为px | 否 | 500px | 500px |
9 | height | 高度,单位为px | 否 | 600px | 600px |
11 | multiple | 是否多选 | 否 | false | false |
12 | verify | 验证规则名 | 否 | ||
13 | queryParam | 明文传参到ftl页面 | 否 |
sql应该固定返回id
和name
字段,比如select id as id,name as name from xxxx
<div class="layui-form-item">
<label class="layui-form-label">角色</label>
<div class="layui-input-block">
<@core.dialog name="roleNames" key="base.RoleMapper.treeNodes" value="" multiple=true refer="roleIds" title="请选择角色" height="600px" />
</div>
</div>
序号 | 属性名 | 描述 | 是否必须 | 默认值 | 示例 |
---|---|---|---|---|---|
1 | name | select选择框名称 | 是 | status | |
2 | value | 当前值,支持多个值 | 是 | 1,2 | |
3 | display | 显示文本 | 否 | 程序员,前端工程师 | |
4 | refer | 引用页面dom的ID,在页面为隐藏域,开发人员不需要手动增加隐藏域 | 是 | roleIds | |
5 | key | sql,对应xml里的sqlid | 是 | base.RoleMapper.roles | |
6 | args | 附加参数 | 是 | ||
7 | title | 标题 | 是 | 请选择角色 | |
8 | width | 长度,单位为px | 否 | 500px | 500px |
9 | height | 高度,单位为px | 否 | 600px | 600px |
11 | multiple | 是否多选 | 否 | false | false |
12 | verify | 验证规则名 | 否 |
sql应该固定返回id
和name
字段,比如select id as id,name as name from xxxx
<div class="layui-form-item">
<label class="layui-form-label">父节点</label>
<div class="layui-input-block">
<@core.tree name="parentName" key="base.AreaMapper.treeNodes" value="${(obj.parentId)!}" display="${(obj.tails.parentName)!}" multiple=true refer="parentId" title="请选择上级区域"/>
</div>
</div>
序号 | 属性名 | 是否必填 | 描述 | 示例 |
1 | lngName | 是 | 经度html元素名称 | lng |
2 | latName | 是 | 纬度html元素名称 | lat |
3 | lng | 否 | 当前经度值 | 0 |
4 | lng | 否 | 当前纬度值 | 0 |
5 | verifyLngName | 否 | 经度校验规则名称 | |
6 | verifyLatName | 否 | 纬度校验规则名称 |
<div class="layui-form-item">
<@core.lngLat lngName="lng" latName="lat" lng="${(obj.lng)!0}" lat="${(obj.lat)!0}" addressFrom="address"/>
<div>
序号 | 属性名 | 描述 | 是否必须 | 默认值 | 示例 |
---|---|---|---|---|---|
1 | code | 字典编码 | 是 | 无 | BASE_EMPLOYEE_IS_USE |
2 | key | 字段名,对应column的field名 | 是 | 无 | inUser |
示例
<@formatter.dict code='BASE_EMPLOYEE_IS_USE' key='isUse'/>
#表格
{field: 'isUse', title: '权限状态', width: 120, templet:"#isUse"},
此标签主要用于列表格式化显示,另外`DataLoader.loadNames(Object)`方法可用于在编辑、查看页面,将外键关联的名称显示出来,而不必通过关联表查询。同样在处理导出时,调用此方法,也可以将相关数据查询出来。
序号 | 属性名 | 描述 | 是否必须 | 默认值 | 示例 |
---|---|---|---|---|---|
1 | key | 字段名,对应column的field名 | 是 | 无 | roleIds |
2 | url | 点击弹出页面,一般为查看详情页面,若url为空,width和height可为空 | 否 | 无 | /role/view |
3 | width | 窗口宽度 | 否 | 无 | 500px |
4 | height | 窗口高度 | 否 | 无 | 500px |
1、 在domain实体的相应get方法增加@LinkName
注解
@LinkName(table = "base_role")
public String getRoleIds() {
return roleIds;
}
2、 在service层显示调用DataLoader.loadNames(Object)
方法(目前传参支持List、LayModel和TailBean的子类)
LayModel layModel = new LayModel();
ayModel.setCount(pm.getTotal());
layModel.setData(pm.getRows());
DataLoader.loadNames(layModel);
return layModel;
3、在前端页面使用标签
<@formatter.name key='roleIds' url='/role/update' width="600px" height='500px'/>
<script>
#表格列定义
{field: 'roleNames', title: '角色',templet: '#roleIds'},
</script>
此章节主要约定了开发过程中的规范,避免开发人员在开发过程中,出现遗漏和不规范的情况。
该框架采用 Apache Shiro实现用户访问权限的控制,支持前后端的权限控制。其中前端采用的是Freemarker标签方式,而后台是需要在控制器方法中,增加注解。而权限控制的核心元素,则是资源编码(对应模块管理中的编码)。另外,建议编码的命名为业务大模块_功能模块_动作
,比如新增用户,命名为BASE_USER_ADD
通过代码生成器生成的代码,已经生成了对应的资源信息。如果是单独开发的,需要必须手工增加资源信息,并在前后端代码中,加以控制。我们约定,在下面章节点,我们将以新增用户的权限处理来举例说明,权限是如何控制的
前端通过freemarker标签进行控制,常用的标签包括:
- hasPermission: 验证当前用户是否拥有该权限
- authenticated: 验证用户是否已经登录系统
- lacksPermission:验证当前用户不拥有某种权限,与hasPermission标签是相对的
1、 为了对新增用户进行权限控制,首先我们需要在前台页面/base/user/list.ftl页面中,html的新增按钮元素用freemarker标签已经包括起来
<@shiro.hasPermission name="BASE_USER_ADD">
<a class="layui-btn btn-add btn-default" id="btn-add">新增</a>
</@shiro.hasPermission>
2、然后,出于安全和隐私控制,我们同时将新增相关的JS代码也进行控制
<@shiro.hasPermission name="BASE_USER_ADD">
//绑定新增按钮事件
bindAdd('/base/user/add','新增',"540px","530px",gridObj);
</@shiro.hasPermission>
在控制器通过注解@RequiresPermissions
控制权限(注意,功能关联的其他请求,也应该加上注解进行控制,常用的就是包括页面和Ajax调用)
/**
* 新增页面
* @param model
* @return
*/
@GetMapping(value = "/add")
@RequiresPermissions("BASE_USER_ADD")
@SLog(action = "新增页面")
public String add(Model model) {
return BASE+"add";
}
/**
* 保存
* @param job
* @return
*/
@PostMapping(value = "/add")
@ResponseBody
@RequiresPermissions("BASE_USER_ADD")
@SLog(action = "新增用户")
public AppBean add(User user){
userService.insert(user);
return new AppBean("增加成功");
}
系统日志目前是通过提供自定义的注解方式实现,提供的注解为下:
* Module: 模块名,比如用户管理
* SLog: 动作名,比如新增
下面我们以新增用户举例:
1、需要在控制类声明上加上@Module注解
/**
* 用户管理
* @author 陈鹏
* @Time 2017-07-04 18:29:52
*/
@Module(name = "用户管理")
@Controller
@RequestMapping(value = "/user")
2、在新增方法加上注解SLog注解,由于新增涉及到两个请求,所以此处在这两个方法都加上SLog注解
/**
* 新增页面
* @param model
* @return
*/
@GetMapping(value = "/add")
@RequiresPermissions("BASE_USER_ADD")
@SLog(action = "新增页面")
public String add(Model model) {
return BASE+"add";
}
/**
* 保存
* @param job
* @return
*/
@PostMapping(value = "/add")
@ResponseBody
@RequiresPermissions("BASE_USER_ADD")
@SLog(action = "新增用户")
public AppBean add(User user){
userService.insert(user);
return new AppBean("增加成功");
}
3、日志采集情况可以通过日志管理中查看。
框架对于Mybatis二级缓存进行扩展,由Mybatis默认的内存改为了Redis。使用方式如下:
1、配置文件,在application.yml的redis配置中,增加mybatis缓存配置spring.redis.mybatis.index,即指定二级缓存放的redis的db
spring:
redis:
database: 12
host: 192.168.6.141
port: 6380
password: 123456
mybatis:
index: 13
2、需要在mybatis的mapper的xml开启二级缓存支持,即cache的type为com.bitnei.cloud.common.cache.MybatisRedisCache
<mapper namespace="com.bitnei.cloud.base.mapper.JobMapper">
<cache type="com.bitnei.cloud.common.cache.MybatisRedisCache" eviction="LRU" flushInterval="6000000" size="1024" readOnly="false"/>
...........
</mapper>
3、缓存管理,为了避免出现开发人员使用不当导致内存不同步的情况,框架提供了mybatis二级缓存的管理功能,支持查看和清理等操作。
在这里,以导出系统日志为示例:
1、编写mysql语句: 正常情况下,我们可以直接使用数据列表的sql语句,如下
<!-- 分页查询 -->
<select id="pagerModel" resultMap="tailResults" parameterType="java.util.HashMap">
select
<include refid="moreColumns"/>
from
base_log log
where
1=1
<if test="username != null">
and log.username like "%"#{username}"%"
</if>
<if test="moudle != null">
and log.moudle like "%"#{moudle}"%"
</if>
<if test="action != null">
and log.action like "%"#{action}"%"
</if>
ORDER BY log.TIME DESC
</select>
2、业务层采集数据: 如果模块代码是通过代码生成工具生成的,正常业务层代码是不需要改动的
@Override
public void export() {
List list = findBySqlId("pagerModel",ServletUtil.getQueryParams());
String srcBase = RequestContext.class.getResource("/templates/").getFile();
String srcFile = srcBase +"module/base/log/export.xls";
ExcelData ed = new ExcelData();
ed.setTitle("日志管理");
ed.setExportTime(DateUtil.getNow());
ed.setData(list);
String outName = String.format("%s-导出-%s.xls", "日志管理", DateUtil.getShortDate());
EasyExcel.renderResponse(srcFile,outName,ed);
}
3、配置excel模板: 框架的excel模板为export.xls
,excel文件中共有两个sheet,一个为列定义,一个参数配置。详细的excel配置,将在下面章节进行描述。
列定义采用Freemarker实现,支持freemarker指令表达式。在这里,框架默认对象名为obj
,比如Log实体定义为
public class Job extends TailBean {
/** **/
private String id;
/** 任务名称 **/
private String name;
/** 类名 **/
private String className;
/** 方法名 **/
private String methodName;
/** Cron表达式 **/
private String cron;
/** 上次执行时间 **/
private String lastJobTime;
/** 最后异常信息 **/
private String lastException;
/** 启用状态 **/
private Integer status;
/** 耗时 **/
private Integer takeTime;
/** 创建时间 **/
private String createTime;
/** 创建人 **/
private String createBy;
/** 更新时间 **/
private String updateTime;
/** 更新人 **/
private String updateBy;
/** 备注 **/
private String note;
....getter/setter........
}
然后在excel中就可以根据实现情况,进行配置模板。另外,导出文件的样式,也可以直接调整。导出文件,样式和模板的保持一致。
目前框架支持的参数项如下:
日志管理-20180410154150.xls
或日志管理-20180410154150.zip
代码生成依赖于数据库表的注释,详细注释规则参见# 2 数据库规范
。