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 |
gdsmodule ⋈ gdsconfigformmaster ⋈ gdsconfigformslave (+ 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:
-
sTablevalidation inaddUpdateDelBusinessData. 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. -
ADMIN bypasses permissions.
BusinessBaseServiceImpl.java:196-198skips thegdsjurisdictionload entirely forUserType.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.