NCC架构参照开发源码研究
1.参照
在界面开发过程中,经常会出现需要引用系统中已定义的数据场景。在编辑界面通过弹出一个参照展示界面供选择参照来源数据。在开发过程中,会经常重复使用相同的 数据选择界面,例如单据上一般都会引用组织。因此需要提供一套统一的数据选择控件及服务,在业务单据开发时,只需要直接使用,减少业务开发的工作量。其次是基于表单模版进行开发时,框架需要一套标准的数据选择控件,已便于动态的进行控制。当需要引用数据时,使用统一的前端控件即可完成数据的选择,而不需要开发。为此,在yonbip中提供了统一公共的数据选择控件及服务框架,简称为参照。 参照管理,即管理各个领域服务中注册的参照信息,提供各个领域的参照查询、编辑、新增功能,简单来说,一个实体依赖另外一个实体的数据,另外一个实体就叫参照,参照是主要用于其他页面选择使用的。
参照,就是对其他实体信息的参照和对照
YonBIP高级版参照:
- 前端JS:通过配置属性控制参照的界面显示。
- 后端Java:拼接查询参数数据的具体SQL语句。
2.参照的业务场景
使用参照的场景通常满足以下几个要求:
- 第一,用户需要填写的数据不可以随意填写,且已经存在于数据库。
- 第二,这些数据是一些常用和固定的数据,如组织、部门、人员、岗位等。
- 第三,用户在选择数据时需要进行权限过滤,以防止用户越权选择自己无权管理的数据。
3. 参照分类(样式截图)
- 表型参照
- 后端 Java 类需继承
DefaultGridRefAction
类,前端 JS 配置中需加入 ColumnConfig 的配置一次请求。
- 列表参照(单/多选)

单选

下拉样式参照:

树形参照
后端 Java 类需继承 DefaultTreeRefAction 类,前端 JS 配置中需加入 rootNode 和 TreeConfig 的配置一次请求。
单选

多选

树表型参照
实际上是树形参照和表形参照的集合。两次请求,一次请求走树形参照 action,一次请求走表形参照 action。

4. 参照的实现原理
参照所在数据库表为:bd_refinfo 。

