Commit 2930ca97 authored by 高洋's avatar 高洋

Track 9 files into repository.

- modified codeStyle.md
- modified common-window-javascript.md
- untracked 前端组件/HlsBarChart.md
- untracked 前端组件/hlsChart.md
- untracked 前端组件/头行保存.md
- modified 后端开发/activiti_demo.md
- modified 后端开发/RabbitMq消息队列.md
- modified 框架功能描述/计划任务.md
- modified 融租易开发手册.md

Auto commit by GitBook Editor
parent c4422981
## [一、后端开发规范](id:backEndDev)
1. 所有的项目文件必须采用UTF-8编码,IDEA及Eclipse需要手动设置项目编码以及编译编码。
- Eclipse中修改项目编码的方法参考:[Eclipse修改编码方法](http://jingyan.baidu.com/article/647f0115b0c9887f2148a822.html)
- IDEA中修改项目编码的方法参考:[IDEA修改编码方法](http://jingyan.baidu.com/article/948f5924e4de57d80ff5f998.html])
2. 提供他人使用的接口,原则上不允许修改**方法签名**,若是不再推荐使用,可以加**@ Deprecated**注解,同时提示新的接口名称。
3. **DTO**类中所有的字段,不允许设置**默认值**,且DTO必须**重写toString()方法**
4. 原则上不允许使用递归,部分情况可以使用尾递归。
5. 代码中不允许出现魔法值,即未定义的任何常量。错误的用法不限于以下形式:
```java
if(user.getStatus() == 5){
// 5即为魔法值,应当避免使用
// do something
}
// 推荐使用常量
private static final int EXPIRED_USER_STATUS = 5;
if(user.getStatus() == EXPIRED_USER_STATUS){
// do something
}
```
6. 在类中定义的常量、变量及方法,需要严格控制访问修饰符,提供自己使用的设为private,可以供别人使用的可以设为public、protected等。
7. 所有的覆写方法,必须加**@Override**注解,防止错误的拼写导致意外。
8. Long类型的数据在初始化时必须使用大写的字母L, Double类型的数据必须使用大写的字母D。常见形式如
- **Long time=10000L**
- **Double money=12.3D**
9. 所有的数值的包装类型之间的比较不允许使用<>、==之类的简单运算符,需要使用equals方法或者compareTo方法。
10. 所有方法的引用类型参数,若是未添加**@NotNull**注解,必须先进行null判断。
11. 捕获异常一般不允许直接捕获基类Exception,也不可捕获异常后不进行处理。方法中也不可抛出基类Exception。
12. 部分异常若是上层(调用层)不能解决,则不允许抛出。最外层若是出现异常必须自行处理,不可将异常信息直接展示给用户。
13. 所有的日志信息**不允许使用System.out.println**输出,异常的日志信息使用**log.error**打印时,必须使用重载方法将捕获的异常作为第二个参数。如:
```java
try{
// throw some exceptions
}catch(IOException e){
logger.error(e.getMessage(), e);
}
```
--- ---
## [二、后端命名规范](id:backEndName)
1. 所有的命名不允许使用**拼音或者拼音英文混合**方式,但部分公认的拼音允许使用,如**shanghai,beijing**等。
2. 所有的命名不允许使用**下划线`_`**或者**美元符`$`**作为起始或者结束。错误的情况有不限于以下几种:
- **_param**
- **$param**
- **param_**
- **param$**
- **_param$**
### 包命名规范
1. 包名一般为域名倒序开头,后接项目名,再加上单数形式的名词(项目中一般使用模块代码),且全部为小写字母,如:
- 系统功能模块:**com.hand.hls.sys**
- 合同功能模块:**com.hand.hls.cont**
2. 在功能模块包中一般包含如下几种形式的包:
- 存放SpringMVC的控制层代码: **controllers**
- 存放该模块数据库实体对象: **dto**
- 存放该模块的部分组件: **components**
- 存放该模块的业务接口: **service**
- 存放该模块的业务实现类: **service.impl**
- 存放该模块的Mybatis数据库交互层代码: **mapper**
- 存放该模块的工具类代码: **utils**
- 存放自定义的异常类代码: **exception**
### 类命名规范
1. 一般类名采用Pascal命名法,所有单词的首字母大写,其余字母小写,单词与单词之间不使用**下划线_**分割,常见形式如:
- **HlsClassName**
- **HlsNormalClass**
2. 数据库实体类一般与数据表名称相同并改为Pascal命名规则,**DTO**结尾,如:
- **SysUserDTO**
- **SysRoleDTO**
3. 抽象类命名使用**Abstract**开头,接口一般以 **I** 开头,Mybatis的mapper对象可不用 **I** 开头但必须使用**Mapper**结尾,如:
- **AbstractClass**
- **ILog**
- **SysUserMapper**
4. 业务逻辑层接口类使用 **I** 开头,且必须以**Service**结尾;业务的实现类在接口的基础上去掉开头的字母 **I**,最后加上**Impl**,如:
- **ISysUserService**
- **SysUserServiceImpl**
5. 自定义的异常类以**Exception**结尾,如:
- **UserNotFoundException**
- **UserDefineException**
6. 项目中的测试类一般以测试对象的类名开头,以**Test**结尾,如:
- **SysUserServiceImplTest**
7. 若是采用了设计模式的类,在命名时,可在最后添加设计模式的名称,如:
- 工厂模式: **LoggerFactory**
- 代理模式: **UserProxy**
- 适配器模式: **ArrayAdapter**
### 变量命名规范
1. 成员变量、局部变量都统一使用lowerCamelCase风格,必须遵从驼峰形式,即**首单词**字母都小写,后面单词的**首字母大写**。如
+ **hlsClassFieldName**
+ **hlsLocalParamName**
2. 数据库对象的成员变量中若是变量的类型为Boolean类型,则变量名不允许使用 **is**开头,错误的命名如下:
- **private Boolean isAdmin**
### 常量命名规范
1. 常量的命名一般所有单词都**大写**,各个单词之间使用下划线`_`分隔,如:
- **PI**
- **PROJECT_PATH**
2. 常量的命名尽量使用单词表达出常量的用途及含义,力求语义清晰,不用担心名字太长,如:
- 周期的第一天:**FIRST_DAY_OF_CYCLE**
- 用户允许的最大错误次数:**USER_ALLOWED_MAX_ERROR_COUNT**
### 方法命名规范
1. 方法的命名规则采用lowerCamelCase风格,方法名的首单词字母全部小写,其余单词首字母大写,如:
- **walkMyWay()**
- **doSomething()**
2. 对数据库进行查询的方法,一般以**select、find、query**开头,后面接查询的对象,若是查询结果为List集合,对象名可变为复数,如:
- `public SysUser selectSysUser()`
- `public List<SysRole> findSysRoles()`
3. 对数据进行数据插入的方法,一般以**insert**开头,后接插入的对象,若是允许批量插入对象,对象名可变为复数,如:
- `public int insertSysUser(SysUser user)`
- `public int insertSysRoles(List<SysRole> roles)`
4. 对数据库进行数据删除的方法,一般以**delete**开头,后接插入的对象,若是允许批量插入对象,对象名可变为复数,如:
- `public int deleteSysUser(SysUser user)`
- `public int deleteSysRoleByIds(List<Long> roleIds)`
5. 对数据库进行数据更新的方法,一般以**update**开头,后接插入的对象,若是允许批量插入对象,对象名可变为复数,如:
- `public SysRole updateSysRole(SysRole role)`
- `public int updateSysUsers(List<SysUser> users)`
## [一、后端开发规范](id:backEndDev)
1. 所有的项目文件必须采用UTF-8编码,IDEA及Eclipse需要手动设置项目编码以及编译编码。
- Eclipse中修改项目编码的方法参考:[Eclipse修改编码方法](http://jingyan.baidu.com/article/647f0115b0c9887f2148a822.html)
- IDEA中修改项目编码的方法参考:[IDEA修改编码方法](http://jingyan.baidu.com/article/948f5924e4de57d80ff5f998.html])
2. 提供他人使用的接口,原则上不允许修改**方法签名**,若是不再推荐使用,可以加**@ Deprecated**注解,同时提示新的接口名称。
3. **DTO**类中所有的字段,不允许设置**默认值**,且DTO必须**重写toString()方法**
4. 原则上不允许使用递归,部分情况可以使用尾递归。
5. 代码中不允许出现魔法值,即未定义的任何常量。错误的用法不限于以下形式:
```java
if(user.getStatus() == 5){
// 5即为魔法值,应当避免使用
// do something
}
// 推荐使用常量
private static final int EXPIRED_USER_STATUS = 5;
if(user.getStatus() == EXPIRED_USER_STATUS){
// do something
}
```
6. 在类中定义的常量、变量及方法,需要严格控制访问修饰符,提供自己使用的设为private,可以供别人使用的可以设为public、protected等。
7. 所有的覆写方法,必须加**@Override**注解,防止错误的拼写导致意外。
8. Long类型的数据在初始化时必须使用大写的字母L, Double类型的数据必须使用大写的字母D。常见形式如
- **Long time=10000L**
- **Double money=12.3D**
9. 所有的数值的包装类型之间的比较不允许使用<>、==之类的简单运算符,需要使用equals方法或者compareTo方法。
10. 所有方法的引用类型参数,若是未添加**@NotNull**注解,必须先进行null判断。
11. 捕获异常一般不允许直接捕获基类Exception,也不可捕获异常后不进行处理。方法中也不可抛出基类Exception。
12. 部分异常若是上层(调用层)不能解决,则不允许抛出。最外层若是出现异常必须自行处理,不可将异常信息直接展示给用户。
13. 所有的日志信息**不允许使用System.out.println**输出,异常的日志信息使用**log.error**打印时,必须使用重载方法将捕获的异常作为第二个参数。如:
```java
try{
// throw some exceptions
}catch(IOException e){
logger.error(e.getMessage(), e);
}
```
--- ---
## [二、后端命名规范](id:backEndName)
1. 所有的命名不允许使用**拼音或者拼音英文混合**方式,但部分公认的拼音允许使用,如**shanghai,beijing**等。
2. 所有的命名不允许使用**下划线`_`**或者**美元符`$`**作为起始或者结束。错误的情况有不限于以下几种:
- **_param**
- **$param**
- **param_**
- **param$**
- **_param$**
### 包命名规范
1. 包名一般为域名倒序开头,后接项目名,再加上单数形式的名词(项目中一般使用模块代码),且全部为小写字母,如:
- 系统功能模块:**com.hand.hls.sys**
- 合同功能模块:**com.hand.hls.cont**
2. 在功能模块包中一般包含如下几种形式的包:
- 存放SpringMVC的控制层代码: **controllers**
- 存放该模块数据库实体对象: **dto**
- 存放该模块的部分组件: **components**
- 存放该模块的业务接口: **service**
- 存放该模块的业务实现类: **service.impl**
- 存放该模块的Mybatis数据库交互层代码: **mapper**
- 存放该模块的工具类代码: **utils**
- 存放自定义的异常类代码: **exception**
### 类命名规范
1. 一般类名采用Pascal命名法,所有单词的首字母大写,其余字母小写,单词与单词之间不使用**下划线_**分割,常见形式如:
- **HlsClassName**
- **HlsNormalClass**
2. 数据库实体类一般与数据表名称相同并改为Pascal命名规则,如:
- **SysUser**
- **SysRole**
3. 抽象类命名使用**Abstract**开头,接口一般以 **I** 开头,Mybatis的mapper对象可不用 **I** 开头但必须使用**Mapper**结尾,如:
- **AbstractClass**
- **ILog**
- **SysUserMapper**
4. 业务逻辑层接口类使用 **I** 开头,且必须以**Service**结尾;业务的实现类在接口的基础上去掉开头的字母 **I**,最后加上**Impl**,如:
- **ISysUserService**
- **SysUserServiceImpl**
5. 自定义的异常类以**Exception**结尾,如:
- **UserNotFoundException**
- **UserDefineException**
6. 项目中的测试类一般以测试对象的类名开头,以**Test**结尾,如:
- **SysUserServiceImplTest**
7. 若是采用了设计模式的类,在命名时,可在最后添加设计模式的名称,如:
- 工厂模式: **LoggerFactory**
- 代理模式: **UserProxy**
- 适配器模式: **ArrayAdapter**
### 变量命名规范
1. 成员变量、局部变量都统一使用lowerCamelCase风格,必须遵从驼峰形式,即**首单词**字母都小写,后面单词的**首字母大写**。如
+ **hlsClassFieldName**
+ **hlsLocalParamName**
2. 数据库对象的成员变量中若是变量的类型为Boolean类型,则变量名不允许使用 **is**开头,错误的命名如下:
- **private Boolean isAdmin**
### 常量命名规范
1. 常量的命名一般所有单词都**大写**,各个单词之间使用下划线`_`分隔,如:
- **PI**
- **PROJECT_PATH**
2. 常量的命名尽量使用单词表达出常量的用途及含义,力求语义清晰,不用担心名字太长,如:
- 周期的第一天:**FIRST_DAY_OF_CYCLE**
- 用户允许的最大错误次数:**USER_ALLOWED_MAX_ERROR_COUNT**
### 方法命名规范
1. 方法的命名规则采用lowerCamelCase风格,方法名的首单词字母全部小写,其余单词首字母大写,如:
- **walkMyWay()**
- **doSomething()**
2. 对数据库进行查询的方法,一般以**select、find、query**开头,后面接查询的对象,若是查询结果为List集合,对象名可变为复数,如:
- `public SysUser selectSysUser()`
- `public List<SysRole> findSysRoles()`
3. 对数据进行数据插入的方法,一般以**insert**开头,后接插入的对象,若是允许批量插入对象,对象名可变为复数,如:
- `public int insertSysUser(SysUser user)`
- `public int insertSysRoles(List<SysRole> roles)`
4. 对数据库进行数据删除的方法,一般以**delete**开头,后接插入的对象,若是允许批量插入对象,对象名可变为复数,如:
- `public int deleteSysUser(SysUser user)`
- `public int deleteSysRoleByIds(List<Long> roleIds)`
5. 对数据库进行数据更新的方法,一般以**update**开头,后接插入的对象,若是允许批量插入对象,对象名可变为复数,如:
- `public SysRole updateSysRole(SysRole role)`
- `public int updateSysUsers(List<SysUser> users)`
### 窗口级通用方法
#### 打开功能窗口
>Hel.openMenuWindow(opts);
其中参数为:
属性名 | 类型 | 含义
-------- | ----- | -----
menuCode | String(必填) | 菜单代码
title | String(必填) | 窗口描述
url | Object(必填) | 窗口地址
menuName | String| 菜单名称
moduleFlag| String | 模块标志(Y/N)
documentKey| String | 打开同一个功能时,识别不同单据的唯一标识
reflashFlag| String | 关闭该功能菜单时是否刷新父级标志(Y/N)
moduleName| String | 模块名称
```
Hel.openMenuWindow({
menuCode:'',//传入相应的参数
title:'',
url:'',
menuName:'',
moduleFlag:'',
documentKey:'',
reflashFlag:'',
moduleName:''
});
```
#### 关闭功能窗口
>Hel.closeMenuWindow(opts);
其中参数为:
属性名 | 类型 | 含义
-------- | ----- | -----
menuCode | String(必填) | 菜单代码
```
Hel.closeMenuWindow({
menuCode:''//传入相应的参数
});
```
#### 打开右弹窗口
>Hel.openBarWindow(opts);
其中参数为:
属性名 | 类型 | 含义
-------- | ----- | -----
id| String(必填) | 打开窗口的div的id
url| String(必填) | 窗口的url地址
size| String(必填) | 右弹窗口的宽度(THIRD/HALF/FULL/任意px像素)
```
<div id="win"></div>
<script><![CDATA[
Hel.openBarWindow({
id:'win',
content:'',
size:''
});
]]></script>
```
#### 打开抽屉
> Hel.openBox()函数接收一个对象,对象属性含义如下:
属性名 | 类型 | 含义
-------- | ----- | -----
winId | String(必填) | html元素标签的id
functionCode | String(必填) | 抽屉的唯一标识,用以确定该抽屉的相关信息
params | Object | 需传递的参数,将自动拼到url上
closeFunction | function | 关闭抽屉调用的方法
width | Number | 自定义宽度
```javascript
function test(e){
...
}
Hel.openBox({
winId:"domId",
functionCode:"CSH200B",
params:{
contractId:1327,
conContractCashflowId:4321
},
closeFunction:test,
width:900
});
```
##### 注意:
> - winId和functionCode必须有字符串类型的值
> - params可以没有,表示不拼接条件;
> - closeFunction可以没有,表示关闭抽屉不进行操作
> - width可以没有,表示使用配置的宽度
### 窗口级通用方法
#### 打开功能窗口
>Hel.openMenuWindow(opts);
其中参数为:
属性名 | 类型 | 含义
-------- | ----- | -----
menuCode | String(必填) | 菜单代码
title | String(必填) | 窗口描述
url | Object(必填) | 窗口地址
menuName | String| 菜单名称
moduleFlag| String | 模块标志(Y/N)
documentKey| String | 打开同一个功能时,识别不同单据的唯一标识
reflashFlag| String | 关闭该功能菜单时是否刷新父级标志(Y/N)
moduleName| String | 模块名称
```
Hel.openMenuWindow({
menuCode:'',//传入相应的参数
title:'',
url:'',
menuName:'',
moduleFlag:'',
documentKey:'',
reflashFlag:'',
moduleName:''
});
```
#### 关闭功能窗口
>Hel.closeMenuWindow(opts);
其中参数为:
属性名 | 类型 | 含义
-------- | ----- | -----
menuCode | String(必填) | 菜单代码
```
Hel.closeMenuWindow({
menuCode:''//传入相应的参数
});
```
#### 打开右弹窗口
>Hel.openBarWindow(opts);
其中参数为:
属性名 | 类型 | 含义
-------- | ----- | -----
id| String(必填) | 打开窗口的div的id
url| String(必填) | 窗口的url地址
size| String(必填) | 右弹窗口的宽度(THIRD/HALF/FULL/任意px像素)
```
<div id="win"></div>
<script><![CDATA[
Hel.openBarWindow({
id:'win',
content:'',
size:''
});
]]></script>
```
#### 打开抽屉
> Hel.openBox()函数接收一个对象,对象属性含义如下:
属性名 | 类型 | 含义
-------- | ----- | -----
winId | String(必填) | html元素标签的id
functionCode | String(必填) | 抽屉的唯一标识,用以确定该抽屉的相关信息
params | Object | 需传递的参数,将自动拼到url上
closeFunction | function | 关闭抽屉调用的方法
width | Number/字符串(100% , 100px) | 自定义宽度
```javascript
function test(e){
...
}
Hel.openBox({
winId:"domId",
functionCode:"CSH200B",
params:{
contractId:1327,
conContractCashflowId:4321
},
closeFunction:test,
width:900
});
```
##### 注意:
> - winId和functionCode必须有字符串类型的值
> - params可以没有,表示不拼接条件;
> - closeFunction可以没有,表示关闭抽屉不进行操作
> - width可以没有,表示使用配置的宽度
## HlsBarChart
```xml
<h:hlsChart chartType="BAR" style="margin-top:5px;margin-left:6px;" barSourceData="barSourceData" titleBgColor="red"
title="商业伙伴" modify="modifyFunc" add="addFunc" color="#ed4e2a"></h:hlsChart>
```
**常用的属性**
| 属性名 | 类型 | 作用 | 是否必输|
|:---: | :---: | :---: | :---: |
| id | string | 唯一标识 |
| chartType | string | 组件类型 | Y
| style | string | 组件box样式 |
| barSourceData | object | 组件数据源 | Y
| titleBgColor | string | 组件标题背景颜色 |
| title | string | 组件标题 |
| modify | function | 编辑icon触发的事件 |
| add | function | 新增icon触发的事件 |
|color|string |字体颜色|
**下面是一个例子**
```javascript
var datas = function (url) {
var odatas = [],
$.ajax({
type: 'GET',
url: "${base.contextPath}/hls/bp/master/home/secord/query",
async: false,
contentType: "application/json; charset=utf-8",
success: function (datas) {
odatas = datas.rows;
}
});
return odatas;
}();
var statisticalData = function () {
var o = {};
$.ajax({
type: 'GET',
url: "${base.contextPath}/hls/bp/master/count/query",
async: false,
contentType: "application/json; charset=utf-8",
success: function (datas) {
o.allCount = datas.rows[0].allCount;
o.monthAddCount = datas.rows[0].monthAddCount;
}
});
return o;
}();
//数据源
var barSourceData = {
barModel: {
xkey: 'description',
ykeys: 'count',
data: datas,
labels: '数值', //鼠标经过柱子图显示的描述
barColors: 'green',
barSizeRatio: 0.5,
},
statisticalModel: {
statisticalTitle: {
allCount: "总数",
monthAddCount: "本月新增"
},
statisticalData: statisticalData
}
};
function modifyFunc(e) {
alert("modifyFunc");
}
function addFunc(e) {
alert("addFunc");
}
```
#### 注意: 数据源中的属性名,需要固定,这样做是考虑到将不同的查询结果整合成统一的数据格式,方便组件渲染。
> - barModel:柱形图
| 属性名 | 类型 | 作用 |
|:---: | :---: | :---: | :---: |
| xkey | string | x轴标题对应的属性名
| ykeys | string | y轴数据对应的属性名 |
| data | Array | 数据集 |
| labels | string | 鼠标经过柱状图时ykeys对应的值的描述 |
| barColors | string | 柱子颜色 |
| barSizeRatio | Number | 柱子和数据的比例 |
> - statisticalModel:上方的统计框
| 属性名 | 类型 | 作用 |
|:---: | :---: | :---: |
| statisticalTitle | object | 统计框的属性名以及属性描述 |
| statisticalData | object | 数据源 (注意statisticalData的属性名和statisticalTitle中的属性名要对应上)
```xml
<h:hlsChart chartType="BAR" style="margin-top:5px;margin-left:6px;" barSourceData="barSourceData" titleBgColor="red"
title="商业伙伴" modify="modifyFunc" add="addFunc" color="#ed4e2a"></h:hlsChart>
```
\ No newline at end of file
## hlsChart 图表
### 环状图(CIRCULAR)
使用方法:
```xml
<h:hlsChart
chartType="CIRCULAR"
style="position: relative;"
url="${base.contextPath}/con/conHomepage/ApprovalQuantity/query"
color="#FFCD55,#2EC3E8,#FA6A4D,#A0D469"
labels="新建,审批中,审批拒绝,审批通过"
values="newCount,approvingCount,rejectedCount,approvedCount"
selectedChanged="select">
</h:hlsChart>
<script>
var select = function(arg,item){
console.log('label:'+item.label);
}
</script>
```
| 属性名 | 类型 | 描述 |
| :--- | :--- | :--- |
| chartType | String | 图表类型 |
| style | String | 图表外层的style样式 |
| url | String | 图表数据源的获取地址 |
| color | String | 图表各数据块所对应的颜色,多个数据块之间使用“,”分隔 |
| labels | String | 图表中各数据块所对应的标签,多个数据块之间使用“,”分隔 |
| values | String | 图表中各数据块所对应响应数据中的字段,多个数据块之间使用“,”分隔 |
| selectedChanged | String | 图表中各数据块的点击回调事件 |
## HlsBarChart 图表
### 柱状图(BAR)
```xml
<h:hlsChart chartType="BAR" style="margin-top:5px;margin-left:6px;" barSourceData="barSourceData" titleBgColor="red"
title="商业伙伴" modify="modifyFunc" add="addFunc" color="#ed4e2a"></h:hlsChart>
```
**常用的属性**
| 属性名 | 类型 | 作用 | 是否必输|
|:---: | :---: | :---: | :---: |
| id | string | 唯一标识 |
| chartType | string | 组件类型 | Y
| style | string | 组件box样式 |
| barSourceData | object | 组件数据源 | Y
| titleBgColor | string | 组件标题背景颜色 |
| title | string | 组件标题 |
| modify | function | 编辑icon触发的事件 |
| add | function | 新增icon触发的事件 |
|color|string |字体颜色|
**下面是一个例子**
```javascript
var datas = function (url) {
var odatas = [],
$.ajax({
type: 'GET',
url: "${base.contextPath}/hls/bp/master/home/secord/query",
async: false,
contentType: "application/json; charset=utf-8",
success: function (datas) {
odatas = datas.rows;
}
});
return odatas;
}();
var statisticalData = function () {
var o = {};
$.ajax({
type: 'GET',
url: "${base.contextPath}/hls/bp/master/count/query",
async: false,
contentType: "application/json; charset=utf-8",
success: function (datas) {
o.allCount = datas.rows[0].allCount;
o.monthAddCount = datas.rows[0].monthAddCount;
}
});
return o;
}();
//数据源
var barSourceData = {
barModel: {
xkey: 'description',
ykeys: 'count',
data: datas,
labels: '数值', //鼠标经过柱子图显示的描述
barColors: 'green',
barSizeRatio: 0.5,
},
statisticalModel: {
statisticalTitle: {
allCount: "总数",
monthAddCount: "本月新增"
},
statisticalData: statisticalData
}
};
function modifyFunc(e) {
alert("modifyFunc");
}
function addFunc(e) {
alert("addFunc");
}
```
#### 注意: 数据源中的属性名,需要固定,这样做是考虑到将不同的查询结果整合成统一的数据格式,方便组件渲染。
> - barModel:柱形图
| 属性名 | 类型 | 作用 |
|:---: | :---: | :---: | :---: |
| xkey | string | x轴标题对应的属性名
| ykeys | string | y轴数据对应的属性名 |
| data | Array | 数据集 |
| labels | string | 鼠标经过柱状图时ykeys对应的值的描述 |
| barColors | string | 柱子颜色 |
| barSizeRatio | Number | 柱子和数据的比例 |
> - statisticalModel:上方的统计框
| 属性名 | 类型 | 作用 |
|:---: | :---: | :---: |
| statisticalTitle | object | 统计框的属性名以及属性描述 |
| statisticalData | object | 数据源 (注意statisticalData的属性名和statisticalTitle中的属性名要对应上)
```xml
<h:hlsChart chartType="BAR" style="margin-top:5px;margin-left:6px;" barSourceData="barSourceData" titleBgColor="red"
title="商业伙伴" modify="modifyFunc" add="addFunc" color="#ed4e2a"></h:hlsChart>
```
\ No newline at end of file
## 头行保存
头行保存在实用中经常用到,头行保存指的是头表和行表(一对多)的数据同时插入,如中途失败则这次事务不进行提交。
假设我们有两张表
**hls_person(头表)**
| pid | name | age |
|:---: | :---: | :---: |
| 1 | 张三 | 21 |
| 2 | 李四| 36 |
**hls_hobby(行表)**
| hid | pid | hobby | cause |
|:---: | :---: | :---: | :---:|
| 1 | 1 | 篮球 |因为篮球好玩|
| 2 | 1| 游泳 | 因为游泳好玩|
| 3 | 1 |动画片 | 最爱看大头儿子|
| 4 | 2 |画画| 因为画画好玩|
需求是新增一个人的信息以及它的爱好(向hls_person和hls_hobby表新增记录)
下面是一个头行保存的列子:
#### 准备工作
1. 建表,主键默认自增长
2. 搭建数据模型,根据表建立相应的DTO,即HlsPerson.java和HlsHobby.java,注意HlsPerson.java中应存在List \<HlsHobby\> hlsHobbyList属性。
3. 搭建控制层,建立controller
4. 搭建业务逻辑,建立service及其实现类。
5. 搭建数据持久化层,新建mapper.java和mapper.xml
>- 先建立结构,在具体实现功能,以免疏漏。
#### 前台
```javascript
<script><![CDATA[
//提交数据用到的容器
var viewModel = kendo.observable({
isEnabled: true,
data: {},
mySubmit: function (e) {
if (e) {
e.preventDefault();
}
Hap.submitForm({
url: '${base.contextPath}/hls/test/hdLnSave',
formModel: viewModel.data,
asArray: false,
grid: {
"hlsHobbyList": $("#grid")
},
success: function () {
viewModel.showInfoDialog("保存成功!");
$('#grid').data('kendoGrid').dataSource.page(1);
},
error:function(){
viewModel.showInfoDialog("保存失败!");
}
});
},
showInfoDialog: function(pMessage)
{
kendo.ui.showInfoDialog({
title: $l('提示'),
message: pMessage
});
}
});
//请求处理方法
function parameterMap(options, type){
if (type !== "read" && options.models) {
var datas = options.models
if (type == 'create' || type == 'update') {
datas = options.models.map(function(data) {
data['__status'] = (type == 'create' ? 'add' : 'update');
return data;
})
}
return kendo.stringify(datas);
} else if (type === "read") {
var map = {};
map.page = options.page || 1;
map.pagesize = options.pageSize|| 5;
return kendo.stringify(map);
}
}
//属性列是否可编辑
function dsEditable(field){
return true;
}
]]></script>
```
```xml
<!--头-->
<h:hlsForm title="个人信息" width="100%">
<h:hlsHBox>
<h:hlsMaskedTextBox name="name" id="name" bind="enabled: isEnabled, value:data.name" colspan="3" prompt="姓名:" required="true" style="width:100%;"/>
<h:hlsMaskedTextBox name="age" id="age" bind="enabled: isEnabled, value:data.age" colspan="3" prompt="年龄:" required="true" style="width:100%;"/>
</h:hlsHBox>
</h:hlsForm>
<!--行-->
<h:dataSource id="dataSource" batch="true" pageSize="10" serverPaging="true">
<h:transport parameterMap="parameterMap">
<h:read url="${base.contextPath}/hls/test/ln/query" type="GET" dataType="json"/>
<h:destroy url="${base.contextPath}/hls/test/ln/remove" type="POST" contentType="application/json" />
</h:transport>
<h:schema data="rows" total="total" errors="schemaError">
<h:model id="pid" editable="dsEditable">
<h:fields>
</h:fields>
</h:model>
</h:schema>
</h:dataSource>
<h:hlsGridBox hlsGridId="grid" hlsBtnType="add">
<h:hlsGrid id="grid" dataSource="dataSource" selectable="" hlsBtnType="ADD,DELETE" editable="true" height="240">
<h:pageable pageSizes="5,10,20,50" buttonCount="2" refresh="true">
</h:pageable>
<h:columns>
<h:column field="hobby" title='爱好' width="150">
<h:headerAttributes style="text-align:center"/>
<h:attributes style="text-align:center"/>
</h:column>
<h:column field="cause" title='原因'>
<h:headerAttributes style="text-align:center"/>
<h:attributes style="text-align:center"/>
</h:column>
</h:columns>
</h:hlsGrid>
</h:hlsGridBox>
<!--按钮-->
<h:hlsToolBar>
<h:hlsButton click="viewModel.mySubmit" text="保存"></h:hlsButton>
</h:hlsToolBar>
```
#### 后台
保存按钮注册了点了事件,点击保存将数据提交到'${base.contextPath}/hls/test/hdLnSave'
> 在后端controller通过定义 @RequestMapping("/hls/test/hdLnSave") 注解映射到对应的url,捕获到对应请求。
后端收到前台传过来的数据,调用service层对数据进行持久化。
HlsTESTController.java
```java
@Controller
public class HlsTESTController extends BaseController {
@Autowired
private HlsPersonService hlsPersonService;
@Autowired
private HlsHobbyService hlsHobbyService;
@RequestMapping(value = "/hls/test/query")
@ResponseBody
public ResponseData hdQuery(final HlsPerson hlsPerson, @RequestParam(defaultValue = DEFAULT_PAGE) final int page,
@RequestParam(defaultValue = DEFAULT_PAGE_SIZE) final int pagesize, final HttpServletRequest request) {
IRequest requestContext = createRequestContext(request);
return new ResponseData(hlsPersonService.select(requestContext,hlsPerson,page,pagesize));
}
@RequestMapping(value="/hls/test/hdLnSave",method=RequestMethod.POST)
@ResponseBody
public ResponseData hdLnSave(HttpServletRequest request,@RequestBody HlsPerson hlsPerson, @RequestParam(defaultValue = DEFAULT_PAGE) final int page,
@RequestParam(defaultValue = DEFAULT_PAGE_SIZE) final int pagesize){
IRequest iRequest = createRequestContext(request);
hlsPersonService.batchChildUpdate(iRequest, hlsPerson);
return new ResponseData();
}
@RequestMapping(value = "/hls/test/ln/query")
@ResponseBody
public ResponseData lnQuery(final HlsHobby hlsHobby, @RequestParam(defaultValue = DEFAULT_PAGE) final int page,
@RequestParam(defaultValue = DEFAULT_PAGE_SIZE) final int pagesize, final HttpServletRequest request) {
IRequest requestContext = createRequestContext(request);
return new ResponseData(hlsHobbyService.select(requestContext,hlsHobby,page,pagesize));
}
@RequestMapping(value="/hls/test/ln/remove",method=RequestMethod.POST)
@ResponseBody
public ResponseData delete(HttpServletRequest request, @RequestBody List<HlsHobby> hlsHobbyList) {
hlsHobbyService.batchDelete(hlsHobbyList);
return new ResponseData();
}
}
```
> **提示:**
>* 通常头行结构还会涉及对头行数据的删和查,根据需要在controller中加入入口。
>* bathUpdate会根据传入的List对象中单个对象的属性值__status判断,如为update即做更新操作,add为插入操作, __status的值由前端paramter函数决定。
>* 这里的select()、batchDelete()和batchUpdate()由相应的service继承自IBaseService,自己无需实现,类似方法还有许多,请自行练习使用。
HlsPersonService.java
```java
public interface HlsPersonService extends IBaseService<HlsPerson>,ProxySelf<HlsPersonService>{
void batchChildUpdate(IRequest iRequest, HlsPerson hlsPerson);
}
```
接口实现类HlsPersonServiceImpl定义了batchChildUpdate方法:
HlsPersonServiceImpl.java
```java
@Service
@Transactional
public class HlsPersonServiceImpl extends BaseServiceImpl<HlsPerson> implements HlsPersonService {
@Autowired
private HlsHobbyService hlsHobbyService;
@Override
public void batchChildUpdate(IRequest iRequest, HlsPerson hlsPerson) {
if(hlsPerson != null ){
hlsPerson.set__status("add");
List<HlsPerson> tempHlsPerson = new ArrayList<HlsPerson>();
tempHlsPerson.add(hlsPerson);
self().batchUpdate(iRequest,tempHlsPerson);
Long pid = hlsPerson.getPid();
List<HlsHobby> hlsHobbyList = hlsPerson.getHlsHobbyList();
for(HlsHobby hh : hlsHobbyList){
hh.setPid(pid);
}
hlsHobbyService.batchUpdate(iRequest,hlsHobbyList);
}
}
}
......@@ -22,7 +22,8 @@ RabbitMQ 是实现 AMQP(高级消息队列协议)的消息中间件的一种
### 2.1 定义交换机
在接口管理的消息队列定义模块中,首先进行交换机的定义,界面如图:![](/assets/exchange.png)注意:
在接口管理的消息队列定义模块中,首先进行交换机的定义,界面如图:![](/assets/exchange.png)
注意:
交换机名称不可以重复定义,一个交换机可以对应多个队列。
......@@ -34,7 +35,9 @@ RabbitMQ 是实现 AMQP(高级消息队列协议)的消息中间件的一种
### 2.2 定义队列和路由键
定义完交换机后,你还需要定义你的队列和相应的匹配模式(既路由键)界面如图:![](/assets/queue.png)注意:
定义完交换机后,你还需要定义你的队列和相应的匹配模式(既路由键)界面如图:![](/assets/queue.png)
注意:
队列名称不可以重复,但是一个队列可以对应多个交换机。
......@@ -137,3 +140,6 @@ public class ConsumerDemoServiceImpl implements IRabbitMessageConsumerService {
```
###
# 工作流demo
# 工作流开发指南
整体流程
* 打开工作流模块,设计工作流流程
* 实现一个当前功能启动工作流的接口
* 在自己的业务层调用自己实现的工作流类
* 启动工作流
一、工作流开发整体思路
* 流程设计
* 实现启动接口
* 调用实现类
* 启动工作流
二、流程设计
1 新建工作流并填写对应的信息
![](/assets/wfl_demo_1.png)
![](/assets/wfl_demo_2.png)
2 编辑对应的审批节点链,可参考已实现的工作流程
*这里需要注意分类跟唯一标识这个字段,后面编写实现类的时候需要传入分类跟唯一标识。
2 保存之后点击对应工作流的第一个图标,即可编辑对应的工作流节点,下面将详细介绍一些常用的工作流属性(新建工作流的时候可参考已实现工作流)
* ID:自动生成,节点唯一标识
* 名称:当前节点中文描述
* 文档:消息机制,可在上下文中取到,如:我是${name},name为实现类里面配置的参数
* 审批方式:默认为全部通过
* 审批方式变量:当审批方式选择一定比例时,可设置变量如0.4,表示当审批人数达到这个比例后将会通过
* 审批规则:选择对应的审批人,可在审批规则中定义
* 加签:若勾选,则当前审批者可添加审批人
* 表单url:表示审批流程中可插入的页面,能让审判者读阅
* 执行监听器:执行监听器start跟end两种分别代表在该节点之前跟在该节点之后,在代理表达式里面可调用对应自己写的java类,格式如下:${endActionEventTask}
* 任务监听器:任务监听器可参考执行监听器
下图是一个完整的工作流流程设计
![](/assets/wfl_demo_3.png)
3 编写一个自己的实现类,实现IActivitiCommonService接口
二、实现启动接口
* 编写一个自己的实现类,实现IActivitiCommonService接口
![](/assets/wfl_demo_4.png)
......@@ -22,88 +42,88 @@
实现类代码如下
```java
package hls.core.wfl.service.impl;
import com.hand.hap.activiti.dto.ReProcdef;
import com.hand.hap.activiti.service.IActivitiService;
import com.hand.hap.activiti.service.IReProcdefService;
import com.hand.hap.core.IRequest;
import hls.core.prj.dto.PrjProject;
import hls.core.prj.dto.PrjProjectMeeting;
import hls.core.prj.mapper.PrjProjectMeetingMapper;
import hls.core.prj.service.PrjProjectService;
import hls.core.wfl.service.IActivitiCommonService;
import net.sf.json.JSONObject;
import org.activiti.rest.service.api.engine.variable.RestVariable;
import org.activiti.rest.service.api.runtime.process.ProcessInstanceCreateRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;import java.util.List;
import java.util.Map;
@Service
@Transactional
public class PrjActivitStartServiceImpl implements IActivitiCommonService
{
private static final String workFlowType = "PRJ_PROJECT"; @Autowired
private IActivitiService activitiService;
@Autowired
private IReProcdefService reProcdefService;
@Autowired
private PrjProjectService projectService;
@Autowired
private PrjProjectMeetingMapper meetingMapper;
@Override
public String getWorkFlowType() { return workFlowType; }
@Override
public void process(IRequest iRequest, List list, Map params)
{
ProcessInstanceCreateRequest processInstanceCreateRequest = getProcessInstanceCreateRequest((PrjProject)list.get(0),iRequest);
activitiService.startProcess(iRequest, processInstanceCreateRequest);
}
private ProcessInstanceCreateRequest getProcessInstanceCreateRequest(PrjProject prjProject, IRequest iRequest)
{
ProcessInstanceCreateRequest createRequest = new ProcessInstanceCreateRequest();
PrjProject project=projectService.selectByPrimaryKey(iRequest,prjProject); ReProcdef reProcdefs ;
reProcdefs = reProcdefService.queryReProcdef("PRJ_PROJECT_APPROVE","PRJ_PROJECT");
String id = reProcdefs.getId_();
String name = reProcdefs.getName_(); createRequest.setProcessDefinitionId(id); createRequest.setBusinessKey(prjProject.getProjectId().toString());
List<RestVariable> variables = new ArrayList<RestVariable>(); List<RestVariable> transientVariables = new ArrayList<RestVariable>();
RestVariable restVariable1 = new RestVariable(); RestVariable restVariable2 = new RestVariable();
RestVariable restVariable3 = new RestVariable();
RestVariable restVariable4 = new RestVariable();
RestVariable restVariable5 = new RestVariable();
RestVariable restVariable6 = new RestVariable();
restVariable1.setName("processDefinitionId");
restVariable1.setValue(id); variables.add(restVariable1);
restVariable2.setName("prjProject");
JSONObject jsonObject= new JSONObject().fromObject(prjProject); restVariable2.setValue(jsonObject.toString()); variables.add(restVariable2);
restVariable3.setName("iRequest"); restVariable3.setValue(iRequest);
variables.add(restVariable3);
restVariable4.setName("projectNum"); restVariable4.setValue(project.getProjectNumber()); variables.add(restVariable4); restVariable5.setName("projectName"); restVariable5.setValue(project.getProjectName()); variables.add(restVariable5); restVariable6.setName("startUserName"); restVariable6.setValue(iRequest.getEmployeeCode()); variables.add(restVariable6);
RestVariable restVariable7 = new RestVariable();
RestVariable restVariable8 = new RestVariable(); RestVariable restVariable9 = new RestVariable(); restVariable7.setName("documentCategory"); restVariable7.setValue(project.getDocumentCategory()); variables.add(restVariable7); restVariable8.setName("documentType"); restVariable8.setValue(project.getDocumentType());
variables.add(restVariable8); restVariable9.setName("documentId"); restVariable9.setValue(project.getProjectId());
variables.add(restVariable9);
RestVariable restVariable10 = new RestVariable();
restVariable10.setName("doubleFlag");
PrjProjectMeeting meeting = new PrjProjectMeeting();
meeting.setProjectId(prjProject.getProjectId());
List<PrjProjectMeeting> list = meetingMapper.select(meeting); if(list.size() >0) { restVariable10.setValue("Y"); }else{ restVariable10.setValue("N"); }
variables.add(restVariable10);
RestVariable restVariable11 = new RestVariable(); restVariable11.setName("pName");
restVariable11.setValue(name);
variables.add(restVariable11); createRequest.setVariables(variables); createRequest.setTransientVariables(transientVariables);
return createRequest;
private static final String workFlowType = "PRJ_PROJECT";
@Autowired
private IActivitiService activitiService;
@Autowired
private IReProcdefService reProcdefService;
@Autowired
private PrjProjectService projectService;
@Autowired
private PrjProjectMeetingMapper meetingMapper;
@Override
public String getWorkFlowType() { return workFlowType; }
@Override
public void process(IRequest iRequest, List list, Map params)
{
ProcessInstanceCreateRequest processInstanceCreateRequest = getProcessInstanceCreateRequest((PrjProject)list.get(0),iRequest);
activitiService.startProcess(iRequest, processInstanceCreateRequest);
}
private ProcessInstanceCreateRequest getProcessInstanceCreateRequest(PrjProject prjProject, IRequest iRequest)
{
ProcessInstanceCreateRequest createRequest = new ProcessInstanceCreateRequest();
PrjProject project=projectService.selectByPrimaryKey(iRequest,prjProject); ReProcdef reProcdefs ;
reProcdefs = reProcdefService.queryReProcdef("PRJ_PROJECT_APPROVE","PRJ_PROJECT");
String id = reProcdefs.getId_();
String name = reProcdefs.getName_(); createRequest.setProcessDefinitionId(id);
createRequest.setBusinessKey(prjProject.getProjectId().toString());
List<RestVariable> variables = new ArrayList<RestVariable>(); List<RestVariable> transientVariables = new ArrayList<RestVariable>();
RestVariable restVariable1 = new RestVariable(); RestVariable restVariable2 = new RestVariable();
RestVariable restVariable3 = new RestVariable();
RestVariable restVariable4 = new RestVariable();
RestVariable restVariable5 = new RestVariable();
RestVariable restVariable6 = new RestVariable();
restVariable1.setName("processDefinitionId");
restVariable1.setValue(id); variables.add(restVariable1);
restVariable2.setName("prjProject");
JSONObject jsonObject= new JSONObject().fromObject(prjProject); restVariable2.setValue(jsonObject.toString());
variables.add(restVariable2);
restVariable3.setName("iRequest"); restVariable3.setValue(iRequest);
variables.add(restVariable3);
restVariable4.setName("projectNum"); restVariable4.setValue(project.getProjectNumber()); variables.add(restVariable4);
restVariable5.setName("projectName"); restVariable5.setValue(project.getProjectName()); variables.add(restVariable5);
restVariable6.setName("startUserName"); restVariable6.setValue(iRequest.getEmployeeCode()); variables.add(restVariable6);
RestVariable restVariable7 = new RestVariable();
RestVariable restVariable8 = new RestVariable(); RestVariable restVariable9 = new RestVariable();
restVariable7.setName("documentCategory"); restVariable7.setValue(project.getDocumentCategory()); variables.add(restVariable7);
restVariable8.setName("documentType"); restVariable8.setValue(project.getDocumentType());
variables.add(restVariable8); restVariable9.setName("documentId"); restVariable9.setValue(project.getProjectId());
variables.add(restVariable9);
RestVariable restVariable10 = new RestVariable();
restVariable10.setName("doubleFlag");
PrjProjectMeeting meeting = new PrjProjectMeeting();
meeting.setProjectId(prjProject.getProjectId());
List<PrjProjectMeeting> list = meetingMapper.select(meeting); if(list.size() >0) { restVariable10.setValue("Y"); }else{
restVariable10.setValue("N"); }
variables.add(restVariable10);
RestVariable restVariable11 = new RestVariable(); restVariable11.setName("pName");
restVariable11.setValue(name);
variables.add(restVariable11); createRequest.setVariables(variables); createRequest.setTransientVariables(transientVariables);
return createRequest;
}}
```
4 启动工作流
* 关键参数讲解:
private static final String workFlowType = "PRJ_PROJECT";在启动工作流的时候工作流会根据这个类型找到对应的实现类,
在启动工作流的时候会调用process方法,该方法会调用getProcessInstanceCreateRequest方法,在getProcessInstanceCreateRequest方法里面
可以将自己工作流所需参数都放到里面去,可以在后面的流程中取到自己所需参数。
reProcdefs = reProcdefService.queryReProcdef("PRJ_PROJECT_APPROVE","PRJ_PROJECT");参数一为创建工作流时候的唯一标志,参数二为工作流的分类
三 调用实现类并启动工作流
```
Map<String,Object> params = new HashMap<String,Object>();
params.put("workFlowType","PRJ_PROJECT");
activitiStartService.start(iRequest,projects,params);
```
\ No newline at end of file
```
* 代码解析
params.put("workFlowType","PRJ_PROJECT");放入的为工作流实现类的类型
# 计划任务
### 1、任务周期定义
![](/assets/task_define.png)
新建一条计划任务后,可点击任务计划修改,打开计划修改页面:
![](/assets/schedule_edit.png)
计划任务可以定义五种频率,分别是:月、周、日、时、分。
* 月:可定义每几个月的第几天(可选择多个,使用逗号隔开)执行,同时可以指定执行的具体时分。
* 周:可定义每几个周的周几执行,同时可指定执行的具体时分。
* 日:可定义每几天执行一次,同时可指定执行的具体时分。
* 时:可定义每几个小时执行一次。
* 分:可定义每几分钟执行一次。
### 2、任务维护
可在任务维护主界面进行新增、修改、删除操作。
![](/assets/task_maintain.png)
新增一条任务记录之后可以对该任务进行参数配置和权限控制:
#### 2.1 任务配置
点击任务配置,打开任务配置明细弹窗,可在此处添加、删除、修改任务所需参数。 ![](/assets/task_parameter.png)
#### 2.2 权限控制
点击权限设置,打开权限控制明细弹窗,可在此处对任务权限人进行添加、删除、修改操作:
角色代码为权限人的代码,角色名称为权限人的名字,起始日期和结束日期控制该人员可对该任务操作的时间。 ![](/assets/task_authority.png)
#### 2.3 任务类的编写
想要自定义一个job,必须要继承一个抽象类AbstractJob,然后在`safeExecute()`方法中执行业务代码,示例代码如下:
```java
public class demoJob extends AbstractJob{
@Autowired
private xxxService service;//业务类
@Override
public void safeExecute(JobExecutionContext jobExecutionContext) throws Exception {
//map中可以获取上方定义的参数,key为参数名称,value为参数值
JobDataMap map = jobExecutionContext.getMergedJobDataMap();
try {
service.dosomething();
} catch (Exception e) {
if (logger.isErrorEnabled()) {
logger.error(e.getMessage(), e);
}
exception = e;
throw e;
}
if (exception != null) {
setExecutionSummary(exception.getClass().getName() + ":" + exception.getMessage());
} else {
setExecutionSummary("执行完成!" );
}
}
@Override
public boolean isRefireImmediatelyWhenException() {
//任务发生异常时候进行的动作
//false 挂起当前JOB等待处理
//true 继续执行
return false;
}
}
```
注意:
* 调用`setExecutionSummary()`方法可以在执行记录中,记录你的业务数据的记录,或者抛出的异常的具体信息。
* 在上下文中获取JobDataMap可以拿到你在任务配置中定义的参数
### 3、计划任务工作台
#### 3.1 新建任务
1.点击左上角的新建任务按钮,可以进入以下界面创建一个新的任务:
![](/assets/job_create.png)
此处任务名称必须唯一,在lov中选择对应的任务代码。
2.下拉滚动条,可以看到如下所示的界面:
![](/assets/job_create2.png)
周期性:表示一个cron任务,可以在计划名称的lov中选定自己定义的一个周期,然后计划任务可以根据任务周期定义功能中的执行频率,以及执行的开始和结束时间,进行执行。
制定时间:选择执行的时间,然后计划任务可以根据选中的执行时间,开始执行。
立即执行:可以直接出发你定义的计划任务。
以上三种方式,在定义时只能选择一种,点击保存后,任务会自动开始进行调度。
注意:
* 在集群环境中,请确保各个节点的机器的时间一致,否则会造成job的调度出现问题。
* 在集群环境中,请不要用节点外的机器操作job。
* 在开发环境中,在config.properties中调度器自动启动的状态应该默认设置为false,在正式环境中应该设置为true(设置为true,表示调度器随着服务器启动而启动):
在开发环境中,由于隐藏了调度的启动和关闭按钮,所以如果想打开调度器,必须要手动输入url:/job/scheduler/start,否则你的计划任务将不会执行。
#### 3.2 任务状态
1.任务执行时,状态不同,颜色也不同:
![](/assets/job_status.png)
状态说明:
* 正在执行,颜色显示为绿色。
* 发生异常,颜色显示为红色。
* 任务暂停,颜色显示为橙色。
* 任务完成,颜色显示为灰色。
* 任务阻塞,颜色显示为黑色。
2.想要修改任务的状态,或者删除任务,可以勾选对应的计划任务进行操作:
![](/assets/job_change_status.png)
备注:执行完成的任务无法恢复到执行状态。
### 4、执行记录
#### 4.1 查看任务的执行记录
![](/assets/job_infomation.png)
参数说明:
* 任务名称:计划任务名称
* 任务组:计划任务所属组别
* 任务状态:任务完成状态,正常执行完为FINISH,执行出错为FAILED,任务被禁止为VETOED
* 执行概要:任务执行过程中的信息,如执行结果,异常信息等(既setExecutionSummary方法中所设置的值)。
* 上次执行时间:上一次任务预计执行的时间点。
* 计划执行时间:预计完成上一次任务后,根据指定的执行间隔推算的本次任务执行的时间。
* 下次执行时间:预计执行完本次任务后,根据指定的执行间隔推算的下一次执行时间点。
* 实际执行时间:本次任务实际执行的时间点。
### 5、后台创建周期任务
由于在某些业务模块中,可能需要直接在后端业务代码中定义计划任务,那么这个时候,融租易中提供了创建计划任务的接口可以供直接调用。
#### 5.1 通过post请求直接创建周期任务
访问`"/hls/job/create"`地址,必须要为post请求类型,方法返回的值为jobId,请求体中的参数也必须为json格式,如下:
```
{
"jobCreateDto": {
"jobClassName":"default",
"jobName": "jobname",
"jobGroup": "DEFAULT",
"triggerType": "CRON"
},
"taskId": "10001",
"scheduleName": "schname",
"defineStartTime": "14000000",
"defineEndTime": "140000000",
"businessParam": {
"contractId": "1"
}
}
```
json格式说明:
* jobCreateDto:该元素中,只有job是自己定义的,其他全部按照如上所示的规范填写。
* taskId:taskId表示在任务维护中,定义的任务的ID,创建的job执行的类实际上是根据任务中定义的类,所以请确保此处填写无误。
* scheduleName:scheduleName表示任务周期中定义的周期名,任务会按照scheduleName对应的周期执行。
* defineStartTime:自定义的任务开始时间,如果有需要则填写,否则直接根据周期定义中的开始时间执行,传到后台的值必须为Long类型。
* defineEndTime:自定义的任务结束时间,如果有需要则填写,否则直接根据周期定义中的时间结束,传到后台的值必须为Long类型。
* businessParam:业务所需的参数,填写后可以在任务执行时获取到。
#### 5.2 通过service中的方法创建周期任务
# 计划任务
### 1、任务周期定义
![](/assets/task_define.png)
新建一条计划任务后,可点击任务计划修改,打开计划修改页面:
![](/assets/schedule_edit.png)
计划任务可以定义五种频率,分别是:月、周、日、时、分。
* 月:可定义每几个月的第几天(可选择多个,使用逗号隔开)执行,同时可以指定执行的具体时分。
* 周:可定义每几个周的周几执行,同时可指定执行的具体时分。
* 日:可定义每几天执行一次,同时可指定执行的具体时分。
* 时:可定义每几个小时执行一次。
* 分:可定义每几分钟执行一次。
### 2、任务维护
可在任务维护主界面进行新增、修改、删除操作。
![](/assets/task_maintain.png)
新增一条任务记录之后可以对该任务进行参数配置和权限控制:
#### 2.1 任务配置
点击任务配置,打开任务配置明细弹窗,可在此处添加、删除、修改任务所需参数。 ![](/assets/task_parameter.png)
#### 2.2 权限控制
点击权限设置,打开权限控制明细弹窗,可在此处对任务权限人进行添加、删除、修改操作:
角色代码为权限人的代码,角色名称为权限人的名字,起始日期和结束日期控制该人员可对该任务操作的时间。 ![](/assets/task_authority.png)
#### 2.3 任务类的编写
想要自定义一个job,必须要继承一个抽象类AbstractJob或者AbstractJobWithIRequest,然后在`safeExecute()`方法中执行业务代码,示例代码如下:
```java
public class demoJob extends AbstractJob{
@Autowired
private xxxService service;//业务类
@Override
public void safeExecuteWithIRequest(JobExecutionContext jobExecutionContext) throws Exception {
//map中可以获取上方定义的参数,key为参数名称,value为参数值
JobDataMap map = jobExecutionContext.getMergedJobDataMap();
try {
service.dosomething();
} catch (Exception e) {
if (logger.isErrorEnabled()) {
logger.error(e.getMessage(), e);
}
exception = e;
throw e;
}
if (exception != null) {
setExecutionSummary(exception.getClass().getName() + ":" + exception.getMessage());
} else {
setExecutionSummary("执行完成!" );
}
}
@Override
public boolean isRefireImmediatelyWhenException() {
//任务发生异常时候进行的动作
//false 挂起当前JOB等待处理
//true 继续执行
return false;
}
}
```
注意:
* 调用`setExecutionSummary()`方法可以在执行记录中,记录你的业务数据的记录,或者抛出的异常的具体信息。
* 在上下文中获取JobDataMap可以拿到你在任务配置中定义的参数
### 3、计划任务工作台
#### 3.1 新建任务
1.点击左上角的新建任务按钮,可以进入以下界面创建一个新的任务:
![](/assets/job_create.png)
此处任务名称必须唯一,在lov中选择对应的任务代码。
2.下拉滚动条,可以看到如下所示的界面:
![](/assets/job_create2.png)
周期性:表示一个cron任务,可以在计划名称的lov中选定自己定义的一个周期,然后计划任务可以根据任务周期定义功能中的执行频率,以及执行的开始和结束时间,进行执行。
制定时间:选择执行的时间,然后计划任务可以根据选中的执行时间,开始执行。
立即执行:可以直接出发你定义的计划任务。
以上三种方式,在定义时只能选择一种,点击保存后,任务会自动开始进行调度。
注意:
* 在集群环境中,请确保各个节点的机器的时间一致,否则会造成job的调度出现问题。
* 在集群环境中,请不要用节点外的机器操作job。
* 在开发环境中,在config.properties中调度器自动启动的状态应该默认设置为false,在正式环境中应该设置为true(设置为true,表示调度器随着服务器启动而启动):
在开发环境中,由于隐藏了调度的启动和关闭按钮,所以如果想打开调度器,必须要手动输入url:/job/scheduler/start,否则你的计划任务将不会执行。
#### 3.2 任务状态
1.任务执行时,状态不同,颜色也不同:
![](/assets/job_status.png)
状态说明:
* 正在执行,颜色显示为绿色。
* 发生异常,颜色显示为红色。
* 任务暂停,颜色显示为橙色。
* 任务完成,颜色显示为灰色。
* 任务阻塞,颜色显示为黑色。
2.想要修改任务的状态,或者删除任务,可以勾选对应的计划任务进行操作:
![](/assets/job_change_status.png)
备注:执行完成的任务无法恢复到执行状态。
### 4、执行记录
#### 4.1 查看任务的执行记录
![](/assets/job_infomation.png)
参数说明:
* 任务名称:计划任务名称
* 任务组:计划任务所属组别
* 任务状态:任务完成状态,正常执行完为FINISH,执行出错为FAILED,任务被禁止为VETOED
* 执行概要:任务执行过程中的信息,如执行结果,异常信息等(既setExecutionSummary方法中所设置的值)。
* 上次执行时间:上一次任务预计执行的时间点。
* 计划执行时间:预计完成上一次任务后,根据指定的执行间隔推算的本次任务执行的时间。
* 下次执行时间:预计执行完本次任务后,根据指定的执行间隔推算的下一次执行时间点。
* 实际执行时间:本次任务实际执行的时间点。
### 5、后台创建周期任务
由于在某些业务模块中,可能需要直接在后端业务代码中定义计划任务,那么这个时候,融租易中提供了创建计划任务的接口可以供直接调用。
#### 5.1 通过post请求直接创建周期任务
访问`"/hls/job/create"`地址,必须要为post请求类型,方法返回的值为jobId,请求体中的参数也必须为json格式,如下:
```
{
"jobCreateDto": {
"jobClassName":"default",
"jobName": "jobname",
"jobGroup": "DEFAULT",
"triggerType": "CRON"
},
"taskId": "10001",
"scheduleName": "schname",
"defineStartTime": "14000000",
"defineEndTime": "140000000",
"businessParam": {
"contractId": "1"
}
}
```
json格式说明:
* jobCreateDto:该元素中,只有job是自己定义的,其他全部按照如上所示的规范填写。
* taskId:taskId表示在任务维护中,定义的任务的ID,创建的job执行的类实际上是根据任务中定义的类,所以请确保此处填写无误。
* scheduleName:scheduleName表示任务周期中定义的周期名,任务会按照scheduleName对应的周期执行。
* defineStartTime:自定义的任务开始时间,如果有需要则填写,否则直接根据周期定义中的开始时间执行,传到后台的值必须为Long类型。
* defineEndTime:自定义的任务结束时间,如果有需要则填写,否则直接根据周期定义中的时间结束,传到后台的值必须为Long类型。
* businessParam:业务所需的参数,填写后可以在任务执行时获取到。
#### 5.2 通过service中的方法创建周期任务
注入`HlsJobCreateService`,调用的方法为`createHlsJob(HlsJobDto hlsJobDto, IRequest requestCtx)`,其中HlsJobDto参数可以与上述的json相互转换,实现的效果也是一致的。
\ No newline at end of file
# 融租易开发手册
* [GitBook使用](/gitbook.md)
---
* I. 开发环境准备
* [1.1 Git 使用](/git-guide.md "git指令")
* [1.2 Maven 使用](/maven.md "maven使用")
* [1.3 开发环境搭建](/project-create.md)
* [1.4 更新项目的HEL依赖版本](/project-update.md)
* [1.5 Liquibase](/liquibase-use.md)
* II. 项目开发规范
* [2.1 项目开发规范](/codeStyle.md#backEndDev)
* [2.2 编码规范](/codeStyle.md#backEndName)
* 2.3 Checkstyle
* III. 后端开发
* [3.1 后端开发说明\(1.0\)](/后端开发/dev-flow.md)
* [3.2 用户安全策略](/后端开发/user-security-strategy.md)
* [3.3 审计](/后端开发/audit.md)
* [3.4 锁机制](/后端开发/lock.md)
* [3.5 日志管理](/后端开发/elk.md)
* [3.6 代码生成器](/后端开发/code-generator.md)
* [3.7 跨域访问](/后端开发/3.24-cors.md)
* [3.8 消息机制](/后端开发/消息机制.md)
* IV. 前端JavaScript开发
* [4.1 前端开发说明 \(1.0\)](/front-kendoui.md)
* [4.2 字段级通用方法](/common-field-javascript.md)
* [4.3 窗口级通用方法](/common-window-javascript.md)
* [4.4 锁屏和解屏通用方法](/common-mask-javascript.md)
* V. 前端UI开发
* [5.1 hlsCombobox\(下拉框\)](/前端组件/hlsCombobox.md)
* [5.2 hlsDataSource\(数据源\)](/前端组件/hlsDataSource.md)
* [5.3 hlsMaskedTextBox\(文本框\)](/前端组件/hlsMaskedTextBox.md)
* [5.4 hlsPage\(分页控件\)](/前端组件/hlsPage.md)
* [5.5 hlsTextArea\(文本域\)](/前端组件/hlsTextArea.md)
* [5.6 hlsTlEdit\(多语言\)](/前端组件/hlsTlEdit.md)
* [5.7 hlsDatePicker\(日期选择框\)](/前端组件/hlsDatePicker.md)
* [5.8 hlsDateTimePicker\(时间选择框\)](/前端组件/hlsDateTimePicker.md)
* [5.9 hlsLov\(lov选择框\)](/前端组件/hlsLov.md)
* [5.10 hlsToolBar\(底部菜单栏\)](/前端组件/hlsToolBar.md)
* [5.11 TabStrip\(sheet页切换卡\)](/前端组件/tabStrip.md)
* [5.12 hlsForm\(表单\)](/前端组件/hlsForm.md)
* [5.13 hlsCombobox\(下拉框\)](/前端组件/hlsCombobox.md)
* [5.14 hlsCheckBox\(复选框\)](/前端组件/hlsCheckBox.md)
* [5.15 hlsGrid\(表格\)](/前端组件/hlsGrid.md)
* [5.16 dataSource\(数据源\)](/前端组件/dataSource.md)
* [5.17 hlsGridBox\(表格\)](/前端组件/hlsGridBox.md)
* [5.18 hlsNumericTextBox\(数字框\)](/前端组件/hlsNumericTextBox.md)
* [5.19 hlsNavigationBar\(导航栏\)](/前端组件/hlsNavigationBar.md)
* VI. 框架功能描述
* [6.1 计划任务](/框架功能描述/计划任务.md)
* [6.2 RabbitMq消息队列](/后端开发/RabbitMq消息队列.md)
* [6.3 应用服务部署\(tomcat/weblogic\)](/框架功能描述/deployment.md)
* [6.4 合同文本生成](/框架功能描述/docx4j.md)
* [6.5 Excel导入导出](/框架功能描述/jad.md)
* [6.6 redis安装和部署](/后端开发/redis.md)
* [6.7 工作流功能说明](/后端开发/activiti-helper.md)
* [6.8 工作流开发指南](/后端开发/activiti.md)
* [6.9 工作流demo](/后端开发/activiti_demo.md)
* [6.10 流程设计](/后端开发/activiti_editor_helper.md)
# 融租易开发手册
* [GitBook使用](/gitbook.md)
---
* I. 开发环境准备
* [1.1 Git 使用](/git-guide.md "git指令")
* [1.2 Maven 使用](/maven.md "maven使用")
* [1.3 开发环境搭建](/project-create.md)
* [1.4 更新项目的HEL依赖版本](/project-update.md)
* [1.5 Liquibase](/liquibase-use.md)
* II. 项目开发规范
* [2.1 项目开发规范](/codeStyle.md#backEndDev)
* [2.2 编码规范](/codeStyle.md#backEndName)
* 2.3 Checkstyle
* III. 后端开发
* [3.1 后端开发说明\(1.0\)](/后端开发/dev-flow.md)
* [3.2 用户安全策略](/后端开发/user-security-strategy.md)
* [3.3 审计](/后端开发/audit.md)
* [3.4 锁机制](/后端开发/lock.md)
* [3.5 日志管理](/后端开发/elk.md)
* [3.6 代码生成器](/后端开发/code-generator.md)
* [3.7 跨域访问](/后端开发/3.24-cors.md)
* [3.8 消息机制](/后端开发/消息机制.md)
* IV. 前端JavaScript开发
* [4.1 前端开发说明 \(1.0\)](/front-kendoui.md)
* [4.2 字段级通用方法](/common-field-javascript.md)
* [4.3 窗口级通用方法](/common-window-javascript.md)
* [4.4 锁屏和解屏通用方法](/common-mask-javascript.md)
* [4.5 头行保存](/前端组件/头行保存.md)
* V. 前端UI开发
* [5.1 hlsCombobox\(下拉框\)](/前端组件/hlsCombobox.md)
* [5.2 hlsDataSource\(数据源\)](/前端组件/hlsDataSource.md)
* [5.3 hlsMaskedTextBox\(文本框\)](/前端组件/hlsMaskedTextBox.md)
* [5.4 hlsPage\(分页控件\)](/前端组件/hlsPage.md)
* [5.5 hlsTextArea\(文本域\)](/前端组件/hlsTextArea.md)
* [5.6 hlsTlEdit\(多语言\)](/前端组件/hlsTlEdit.md)
* [5.7 hlsDatePicker\(日期选择框\)](/前端组件/hlsDatePicker.md)
* [5.8 hlsDateTimePicker\(时间选择框\)](/前端组件/hlsDateTimePicker.md)
* [5.9 hlsLov\(lov选择框\)](/前端组件/hlsLov.md)
* [5.10 hlsToolBar\(底部菜单栏\)](/前端组件/hlsToolBar.md)
* [5.11 TabStrip\(sheet页切换卡\)](/前端组件/tabStrip.md)
* [5.12 hlsForm\(表单\)](/前端组件/hlsForm.md)
* [5.13 hlsCombobox\(下拉框\)](/前端组件/hlsCombobox.md)
* [5.14 hlsCheckBox\(复选框\)](/前端组件/hlsCheckBox.md)
* [5.15 hlsGrid\(表格\)](/前端组件/hlsGrid.md)
* [5.16 dataSource\(数据源\)](/前端组件/dataSource.md)
* [5.17 hlsGridBox\(表格\)](/前端组件/hlsGridBox.md)
* [5.18 hlsNumericTextBox\(数字框\)](/前端组件/hlsNumericTextBox.md)
* [5.19 hlsNavigationBar\(导航栏\)](/前端组件/hlsNavigationBar.md)
* [5.20 hlsChart\(图表\)](/前端组件/hlsChart.md)
* VI. 框架功能描述
* [6.1 计划任务](/框架功能描述/计划任务.md)
* [6.2 RabbitMq消息队列](/后端开发/RabbitMq消息队列.md)
* [6.3 应用服务部署\(tomcat/weblogic\)](/框架功能描述/deployment.md)
* [6.4 合同文本生成](/框架功能描述/docx4j.md)
* [6.5 Excel导入导出](/框架功能描述/jad.md)
* [6.6 redis安装和部署](/后端开发/redis.md)
* [6.9 工作流开发指南](/后端开发/activiti_demo.md)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment