01_功能迁移指引

前言

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://host:{host}:{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的命名规则为:基表名.校验结果
  • baseUrlqueryUrlsubmitUrl

    • 页面内的DataSet的model切换成baseUrlqueryUrlsubmitUrl也切换成相关地址
    • baseUrl无需加添加 context
  • model-queryloadData

    • 页面的所有的初始化查询:model-queryloadData ,都需要改为由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)通过给实体类添加 JoinTableJoinColumn 注解

	/**
	 * 预算中心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添加 dtodtoId
<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对查询参数进行了限制,所有的条件查询,均需用 @WhereCriteria 手动声明

  • 条件查询: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

(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';
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章