5.代码研究
5.1 ICommonAction(接口)
1 2 3 4 5 6 7 8 9
| package nccloud.framework.web.action.itf;
import nccloud.framework.web.container.IRequest;
public interface ICommonAction { Object doAction(IRequest var1); }
|
5.2 NCCAction
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
|
public abstract class NCCAction implements ICommonAction { private String strMdOperateCode = null; private String strOperateCode = null; private String strResourceCode = null;
public NCCAction() { }
protected void checkDataPermission(IRequest request, Object objData) throws Exception { DataPermissionAction dataPermissionAction = new DataPermissionAction(); ValidationException validException = dataPermissionAction.checkDataPermission(this.getResourceCode(), this.getMdOperateCode(), this.getOperateCode(), objData); dataPermissionAction.dealValidationException(validException); }
public final Object doAction(IRequest request) { Logger.debug("begin action-->" + this.getClass().getName() + ".doAction()"); Object para = null; Object result = null;
try { para = this.getPara(request, this.getParaClass()); if (!this.doBeforeAction(request, para)) { Object var10 = result; return var10; }
result = this.execute(request, para); this.doAfterSuccess(request, para); } catch (Exception var8) { Exception ex = var8; this.doAfterFailure(request, para); this.handleException(ex); } finally { Logger.debug("end action-->" + this.getClass().getName() + ".doAction()"); }
return result; }
protected <T> void doAfterFailure(IRequest request, T para) { }
protected <T> void doAfterSuccess(IRequest request, T para) throws Exception { }
protected <T> boolean doBeforeAction(IRequest request, T para) throws Exception { return true; }
public abstract <T> Object execute(IRequest var1, T var2) throws Exception; public final String getMdOperateCode() { return this.strMdOperateCode; }
public final String getOperateCode() { return this.strOperateCode; }
public <T> T getPara(IRequest request, Class paraClass) { String strRead = request.read(); T para = JsonFactory.create().fromJson(strRead, paraClass); return para; }
protected Class getParaClass() { return HashMap.class; }
public final String getResourceCode() { return this.strResourceCode; }
protected void handleBusinessException(BusinessException ex) { String strMsg = null; if (ex instanceof BizLockFailedException) { strMsg = NCLangRes4VoTransl.getNCLangRes().getStrByID("uif2", "DefaultExceptionHanler-000004"); } else if (ex instanceof LockFailedException) { strMsg = NCLangRes4VoTransl.getNCLangRes().getStrByID("uif2", "DefaultExceptionHanler-000000"); } else if (ex instanceof ValidationException) { strMsg = ((ValidationException)ex).getMessage(); } else if (ex instanceof VersionConflictException) { strMsg = NCLangRes4VoTransl.getNCLangRes().getStrByID("uif2", "DefaultExceptionHanler-000002"); } else { strMsg = ex.getMessage(); }
ExceptionUtils.wrapBusinessException(strMsg); }
protected void handleException(Exception ex) { Throwable ex2 = ExceptionUtils.unmarsh(ex); Logger.error("**************************************************** NCCAction Error ****************************************************"); Logger.error(ex2.getMessage(), ex); if (ex2 instanceof RuntimeException) { this.handleRuntimeException((RuntimeException)ex2); } else if (ex2 instanceof BusinessException) { this.handleBusinessException((BusinessException)ex2); } else { this.handleUnknownException(ex2); }
} protected void handleRuntimeException(RuntimeException ex) { if (ex instanceof FrameworkSecurityException) { ExceptionUtils.wrapBusinessException(NCLangRes4VoTransl.getNCLangRes().getStrByID("uif2", "DefaultExceptionHanler-000006")); } else if (ex instanceof BusinessExceptionAdapter) { this.handleBusinessException(((BusinessExceptionAdapter)ex).originalException); } else if (!(ex instanceof nccloud.base.exception.BusinessException) && !(ex instanceof nccloud.framework.core.exception.BusinessException)) { this.handleUnknownException(ex); } else { this.handleUnknownException(ex); }
} protected void handleUnknownException(Throwable ex) { String strMsg = ex.getMessage(); if (StringUtils.isBlank(strMsg)) { strMsg = NCLangRes4VoTransl.getNCLangRes().getStrByID("uif2", "DefaultExceptionHanler-000001"); }
BusinessException business = new BusinessException(strMsg); business.setStackTrace(ex.getStackTrace()); ExceptionUtils.wrapException(business); }
public void setMdOperateCode(String mdOperateCode) { this.strMdOperateCode = mdOperateCode; }
public void setOperateCode(String operateCode) { this.strOperateCode = operateCode; }
public void setResourceCode(String resourceCode) { this.strResourceCode = resourceCode; } }
|
5.3 IRefSqlBuilder
1 2 3 4 5 6 7 8 9 10 11
| public interface IRefSqlBuilder { String getExtraSql(RefQueryInfo var1, RefMeta var2);
SqlParameterCollection getExtraSqlParameter(RefQueryInfo var1, RefMeta var2);
String getOrderSql(RefQueryInfo var1, RefMeta var2); }
|
5.4 AbstractRefAction
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
| public abstract class AbstractRefAction extends NCCAction implements IRefSqlBuilder { private Boolean blShowDisabledData = null; private String strDataPowerColumn; private String strMdClassId; private String strUnitPkKey = null; private String strUsualDataPkFieldName = null; private String strUsualDataTableName = null;
public AbstractRefAction() {}
public <T> Object execute(IRequest request, T para) throws Exception { TreeRefQueryInfo refQueryInfo = (TreeRefQueryInfo) para; Map<String, String> queryCondition = refQueryInfo.getQueryCondition(); boolean isShowUsual = UFBoolean.valueOf(queryCondition.get("isShowUsual")).booleanValue();
if (isShowUsual) { String strUsualGridRefActionExt = queryCondition.get("UsualGridRefActionExt"); strUsualGridRefActionExt = StringUtils.isBlank(strUsualGridRefActionExt) ? UsualRefSqlBuilder.class.getName() : strUsualGridRefActionExt + "," + UsualRefSqlBuilder.class.getName(); String gridRefActionExts = queryCondition.get("GridRefActionExt"); gridRefActionExts = StringUtils.isBlank(gridRefActionExts) ? strUsualGridRefActionExt : gridRefActionExts + "," + strUsualGridRefActionExt; queryCondition.put("GridRefActionExt", gridRefActionExts);
if (StringUtils.isBlank(this.getQueryValue(refQueryInfo, "unitPks"))) { this.setQueryValue(refQueryInfo, "unitPks", this.getPk_org(refQueryInfo)); } } else { this.initPageInfo(refQueryInfo.getPageInfo()); }
this.initUnitPk(refQueryInfo, this.getKeyUnitPks());
RefQueryResult refQueryResult = this.processData(refQueryInfo); return refQueryResult; }
public final String getDataPowerColumn(RefQueryInfo refQueryInfo, RefMeta refMeta) { return StringUtils.isBlank(this.strDataPowerColumn) ? refMeta.getPkField() : this.strDataPowerColumn; }
public String getExtraSql(RefQueryInfo refQueryInfo, RefMeta refMeta) { return null; }
public SqlParameterCollection getExtraSqlParameter(RefQueryInfo refQueryInfo, RefMeta refMeta) { return null; }
protected RefVO_mlang[] getMultiLangRefVO() { return null; }
protected String getMultiLangResource(String strDirName, String strFieldValue, String strResId) { return NCLangRes4VoTransl.getNCLangRes().getString(strDirName, strFieldValue, strResId); }
public abstract RefMeta getRefMeta(RefQueryInfo var1);
protected IRefSqlBuilder getRefSqlBuilder(RefQueryInfo refQueryInfo) { return new DefaultRefSqlBuilder(this, this, refQueryInfo); }
protected void initUnitPk(RefQueryInfo refQueryInfo, String strQueryKey) { if (!StringUtils.isBlank(strQueryKey)) { String[] strUnitPks = this.getUnitPks(refQueryInfo); if (!ArrayUtils.isEmpty(strUnitPks) && !StringUtils.isBlank(strUnitPks[0])) { this.setQueryValue(refQueryInfo, strQueryKey, strUnitPks[0]); } } }
protected abstract RefQueryResult processData(TreeRefQueryInfo var1);
protected void processMultiLang(RefQueryInfo refQueryInfo, RefRow refRow) { RefVO_mlang[] multiLangRefVOs = this.getMultiLangRefVO(); if (!ArrayUtils.isEmpty(multiLangRefVOs)) { Map<String, Cell> mapRowValues = refRow.getValues(); for (RefVO_mlang mlRefVO : multiLangRefVOs) { String strResId = mlRefVO.getPreStr(); String[] strResIdFieldNames = mlRefVO.getResIDFieldNames();
if (!ArrayUtils.isEmpty(strResIdFieldNames)) { for (String fieldName : strResIdFieldNames) { Object objValue = mapRowValues.get(fieldName).getValue(); if (objValue != null) { strResId += objValue.toString(); } }
Object objFieldValue = mapRowValues.get(mlRefVO.getFieldName()).getValue(); String strDirName = mlRefVO.getDirName(); if (mlRefVO.getDirFieldName() != null) { Object objDirFieldName = mapRowValues.get(mlRefVO.getDirFieldName()).getValue(); if (objDirFieldName != null) { strDirName = objDirFieldName.toString(); } }
String strFieldValue = objFieldValue == null ? null : objFieldValue.toString(); String strMultiLang = this.getMultiLangResource(strDirName, strFieldValue, strResId); mapRowValues.get(mlRefVO.getFieldName()).setValue(strMultiLang);
RefMeta refMeta = this.getRefMeta(refQueryInfo); if (refMeta != null && ObjectUtils.equals(refMeta.getNameField(), mlRefVO.getFieldName())) { refRow.setRefname(strMultiLang); } } } } }
protected void processMultiLangForEnum(RefQueryInfo refQueryInfo, RefRow refRow) { Map<String, Map<String, String>> mapRes = this.getMultiLangForEnum(); if (!MapUtils.isEmpty(mapRes)) { Map<String, Cell> mapRowValues = refRow.getValues(); for (String strEnumFieldName : mapRes.keySet()) { Cell cell = mapRowValues.get(strEnumFieldName); Object objFieldValue = cell.getValue(); String strMultiLang = mapRes.get(strEnumFieldName).get(objFieldValue); cell.setValue(strMultiLang); } } }
protected String[] processRefPks(RefQueryInfo refQueryInfo, IRefSqlBuilder refSqlBuilder, String... strQueryRefPks) { return strQueryRefPks; }
protected RefRow[] processRefRows(RefQueryInfo refQueryInfo, IRefSqlBuilder refSqlBuilder, RefRow... refRows) { if (!ArrayUtils.isEmpty(refRows)) { for (RefRow refRow : refRows) { this.processMultiLang(refQueryInfo, refRow); this.processMultiLangForEnum(refQueryInfo, refRow); } } return refRows; }
public void setQueryValue(RefQueryInfo refQueryInfo, String strQueryKey, String strQueryValue) { refQueryInfo.getQueryCondition().put(strQueryKey, strQueryValue); } }
|
5.5 DefaultGridRefAction
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public abstract class DefaultGridRefAction extends AbstractRefAction { public DefaultGridRefAction() { }
public abstract RefMeta getRefMeta(RefQueryInfo var1);
@Deprecated protected void initPageInfo(PageInfo pageInfo) { }
protected RefQueryResult processData(TreeRefQueryInfo refQueryInfo) { IRefSqlBuilder refSqlBuilder = this.getRefSqlBuilder(refQueryInfo); NCGridRefDBProcessor processor = new NCGridRefDBProcessor(this.getRefMeta(refQueryInfo), refSqlBuilder); String[] strQueryRefPks = processor.queryRefPks(refQueryInfo); strQueryRefPks = this.processRefPks(refQueryInfo, refSqlBuilder, strQueryRefPks); RefRow[] refRows = processor.getRowsByPks(strQueryRefPks); refRows = this.processRefRows(refQueryInfo, refSqlBuilder, refRows); RefQueryResult refQueryResult = processor.constructResult(refRows, refQueryInfo); return refQueryResult; } }
|
5.6 NCGridRefDBProcesso
5.7 Tax_hws_serviceDefaultGridRefAction
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class Tax_hws_serviceDefaultGridRefAction extends DefaultGridRefAction { public Tax_hws_serviceDefaultGridRefAction() { super(); setResourceCode(IOrgResourceCodeConst.ORG); }
@Override public RefMeta getRefMeta(RefQueryInfo refQueryInfo) { RefMeta refMeta = new RefMeta(); setResourceCode(IOrgResourceCodeConst.ORG); refMeta.setCodeField("code"); refMeta.setNameField("name"); refMeta.setPkField("pk_vtax_tax_hws_service"); refMeta.setTableName("vtax_tax_hws_service"); refMeta.setMutilLangNameRef(true); return refMeta; }
}
|
6.参照前端



