Commit c8ca7352 authored by Jefferyne's avatar Jefferyne

Track 52 files into repository.

- modified .gitignore
- untracked assets/cors-login.png
- untracked assets/cors-login1.png
- untracked assets/cors-quer1.png
- untracked assets/cors-query.png
- untracked assets/cors-web.png
- untracked assets/docxGen.png
- untracked assets/docxGenEntry.png
- untracked assets/excelImport.png
- untracked assets/generator2.png
- untracked assets/generator3.png
- untracked assets/generator4.png
- untracked assets/generator5.png
- untracked assets/generator6.png
- untracked assets/gernerator7.png
- untracked assets/gnerator1.png
- untracked assets/paramDefine.png
- untracked assets/paramSet.png
- untracked assets/tempDefine.png
- untracked assets/tempUpload.png
- untracked common-field-javascript.md
- untracked common-mask-javascript.md
- untracked common-window-javascript.md
- untracked docx4j.md
- untracked front-kendoui.md
- untracked jad.md
- untracked mutillanguage.md
- modified project-create.md
- modified 前端组件/box.md
- modified 前端组件/HlsCombobox.md
- removed 前端组件/hlsDataSource
- modified 前端组件/HlsDatePicker.md
- modified 前端组件/hlsMaskedTextBox.md
- modified 前端组件/hlsTextArea.md
- modified 前端组件/hlsTlEdit.md
- untracked 后端开发/3.24-cors.md
- modified 后端开发/activiti-helper.md
- modified 后端开发/activiti.md
- modified 后端开发/activiti_demo.md
- modified 后端开发/activiti_editor_helper.md
- untracked 后端开发/audit.md
- untracked 后端开发/code-generator.md
- modified 后端开发/deployment.md
- untracked 后端开发/elk.md
- untracked 后端开发/lock.md
- untracked 后端开发/RabbitMq消息队列.md
- untracked 后端开发/redis.md
- untracked 后端开发/user-security-strategy.md
- removed 后端开发/消息机制.md
- untracked 框架功能描述/deployment.md
- modified 框架功能描述/计划任务.md
- modified 融租易开发手册.md

