runtime.md 5.38 KB

The runtime: BusinessBaseController & friends

xlyEntry/src/main/java/com/xly/web/businessweb/ is where the metadata-driven runtime lives — 51 controllers, of which a few do all the heavy lifting. This page is the maintainer's map of those classes.

The load-bearing controllers

Class Role Most-cited endpoints
BusinessBaseController Universal CRUD for metadata-driven modules. The default API surface for every form. /business/getModelBysId/{moduleId}, /business/getBusinessDataByFormcustomId/{formId}, /business/addUpdateDelBusinessData, /business/getSelectDataBysControlId/{controlId}
BusinessConfigformController The BACK builder's API for editing form definitions. endpoints under /business/configform/*
BusinessModelCenterController The BACK module-tree manager. endpoints around gdsmodule CRUD
BusinessTreeGridController Tree-grid widget for hierarchical forms. renders sParentId-linked records as a tree
BusinessParameterController Reads / writes gdsparameter (system-wide named operations). parameter lookup and edit
FilterTreeController Saved-filter tree — the user's named search snippets in syssearch. filter CRUD
GenericProcedureCallController Generic stored-procedure invocation by name + parameters. dispatch arbitrary procs
CharController Chart configuration runtime — reads gdsconfigchar*. chart fetch
ConfigformPanelController Multi-panel form config editor. layout edit
BillController Document-bill helpers (bill numbers, status). bill numbering, billing helpers

The remaining 41 are more specific (calculation, work-order helpers, mobile, AI, comparator-tree, etc.).

The four-table read

For any metadata-driven module, the request lifecycle (see Concepts → request lifecycle) boils down to:

public Map<String, Object> getModelBysId(Map<String, Object> map) {
    List<Map<String, Object>> formList = this.getModelConfigByModleId(map);   // 1. join gdsmodule⋈form-master⋈form-slave
    List<Map<String, Object>> fList = businessGdsconfigformsService.getFormconstData(qMap);   // 2. gdsformconst
    List<Map<String, Object>> jList = businessGdsconfigformsService.getJurisdictionData(qMap); // 3. gdsjurisdiction (skipped for ADMIN)
    Map<String, Object> billnosettingMap = businessGdsconfigformsService.getBillnosettingData(param); // 4. sysbillnosettings
    List<Map<String, Object>> reportList = printReportService.getReportData(qMap);            // 5. sysreport
    return composite(formList, fList, jList, billnosettingMap, reportList);
}

BusinessBaseServiceImpl.java:181-211. Read this method first; the rest of the runtime is variations on it.

The five-key composite returned

Key Source Frontend uses for
formData gdsmodulegdsconfigformmastergdsconfigformslave (+ overlays) Form layout
gdsformconst gdsformconst Form-level constants, dropdown labels
gdsjurisdiction gdsjurisdiction Per-button / per-data permissions
billnosetting sysbillnosettings Document numbering rules
report sysreport Print templates

The save endpoint

POST /business/addUpdateDelBusinessData — handler at BusinessBaseController.java:165-177 — bundles add+update+delete in one transactional batch. The frontend supplies sTable and a column map per row, in this shape:

{
  "addData":    [{"sTable": "<table>", "column": {"sId": "", ...}}],
  "updateData": [{"sTable": "<table>", "column": {"sId": "", ...}}],
  "delData":    [{"sTable": "<table>", "column": {"sId": "", ...}}]
}

When gdsmodule.sSaveProName is empty, the framework's default Add/Update path runs — AddDelUpdCommonServiceImpl.java. When it's populated, the named stored proc is invoked instead.

Multi-tenant boundary

Every controller method's first non-trivial line is:

RequestAddParamUtil.me().addParams(params, userInfo);

RequestAddParamUtil.java, 44 lines. This is the single point where the user's session identity (sBrandsId, sSubsidiaryId, sLoginId, sLanguage, sTeamId, sMachineId, …) is injected into the downstream params map. Every MyBatis query and stored-procedure call that references #{sBrandsId}/#{sSubsidiaryId} is automatically scoped from there.

A new controller method that doesn't call RequestAddParamUtil is a multi-tenant bug.

Security concerns to audit

Two flagged in slices that belong here permanently:

  1. sTable validation in addUpdateDelBusinessData. The frontend names the target table directly. The runtime must cross-check that the supplied table is one of the form's authorised backing tables, or it's a privilege-escalation surface. Confirm the check exists; if it doesn't, raise it as a security ticket. Tracked in the Slice 1 v2 follow-up.
  2. ADMIN bypasses permissions. BusinessBaseServiceImpl.java:196-198 skips the gdsjurisdiction load entirely for UserType.ADMIN. ADMIN account governance must come from outside the app.

Cache invalidation

When BACK saves a metadata change, a JMS message fires and ConsumerChangeGdsModuleThread (in xlyErpJmsConsumer) clears the cached metadata on every running node. See cache invalidation on metadata change.