点击(事件)参照表格后返回的 json 对象:


7.YonBIP 参照创建(应用注册)




8.讲解思路
- 模型层 (Model)
NCGridRefDBProcessor
IRefSqlBuilder
INCDataQuery
IMultiNCGridRefRowService
ServiceLocator
- 视图层 (View)
Refer
组件(前端 React 组件)
- 控制器层 (Controller)
DefaultGridRefAction
AbstractRefAction
NCCAction
9.参照前端(React)
参照前端的相关属性配置
前端主要设置了参照的相关属性,包括多余配置(领域模块名、默认语言、多语文件);
选择生成的参照类型(grid-表型参照;tree-树形参照;gridtree-树表型参照);
refName
为参照标题名字,
placeholder
是指参照输入框的占位提示文字,即在输入框中还未输入任何内容时,会显示的提示文本。
columnConfig
定义了参照弹窗中表格的列配置,决定了弹窗中展示的数据列和它们的顺序。这个配置通常与我们的业务需要相关,业务需要列显示什么字段就进行配置;
queryGridUrl
是后端接口路径,用于从后端获取参照数据。当参照组件加载时,系统会使用这个 URL 发送请求,以获得可以选择的具体数据列表。
1 2 3
| columnConfig: [{name: ['编码', '名称'], code: ['refcode', 'refname']}]
|
10.参照后端(Java)-MVC 模式讲解
1.参照类Tax_hws_serviceDefaultGridRefAction
Tax_hws_serviceDefaultGridRefAction
类是整个参照功能的入口类,继承自 DefaultGridRefAction
,该类主要用于处理用户从前端触发的参照请求,并生成查询参照数据的关键元数据。在这个类中,我们看到最核心的部分是 getRefMeta()
方法,它构建并返回 RefMeta
对象,表示参照的元数据定义。
getRefMeta(RefQueryInfo refQueryInfo)
这个方法是 Tax_hws_serviceDefaultGridRefAction
的核心方法,负责构建并返回参照元数据 RefMeta
,这个对象包含了参照所需的所有信息(如字段名、表名、主键等),这些信息用于后续的 SQL 查询和数据展示。包括以下几部分:
- 编码字段:
codeField
是 code
,表示在表格中展示的每条记录的编码字段。
- 名称字段:
nameField
是 name
,对应表格中展示的记录名称字段。
- 主键字段:
pkField
是 pk_vtax_tax_hws_service
,这是数据库表 vtax_tax_hws_service
的主键字段,用于标识每条记录。
- 表名:
tableName
是 vtax_tax_hws_service
,表示从数据库中查询的表名。
- 多语言支持:通过
setMutilLangNameRef(true)
说明参照支持多语言。
主要作用
- 定义当前参照的元数据,包括参照表的名称、参照字段(编码、名称、主键)以及是否支持多语言。
- 通过
getRefMeta()
返回 RefMeta
,为 DefaultGridRefAction
的核心查询逻辑提供必要的元数据信息。
- 配置数据权限控制和是否显示被停用数据等业务规则(如
setResourceCode
和 setShowDisabledData
)。
RefMeta
存储的数据示例:
Code Field: code
Name Field: name
PK Field: pk_vtax_tax_hws_service
Table Name: vtax_tax_hws_service
Multi-language Support: true