Auto commit by GitBook Editor
parent 6e9e80d4
###字段级通用方法
#### 设置字段必填属性
>Hel.setRequired(id,flag);
第一个参数id为字段的id,第二个参数flag为true时将该字段设为必填,为false时将该字段设为非必填。
```html
<h:hlsMaskedTextBox id="maskedTextBox"/>
<script><![CDATA[
Hel.setRequired('maskedTextBox',true);
]]></script>
```
#### 设置字段只读属性
>Hel.setReadonly(id,flag);
第一个参数id为字段的id,第二个参数flag为true时将该字段设为只读,为false时将该字段设为可输入。
```html
<h:hlsMaskedTextBox id="maskedTextBox"/>
<script><![CDATA[
Hel.setReadonly('maskedTextBox',true);
]]></script>
```
### 锁屏和解屏
#### 锁屏
>Hel.mask(opts);
其中参数为:
属性名 | 类型 | 含义
-------- | ----- | -----
id| String(选填) | 当前窗口的id,缺省值为body
```
Hel.mask(); //缺省值为body
Hel.mask({
id:'',//传入相应的参数
});
```
#### 解屏
```
Hel.unmask();
```
### 窗口级通用方法
#### 打开功能窗口
>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可以没有,表示使用配置的宽度
## 合同文本生成
合同文本生成允许用户定义不同内容的合同模板,通过各项数据配置,对其中的文字、表格、水印以及批注等内容进行修改。
1. 进入合同模板定义功能
先在表格中定义好模板的代码、名称、用途、类型以及说明等信息进行保存。
| 字段名 | 说明 |
| :--: | :--: |
| 模板代码 | 模板的唯一标示,不可重复 |
| 模板名称 | 用于标识一个文件模板 |
| 模板用途 | 暂时只有*合同文本*一种用途 |
| 模板类型 | |
| 说明 | 文件模板的说明 |
| 参数集 | 参与该模板生成时,所需要使用到的参数 |
![合同模板定义功能](/assets/tempDefine.png)
2. 上传合同模板
通过合同模板定义功能表格中的**模板上传**功能,将预先设计好的模板上传到服务器。**该功能只支持2007版本以上的,docx后缀的word文档**
![合同模板上传](/assets/tempUpload.png)
3. 定义合同模板参数
通过合同模板定义功能表格中**参数集**设置,将需要与合同模板关联的参数进行设置。
![合同模板参数集设置](/assets/paramSet.png)
- 若是有在已有的参数列表中没有需要的使用参数设置,则可以在参数集配置中手动添加
- 参数定义中的字段说明
> | 字段名 | 说明 |
> | :--: | :--: |
> | 书签代码 | 书签的唯一标识,需要和模板文件中定义的书签名称一致 |
> | 书签描述 | 对该书签的文字描述 |
> | 书签类型 | 书签类型目前有:文本、表单、表单域、横向表单四种 <ul><li>文本类型对应的是替换后为文档中普通文本 </li><li>表单类型对应着word文档中一个表格的数据,表格的每一列的配置信息都是在列配置中完成</li><li>表单域对应word文档中一个文本域\窗体域,最终的替换结果会显示在文本域的位置</li><li>横向表单对应的是替换的文档中,书签所对应的是文档中一整块内容,内容中可能包含了多个书签,每个书签的名称在列配置中进行配置,最后根据结果生成多块结构类似的文本</ul> |
> | 数据源 | 选择该参数的值来源,配置该项之后可不用配置SQL |
> | SQL | 从数据库进行数据查询使用的SQL语句 |
> | 列配置 | 只有在书签类型为表单或横向表单时,才可以进行配置 |
> | 字体型号 | 生成的文本使用的字体类型 |
> | 字体大小 | 生成的文本使用的字体大小 |
> | 下划线 | 生成的文本使用的下划线类型:无、单下划线、双下划线 |
> | 是否加粗 | 生成的文本是否需要加粗 |
![合同模板参数定义](/assets/paramDefine.png)
4. 去生成最终的合同文本
生成合同文本时在合同状态为**新建**时才可以生成合同文本
![合同文本生成入口](/assets/docxGenEntry.png)
![合同文本生成](/assets/docxGen.png)
\ No newline at end of file
# 前端开发手册 \(1.0\)
#### 开发说明
前端界面采用kendoUI开源框架,相同的显示效果可以采用多种代码方式来实现,为了规范项目组成员的代码样式,统一编码风格,避免以后维护的工作量,融租易采用封装标签的开发方式,当然如果在项目开发过程中遇到比较复杂的页面通过标签的方式实现不了的功能,需要跟产品组报备,然后采取源生的开发方式。
## Excel文件导入
使用poi解析xml方式进行导入,只支持单表导入。
数据库批量导入默认batch为100.
支持多sheet导入,sheet1从第三行开始读取数据,其他sheet页从第一行导入数据。
使用方法:
1. Excel文件上传
```javascript
$("#files").kendoUpload({
async: {
saveUrl: "${base.contextPath}/hls/excel/import?${_csrf.parameterName}=${_csrf.token}&templateCode=HLS_FIN_STATEMENT_LN",
removeUrl: "remove"
},
showFileList: false,
upload: onUpload,
success: onSuccess
});
```
| 参数名 | 描述 |
| :--: | :--: |
| _csrf.token | 防跨域token |
| templateCode | 作为模块标识,会出现先在fnd_interface_header中,供后续业务逻辑进行处理 |
2. 处理数据
经过第一步的文件上传,后台会在fnd_interface_header表中生成一条数据,其中包含了传递的templateCode参数作为code,并且,在fnd_interface_lines表中按照顺序,将Excel文件中的每一行数据保存为一条数据,数据的第一列保存在attributes_1上,依次类推。
![ExcelImport](/assets/excelImport.png)
## Excel文件批量导出
本系统支持Excel文件导出排队处理,支持超大数据量,能实时查询文件生成情况,支持取消导出。
#### 前端使用方法
调用js方法
```javascript
Hel.exportExcel=function(opts){
var contextPath =opts.contextPath,
id=opts.id,
view_model=opts.viewModel,
viewModelData=opts.viewModelData,
controller_name = opts.controller,
fileName = opts.fileName,
temp_div_id=opts.tempDivId,
dataSourceId = opts.dataSourceId,
_csrf_token = opts._csrf_token;
```
| 参数名 | 描述 |
| :--: | :--: |
| contextPath | 项目的url路径 |
| id | 页面上grid的id |
| view_model | grid绑定的model数据模型 |
| viewModelData | model模型中的数据 |
| controller_name | 后端控制器名称 |
| fileName | excel文件名 |
| temp_div_id | 临时div的id |
| dataSourceId | 数据源id |
| _csrf_token | 防跨域的token |
#### 后端使用方法
1. 在代码中注入Excel导出Service
```java
@AutoWired
private ExcelExportServiceImpl excelService;
```
2. 在自己的controller中调用方法
```java
excelService.saveExportInfo(sqlId,iRequest,config,rowMaxNumber);
```
| 参数名 | 类型 | 描述 |
| :--: | :--: | :--: |
| sqlId | String | mybatis对应的数据库查询语句的ID |
| iRequest | IRequest | 带有上下文信息的reuqest对象 |
| config | ExportConfig | 包含Excel各列信息的对象,由前台传递json对象转换而来 |
| rowMaxNumber | int | 生成Excel的最大行数,可使用重载方法,不包含次参数默认为1,000,000 |
3. 运行Excel导出程序(获取该程序,请联系部门相关负责人)
```shell
java -jar hel-batch-parent.jar &
```
4. Excel导出情况查询
用户若是为管理员身份,则查询全部人的导出情况,否则只显示当前用户的导出数据
```java
excelService.queryExportInfo(status, iRequest);
```
| 参数名 | 类型 | 描述 |
| :--: | :--: | :--: |
| status | String | 指定Excel导出的状态,该参数可为空查询全部状态数据<br><ll><li>new->等待</li><li>generating->文件导出中</li><li>finished->导出完成</li><li>failed-> 导出失败</li></ll> |
| iRequest | IRequest | 带有上下文信息的reuqest对象 |
5. 下载已完成的Excel文件
```java
excel.downloadExcel(filePath, fileName, request, response);
```
| 参数名 | 类型 | 描述 |
| :--: | :--: | :--: |
| filePath | String | 需要下载的文件的路径 |
| fileName | String | 想要保存的文件的名称 |
| request | HttpServletRequest | 用户的请求对象 |
| response | HttpServletResponse | 用户的响应对象 |
**下载前,需要检查config.properties文件中的export.offerUrl配置项是否配置正确,且为hel-batch-parent.jar提供的文件下载url**
\ No newline at end of file
#界面多语言实现
界面中的多语言在数据库中统一存放在sys_prompts表中,系统启动时加载进redis缓存。界面中实现多语言是通过freemarker的标签以及对应的多语言code来实现。
例如:“确定”的多语言code是“sys.hand.btn.ok”在界面中的写法:
```html
<@spring.message "sys.hand.btn.ok"/>
```
# 新开项目
本章节将引导您从 零 开始,创建一个可以运行的 Demo 工程。此工程基于HEL融租易标准版,包含一个 demo 实例。
本章节将引导您从零开始,创建一个可以运行的 Demo 工程。此工程基于HEL融租易标准版,包含一个 demo 实例。
## 后端项目
### 确定项目信息
1. groupId 本项目的代号,比如融租易项目,代号为 hel
2. artifactId 本项目的顶层目录名称,使用项目代号(第一个字母大写)
+ Parent,如 HelParent
2. artifactId 本项目的顶层目录名称,使用项目代号(第一个字母大写) +Parent,如 HelParent
3. package 包名称,使用项目代号 + core ,如 Hel.core
4. archetypeVersion 是指模板项目的版本,可以使用以下版本号
> 1.0-RELEASE
......@@ -101,8 +100,9 @@ mvn clean install -Dmaven.test.skip=true
- SqlServer
- `mvn process-resources -D skipLiquibaseRun=false -Ddb.user=hel_dev -Ddb.password=hel_dev-D db.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver -D db.url="jdbc:sqlserver://127.0.0.1:1433; DatabaseName=hel"`
- Oracle
- `mvn process-resources -D skipLiquibaseRun=false -D db.driver=oracle.jdbc.driver.OracleDriver -D db.url=jdbc:oracle:thin:@127.0.0.1:1521:hel -Ddb.user=hel_dev -Ddb.password=hel_dev
- 以上命令中,需要按实际情况修改 url,user,password
- `mvn process-resources -D skipLiquibaseRun=false -D db.driver=oracle.jdbc.driver.OracleDriver -D db.url=jdbc:oracle:thin:@127.0.0.1:1521:hel -Ddb.user=hel_dev -Ddb.password=hel_dev`
- 以上命令中,需要按实际情况修改 url,user,password
### 测试
1. 在 HelParent 工程目录下执行命令(IntelliJ IDEA 用户可以跳过此步骤)
......
# hlsCombobox标签
# hlsCombobox标签(下拉框)
ComboBox下拉列表组件,通常数据源以code - meaning形式出现,用户操作的是meaning,实际保存的是code。
......@@ -20,52 +20,24 @@ ComboBox下拉列表组件,通常数据源以code - meaning形式出现,用
```
### **主要属性**
属性名 | 类型
-------- | ---
id | String
promptColspan | String
promptClassName | String
promptImage | String
prompt | String
colspan | String
hlsClassName | String
animation | Boolean
autoBind | Boolean
autoWidth | Boolean
cascadeFrom| String
cascadeFromField | String
clearButton| Boolean
dataSource | DataSource
dataTextField | String
dataValueField| String
delay | Number
enable | Boolean
enforceMinLength| Boolean
filter | String
fixedGroupTemplate| String \| Function
footerTemplate| String \| Function
groupTemplate| String \| Function
height| Number
highlightFirst| Boolean
ignoreCase| Boolean
index| Number
minLength| Number
noDataTemplate| String \| Function
placeholder | String
suggest| Boolean
headerTemplate| String \| Function
template| String \| Function
text| String
value| String
valuePrimitive| Boolean
virtual| Boolean
change| Function
close| Function
dataBound | Function
filtering| Function
open| Function
select| Function
cascade| Function
属性名 | 类型 | 说明 |
--- | --- | --- |
id | String | id |
promptColspan | String | 提示语句需要占几列 |
promptClassName | String | 提示语句类名,默认不填 |
promptImage | String | 提示前面的文字图形,默认不填 |
prompt | String | 提示信息 |
colspan | String | 所占列数 |
hlsClassName | String | 类名,默认不填 |
dataSource | DataSource | 数据源 |
dataTextField | String | 返回的显示描述字段 |
dataValueField| String | 绑定的英文字段 |
enable | Boolean | 是否可编辑,true为可编辑,false不可编辑 |
placeholder | String | 占位符 |
template| Function| 渲染函数 |
change| Function | 数据变化时触发的函数 |
> 属性用法请参考KendoUI文档 [http://docs.telerik.com/kendo-ui/api/javascript/ui/combobox](http://docs.telerik.com/kendo-ui/api/javascript/ui/combobox)
......
# hlsDatePicker标签
日期选择器(不包含时分秒)
xml配置
```
```xml
<!--基本用法-->
<h:hlsDatePicker id="hlsDatePickerId" bind="enabled:isEnabled,value:data.value" placeholder="hlsDatePicker"/>
```
### **主要属性**
属性名 | 类型
-------- | -----
promptColspan | Integer
promptClassName | String
promptImage | String
prompt | String
colspan | Integer
hlsClassName | String
animation | Boolean
ARIATemplate| String
culture | String
depth| String
footer| String & Function
format| String
max| String
min| String
start| String
value | String
name | String
bind | Function
required | Boolean
change | Function
close| Function
open | Function
placeholder | String
interval |Integer
timeFormat |String
属性名 | 类型 | 说明 |
-------- | -----| --- |
promptColspan | Integer | 描述字段所占列数 |
promptClassName | String| 描述的样式名称 |
prompt | String| 描述 |
colspan | Integer | datePicker所占列数 |
hlsClassName | String | 样式名称 |
animation | Boolean | 动画 |
format| String | 格式化 |
max| String | 最大时间 |
min| String | 最小时间 |
value | String | 值 |
name | String | name属性 |
bind | Function | 绑定数据 |
required | Boolean | 必输 |
change | Function | chang事件 |
placeholder | String | 占位符 |
timeFormat |String| 时间格式化 |
> **提示:** 属性用法请参考kendoui API文档 http://docs.telerik.com/kendo-ui/api/javascript/ui/datetimepicker
......@@ -95,3 +85,4 @@ prompt:为控件添加一个label,该属性一般和<h:hlsForm>、<h:hlsHBox>一
......@@ -12,6 +12,7 @@ winId | String(必填) | html元素标签的id
functionCode | String(必填) | 抽屉的唯一标识,用以确定该抽屉的相关信息
params | Object | 需传递的参数,将自动拼到url上
closeFunction | function | 关闭抽屉调用的方法
width | Number | 自定义宽度
```javascript
......@@ -26,7 +27,8 @@ Hel.openBox({
contractId:1327,
conContractCashflowId:4321
},
closeFunction:test
closeFunction:test,
width:900
});
```
......@@ -34,3 +36,4 @@ Hel.openBox({
> - winId和functionCode必须有字符串类型的值
> - params可以没有,表示不拼接条件;
> - closeFunction可以没有,表示关闭抽屉不进行操作
> - width可以没有,表示使用配置的宽度
......@@ -15,20 +15,17 @@
>
> * 属性用法请参考kendoui API文档的maskedTextBox:[http:\/\/docs.telerik.com\/kendo-ui\/api\/javascript\/ui\/maskedtextbox](http://docs.telerik.com/kendo-ui/api/javascript/ui/maskedtextbox)
| 属性名 | 类型 |
| --- | --- |
| clearPromptChar | Boolean |
| culture | String |
| mask | String |
| promptChar | String |
| unmaskOnPost | Boolean |
| value | String |
| change | Function |
| caseLetter | String |
| clearButton | Boolean |
| placeholder | String |
| bind | Function |
| required | Boolean |
| 属性名 | 类型 | 说明 |
| --- | --- | --- |
| id | String | 唯一英文标识 |
| promptColspan | number | 该数字将会与col-sm-?进行拼接,替代问号,生成对应bootstrap的css样式,渲染描述的样式 |
| promptClassName | String | 描述的样式名称,会将对应的样式添加到描述中 |
| promptImage | String | 描述前面的一个文本图像,在设置为必填的时候会出现一个红色的* |
| prompt | String | 中文描述 || colspan| number | 该数字会与col-sm-?进行拼接,替代问号,生成对应bootStrap的css样式,渲染文本框的样式 |
| hlsClassName | String | 标签的样式名称 |
| placeholder | String | 占位符 |
| bind | expressions | 绑定数据 |
用法示例:
......
# hlsTextArea
# hlsTextArea(文本域)
文本框
......@@ -14,3 +14,10 @@
| 属性 | 类型 | 说明 |
| -------- | -------- | -------- |
| id | String | 唯一英文标识 |
| promptColspan | number | 该数字将会与col-sm-?进行拼接,替代问号,生成对应bootstrap的css样式,渲染文本域中描述的样式 |
| promptClassName | String | 描述的样式名称,会将对应的样式添加到描述中 |
| promptImage | String | 描述前面的一个文本图像,在设置为必填的时候会出现一个红色的* |
| prompt | String | 文本域前面的中文描述 |
| colspan| number | 该数字会与col-sm-?进行拼接,替代问号,生成对应bootStrap的css样式,渲染文本框的样式 |
| hlsClassName | String | 包裹文本框的div的样式名称 |
\ No newline at end of file
## TlEdit
## hlsTlEdit
多语言编辑
......@@ -11,20 +11,23 @@
#### **一般属性**
| 属性名 | 类型 |
| --- | --- |
| idField | String |
| field | String |
| dto | String |
| model | Function |
| open | Function |
| close | Function |
| placeholder | String |
| bind | Function |
| 属性名 | 类型 | 说明 |
| --- | --- | --- |
| id | String | 唯一英文标识 |
| promptColspan | number | 该数字将会与col-sm-?进行拼接,替代问号,生成对应bootstrap的css样式,渲染描述的样式 |
| promptClassName | String | 描述的样式名称,会将对应的样式添加到描述中 |
| promptImage | String | 描述前面的一个文本图像,在设置为必填的时候会出现一个红色的* |
| prompt | String | 中文描述 |
| colspan| number | 该数字会与col-sm-?进行拼接,替代问号,生成对应bootStrap的css样式,渲染文本框的样式 |
| hlsClassName | String | 标签的样式名称 |
| placeholder | String | 占位符 |
| bind | expressions | 绑定数据 |
用法示例:
```javascript
```xml
<h:hlsTlEdit id="tl" placeholder="多语言" bind="value:data.name" idField="id" field="name" dto="com.hand.hap.function.dto.Resource" model="viewModel.data">
</h:hlsTlEdit>
```
......
# 跨域访问(CORS)
## 简介:
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
## 使用说明:
#### 1.修改web.xml文件:
添加Filter:
![](/assets/cors-web.png)
各参数含义:
allowedMappings: 允许跨域资源(必填)
allowedHeader:\(允许的头部参数)
allowedOrigin\(允许的请求源)
allowedMethod\(允许的请求方法\)
allowedCredentials\(是否允许携带证书)
MaxAge\(最大时长)
#### 2.发送跨域请求:
2.1 跨域登录,观察http请求response
![](/assets/cors-login.png)
2.2 登录成功所返回的信息:sessionId\(用于用户登录验证) csrf\_token(用于csrf验证)
![](/assets/cors-login1.png)
2.3 将sessionId\(Authorization\) csrf\_\_token\(X-CSRF-\_TOKEN\)添加进requestHeader中进行后续访问
![](/assets/cors-query.png)
2.4 得到返回信息
![](/assets/cors-quer1.png)
审计
---
融租易支持在代码级别记录用户对指定表的操作记录.
操作包括 : 插入, 更新, 删除.
## 1. 代码准备
再代码层面, 有两个注解 `AuditEnabled`,`AuditEntry`
#### 1.1 AuditEnabled
这个注解加在 DTO 类上, 表示这个 DTO 代表的 表需要开启审计功能.
```java
@Table("SYS_USER")
@AuditEnabled
public class User {
}
```
#### 1.2 AuditEntry
这个注解加在 `Service 接口的方法`上, 表示, 再这个方法的执行周期内开启审计功能.
> 这个方法内部可能会对多个表进行操作, 也可能调用其他的方法 f1, f1 在去操作其他的某个表.
这些调用涉及到的审计操作, 全部共享一个审计的 session (auditSessionId相同).
```java
public interface UserService {
@AuditEntry
User updateUser(User user);
}
```
## 2. 表结构
所有需要开启审计功能的表, 需要有一个与之相对应的 `审计表`.
命名规则 : `基表名`_a
可以在 `AuditEnabled` 注解中通过参数 `auditTable` 来指定.
>这个规则可以 实现接口 `IAuditTableNameProvider` 来自定义.
实现类需要定义为 spring bean
审计表字段`包含所有字段`, 但不包含`基表的唯一索引, 主键约束`
另外必须包括审计专用字段:
* `audit_id` (bigint) 自增长主键
* `audit_transaction_type` (varchar (10)) 审计操作(insert,update,delete)
* `audit_timestamp` (datetime) 审计时间
* `audit_session_id` (varchar(64)) 审计 session id
## 3 基本原理
`AuditInterceptor` 会拦截所有的 Mybatis 通过 dto 执行的操作,
根据当前有没有 `audit session` , 以及 dto 上的 AuditEnabled 注解 来决定是不是要执行 审计操作.
如果需要执行, 则动态生成 SQL 语句, 完成对新记录的`备份` 操作.
`插入`,`更新` 执行的操作是 先操作, 后记录.
`删除` 执行的操作是 先记录, 后操作.
也就是说, 审计表中插入的都是`最新的快照`.
> 基于这个原理的审计, 只能做到行级的记录, 无法具体到字段级.
但是结合一定的比较手段, 可以知道, 某次修改, 到底修改了哪些字段.
另外, 由于 audit session 的存在, 我们大概也可以知道,某次提交,同时修改了哪些数据.
当然操作的记录如何展示出来, 是需要另外开发页面的.
\ No newline at end of file
# 代码生成器
# 简介:
本功能可根据数据表生成相关的dto,mapper impl,service,controller与html,包含相关的增删改查功能。
**网页入口**:http:\/\/localhost:8080\/hel\/generator\/generator.html
## 使用说明:
**主页面:**
![](/assets/gnerator1.png)
**项目路径**:指向本机hap。
**包父路径:**指向hap的包路径。
**包路径:**为所要生成的包名。
**选择表:**选中所要维护的表。
**文件名:** 将自动根据表名生成对应名称(修改dto可选择是否根据dto修改其余文件,也可单独修改其余文件)( 文件创建之前会判断项目中是否有同名文件 ) 。
**是否创建:**勾选创建文件。
**是否覆盖:**勾选则可以覆盖同路径下同名文件。
**选择ftl模板:**可根据选择的ftl模板生成对应的html页面。
## 生成示例:
**1:相关文件**
![](/assets/generator2.png)
2:相关的dto
![](/assets/generator4.png)
**3:相关controller**(包含增删改查)
![](/assets/generator5.png)
**4:相关mapper**(包含基础resultMap)
![](/assets/generator6.png)
**5:生成基础的增删改查功能的html页面**
![](/assets/generator3.png)
**6:service文件** (mapper类似)
![](/assets/gernerator7.png)
......@@ -86,3 +86,5 @@ weblogic选择要部署的war包,若出现_wl_cls_gen.jar!这样的日志异
上述 3 点在部署的时候请留意。
# 日志管理 ELK(ElasticSearch+Logstash+Kibana)
## 简介:
**ElasticSearch:**一个开源分布式搜索引擎,具有分布式,零配置,自动发现,索引自动分片,索引副本机制,restful风格接口,多数据源,自动搜索负载等特点。<p>**Logstash:**一个完全开源的工具,可以对你的日志进行搜集,过滤,并将其储存供以后使用。<p>**Kibana:**为Logstash和ElasticSearch提供日志分析的友好Web界面,可以汇总,分析和搜索重要的数据日志。
##下载说明:
由于Logstash的运行依赖于Java环境, 而Logstash 1.5以上版本不低于java 1.7,因此推荐使用最新版本的Java。因为我们只需要Java的运行环境,所以可以只安装JRE,不过这里我依然使用JDK,请自行搜索安装<p>
ELK下载https://www.elastic.co/downloads/
## 使用说明:
### ElasticSearch:
#### 启动服务:
运行bin/elasticsearch.bat文件开启服务。查看127.0.0.1:9200出现如下页面运行成功<p>
#![](/assets/elasticsearch.png) <p>
#### 基础操作:es支持restful操作。<p>
获取对应文档:<p>
GET /[_index]/[_type]/_search <p>
上传文档: <p>
```javascript
PUT /[_index]/[_type]/[_id}
{ "first_name" : "Jane",
"last_name" : "Smith",
"age" : 32,
"about" : "I like to collect rock albums",
"interests": [ "music" ] }
```
<p>
操作文档:http://es.xiaoleilu.com/030_Data/15_Get.html
#### 面向文档:
Elasticsearch是面向文档(document oriented)的,这意味着它可以存储整个对象或文档(document)。然而它不仅仅是存储,还会索引(index)每个文档的内容使之可以被搜索。在Elasticsearch中,你可以对文档(而非成行成列的数据)进行索引、搜索、排序、过滤。这种理解数据的方式与以往完全不同,这也是Elasticsearch能够执行复杂的全文搜索的原因之一。<p>
ELasticsearch使用JSON,作为文档序列化格式。
以下使用JSON文档来表示一个用户对象:<p>
```javascript
{
"email": "john@smith.com",
"first_name": "John",
"last_name": "Smith",
"info": {
"bio": "Eco-warrior and defender of the weak",
"age": 25,
"interests": [ "dolphins", "whales" ]
},
"join_date": "2014/05/01"
}
```
在Elasticsearch中,文档归属于一种类型(type),而这些类型存在于索引(index)中,我们可以画一些简单的对比图来类比传统关系型数据库:<p>
Relational DB -> Databases -> Tables -> Rows -> Columns<p>
Elasticsearch -> Indices -> Types -> Documents -> Fields<p>
Elasticsearch集群可以包含多个索引(indices)(数据库),每一个索引可以包含多个类型(types)(表),每一个类型包含多个文档(documents)(行),然后每个文档包含多个字段(Fields)(列)。
#### elasticsearch 分布式:
Elasticsearch为分布式而生
Elasticsearch致力于隐藏分布式系统的复杂性。以下这些操作都是在底层自动完成的:<p>
*将你的文档分区到不同的容器或者分片(shards)中,它们可以存在于一个或多个节点中。<p>
*将分片均匀的分配到各个节点,对索引和搜索做负载均衡。<p>
*冗余每一个分片,防止硬件故障造成的数据丢失。<p>
*将集群中任意一个节点上的请求路由到相应数据所在的节点。<p>
*无论是增加节点,还是移除节点,分片都可以做到无缝的扩展和迁移<p>
#### 集群部署:
伪分布式环境搭建:创建3个es环境,修改其config/elasticsearch.yml配置文件<p>
1:<p>
cluster.name: elasticsearch<p>
node.name: node1<p>
2:<p>
cluster.name: elasticsearch<p>
node.name: node2<p>
http.port: 9202<p>
3:<p>
cluster.name: elasticsearch<p>
node.name: node3<p>
http.port: 9203<p>
es会自动搜索同一网段下的cluster.name(集群名)相同的es做成集群
将indeces(索引)下的分片(默认一个索引5个主分片每个分片一个复制分片)平分到不同es节点(node)下。
#### elasticsearch-head插件安装:
是es集群管理插件。执行如下命令安装插件:<p>
elasticsearch/bin/plugin install mobz/elasticsearch-head<p>
打开:http://localhost:9200/_plugin/head/ <p>
下图为以上操作建立的集群。
![](/assets/es.png) <p>
相关文档:http://es.xiaoleilu.com/020_Distributed_Cluster/05_Empty_cluster.html <p>
### Logstash:
#### 运行:
logstash -e input { stdin { } } output { stdout { codec => rubydebug } } <p>
输入报文 helloworld 可以在控制台看到对应报文。<p>
2016-10-20T09:05:53.446Z LAPTOP-RKIO0CO4 hellowrold <p>
#### 通过配置文件运行:
在bin目录下创建配置文件test.conf: <p>
input为logstash配置输入流,logstash支持多种input方式包括file redis TCP UDP syslog lumberjack等。<p>
filter过滤logstash输入流,并可以解析输入流。<p>
ouput为logstash输出流,支持多种输出方式如elsaticearch file email tcp hdfs等,并可以配置相关参数如在es中配置索引名和type名<p>
<p> 示例使用file方式获取logstash输入流需将path更改为项目log地址<p>
```
input {
file{
path => "C:\Users\zjl\.IntelliJIdea2016.2\system\tomcat\Unnamed_hap-parent\logs\hap.log"
start_position =>"beginning"
}
}
filter{
if ([message] =~ "^\s") {
drop {}
}
grok{
match => ["message", " .* %{GREEDYDATA:level} \[%{GREEDYDATA:accountId}\] \[%{GREEDYDATA:requestId}\] %{GREEDYDATA:dao} - %{GREEDYDATA:info}\s"]
}
}
output {
stdout {
}
elasticsearch {
hosts => "localhost:9200"
}
}
```
<p>若使用tcp为logstash配置输入修改logback.xml文件添加输出方式<p>
```
<appender name="stash" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%X{accountId}] [%X{requestId}] %logger - %msg%n</pattern>
</encoder>
<destination>elk-hap:4560</destination></appender>
```
<p>
相关文档:http://kibana.logstash.es/content/logstash/plugins/input/file.html
<p>
在Logstash文件/bin目录下打开终端输入logstsh -f test.conf运行logstash解析日志文件 <p>
作为一个要长期运行的程序。发行包内都带有sysV或者systemd风格的启动程序配置,你只需要直接使用即可,以RPM为例 /etc/init.d/logstash 脚本中,会加载 /etc/init.d/functions 库文件,利用其中的 daemon 函数,将 logstash 进程作为后台程序运行。所以,你只需把自己写好的配置文件,统一放在 /etc/logstash/conf.d 目录下(注意目录下所有配置文件都应该是 .conf 结尾,且不能有其他文本文件存在。因为 logstash agent 启动的时候是读取全文件夹的),然后运行 service logstash start 命令即可。<p>
![](/assets/logstash.png)
<p>
### Kibana:
##### 打开文件bin目录下kibana.bat开启服务 <p> <p>
##### 浏览器打开localhost:5601查看通过logstash解析的日志文件
##### config/kibana.yml文件可进行对kibana相关配置 <p> <p>
![](/assets/kibana.png)
![](/assets/kibanaview.png)
# 锁机制
融租易提供两种锁机制, 满足项目上对数据并发修改的需求.
## 1.数据库锁
***
根据适当的参数进行物理锁定(数据库级锁),支持3种数据库:oracle,mysql,sqlserver。提供 API, 自动执行 sql
>
mysql,orcale 执行 select * from xxx where ... for update
> sqlserver 执行 select * from xxx with (ROWLOCK) where ...
> 都是数据库原生的锁机制
使用方式:
### 单数据源
在Java代码中,注入`DatabaseLockProvider`类,
```java
public class XXXServiceImpl {
@Autowired
private DatabaseLockProvider databaseLockProvider;
public int update (XXX dto, ...){
// 传入锁定对象,锁定数据库相关行
databaseLockProvider.lock(dto);
//...
}
}
```
### 多数据源
在Java代码中,`自己创建DatabaseLockProvider类`,指定`dataSource`
```java
public class XXXServiceImpl {
@Autowired
@Qualifier("xxxDataSource")
private DataSource dataSource;
private DatabaseLockProvider databaseLockProvider;
@Transactional(propagation = Propagation.REQUIRED)
public int update (XXX dto, ...){
databaseLockProvider = new DatabaseLockProvider(dataSource)
// 传入锁定对象,锁定数据库相关行
databaseLockProvider.lock(dto);
//...
}
}
```
> 事务提交以后,锁会自动释放
DatabaseLockProvider提供的接口
```java
//根据传入对象,自动加锁。
//确保bean上有@Table 注解,能自动解析出对应的表。 默认根据有@ID注解的字段进行加锁,确保id有值
public void lock(Object dto)
//根据传入对象和自定义的where条件,自动加锁。
//传入类似 "name = ? and age = ?" 的条件语句,根据whereCondition,依次对应传入属性对应的值。
public void lock(Object dto, String whereCondition, Object... whereParameter)
// 可以自定义表名,不必传入dto
public void lock(String tableName, String whereCondition, Object... whereParameter)
```
## 2.分布式锁
基于`redis`的锁,实现跨平台, 分布式锁
使用方式:
1.根据实际配置的redis,修改配置文件`config.properties`
```properties
redisson.server.url=127.0.0.1:6379
#redissson.server.password=
```
> 支持`多节点`配置,按照如下规范配置
>redisson.server.url=\
> 127.0.0.1:6379,\
> 10.211.103.142:6379
>内部使用redisson提供的`RedLock`进行加锁
2.在java代码中注入DistributedLockProvider
```java
public class XXXServiceImpl {
@Autowired
@Qualifier("distributeLockTemplate")
private DistributedLockProvider distributedLockProvider;
public int update (XXX dto, ...){
//使用回调方式,执行自己的业务逻辑
distributedLockProvider.lock(dto,new DistributedLockCallback<Object>() {
@Override
public Object process() {
//doSomething();
return null;
})
}
}
```
> 回调函数执行以后,锁都会自动释放
DistributedLockProvider提供的接口:
```java
/**
* 使用分布式锁,使用锁默认超时时间。
*
* @param lockKey
* 加锁对象,确保有@ID属性,建议BaseDto
* @param callback
* @return 回调函数返回的内容
*/
<T> T lock(Object lockKey, DistributedLockCallback<T> callback);
/**
* 使用分布式锁,使用锁默认超时时间。
*
* @param lockKey
* 确保唯一
* @param callback
* @return 回调函数返回的内容
*/
<T> T lock(String lockKey, DistributedLockCallback<T> callback);
/**
* 使用分布式锁。自定义锁的超时时间
*
* @param lockKey
* 加锁对象,确保有@ID属性,建议BaseDto
* @param callback
* @param leaseTime
* 锁超时时间。超时后自动释放锁。
* @param timeUnit
* @return 回调函数返回的内容
*/
<T> T lock(Object lockKey, DistributedLockCallback<T> callback, long leaseTime, TimeUnit timeUnit);
/**
* 使用分布式锁。自定义锁的超时时间
*
* @param lockKey
* 确保唯一
* @param callback
* @param leaseTime
* 锁超时时间。超时后自动释放锁。
* @param timeUnit
* @return 回调函数返回的内容
*/
<T> T lock(String lockKey, DistributedLockCallback<T> callback, long leaseTime, TimeUnit timeUnit);
/**
* 使用分布式锁,使用锁默认超时时间。
*
* @param lockKey
* 确保唯一
* @param callback
* @return 回调函数返回的内容
*
* @exception Exception 加锁过程的异常,比如锁已被占用,加锁失败
*/
<T> T tryLock(String lockKey, DistributedLockCallback<T> callback) throws Exception;
/**
* 使用分布式锁,使用锁默认超时时间。默认等待时间1秒
*
* @param lockKey
* 加锁对象,确保有@ID属性,建议BaseDto
* @param callback
* @return 回调函数返回的内容
*
* @exception Exception 加锁过程的异常,比如锁已被占用,加锁失败
*/
<T> T tryLock(Object lockKey, DistributedLockCallback<T> callback) throws Exception;
/**
* 使用分布式锁。自定义锁的超时时间
*
* @param lockKey
* 加锁对象,确保有@ID属性,建议BaseDto
* @param callback
* @param waitTime
* 获取锁等待时间,超过设置时间未获得锁则抛出异常
* @param leaseTime
* 锁超时时间。超时后自动释放锁。
* @param timeUnit
* waitTime,leaseTime 时间单位
* @return 回调函数返回的内容
*
* @exception Exception 加锁过程的异常,比如锁已被占用,加锁失败
*/
<T> T tryLock(Object lockKey, DistributedLockCallback<T> callback, long waitTime, long leaseTime, TimeUnit timeUnit)
throws Exception;
/**
* 使用分布式锁。自定义锁的超时时间
*
* @param lockKey
* 确保唯一
* @param callback
* @param waitTime
* 获取锁等待时间,超过设置时间未获得锁则抛出异常
* @param leaseTime
* 锁超时时间。超时后自动释放锁。
* @param timeUnit
* waitTime,leaseTime 的时间单位
* @return 回调函数返回的内容
*
* @exception Exception 加锁过程的异常,比如锁已被占用,加锁失败
*/
<T> T tryLock(String lockKey, DistributedLockCallback<T> callback, long waitTime, long leaseTime, TimeUnit timeUnit)
throws Exception;
```
# 用户安全策略
框架提供标准的用户安全策略接口
com.hand.hap.security.IUserSecurityStrategy
> 默认实现DefaultUserSecurityStrategy,order值为9999
编写自定义实现类,需要在 Spring 中定义为 bean (也可以通过 @Component之类的注解自动扫描注册)
可以实现下列方法,自定义安全策略:
### 登录成功以后,跳转至index页面前的策略
```java
ModelAndView loginVerifyStrategy(User user, HttpServletRequest request);
```
参数及返回类型说明
> - user 通过登录验证的User对象
- ModelAndView 重定向到该 ModelAndView
>
如果想要正常跳转到index页面,请返回null
注意:会根据order大小依次执行实现类的该方法,注意顺序
### 用户修改密码时,自定义密码复杂度
```java
void passwordVerifyStrategy(IRequest request ,User user,String oldPwd, String newPwd, String newPwdAgain) throws UserException;
```
参数及异常说明
> - user 通过登录验证的User对象
- oldPwd 旧密码
- newPwd 新密码
- newPwdAgain 再次输入的新密码
- 如果验证不通过,请抛出自定义的UserException
一般来说修改了复杂度验证策略,需要修改sys_config页面。
### 新建用户时的策略
```java
User beforeCreateUser(IRequest request ,User user)
```
可以对用户做统一的信息处理,如统一设置一些属性值,注意如果实现了该方法,一定要返回处理后的User对象,默认返回传入的user
> 实现IAuthenticationSuccessListener
接口, 是在用户登录验证成功时执行.
>
一般用来往session里面放一些值,或其他逻辑,如果抛出异常,则会在login页面显示异常信息,注意区别。
# 部署
# tomcat
<a href="#tomcat"></a>
### 1. 关闭 eclipse server `Auto Reload` 特性
* 禁用默认值
<img src="/assets/disable_autoreload_all.png" width="50%"/>
* 单独禁用项
<img src="/assets/disable_autoreload_1.png" width="50%"/>
* 建议关闭 jar 扫描, 提高启动速度, 减少内存占用 , 修改 `catalina.properties `
```properties
tomcat.util.scan.StandardJarScanFilter.jarsToSkip=*.jar
```
### 2. 内存设置
* Linux 修改 `catalina.sh` ,开始处添加
```bash
JAVA_OPTS='-Xms512m -Xmx2048m'
```
* Windows 修改 `catalina.bat`
```bash
set JAVA_OPTS=-Xms512m -Xmx2048m
```
### 3. 启用远程 JMX 连接
修改 catalina.sh , 搜索 `[ "$1" = "start" ]` , 在下方添加
```bash
JAVA_OPTS="-Dcom.sun.management.jmxremote \
-Dcom.sun.management.jmxremote.port=1099 \
-Djava.rmi.server.hostname=192.168.1.111 \
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.authenticate=false $JAVA_OPTS"
```
> linux 系统可以用 `` `hostname -i` `` 获取 ip
# Weblogic
<a href="#weblogic"></a>
weblogic 上的部署有些特殊,主要注意以下几点:
> **以下设置仅仅针对 weblogic 12 版本,其他版本可能存在通配符等问题**
### 1. JNDI 数据源
weblogic 上定义好数据源后,在 `config.properties` 中需要修改 jndi 的名字
```properties
db.jndiName=hap_dev
```
> tomcat 中是 java:comp/env/jdbc/hap_dev,这点不一样
### 2. 新增 weblogic.xml
在 WEB-INF 目录下新增 weblogic.xml
```bash
<?xml version="1.0" encoding="UTF-8"?>
<weblogic-web-app>
<container-descriptor>
<!--优先加载应用下的jar包,解决jar包冲突问题-->
<!--具体jar包冲突问题,具体解决-->
<prefer-application-packages>
<package-name>org.springframework.*</package-name>
<package-name>org.hibernate.*</package-name>
<package-name>javax.validation.*</package-name>
<package-name>javax.validation.spi.*</package-name>
<package-name>org.slf4j.*</package-name>
<package-name>com.fasterxml.*</package-name>
</prefer-application-packages>
<show-archived-real-path-enabled>true</show-archived-real-path-enabled>
</container-descriptor>
</weblogic-web-app>
```
### 3. weblogic部署异常解决方案
weblogic选择要部署的war包,若出现_wl_cls_gen.jar!这样的日志异常,可将war包,直接解压,进行部署。
上述 3 点在部署的时候请留意。
......@@ -156,5 +156,41 @@ public class demoJob extends AbstractJob{
* 下次执行时间:预计执行完本次任务后,根据指定的执行间隔推算的下一次执行时间点。
* 实际执行时间:本次任务实际执行的时间点。
### 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
......@@ -3,7 +3,6 @@
* [GitBook使用](/gitbook.md)
---
* I. 开发环境准备
* [1.1 Git 使用](/git-guide.md "git指令")
......@@ -19,36 +18,48 @@
* 2.3 Checkstyle
* III. 后端开发
* [3.1 用户安全策略](/后端开发/user-security-strategy.md)
* [3.2 审计](/后端开发/audit.md)
* [3.3 锁机制](/后端开发/lock.md)
* [3.4 日志管理](/后端开发/elk.md)
* [3.5 代码生成器](/后端开发/code-generator.md)
* [3.6 跨域访问](/后端开发/3.24-cors.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](/前端组件/HlsLov.md)
* [5.10 hlsToolBar](/前端组件/HlsToolBar.md)
* [5.11 TabStrip](/前端组件/TabStrip.md)
* [5.12 hlsForm](/前端组件/hlsForm.md)
* [5.13 hlsCombobox](/前端组件/HlsCombobox.md)
* [5.14 hlsCheckBox](/前端组件/HlsCheckBox.md)
* [5.15 Grid](/前端组件/Grid.md)
* [5.16 DataSource](/前端组件/DataSource.md)
* [5.17 hlsGridBox](/前端组件/hlsGridBox.md)
* [5.18 NumericTextBx](/前端组件/NumericTextBox.md)
* [5.19 HlsNavigationBar](/前端组件/HlsNavigationBar.md)
* VI. 框架功能描述
* IV. 前端开发
* 4.1 前端开发说明 \(1.0\)
* [4.2 hlsCombobox](/前端组件/hlsCombobox.md)
* [4.3 hlsDataSource](/前端组件/hlsDataSource.md)
* [4.4 hlsMaskedTextBox](/前端组件/hlsMaskedTextBox.md)
* [4.5 hlsPage](/前端组件/hlsPage.md)
* [4.6 hlsTextArea](/前端组件/hlsTextArea.md)
* [4.7 hlsTlEdit](/前端组件/hlsTlEdit.md)
* [4.8 hlsDatePicker](/前端组件/hlsDatePicker.md)
* [4.9 hlsDateTimePicker](/前端组件/HlsDateTimePicker.md)
* [4.10 hlsLov](/前端组件/HlsLov.md)
* [4.11 hlsToolBar](/前端组件/HlsToolBar.md)
* [4.12 TabStrip](/前端组件/TabStrip.md)
* [4.13 hlsForm](/前端组件/hlsForm.md)
* [4.14 hlsCombobox](/前端组件/HlsCombobox.md)
* [4.15 hlsCheckBox](/前端组件/HlsCheckBox.md)
* [4.16 抽屉通用方法](/前端组件/box.md)
* [4.17 Grid](/前端组件/Grid.md)
* [4.18 DataSource](/前端组件/DataSource.md)
* [4.19 hlsGridBox](/前端组件/hlsGridBox.md)
* [4.20 NumericTextBx](/前端组件/NumericTextBox.md)
* [4.21 HlsNavigationBar](/前端组件/HlsNavigationBar.md)
* V. 框架功能描述
* [5.1 计划任务](/框架功能描述/计划任务.md)
* [5.2 消息机制](/框架功能描述/消息机制.md)
* [5.3 部署](/后端开发/deployment.md)
* [6.1 计划任务](/框架功能描述/计划任务.md)
* [6.2 RabbitMq消息队列](/后端开发/RabbitMq消息队列.md)
* [6.3 应用服务部署(tomcat/weblogic)](/框架功能描述/deployment.md)
* [6.4 合同文本生成](/docx4j.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