前言
zyj工作的本質就是將Hec4.0項目邏輯全部搬到zyj項目,整個過程中的工作內容如下:
- 遷表:將Hec4.0的Oracle表遷到 zyj 的mysql表
- 遷移後端代碼
- 遷移前端代碼
代碼部分需針對原有邏輯做相應的調整。
一、遷表
整個遷表過程如下:
1.修改Oracle表
- 表名
- 將複數表名改爲單數
- Number字段
- 將Oracle數據庫中整型含義的Number都改爲Number(38),這樣生成groovy時就會生成爲bigint
- 浮點型含義的Number不用改,生成groovy時會生成爲 Decimal
2.生成groovy
2.1 生成groovy
-
訪問
groovy 文件生成器
地址:http://192.168.12.107:16060 -
填寫 author、fileName,檢索表,勾選表名,然後點擊 `生成Groovy
- 將生成的
groovy 文件
放入到hap-core-db
工程下
2.2 修改groovy
-
描述ID
- 將生成的groovy文件中的comment中的id去掉
-
索引名
3.導入mysql
- 將項目重新
clean install
先將hap-core-db模塊clean install 一下,然後再將hap-db模塊clean install一下(沒有測過)
- 在parent下執行 process-resources 命令
mvn process-resources -D skipLiquibaseRun=false -D db.driver=com.mysql.jdbc.Driver -D db.url=jdbc:mysql://192.168.12.68:3306/hap_dev -D db.user=root -D db.password=h@ndhec
二、遷移後端代碼
1.生成後端代碼
啓動zyj 項目,訪問代碼生成器頁面
http://{port}/${context}/generator/generator.html
com.hand.hec
2.後端調整
2.1 DTO
- 字段需要與表結構嚴格對應
- DTO名稱與表名嚴格對應
- 多表關聯字段儘量使用JoinTable方式實現
2.2 Mapper遷移指引
- Mapper接口應當與DTO命名嚴格對應
- 沒有特殊要寫的SQL邏輯,無需單獨編寫mapper文件
- SQL語句需要確保未使用數據庫方言,能夠在多數據庫之間兼容
- …
2.3 Service遷移指引
- 基表類Service應當與DTO命名嚴格對應,複雜邏輯類Service命名應當與原PKG相對應
- 沒有特殊驗證邏輯,無需編寫Service方法體
- 業務邏輯型驗證應當寫在Service中
- …
2.4 Controller
- 一個頁面應當對應一個Controller
- 一個頁面內的同模塊內的操作應當儘量在當前頁面的Controller內完成
- 如果當前頁面沒有初始化查詢,無需特殊設置ModelAndView,在Controller類上設置RequestMapping
- RequestMapping格式爲:/模塊名/A (A中單詞用中劃線分割)
三、遷移前端頁面
新增的頁面請遵循開發規範
若是遷移表,則screen頁面中需要做如下修改:
-
動態取值
- 頁面的所有[]
-
字段名
- 頁面內的字段名(filed、column等)需要改成駝峯形式,以匹配DTO字段
-
prompt
- 字段級別的prompt在
dataSet
的field上進行定義 - 格式爲小寫
- 所有的prompt都需要在hap內註冊
- 字段級prompt的命名規則爲:基表名.字段名
- 校驗級prompt的命名規則爲:基表名.校驗結果
- 字段級別的prompt在
-
baseUrl
、queryUrl
、submitUrl
- 頁面內的DataSet的model切換成
baseUrl
,queryUrl
和submitUrl
也切換成相關地址 baseUrl
無需加添加 context
- 頁面內的DataSet的model切換成
-
model-query
、loadData
- 頁面的所有的初始化查詢:
model-query
和loadData
,都需要改爲由Controller
中返回值爲ModelAndView
的方法中轉
- 頁面的所有的初始化查詢:
四、常見問題彙總
1.日期選擇
日期格式要精確到時分秒,否則後臺無法接收
使用 renderer="Aurora.formatDateTime"
和 <a:dateTimePicker id="GLD2030_grid_dp"/>
示例如下:
<a:grid id="GLD2030_responsibility_centers_grid" bindTarget="GLD2030_responsibility_centers_result_ds" marginHeight="115" marginWidth="3" navBar="true">
<a:columns>
<a:column name="responsibilityCenterCode" align="center" editor="GLD2030_grid_tf" editorFunction="GLD2030_responsibilityCenterEditFun" sortable="true" width="80"/>
<a:column name="responsibilityCenterName" align="left" editor="GLD2030_grid_tf" width="200"/>
<a:column name="respCenterTypeCodeDisplay" align="center" editor="GLD2030_grid_cb" width="80"/>
<a:column name="startDateActive" align="center" editor="GLD2030_grid_dp" renderer="Aurora.formatDateTime" width="80"/>
<a:column name="endDateActive" align="center" editor="GLD2030_grid_dp" renderer="Aurora.formatDateTime" width="80"/>
<a:column name="summaryFlag" align="center" editor="GLD2030_grid_cx" editorFunction="GLD2030_responsibilityCenterEditFun" width="80"/>
<a:column name="assignBgtEntity" align="center" renderer="GLD2030_AssignBgtEntityRender" width="80"/>
<a:column name="childResponsibilityCenter" align="center" renderer="GLD2030_setSubResbonsibilitys" width="80"/>
</a:columns>
<a:editors>
<a:textField id="GLD2030_grid_tf" typeCase="upper"/>
<a:checkBox id="GLD2030_grid_cx"/>
<a:comboBox id="GLD2030_grid_cb"/>
<a:dateTimePicker id="GLD2030_grid_dp"/>
</a:editors>
</a:grid>
2.lov
2.1 lov實現
(1)field中使用lovCode
<a:field name="bgtEntityName" lovCode="LOV.BGT_ENTITY.BGT_ENTITY_NAME" required="true" prompt="BGT_ENTITY.DESCRIPTION" title="BGT_ENTITY.BGT_ENTITY_NAME">
<a:mapping>
<a:map from="entityId" to="bgtEntityId"/>
<a:map from="entityName" to="bgtEntityName"/>
</a:mapping>
</a:field>
(2)grid中使用lov編輯器
<a:grid id="GLD2030_respCenterRefBeGrid" bindTarget="GLD2030_respCenterRefBeDs" marginHeight="200" navBar="true" width="1000">
<a:columns>
<a:column name="bgtEntityName" align="center" editor="GLD2030_accEntityRefLov" width="200"/>
<a:column name="bgtCenterName" align="center" editorFunction="GLD2030_BgtCenterEditorFun" width="120"/>
<a:column name="defaultFlag" editor="GLD2030_accEntityRefCk" prompt="TRAVEL_PLAN_TYPE.DEFAULT_FLAG"/>
<a:column name="enabledFlag" editor="GLD2030_accEntityRefCk" prompt="FND_COMPANY_GROUP.ENABLED_FLAG"/>
</a:columns>
<a:editors>
<a:lov id="GLD2030_accEntityRefLov"/>
<a:checkBox id="GLD2030_accEntityRefCk"/>
</a:editors>
<a:events>
<a:event name="cellclick" handler="GLD2030_GridCellClick"/>
</a:events>
</a:grid>
(3)然後頁面上去定義lov
2.1 lov字段帶出
需求說明:實現頁面一加載時就自動帶出關聯的lov字段的值,如下圖
(1)通過給實體類添加 JoinTable
、 JoinColumn
註解
/**
* 預算中心ID
*/
@JoinTable(name = "bgtCenterJoin", joinMultiLanguageTable = false, target = com.hand.hec.zyj.bgt.dto.BgtCenter.class,
type = JoinType.LEFT, on = {@JoinOn(joinField = com.hand.hec.zyj.bgt.dto.BgtCenter.FIELD_CENTER_ID)})
@NotNull
private Long bgtCenterId;
/**
* 預算中心名稱
*/
@Transient
@Length(max = 500)
@JoinColumn(joinName = "bgtCenterJoin", field = com.hand.hec.zyj.bgt.dto.BgtCenter.FIELD_DESCRIPTION)
private String bgtCenterName;
(2)使用 Criteria 和 selectOptions
@RequestMapping("/query")
@ResponseBody
public ResponseData query(RespCenterRefBe dto, @RequestParam(defaultValue = DEFAULT_PAGE) int page,
@RequestParam(defaultValue = DEFAULT_PAGE_SIZE) int pageSize, HttpServletRequest request) {
IRequest requestContext = createRequestContext(request);
Criteria criteria = new Criteria(dto);
criteria.where(new WhereField(RespCenterRefBe.FIELD_BGT_ENTITY_NAME),
new WhereField(RespCenterRefBe.FIELD_BGT_CENTER_NAME));
return new ResponseData(service.selectOptions(requestContext,dto,criteria));
}
(3)同時mapper.xml注意要添加 transient字段
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.hand.hec.gld.mapper.RespCenterRefBeMapper">
<resultMap id="BaseResultMap" type="com.hand.hec.gld.dto.RespCenterRefBe">
<result column="REF_ID" property="refId" jdbcType="DECIMAL" />
<result column="RESP_CENTER_ID" property="respCenterId" jdbcType="DECIMAL" />
<result column="BGT_ENTITY_ID" property="bgtEntityId" jdbcType="DECIMAL" />
<result column="BGT_CENTER_ID" property="bgtCenterId" jdbcType="DECIMAL" />
<result column="DEFAULT_FLAG" property="defaultFlag" jdbcType="VARCHAR" />
<result column="ENABLED_FLAG" property="enabledFlag" jdbcType="VARCHAR" />
<result column="BGT_ENTITY_NAME" property="bgtEntityName" jdbcType="VARCHAR" />
<result column="BGT_CENTER_NAME" property="bgtCenterName" jdbcType="VARCHAR" />
</resultMap>
</mapper>
2.3 lov傳參
(1)、lovCode傳參
field的lovCode屬性參數用?連接
<a:field name="unitCode" autoComplete="true" autoCompleteField="unitName" lovGridHeight="320" lovHeight="450" lovCode="LOV_EXP_UNIT_ASSIGN?companyId=$[/parameter/@companyId]?magOrgId=$[/parameter/@magOrgId]" lovWidth="500" required="true" prompt="exp_org_units.unit_code" title="acp_invoice_lines.unit_id">
<a:mapping>
<a:map from="unitId" to="unitId"/>
<a:map from="unitCode" to="unitCode"/>
<a:map from="unitName" to="unitName"/>
<a:map from="companyCode" to="companyCode"/>
<a:map from="companyShortName" to="companyName"/>
</a:mapping>
</a:field>
(2)、js傳參
record.getField('unitCode').setLovPara('companyId', '$[/parameter/@companyId]');
2.4 lov定義自定義sql示例
<if test="pageId != null">
<bind name="pageIdNum" value="@java.lang.Long@parseLong(pageId)"/>
</if>
SELECT
layout_id,
layout_code,
layout_desc
FROM
bpm_page_layout_basic b
where
b.page_id = #{pageIdNum}
<if test="layoutCode!=null">
and b.layout_code LIKE concat('%',
concat(#{layoutCode,jdbcType=VARCHAR}, '%'))
</if>
<if test="layoutDesc!=null">
and b.layout_desc LIKE concat('%',
concat(#{layoutDesc,jdbcType=VARCHAR}, '%'))
</if>
ORDER BY
layout_sequence
3.多語言
- 類上加 @MultiLanguage
- 多語言字段上加 @MultiLanguageField
- 頁面上多語言field添加
dto
、dtoId
<a:field name="responsibilityCenterName" required="true" prompt="GLD_RESPONSIBILITY_CENTER.RESPONSIBILITY_CENTER_NAME" dto="com.hand.hec.gld.dto.ResponsibilityCenter" dtoId="responsibilityCenterId"/>
-
頁面上多語言選擇框如下
<a:tledit id="GLD2030_responsibilityCenterNameTld"/>
4.comboBox
4.1 普通dataset型
- 獲取數據
此步驟也可採取設置默認值的方式,由Controller中轉
<a:dataSet id="FND2140_gldCoaStructureDs" autoQuery="true" fetchAll="true" baseUrl="/gld-coa-structure" queryUrl="$[/request/@context_path]/gld-coa-structure/query">
<a:fields>
<a:field name="coaStructureCode"/>
<a:field name="coaStructureId"/>
<a:field name="structureFormat"/>
<a:field name="description"/>
</a:fields>
</a:dataSet>
- 映射數據到字段上
<a:field name="coaStructureCode" displayField="coaStructureCode" options="FND2140_gldCoaStructureDs" required="true" valueField="coaStructureId" returnField="coaStructureId" prompt="GLD_COA_STRUCTURE.COA_STRUCTURE_CODE">
<a:mapping>
<a:map from="coaStructureId" to="coaStructureId"/>
<a:map from="coaStructureCode" to="coaStructureCode"/>
<a:map from="description" to="coaDescription"/>
<a:map from="structureFormat" to="coaStructureFormat"/>
</a:mapping>
</a:field>
4.2 SysCode型
- 取數據,注意queryUrl後面有個
/
<a:dataSet id="GLD2030_respCenterTypeCodeDs" autoQuery="true" fetchAll="true" queryUrl="$[/request/@context_path]/common/auroraCode/GLD.RESP_CENTER_TYPE/"/>
- 映射數據到comboBox上
<a:field name="respCenterTypeCode"/>
<a:field name="respCenterTypeCodeDisplay" displayField="meaning" options="GLD2030_respCenterTypeCodeDs" prompt="GLD_RESPONSIBILITY_CENTER.RESP_CENTER_TYPE_CODE_DISPLAY" required="false" valueField="value" returnField="respCenterTypeCode" />
- comboBox編輯器
<a:comboBox id="GLD2030_gridCb"/>
5.條件查詢和模糊查詢
hap對查詢參數進行了限制,所有的條件查詢,均需用
@Where
和Criteria
手動聲明
- 條件查詢:Comparison.EQUAL
- 模糊查詢:Comparison.LIKE
- 其他匹配條件請參見
Comparison
枚舉類
- 實體類添加
@Where
/**
* 責任中心名稱
*/
@Length(max = 500)
@MultiLanguageField
@Where
private String responsibilityCenterName;
- 查詢時結合
Criteria
進行查詢
@RequestMapping("/query")
@ResponseBody
public ResponseData query(ResponsibilityCenter dto, @RequestParam(defaultValue = DEFAULT_PAGE) int page,
@RequestParam(defaultValue = DEFAULT_PAGE_SIZE) int pageSize, HttpServletRequest request) {
IRequest requestContext = createRequestContext(request);
Criteria criteria = new Criteria(dto);
if(dto.getResponsibilityCenterCode()!=null){
criteria.where(new WhereField(ResponsibilityCenter.FIELD_RESPONSIBILITY_CENTER_CODE, Comparison.LIKE));
}
if(dto.getResponsibilityCenterName()!=null){
criteria.where(new WhereField(ResponsibilityCenter.FIELD_RESPONSIBILITY_CENTER_NAME, Comparison.LIKE));
}
return new ResponseData(service.selectOptions(requestContext,dto,criteria));
}
6.設置默認值
Screen頁面上的mode-query是爲了準備默認值的,因此遷移時,針對默認值,可以做如下操作以實現相同的功能。
參見部門類型定義ExpOrgUnitTypeController
6.1 中轉站
首先跳轉到頁面之前先經過Controller的方法中轉一下。在此Controller方法,將頁面上需要的參數(也就是默認值)準備好。
- 功能維護:
解讀:
將部門類型定義這個功能的入口頁面配置成
exp/org-unit-type/index
,這樣在點擊功能時,會先跳轉到exp/org-unit-type/index
,這樣我們可以在這個controller方法中準備好頁面上需要的參數,然後再跳轉到頁面上。
- Controller方法:
@RequestMapping(value = "/index")
public ModelAndView index(HttpServletRequest request, Long accountSetId, Long accountId) {
IRequest requestContext = createRequestContext(request);
List<FndManagingOrganization> fndManagingOrganizationList = fndManagingOrganizationService.magOrgOption(requestContext);
ModelAndView view = new ModelAndView("exp/EXP1012/exp_org_unit_type");
view.addObject("fndManagingOrganizationList", fndManagingOrganizationList);
return view;
}
6.2 頁面取值
要想取值,就得先弄懂 AuroraContext,因爲值都在AuroraContext中。
(1)AuroraContext的結構
通過在頁面上加入xmlns:p="uncertain.proc"
命名空間和<p:echo/>
節點,可以頁面加載時,在tomcat控制檯輸出上下文的內容。
可以看到AuroraContext結構如下:
- context
- cookie
- parameter
- session
- model
- 具體model(在此示例中爲 fndManagingOrganizationList)
- records
- record
- record
- records
- 具體model(在此示例中爲 fndManagingOrganizationList)
(2)取值
取值就按照AuroraContext的結構取,根節點爲/
,取到節點中的值時使用@
符號。於是取值示例如下:
'$[/model/fndManagingOrganizationList/records/record/@magOrgCodeName]'
(3)設置默認值
7.批量分配
以部門類型定義頁面 批量分配公司爲例:
[外鏈圖片轉存失敗(img-DmptGygU-1562294483758)(images/1548397772141.png)]
主要步驟:
- 獲取所有被選中的記錄
- 發送Ajax請求
// 見 exp_org_unit_type_batch_assign_com_all.screen
var datas = $au('EXP1012_batch_assign_all_result_ds').getJsonData(true); //獲取所有選中的記錄
Aurora.request({ //發送ajax請求
lockMessage: '$[l:hap_waiting]',
url: $au('EXP1110_org_unit_type_asgn_com_batch_assign_all_link').getUrl(),
para: datas,
success: EXP1012_batchAssignAllBackFun,
scope: this
});
//另外可參見:exp_mo_unit_group_relations_bath_assign.screen
8.附件相關
// 1.隱藏 上傳附件 按鈕
//var url = $au('upload_image_cannotUpload_link').getUrl() + '?tableName=FND_MANAGING_ORGANIZATIONS&tablePkValue=' + magOrgId;
// 2.顯示 上傳附件 按鈕
// var url = $au('upload_image_link').getUrl() + '?tableName=FND_MANAGING_ORGANIZATIONS&tablePkValue=' + magOrgId;
// 3.隱藏 上傳附件與附件刪除 按鈕
var url = $au('upload_image_cannotUpload_link').getUrl() + '?tableName=FND_MANAGING_ORGANIZATIONS&tablePkValue=' + magOrgId + '&showDelete=false';
8.1 使用附件實現上傳、下載、刪除功能
可參見
管理組織定義(
fnd_managing_organizations.screen
) -> 附件上傳
目前已實現附件上傳、下載、刪除功能
要使用附件相關功能,需完成以下3個步驟:
(1)在 screen(fnd_managing_organizations.screen)頁面上定義附件上傳頁面的地址:
<a:link id="upload_image_link" url="$[/request/@context_path]/app/APP2030/app_uploadFile.screen"/>
(2)渲染附件上傳按鈕
function upload_file_link(value, record, name) {
var magOrgId = record.get('magOrgId');
return '<a href="javascript:uploadFile(' + magOrgId + ')">$[l:prompt.upload_attachment]</a>';
}
<a:column name="uploadFile" align="center" renderer="upload_file_link" width="80"/>
(3)跳轉附件上傳頁面時需要帶上兩個參數:
tableName
: 本條記錄所在表名tablePkValue
: 本條記錄對應的主鍵值showDelete
:是否顯示刪除按鈕,默認爲false,不顯示刪除按鈕
function uploadFile(magOrgId) {
var url = $au('upload_image_link').getUrl() + '?tableName=FND_MANAGING_ORGANIZATIONS&tablePkValue=' + magOrgId+ '&showDelete=true';
new Aurora.Window({
url: url,
title: '$[l:prompt.upload_attachment]',
id: 'upload_image_screen',
width: 600,
height: 400
});
}
8.2 隱藏附件上傳按鈕
附件上傳按鈕的隱藏與顯示是通過使用兩個頁面來實現的:
app_uploadFile.screen
:顯示附件上傳按鈕的頁面app_uploadFile_cannotUpload.screen
:不顯示附件上傳按鈕的頁面
因此若要隱藏附件上傳按鈕:
(1)定義附件上傳頁面的地址:
<a:link id="upload_image_cannotUpload_link" url="$[/request/@context_path]/app/APP2030/app_uploadFile_cannotUpload.screen"/>
(2)構造跳轉附件上傳頁面的url
var url = $au('upload_image_cannotUpload_link').getUrl() + '?tableName=FND_MANAGING_ORGANIZATIONS&tablePkValue=' + magOrgId;
因此若要顯示附件上傳按鈕:
(1)定義附件上傳頁面的地址:
<a:link id="upload_image_link" url="$[/request/@context_path]/app/APP2030/app_uploadFile.screen"/>
(2)構造跳轉附件上傳頁面的url
var url = $au('upload_image_link').getUrl() + '?tableName=FND_MANAGING_ORGANIZATIONS&tablePkValue=' + magOrgId;
8.3 隱藏刪除按鈕
刪除按鈕的顯示與隱藏是通過傳參來控制的
showDelete
:
true
: 顯示刪除按鈕false
或其他值:隱藏刪除按鈕。- 默認值爲false
因此附件上傳按鈕、刪除按鈕的顯示隱藏組合如下:
(1)隱藏附件上傳按鈕,隱藏刪除按鈕
var url = $au('upload_image_cannotUpload_link').getUrl() + '?tableName=FND_MANAGING_ORGANIZATIONS&tablePkValue=' + magOrgId;
(2)隱藏 上傳附件按鈕,顯示 附件刪除 按鈕
var url = $au('upload_image_cannotUpload_link').getUrl() + '?tableName=FND_MANAGING_ORGANIZATIONS&tablePkValue=' + magOrgId + '&showDelete=true';
(3)顯示 上傳附件按鈕 並 顯示 附件刪除 按鈕
var url = $au('upload_image_link').getUrl() + '?tableName=FND_MANAGING_ORGANIZATIONS&tablePkValue=' + magOrgId + '&showDelete=true';
(4)顯示 上傳附件按鈕 並 隱藏 附件刪除 按鈕
var url = $au('upload_image_link').getUrl() + '?tableName=FND_MANAGING_ORGANIZATIONS&tablePkValue=' + magOrgId ;
默認值爲false
因此附件上傳按鈕、刪除按鈕的顯示隱藏組合如下:
(1)隱藏附件上傳按鈕,隱藏刪除按鈕
var url = $au('upload_image_cannotUpload_link').getUrl() + '?tableName=FND_MANAGING_ORGANIZATIONS&tablePkValue=' + magOrgId;
(2)隱藏 上傳附件按鈕,顯示 附件刪除 按鈕
var url = $au('upload_image_cannotUpload_link').getUrl() + '?tableName=FND_MANAGING_ORGANIZATIONS&tablePkValue=' + magOrgId + '&showDelete=true';
(3)顯示 上傳附件按鈕 並 顯示 附件刪除 按鈕
var url = $au('upload_image_link').getUrl() + '?tableName=FND_MANAGING_ORGANIZATIONS&tablePkValue=' + magOrgId + '&showDelete=true';