10.2DefaultGridRefAction
DefaultGridRefAction
是一个抽象类,继承自 AbstractRefAction
,它为表格参照功能提供了默认的实现。DefaultGridRefAction
中定义了参照功能的几个核心方法,帮助处理参照的查询逻辑,尤其是通过 processData()
方法完成对数据的查询与处理。
NCGridRefDBProcessor
是负责实际数据库查询的处理器,它结合 RefMeta
和 IRefSqlBuilder
生成 SQL 语句,执行查询,并将结果封装成 RefRow[]
和 RefQueryResult
。
getRefMeta()
:返回 RefMeta
对象,定义参照功能的数据结构,如字段、表名等。
processData()
:processData()
方法是整个数据查询的核心步骤,它负责通过 TreeRefQueryInfo
进行 SQL 查询构造,执行查询,处理主键与字段数据,最后返回一个查询结果集。
- 职责:
- 执行查询逻辑:根据
Tax_hws_serviceDefaultGridRefAction
中返回的 RefMeta
,以及前端传递的查询条件,生成 SQL 查询,并执行查询。
- 数据处理:通过数据库处理器(
NCGridRefDBProcessor
)进行主键查询、字段查询,并进一步处理查询出的数据。
- 返回查询结果:最终将处理后的参照数据封装为
RefQueryResult
对象,返回给前端。
- DefaultGridRefAction.java(核心处理逻辑类)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| public abstract class DefaultGridRefAction extends AbstractRefAction { public DefaultGridRefAction() { }
public abstract RefMeta getRefMeta(RefQueryInfo var1);
@Deprecated protected void initPageInfo(PageInfo pageInfo) { }
protected RefQueryResult processData(TreeRefQueryInfo refQueryInfo) { IRefSqlBuilder refSqlBuilder = this.getRefSqlBuilder(refQueryInfo); NCGridRefDBProcessor processor = new NCGridRefDBProcessor(this.getRefMeta(refQueryInfo), refSqlBuilder); String[] strQueryRefPks = processor.queryRefPks(refQueryInfo); strQueryRefPks = this.processRefPks(refQueryInfo, refSqlBuilder, strQueryRefPks); RefRow[] refRows = processor.getRowsByPks(strQueryRefPks); refRows = this.processRefRows(refQueryInfo, refSqlBuilder, refRows); RefQueryResult refQueryResult = processor.constructResult(refRows, refQueryInfo); return refQueryResult; } }
|
10.3 AbstractRefAction.java
AbstractRefAction
提供了很多参照功能中的基础逻辑,如数据权限、多语言处理、SQL 构建等。它通过接口 IRefSqlBuilder
实现 SQL 查询构建,并为参照功能提供了灵活的扩展接口。
DefaultRefSqlBuilder
会使用 RefQueryInfo
中存储的条件,包括组织、集团 ID 和其他过滤条件,这些都是由入口类或 AbstractRefAction
设置的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
| public abstract class AbstractRefAction extends NCCAction implements IRefSqlBuilder { private Boolean blShowDisabledData = null; private String strDataPowerColumn; private String strMdClassId; private String strUnitPkKey = null; private String strUsualDataPkFieldName = null; private String strUsualDataTableName = null;
public AbstractRefAction() {}
public <T> Object execute(IRequest request, T para) throws Exception { TreeRefQueryInfo refQueryInfo = (TreeRefQueryInfo) para; Map<String, String> queryCondition = refQueryInfo.getQueryCondition(); boolean isShowUsual = UFBoolean.valueOf(queryCondition.get("isShowUsual")).booleanValue(); if (isShowUsual) { String strUsualGridRefActionExt = queryCondition.get("UsualGridRefActionExt"); strUsualGridRefActionExt = StringUtils.isBlank(strUsualGridRefActionExt) ? UsualRefSqlBuilder.class.getName() : strUsualGridRefActionExt + "," + UsualRefSqlBuilder.class.getName(); String gridRefActionExts = queryCondition.get("GridRefActionExt"); gridRefActionExts = StringUtils.isBlank(gridRefActionExts) ? strUsualGridRefActionExt : gridRefActionExts + "," + strUsualGridRefActionExt; queryCondition.put("GridRefActionExt", gridRefActionExts); if (StringUtils.isBlank(this.getQueryValue(refQueryInfo, "unitPks"))) { this.setQueryValue(refQueryInfo, "unitPks", this.getPk_org(refQueryInfo)); } } else { this.initPageInfo(refQueryInfo.getPageInfo()); } this.initUnitPk(refQueryInfo, this.getKeyUnitPks()); RefQueryResult refQueryResult = this.processData(refQueryInfo); return refQueryResult; }
public String getExtraSql(RefQueryInfo refQueryInfo, RefMeta refMeta) { return null; }
public SqlParameterCollection getExtraSqlParameter(RefQueryInfo refQueryInfo, RefMeta refMeta) { return null; } public String getPk_org(RefQueryInfo refQueryInfo) { String strPk_org = this.getQueryValue(refQueryInfo, "pk_org"); return StringUtils.isBlank(strPk_org) ? this.getPk_group(refQueryInfo) : strPk_org; } public String getPk_group(RefQueryInfo refQueryInfo) { String strPk_group_session = SessionContext.getInstance().getClientInfo().getPk_group(); if (refQueryInfo == null) { return strPk_group_session; } else { String strPk_group2 = this.getQueryValue(refQueryInfo, "pk_group"); return StringUtils.isBlank(strPk_group2) ? strPk_group_session : strPk_group2; } }
protected IRefSqlBuilder getRefSqlBuilder(RefQueryInfo refQueryInfo) { return new DefaultRefSqlBuilder(this, this, refQueryInfo); } protected void processMultiLang(RefQueryInfo refQueryInfo, RefRow refRow) { RefVO_mlang[] multiLangRefVOs = this.getMultiLangRefVO(); if (!ArrayUtils.isEmpty(multiLangRefVOs)) { Map<String, Cell> mapRowValues = refRow.getValues(); for (RefVO_mlang mlRefVO : multiLangRefVOs) { String strResId = mlRefVO.getPreStr(); String[] strResIdFieldNames = mlRefVO.getResIDFieldNames();
if (!ArrayUtils.isEmpty(strResIdFieldNames)) { for (String fieldName : strResIdFieldNames) { Object objValue = mapRowValues.get(fieldName).getValue(); if (objValue != null) { strResId += objValue.toString(); } }
Object objFieldValue = mapRowValues.get(mlRefVO.getFieldName()).getValue(); String strDirName = mlRefVO.getDirName(); if (mlRefVO.getDirFieldName() != null) { Object objDirFieldName = mapRowValues.get(mlRefVO.getDirFieldName()).getValue(); if (objDirFieldName != null) { strDirName = objDirFieldName.toString(); } }
String strFieldValue = objFieldValue == null ? null : objFieldValue.toString(); String strMultiLang = this.getMultiLangResource(strDirName, strFieldValue, strResId); mapRowValues.get(mlRefVO.getFieldName()).setValue(strMultiLang);
RefMeta refMeta = this.getRefMeta(refQueryInfo); if (refMeta != null && ObjectUtils.equals(refMeta.getNameField(), mlRefVO.getFieldName())) { refRow.setRefname(strMultiLang); } } } } }
protected void processMultiLangForEnum(RefQueryInfo refQueryInfo, RefRow refRow) { Map<String, Map<String, String>> mapRes = this.getMultiLangForEnum(); if (!MapUtils.isEmpty(mapRes)) { Map<String, Cell> mapRowValues = refRow.getValues(); for (String strEnumFieldName : mapRes.keySet()) { Cell cell = mapRowValues.get(strEnumFieldName); Object objFieldValue = cell.getValue(); String strMultiLang = mapRes.get(strEnumFieldName).get(objFieldValue); cell.setValue(strMultiLang); } } }
protected String[] processRefPks(RefQueryInfo refQueryInfo, IRefSqlBuilder refSqlBuilder, String... strQueryRefPks) { return strQueryRefPks; }
protected RefRow[] processRefRows(RefQueryInfo refQueryInfo, IRefSqlBuilder refSqlBuilder, RefRow... refRows) { if (!ArrayUtils.isEmpty(refRows)) { for (RefRow refRow : refRows) { this.processMultiLang(refQueryInfo, refRow); this.processMultiLangForEnum(refQueryInfo, refRow); } } return refRows; }
}
|
10.4NCCAction
NCCAction
是一个抽象基础类,定义了通用的操作流程和错误处理机制,为具体的业务逻辑类(例如参照功能类)提供支持。
NCCAction
提供了执行业务操作的通用流程,并定义了 doAction()
方法,作为所有具体操作类的执行入口。在参照功能中,这个类的主要作用包括以下几方面:
- 标准化的操作流程:
doAction()
定义了操作执行的通用流程,包含参数获取(getPara
)、预处理(doBeforeAction
)、实际执行(execute
)、后处理(doAfterSuccess
)和异常处理(handleException
)。
- 权限校验:
checkDataPermission()
方法用于数据权限校验,确保只有符合权限的数据可以被访问。
- 异常处理:
handleException()
和 handleBusinessException()
处理不同类型的异常,确保系统稳定运行,并将合适的错误信息返回给用户。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
|
public abstract class NCCAction implements ICommonAction { private String strMdOperateCode = null; private String strOperateCode = null; private String strResourceCode = null;
public NCCAction() { }
protected void checkDataPermission(IRequest request, Object objData) throws Exception { DataPermissionAction dataPermissionAction = new DataPermissionAction(); ValidationException validException = dataPermissionAction.checkDataPermission(this.getResourceCode(), this.getMdOperateCode(), this.getOperateCode(), objData); dataPermissionAction.dealValidationException(validException); }
public final Object doAction(IRequest request) { Logger.debug("begin action-->" + this.getClass().getName() + ".doAction()"); Object para = null; Object result = null;
try { para = this.getPara(request, this.getParaClass()); if (!this.doBeforeAction(request, para)) { Object var10 = result; return var10; }
result = this.execute(request, para); this.doAfterSuccess(request, para); } catch (Exception var8) { Exception ex = var8; this.doAfterFailure(request, para); this.handleException(ex); } finally { Logger.debug("end action-->" + this.getClass().getName() + ".doAction()"); }
return result; }
protected <T> void doAfterFailure(IRequest request, T para) { }
protected <T> void doAfterSuccess(IRequest request, T para) throws Exception { }
protected <T> boolean doBeforeAction(IRequest request, T para) throws Exception { return true; }
public abstract <T> Object execute(IRequest var1, T var2) throws Exception; public final String getMdOperateCode() { return this.strMdOperateCode; }
public final String getOperateCode() { return this.strOperateCode; }
public <T> T getPara(IRequest request, Class paraClass) { String strRead = request.read(); T para = JsonFactory.create().fromJson(strRead, paraClass); return para; }
protected Class getParaClass() { return HashMap.class; }
public final String getResourceCode() { return this.strResourceCode; }
protected void handleBusinessException(BusinessException ex) { String strMsg = null; if (ex instanceof BizLockFailedException) { strMsg = NCLangRes4VoTransl.getNCLangRes().getStrByID("uif2", "DefaultExceptionHanler-000004"); } else if (ex instanceof LockFailedException) { strMsg = NCLangRes4VoTransl.getNCLangRes().getStrByID("uif2", "DefaultExceptionHanler-000000"); } else if (ex instanceof ValidationException) { strMsg = ((ValidationException)ex).getMessage(); } else if (ex instanceof VersionConflictException) { strMsg = NCLangRes4VoTransl.getNCLangRes().getStrByID("uif2", "DefaultExceptionHanler-000002"); } else { strMsg = ex.getMessage(); }
ExceptionUtils.wrapBusinessException(strMsg); }
protected void handleException(Exception ex) { Throwable ex2 = ExceptionUtils.unmarsh(ex); Logger.error("**************************************************** NCCAction Error ****************************************************"); Logger.error(ex2.getMessage(), ex); if (ex2 instanceof RuntimeException) { this.handleRuntimeException((RuntimeException)ex2); } else if (ex2 instanceof BusinessException) { this.handleBusinessException((BusinessException)ex2); } else { this.handleUnknownException(ex2); }
} protected void handleRuntimeException(RuntimeException ex) { if (ex instanceof FrameworkSecurityException) { ExceptionUtils.wrapBusinessException(NCLangRes4VoTransl.getNCLangRes().getStrByID("uif2", "DefaultExceptionHanler-000006")); } else if (ex instanceof BusinessExceptionAdapter) { this.handleBusinessException(((BusinessExceptionAdapter)ex).originalException); } else if (!(ex instanceof nccloud.base.exception.BusinessException) && !(ex instanceof nccloud.framework.core.exception.BusinessException)) { this.handleUnknownException(ex); } else { this.handleUnknownException(ex); }
} protected void handleUnknownException(Throwable ex) { String strMsg = ex.getMessage(); if (StringUtils.isBlank(strMsg)) { strMsg = NCLangRes4VoTransl.getNCLangRes().getStrByID("uif2", "DefaultExceptionHanler-000001"); }
BusinessException business = new BusinessException(strMsg); business.setStackTrace(ex.getStackTrace()); ExceptionUtils.wrapException(business); }
public void setMdOperateCode(String mdOperateCode) { this.strMdOperateCode = mdOperateCode; }
public void setOperateCode(String operateCode) { this.strOperateCode = operateCode; }
public void setResourceCode(String resourceCode) { this.strResourceCode = resourceCode; } }
|
10.5 NCGridRefDBProcessor
NCGridRefDBProcessor
是参照功能中具体负责执行数据库操作的核心类,它处理参照数据的查询、结果处理等功能。
- 这个类的主要任务是通过与
RefMeta
和 RefQueryInfo
协作,生成 SQL 查询语句并执行它,最终返回参照数据。这类的主要方法包括 queryRefPks()
、getRowsByPks()
和 constructResult()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
| @Override public String[] queryRefPks(RefQueryInfo para) { this.refQueryInfo = para; PageInfo page = para.getPageInfo(); String[] pks = null; if (this.getFulTxtFlg(para)) { pks = this.qryByFulltxt(para); } else { if (page.getPageIndex() == -1) { pks = this.queryAll(para); } else { pks = this.queryByPage(para, page); } } return pks; }
public void setMaxRows(int maxRows) { this.maxRows = maxRows; }
public String getQueryIDSql(RefQueryInfo para) { this.refQueryInfo = para; StringBuilder sb = new StringBuilder(); sb.append(" select ").append(this.refMeta.getPkField()).append(" from ").append(this.refMeta.getTableName()); sb.append(" where 1 = 1 "); if (para.getSearchPks() != null && para.getSearchPks().length > 0) { sb.append(" and ").append(this.refMeta.getPkField()).append(" in ("); for (String pk : para.getSearchPks()) { sb.append("'").append(pk).append("',"); } sb.deleteCharAt(sb.length() - 1); sb.append(")"); } sb.append(this.getWhereSql(para)); sb.append(this.getOrderSql(para)); return sb.toString(); }
public RefRow[] getRowsByPks(String[] pks) { IMultiNCGridRefRowService service = ServiceLocator.find(IMultiNCGridRefRowService.class); SqlParameterCollection collection = this.getSqlParameterCollection(this.refQueryInfo); NCRefRow[] rows = service.getRowsByPksAndWheresql(this.getMeta(), pks, this.wheresql, collection); RefRow[] ret = this.convert(rows); return ret; }
public RefQueryResult constructResult(RefRow[] rows, RefQueryInfo para) { RefQueryResult result = new RefQueryResult(); result.setRows(rows); PageInfo page = para.getPageInfo(); int totalPageNum = (this.total + page.getPageSize() - 1) / page.getPageSize(); page.setTotalPage(totalPageNum); result.setPage(page); return result; }
|
整个参照流程包括前端发送查询条件、后端接收和解析条件、生成 SQL 查询并执行数据库查询、数据权限和多语言处理、最终将结果返回前端并展示。在这一过程中,涉及多类协同工作,确保查询高效、灵活,同时满足权限和多语言需求。
具体流程
1. 前端请求阶段
用户在前端页面上操作,可能选择某个字段的参照功能(例如选择某个服务项目),页面会展示一个参照弹窗,允许用户根据关键字搜索、分页浏览或选择组织等条件过滤数据。用户输入的查询条件会通过 AJAX 请求或其他方式,发送到后端 API。
2. 后端接收请求并初始化查询
2.1 NCCAction.doAction()
作为操作入口
NCCAction
是后端接收请求的入口类,通过 doAction()
方法接收用户的查询请求。
doAction()
调用 getPara()
方法读取并解析前端传来的查询条件,将其封装为 RefQueryInfo
对象,包含查询关键字、分页信息、过滤条件(如组织、主键过滤)等。
2.2 执行 AbstractRefAction.execute()
处理查询条件
- 在
NCCAction
中调用 execute()
方法,此时进入 AbstractRefAction
类中实现的 execute()
方法。
execute()
方法负责解析 RefQueryInfo
中的查询条件:
- 判断是否显示常用数据,如果是,则会附加
UsualRefSqlBuilder
的 SQL 构建逻辑。
- 检查并设置
unitPks
(组织主键),为参照查询增加组织过滤。
- 初始化
PageInfo
,用于分页显示数据。
- 最终,
execute()
方法调用 processData()
方法,正式进入参照数据的查询处理阶段。
3. 数据查询和处理阶段
3.1 DefaultGridRefAction.processData()
生成查询 SQL
processData()
方法首先会获取 SQL 构建器 IRefSqlBuilder
,该对象生成参照功能的 SQL 语句。
processData()
负责生成查询 SQL,并调用数据库查询处理类 NCGridRefDBProcessor
执行查询。
3.2 NCGridRefDBProcessor.queryRefPks()
查询符合条件的主键
- 在
NCGridRefDBProcessor
中,queryRefPks()
方法会根据查询条件生成 SQL 语句:
- 判断是否需要进行全文检索,如需要则调用
qryByFulltxt()
,否则按页面分页信息决定调用 queryAll()
或 queryByPage()
。
- 执行查询后,
queryRefPks()
返回符合条件的主键数组。
3.3 NCGridRefDBProcessor.getRowsByPks()
查询参照数据行
- 根据
queryRefPks()
返回的主键数组,getRowsByPks()
会执行进一步的 SQL 查询,获取每条参照数据的完整行。
- 结果以
NCRefRow[]
的格式返回,其中包含了每一行的编码、名称、主键等字段信息。
- 系统会将
NCRefRow[]
转换为 RefRow[]
格式,这是前端更适合使用的数据格式。
3.4 NCGridRefDBProcessor.constructResult()
封装结果
constructResult()
方法将查询到的数据行 RefRow[]
封装为 RefQueryResult
对象。
- 它还会处理分页信息,如计算总页数,设置
PageInfo
等,确保数据分页返回符合用户请求。
4. 数据权限、多语言处理阶段
在 processData()
中,数据行会进一步经过权限控制和多语言处理,确保符合用户权限的控制要求。processMultiLang()
会处理多语言转换,processRefPks()
则进行主键过滤和权限控制,确保只有符合权限的数据行被返回。
5. 返回结果给前端
- 最终,
execute()
返回 RefQueryResult
对象,doAction()
将该结果封装并返回给前端。
- 前端接收
RefQueryResult
数据,该数据包含查询到的参照数据行和分页信息。
6. 前端展示结果
- 前端接收到后端返回的参照数据,将其展示在参照弹窗中。用户可以浏览分页内容、查看参照的名称和编码等字段。
- 用户可以进一步选择或确认某个参照值,从而完成整个参照功能的交互流程。