Commit 353d74cec0bf0933eefd325c1d96bbad8aec310e
1 parent
955918bc
Add maintainer running-locally + tech-stack + notifications pages
en: - new: api-reference/notifications.md, reference/maintainer/running-locally.md, reference/maintainer/tech-stack.md - concepts/index.md: add Mermaid architecture diagram - index.md: scope-note MongoDB store as plat-tier - concepts/api-surface.md: point "the four-table read" link at the reference/maintainer/runtime.md anchor that actually contains the section - maintainer/index.md, api-reference/index.md, mkdocs.yml: nav + cross-links zh: - mirror translations of the new en pages, plus zh api-reference/* section
Showing
21 changed files
with
917 additions
and
4 deletions
en/docs/api-reference/index.md
| @@ -10,6 +10,7 @@ overview lives in [concepts/api-surface](../concepts/api-surface.md). | @@ -10,6 +10,7 @@ overview lives in [concepts/api-surface](../concepts/api-surface.md). | ||
| 10 | | [External API](external.md) | `xlyApi` | `/xlyApi` | You are integrating an outside system that calls xly. | | 10 | | [External API](external.md) | `xlyApi` | `/xlyApi` | You are integrating an outside system that calls xly. | |
| 11 | | [Webhooks](webhooks.md) | `xlyInterface` | `/xlyInterface` | A third-party system needs to push events into xly. | | 11 | | [Webhooks](webhooks.md) | `xlyInterface` | `/xlyInterface` | A third-party system needs to push events into xly. | |
| 12 | | [Messaging](messaging.md) | `xlyEntry` + `xlyErpJms*` | n/a (ActiveMQ / RocketMQ) | An asynchronous, fan-out integration is more appropriate than a synchronous HTTP call. | | 12 | | [Messaging](messaging.md) | `xlyEntry` + `xlyErpJms*` | n/a (ActiveMQ / RocketMQ) | An asynchronous, fan-out integration is more appropriate than a synchronous HTTP call. | |
| 13 | +| [Notifications](notifications.md) | `xlyMsg` (consumed as a library by `xlyEntry`, `xlyBusinessService`, `xlyInterface`) | n/a (DingTalk / WeChat APIs) | A business event needs to push a chat-platform message to a user. | | ||
| 13 | 14 | ||
| 14 | ## Reading order | 15 | ## Reading order |
| 15 | 16 |
en/docs/api-reference/notifications.md
0 → 100644
| 1 | +# Notifications (xlyMsg) | ||
| 2 | + | ||
| 3 | +Outbound notifications — DingTalk and WeChat — go through the `xlyMsg` | ||
| 4 | +module. This is *not* an HTTP surface that callers hit; it's an | ||
| 5 | +internal SDK that in-scope services call when a business event should | ||
| 6 | +push a message out to a chat platform. | ||
| 7 | + | ||
| 8 | +## What's inside | ||
| 9 | + | ||
| 10 | +`xlyMsg/src/main/java/com/xly/`: | ||
| 11 | + | ||
| 12 | +| Package | Role | | ||
| 13 | +|---|---| | ||
| 14 | +| `dingtalk/service/DingTalkService` + `dingtalk/util/SendDingTalkUtil`, `DingTalkMsgContentUtil`, `LocalCacheClient` | DingTalk corp-message dispatch. Wraps `com.aliyun:dingtalk:2.1.14` and `com.aliyun:alibaba-dingtalk-service-sdk:2.0.0`. | | ||
| 15 | +| `wechat/service/WechatService` + `wechat/util/SendWxUtil`, `Wx_SignatureUtil`, `JedisMsgUtil`, `MsgContentUtil`, `Xml2JsonUtil` | WeChat work-platform dispatch — signature + send, including a Redis-backed access-token cache. | | ||
| 16 | +| `notice/service/NoticeService` | Provider-agnostic notice abstraction; routes a logical "notify user X about event Y" to the right backend. | | ||
| 17 | + | ||
| 18 | +`xlyMsg/build.gradle` — sole framework dependency is `xlyPersist`. The | ||
| 19 | +module is consumed as a library, not deployed as its own service. | ||
| 20 | + | ||
| 21 | +## Who calls it (in-scope callers) | ||
| 22 | + | ||
| 23 | +This is what makes `xlyMsg` framework-relevant rather than plat-tier: | ||
| 24 | + | ||
| 25 | +| Caller | What it does | | ||
| 26 | +|---|---| | ||
| 27 | +| `xlyEntry/.../web/businessweb/TestController.java` | Diagnostic endpoint to fire a test DingTalk message. | | ||
| 28 | +| `xlyBusinessService/.../thread/UpdateDingTalkThread.java` | Async worker that pushes DingTalk updates after document changes. | | ||
| 29 | +| `xlyBusinessService/.../service/impl/CheckExamineFlowServiceImpl.java` | Workflow approval notifications — when an Activiti task is reassigned or completed, the assignee gets a chat message. | | ||
| 30 | +| `xlyBusinessService/.../service/impl/GenericProcedureCallServiceImpl.java` | Generic-proc hook: any `gdsmodule` proc that opts in can publish a notice through this path. | | ||
| 31 | +| `xlyInterface/.../util/DingTalkUtil.java` + `scheduler/ScheduledTasks.java`, `ErpJobRunStatus.java` | Scheduled-job heartbeat / failure alerts on the integration side. | | ||
| 32 | + | ||
| 33 | +## Configuration | ||
| 34 | + | ||
| 35 | +Credentials (DingTalk corp-app key/secret, WeChat AppID, agent IDs) are | ||
| 36 | +read from environment-specific yaml profiles. There is no global | ||
| 37 | +default — each customer deployment fills its own values, which is why | ||
| 38 | +the framework wiki cannot give a canonical example. Look at the active | ||
| 39 | +profile yaml under `xlyEntry/src/main/resources/application-<env>.yml` | ||
| 40 | +for the keys actually consumed. | ||
| 41 | + | ||
| 42 | +The WeChat path uses Redis for access-token caching | ||
| 43 | +(`wechat/util/JedisMsgUtil.java`) — same Redis instance the rest of | ||
| 44 | +the framework uses. See [Multi-service deployment](../reference/maintainer/deployment.md) | ||
| 45 | +for the broader picture of which services share which Redis. | ||
| 46 | + | ||
| 47 | +## What this is not | ||
| 48 | + | ||
| 49 | +- **Not** an inbound webhook receiver. DingTalk callbacks (e.g., | ||
| 50 | + approval-button clicks) go through `xlyInterface` with the rest of | ||
| 51 | + the [webhooks](webhooks.md). | ||
| 52 | +- **Not** the `xlyPlat*` push-notification path. The plat tier has | ||
| 53 | + its own channel (`xlyPlatSmsService`, JPush, app-side push) that | ||
| 54 | + this wiki treats as out of scope. |
en/docs/concepts/api-surface.md
| @@ -35,7 +35,7 @@ sacrifice clarity: | @@ -35,7 +35,7 @@ sacrifice clarity: | ||
| 35 | 35 | ||
| 36 | ## What each tier looks like at runtime | 36 | ## What each tier looks like at runtime |
| 37 | 37 | ||
| 38 | -- **Internal** — see [the four-table read](request-lifecycle.md). One | 38 | +- **Internal** — see [the four-table read](../reference/maintainer/runtime.md#the-four-table-read). One |
| 39 | endpoint (`/business/getModelBysId`) returns the entire form layout; | 39 | endpoint (`/business/getModelBysId`) returns the entire form layout; |
| 40 | another (`/business/addUpdateDelBusinessData`) writes any row in any | 40 | another (`/business/addUpdateDelBusinessData`) writes any row in any |
| 41 | table the metadata names. Few endpoints, generic shapes. | 41 | table the metadata names. Few endpoints, generic shapes. |
en/docs/concepts/index.md
| @@ -7,6 +7,64 @@ a customer sees is a row in `gdsmodule` joined to layout rows in | @@ -7,6 +7,64 @@ a customer sees is a row in `gdsmodule` joined to layout rows in | ||
| 7 | `gdsconfigformmaster/slave`, permission rows in `gdsjurisdiction`, and | 7 | `gdsconfigformmaster/slave`, permission rows in `gdsjurisdiction`, and |
| 8 | stored procedures invoked through `BusinessBaseController` in the runtime. | 8 | stored procedures invoked through `BusinessBaseController` in the runtime. |
| 9 | 9 | ||
| 10 | +## At a glance | ||
| 11 | + | ||
| 12 | +```mermaid | ||
| 13 | +flowchart TB | ||
| 14 | + classDef oos stroke-dasharray:5 5,color:#999 | ||
| 15 | + | ||
| 16 | + BACK["BACK<br/>builder UI"] | ||
| 17 | + FROUNT["FROUNT<br/>customer UI"] | ||
| 18 | + EXT([External integrators]) | ||
| 19 | + HOOKS([Third-party webhooks]) | ||
| 20 | + | ||
| 21 | + subgraph framework [Framework runtime - in scope] | ||
| 22 | + XENTRY[xlyEntry] | ||
| 23 | + XAPI[xlyApi] | ||
| 24 | + XIF[xlyInterface] | ||
| 25 | + XFLOW[xlyFlow] | ||
| 26 | + XPLC[xlyPlc] | ||
| 27 | + XMSG[/"xlyMsg<br/>library"/] | ||
| 28 | + end | ||
| 29 | + | ||
| 30 | + DB[("MySQL<br/>xlyweberp")] | ||
| 31 | + REDIS[(Redis)] | ||
| 32 | + AMQ([ActiveMQ]) | ||
| 33 | + XEJMSC[xlyErpJmsConsumer] | ||
| 34 | + PLAT[("xlyPlat* modules<br/>+ MongoDB")]:::oos | ||
| 35 | + | ||
| 36 | + BACK --> XENTRY | ||
| 37 | + FROUNT --> XENTRY | ||
| 38 | + FROUNT --> XAPI | ||
| 39 | + EXT --> XAPI | ||
| 40 | + HOOKS --> XIF | ||
| 41 | + | ||
| 42 | + XENTRY --> DB | ||
| 43 | + XAPI --> DB | ||
| 44 | + XIF --> DB | ||
| 45 | + XFLOW --> DB | ||
| 46 | + XPLC --> DB | ||
| 47 | + | ||
| 48 | + XENTRY <--> REDIS | ||
| 49 | + XENTRY -- "metadata change" --> AMQ | ||
| 50 | + AMQ --> XEJMSC | ||
| 51 | + XEJMSC --> REDIS | ||
| 52 | + | ||
| 53 | + XENTRY -. uses .-> XMSG | ||
| 54 | + XIF -. uses .-> XMSG | ||
| 55 | + | ||
| 56 | + PLAT -.-> DB | ||
| 57 | +``` | ||
| 58 | + | ||
| 59 | +The dashed cluster (`xlyPlat*` + MongoDB) is the B2B printing-platform | ||
| 60 | +tier — present in the build, but [out of scope](../index.md#whats-out-of-scope) | ||
| 61 | +for this wiki. | ||
| 62 | + | ||
| 63 | +For the library inventory behind each box, see the | ||
| 64 | +[Tech stack](../reference/maintainer/tech-stack.md) page. | ||
| 65 | + | ||
| 66 | +## Concept pages | ||
| 67 | + | ||
| 10 | These pages are intentionally short — each one explains one concept, with | 68 | These pages are intentionally short — each one explains one concept, with |
| 11 | links to the [vertical slices](../slices/index.md) that exercise it. | 69 | links to the [vertical slices](../slices/index.md) that exercise it. |
| 12 | Concepts pages should stay short; if one grows past a screenful, that's | 70 | Concepts pages should stay short; if one grows past a screenful, that's |
en/docs/index.md
| @@ -38,6 +38,7 @@ which Reference chapter you go deep on. | @@ -38,6 +38,7 @@ which Reference chapter you go deep on. | ||
| 38 | - Face recognition (`xlyFace`) — niche. | 38 | - Face recognition (`xlyFace`) — niche. |
| 39 | - Per-tenant schema drift between `xlyweberp_*` databases — wiki targets one schema. | 39 | - Per-tenant schema drift between `xlyweberp_*` databases — wiki targets one schema. |
| 40 | - Backup tables (`*_bak`, `*0302`, etc.). | 40 | - Backup tables (`*_bak`, `*0302`, etc.). |
| 41 | +- The MongoDB document store (`spring.data.mongodb.uri` in the yaml profiles, document classes under `xlyEntity/.../mongo/`). Every `@Document` class is `PLAT_*`-named and every `MongoTemplate` caller lives in an `xlyPlat*` module — so MongoDB is part of the plat tier above. The framework layer this wiki covers is MySQL-only. | ||
| 41 | 42 | ||
| 42 | ## How to fix something in this wiki | 43 | ## How to fix something in this wiki |
| 43 | 44 |
en/docs/reference/maintainer/index.md
| @@ -5,6 +5,8 @@ For Java developers maintaining or extending the framework itself. | @@ -5,6 +5,8 @@ For Java developers maintaining or extending the framework itself. | ||
| 5 | This chapter is for the people who will modify `BusinessBaseController`, add a new | 5 | This chapter is for the people who will modify `BusinessBaseController`, add a new |
| 6 | metadata table to the `gds*` family, or wire in a new third-party integration. | 6 | metadata table to the `gds*` family, or wire in a new third-party integration. |
| 7 | 7 | ||
| 8 | +- [Running xlyEntry locally](running-locally.md) — first-run setup for developers (prereqs, profile, DB override, smoke check). | ||
| 9 | +- [Tech stack](tech-stack.md) — library inventory by category (versions, where each is used, and why). | ||
| 8 | - [The runtime: BusinessBaseController & friends](runtime.md) — the metadata-driven dispatch loop. | 10 | - [The runtime: BusinessBaseController & friends](runtime.md) — the metadata-driven dispatch loop. |
| 9 | - [Generic procedure dispatch](proc-dispatch.md) — `GenericProcedureCallController` deep dive. | 11 | - [Generic procedure dispatch](proc-dispatch.md) — `GenericProcedureCallController` deep dive. |
| 10 | - [Cache invalidation on metadata change](cache-invalidation.md) — `ConsumerChangeGdsModuleThread` and friends. | 12 | - [Cache invalidation on metadata change](cache-invalidation.md) — `ConsumerChangeGdsModuleThread` and friends. |
en/docs/reference/maintainer/running-locally.md
0 → 100644
| 1 | +# Running xlyEntry locally | ||
| 2 | + | ||
| 3 | +This page is the developer onboarding path: clone the repo, get | ||
| 4 | +`xlyEntry` started on your machine, and hit a framework endpoint. The | ||
| 5 | +companion [Multi-service deployment](deployment.md) page covers the | ||
| 6 | +operator view (multiple services, profile permutations, nginx). | ||
| 7 | + | ||
| 8 | +## Prerequisites | ||
| 9 | + | ||
| 10 | +| Tool | Version notes | | ||
| 11 | +|---|---| | ||
| 12 | +| JDK 8 | `xly-src/build.gradle` pins `sourceCompatibility = 1.8`. JDK 11+ has not been validated. | | ||
| 13 | +| Gradle wrapper | Bundled (`./gradlew`). Don't install Gradle separately. | | ||
| 14 | +| MySQL 8 | Driver `com.mysql.cj.jdbc.Driver`. The schema in your DB must match what the active profile yaml points at — see "DB override" below. | | ||
| 15 | +| Redis | The `local` profile expects `127.0.0.1:16379` with password `xlyXLY2015` (see `xlyEntry/src/main/resources/application-local.yml`). | | ||
| 16 | +| ActiveMQ + MongoDB | The `local` profile points at `t0.xlyprint.com` for both. If you have network access to that host, you don't need to run them locally. | | ||
| 17 | + | ||
| 18 | +For the full library inventory the runtime brings up — Spring Boot | ||
| 19 | +2.2.5, MyBatis 2.1.2, Druid, Activiti, Shiro, iText, Aspose, and the | ||
| 20 | +rest — see [Tech stack](tech-stack.md). | ||
| 21 | + | ||
| 22 | +The auto-catalog generator (`scripts/gen_catalog.py`) is unrelated to | ||
| 23 | +running xly — it only reads schema metadata via `~/.my.cnf`. See | ||
| 24 | +[Contributing](../../contributing/index.md) for that path. | ||
| 25 | + | ||
| 26 | +## DB override | ||
| 27 | + | ||
| 28 | +The committed `xlyEntry/src/main/resources/application-local.yml` has | ||
| 29 | +`spring.datasource.url` pointing at a remote dev DB. Most developers | ||
| 30 | +override that to a local-or-personal target. Two options: | ||
| 31 | + | ||
| 32 | +1. **Edit the yaml** in your working tree. Don't commit the change. | ||
| 33 | +2. **Override at the JVM level** with `-Dspring.datasource.url=...` | ||
| 34 | + when invoking `bootRun`. | ||
| 35 | + | ||
| 36 | +The wiki's recon scripts use `~/.my.cnf` for `xlyweberp_saas_ai` — | ||
| 37 | +that's a *different* schema than what `application-local.yml` ships | ||
| 38 | +with (`xlyweberp_saas`). Pick one schema and stay consistent. | ||
| 39 | + | ||
| 40 | +## Run | ||
| 41 | + | ||
| 42 | +From `xly-src/`: | ||
| 43 | + | ||
| 44 | +```bash | ||
| 45 | +./gradlew :xlyEntry:bootRun -Dspring.profiles.active=local | ||
| 46 | +``` | ||
| 47 | + | ||
| 48 | +`xlyEntry` is packaged as a WAR (see its `build.gradle`) but Spring | ||
| 49 | +Boot's embedded Tomcat is what `bootRun` uses, so no external Tomcat | ||
| 50 | +deploy is needed for development. | ||
| 51 | + | ||
| 52 | +## Smoke check | ||
| 53 | + | ||
| 54 | +Once startup completes (look for `Tomcat started on port(s): 8080`): | ||
| 55 | + | ||
| 56 | +| URL | What you should see | | ||
| 57 | +|---|---| | ||
| 58 | +| `http://localhost:8080/xlyEntry/` | The framework landing page. Unauthenticated pages render; authenticated ones bounce to `/login`. | | ||
| 59 | +| `http://localhost:8080/xlyEntry/druid/` | The Druid datasource monitor. Default credentials `xly` / `666666` are in the yaml — change them before exposing the port. | | ||
| 60 | + | ||
| 61 | +If the smoke check fails, look in the log directory configured at | ||
| 62 | +`logging.dirpath` in the active profile yaml. | ||
| 63 | + | ||
| 64 | +## What `local` does and doesn't include | ||
| 65 | + | ||
| 66 | +The `local` profile boots **only** the framework runtime. It does not | ||
| 67 | +boot: | ||
| 68 | + | ||
| 69 | +- `xlyApi` — start it as a second JVM if you need the external API surface. | ||
| 70 | +- `xlyInterface` — same. | ||
| 71 | +- `xlyPlc`, `xlyFlow`, `xlyFace` — same; each has its own application class and profile. | ||
| 72 | +- The `xlyErpJms*` consumers — they are standalone Spring Boot apps. Without them, JMS-driven cache invalidation will not happen across nodes (fine for a single-node dev box). | ||
| 73 | + | ||
| 74 | +For multi-service local development, see | ||
| 75 | +[Multi-service deployment](deployment.md). | ||
| 76 | + | ||
| 77 | +## When startup fails | ||
| 78 | + | ||
| 79 | +The two most common failure modes: | ||
| 80 | + | ||
| 81 | +1. **`Communications link failure`** — the `spring.datasource.url` | ||
| 82 | + target is unreachable from your machine. Override it (see "DB | ||
| 83 | + override"). | ||
| 84 | +2. **`Connection refused: t0.xlyprint.com:61616` or `:27017`** — your | ||
| 85 | + network can't reach the shared dev infra. You can either get on | ||
| 86 | + the right network, point the yaml at local instances, or comment | ||
| 87 | + out the relevant beans for the duration of your debugging session. |
en/docs/reference/maintainer/tech-stack.md
0 → 100644
| 1 | +# Tech stack | ||
| 2 | + | ||
| 3 | +A library inventory for the **in-scope** framework modules | ||
| 4 | +(`xlyEntry`, `xlyApi`, `xlyManage`, `xlyBusinessService`, `xlyPersist`, | ||
| 5 | +`xlyEntity`, `xlyFlow`, `xlyPlc`, `xlyInterface`, `xlyMsg`, | ||
| 6 | +`xlyErpJms*`). | ||
| 7 | + | ||
| 8 | +The plat tier (`xlyPlat*` modules), `xlyFace`, and AI libraries are | ||
| 9 | +[out of scope](../../index.md#whats-out-of-scope) and are not listed | ||
| 10 | +here. | ||
| 11 | + | ||
| 12 | +## How to read this page | ||
| 13 | + | ||
| 14 | +Two columns carry evidence: | ||
| 15 | + | ||
| 16 | +- **Where** — the `build.gradle` files that declare the library as | ||
| 17 | + `api(...)` or `implementation(...)`. Most libraries are declared in | ||
| 18 | + `xlyPersist/build.gradle` and propagate transitively to the modules | ||
| 19 | + that depend on `xlyPersist`. | ||
| 20 | +- **In-scope source references** — file count from | ||
| 21 | + `grep -rln <package> xly-src/<module>/src/` across the in-scope | ||
| 22 | + modules above, with a representative file path. A "no source | ||
| 23 | + references found" entry means the library is declared but no Java, | ||
| 24 | + HTML, or yaml source under any in-scope module references it | ||
| 25 | + directly. Such libraries may still be loaded into the classpath as | ||
| 26 | + transitive dependencies or consumed via Spring Boot autoconfig. | ||
| 27 | + | ||
| 28 | +What this page does not do: explain *why* a particular library was | ||
| 29 | +chosen. Where the gradle file or yaml carries an explicit comment | ||
| 30 | +(e.g., the Netty version pin), that comment is quoted. Otherwise the | ||
| 31 | +page records facts only. | ||
| 32 | + | ||
| 33 | +## 1. Application platform | ||
| 34 | + | ||
| 35 | +| Library | Version | Where | In-scope source references | | ||
| 36 | +|---|---|---|---| | ||
| 37 | +| Spring Boot | 2.2.5 | `xlyPersist/build.gradle` (web, starter, aop, data-redis, data-mongodb, websocket, activemq, freemarker), `xlyApi/build.gradle`, `xlyFlow/build.gradle` | All `*ApplicationBoot.java` classes (`xlyEntry`, `xlyApi`, `xlyInterface`, `xlyPlc`, `xlyFace`-when-built) extend `SpringBootServletInitializer`. | | ||
| 38 | +| Embedded Tomcat | (Spring Boot 2.2.5 BOM) | transitively from `spring-boot-starter-web` | `xlyEntry/src/main/resources/application-local.yml` lines 10-29 configure `server.port: 8080`, `server.servlet.context-path: /xlyEntry`, `server.tomcat.*`. | | ||
| 39 | +| Netty | 4.1.65.Final | `xlyPersist/build.gradle` | No direct Java imports. The gradle file comment states: "*引入mq后netty-common-4.1.45.Final.jar、与netty-all-4.0.42.Final.jar冲突,所以引入*" — the version is pinned to override conflicting transitive versions pulled in by MQ libraries. | | ||
| 40 | +| AspectJ Weaver | 1.9.6 | `xlyApi/build.gradle` (declared twice) | 1 file: `xlyFlow/src/main/java/...` (one Java import). Spring Boot's AOP starter is the dominant consumer; the explicit pin in xlyApi is independent of imports. | | ||
| 41 | +| Lombok | 1.18.8 (`xlyPersist`, `xlyFlow`) / 1.18.20 (`xlyApi`) | `xlyPersist/build.gradle`, `xlyApi/build.gradle`, `xlyFlow/build.gradle` | 19 files import `lombok.*`. xlyApi declares it as both `implementation` and `annotationProcessor`. | | ||
| 42 | + | ||
| 43 | +## 2. Persistence | ||
| 44 | + | ||
| 45 | +| Library | Version | Where | In-scope source references | | ||
| 46 | +|---|---|---|---| | ||
| 47 | +| MyBatis | 2.1.2 (`mybatis-spring-boot-starter`) | `xlyPersist/build.gradle`, `xlyApi/build.gradle`, `xlyFlow/build.gradle` | 102 Java files import `org.apache.ibatis.*` or `org.mybatis.*` — 76 in `xlyPersist`, the rest spread across xlyApi, xlyFlow, xlyInterface. Mapper XMLs live at `xlyPersist/src/main/resources/mapper/{erptable,business,test}/`. | | ||
| 48 | +| MyBatis-Plus | 3.3.0 | `xlyApi/build.gradle` | 2 files: `xlyApi/src/main/java/com/xly/api/util/SqlUtil.java`, `xlyApi/src/main/java/com/xly/api/web/BaseController.java`. Not used outside xlyApi. | | ||
| 49 | +| MySQL Connector/J | 8.0.13 | `xlyPersist/build.gradle`, `xlyApi/build.gradle`, `xlyFlow/build.gradle` | yaml `spring.datasource.driverClassName: com.mysql.cj.jdbc.Driver` (e.g., `xlyEntry/.../application-local.yml:127`). | | ||
| 50 | +| MSSQL JDBC | sqljdbc4 3.0 (Maven) + `mssql-jdbc-6.2.2.jre8.jar` (local jar in `xlyFlow/`, `xlyInterface/`) | `xlyApi/build.gradle`, `xlyInterface/build.gradle`, `xlyFlow/build.gradle` | 5 files: 3 in `xlyFlow/src/`, 2 in `xlyInterface/src/`. | | ||
| 51 | +| Oracle JDBC | `ojdbc6-11.2.0.4.jar` (local jar in `xlyFlow/`) | `xlyFlow/build.gradle` | 2 files in `xlyFlow/src/`. | | ||
| 52 | +| Druid | `druid-spring-boot-starter` 1.2.16; `druid` 1.2.16 | `xlyPersist/build.gradle`, `xlyApi/build.gradle` | 25 files import `com.alibaba.druid.*` (xlyEntry=8, xlyPlc=8, xlyFlow=5, xlyBusinessService=2, xlyInterface=2). yaml: `xlyEntry/.../application-local.yml:126` sets `spring.datasource.type: com.alibaba.druid.pool.DruidDataSource`; lines 308-313 configure the `/druid/*` stat-view servlet. | | ||
| 53 | +| HikariCP | 4.0.3 | `xlyApi/build.gradle` | 8 files reference `com.zaxxer.hikari` (xlyApi=6, xlyInterface=2). Java config: `xlyApi/.../api/config/MasterDataSourceConfig.java`, `SlaveDataSourceConfig.java`. yaml: `xlyApi/.../application-{local,dev,linux,win}.yml`. | | ||
| 54 | +| Flyway | 5.2.1 | `xlyPersist/build.gradle` | No Java imports. Configured via yaml `spring.flyway.*` (e.g., `xlyEntry/.../application-local.yml:316-327`) with `enabled: false`. Migration scripts at `xlyEntry/src/main/resources/flyway/V*__*.sql`. | | ||
| 55 | +| PageHelper | 4.1.1 | `xlyPersist/build.gradle`, `xlyApi/build.gradle`, `xlyFlow/build.gradle` | 19 files import `com.github.pagehelper.*`. yaml `pagehelper.helperDialect: mysql` at `xlyEntry/.../application-local.yml:427`. | | ||
| 56 | +| jsqlparser | 3.2 | `xlyPersist/build.gradle` | 1 file: `xlyPersist/src/...` imports `net.sf.jsqlparser`. | | ||
| 57 | + | ||
| 58 | +## 3. Cache & in-memory | ||
| 59 | + | ||
| 60 | +| Library | Version | Where | In-scope source references | | ||
| 61 | +|---|---|---|---| | ||
| 62 | +| Spring Data Redis | 2.2.5 | `xlyPersist/build.gradle`, `xlyApi/build.gradle`, `xlyFlow/build.gradle` | 3 Java files import `org.springframework.data.redis.*` (xlyEntry=1, xlyInterface=2). yaml: `spring.redis.*` blocks across all modules. | | ||
| 63 | +| Lettuce | (Spring Data Redis 2.2.5 default driver) | transitive | No direct Java imports. Configured via yaml `spring.redis.lettuce.pool.*` (e.g., `xlyEntry/.../application-local.yml:385-394`). | | ||
| 64 | +| Jedis | 2.9.0 | `xlyPersist/build.gradle`, `xlyApi/build.gradle`, `xlyFlow/build.gradle` | 5 files import `redis.clients.jedis` (xlyPersist=2, xlyApi=2, xlyMsg=1, e.g. `xlyMsg/.../wechat/util/JedisMsgUtil.java`). | | ||
| 65 | +| Guava | 18.0 (`xlyPersist`, `xlyApi`); 20.0 (`xlyFlow`) | `xlyPersist/build.gradle`, `xlyApi/build.gradle`, `xlyFlow/build.gradle` | 8 files import `com.google.common.*`. | | ||
| 66 | + | ||
| 67 | +## 4. Workflow & scheduling | ||
| 68 | + | ||
| 69 | +| Library | Version | Where | In-scope source references | | ||
| 70 | +|---|---|---|---| | ||
| 71 | +| Activiti Engine | 5.17.0 | `xlyPersist/build.gradle`, `xlyApi/build.gradle`; consumed by `xlyFlow` | 35 files import `org.activiti.*` (xlyFlow=32, plus 1 each in xlyPersist, xlyApi, xlyEntry — the xlyEntry hit is the `SecurityAutoConfiguration` exclusion in `EntryApplicationBoot.java`; the xlyApi hit is `IdGen.java`; the xlyPersist hit is `BaseDao.java`). The version skew with the 6.0 modeler libs is documented in [Activiti integration](activiti.md). | | ||
| 72 | +| Activiti Spring Boot REST API | 6.0.0 | `xlyFlow/build.gradle` | Consumed via Spring Boot autoconfig + REST endpoints under `xlyFlow`. | | ||
| 73 | +| Activiti JSON Converter | 6.0.0 | `xlyFlow/build.gradle` | (Used by xlyFlow's modeler save path.) | | ||
| 74 | +| Quartz | 2.3.0 | `xlyFlow/build.gradle` | 16 files import `org.quartz.*` (xlyEntry=8, xlyFlow=8). yaml: `xlyEntry/.../application-local.yml:329-365` configures `spring.quartz.*` with JDBC JobStore (`qrtz_*` tables), `instanceName: xlyflowScheduler`. | | ||
| 75 | + | ||
| 76 | +## 5. Messaging | ||
| 77 | + | ||
| 78 | +| Library | Version | Where | In-scope source references | | ||
| 79 | +|---|---|---|---| | ||
| 80 | +| Spring JMS + ActiveMQ starter | 2.2.5 | `xlyPersist/build.gradle` (`spring-boot-starter-activemq`) | 3 files import `org.springframework.jms.*` (xlyErpJmsProductor=2, xlyErpJmsConsumer=1); 2 files import `org.apache.activemq.*` (xlyErpJmsProductor=2). yaml: `spring.activemq.*` at `xlyEntry/.../application-local.yml:402-414`. See also [Messaging](../../api-reference/messaging.md). | | ||
| 81 | +| RocketMQ Spring Boot Starter | 2.0.2 | `xlyPersist/build.gradle` | 4 files import `org.apache.rocketmq.*` in `xlyBusinessService/src/`. | | ||
| 82 | + | ||
| 83 | +## 6. View / templates | ||
| 84 | + | ||
| 85 | +| Library | Version | Where | In-scope source references | | ||
| 86 | +|---|---|---|---| | ||
| 87 | +| Thymeleaf | 3.0.15 | `xlyApi/build.gradle`, `xlyFlow/build.gradle`; transitive via `spring-boot-starter-thymeleaf` | 2 Java files import `org.thymeleaf.*` (both in xlyFlow). Modeler templates in `xlyFlow/src/main/resources/templates/`. | | ||
| 88 | +| Freemarker | 2.2.5 (Spring starter) | `xlyPersist/build.gradle`, `xlyApi/build.gradle`, `xlyFlow/build.gradle` | 1 Java file imports `freemarker.*` (xlyFlow). | | ||
| 89 | +| Apache Batik | 1.8 (`xlyPersist`) / 1.7 (`xlyFlow`: codec, css, svg-dom, svggen) | `xlyPersist/build.gradle`, `xlyFlow/build.gradle` | 1 Java file imports `org.apache.batik.*` (xlyFlow). xlyFlow's modeler ships Batik static assets under `src/main/resources/static/modeler/editor-app/`. | | ||
| 90 | + | ||
| 91 | +## 7. Auth | ||
| 92 | + | ||
| 93 | +| Library | Version | Where | In-scope source references | | ||
| 94 | +|---|---|---|---| | ||
| 95 | +| Apache Shiro (`shiro-spring`) | 1.3.2 (`xlyPersist`) / 1.4.2 (`xlyApi`, `xlyFlow`) | `xlyPersist/build.gradle`, `xlyApi/build.gradle`, `xlyFlow/build.gradle` | 6 Java files import `org.apache.shiro.*` (xlyPersist=1, xlyApi=1, xlyFlow=4). The xlyPersist and xlyApi hits are both `IdGen.java` (crypto utilities); the xlyFlow hits are the modeler's auth helpers (`PermissionUtils`, `CacheUtils`, `IpUtils`, `ActExceptionHandler`). `EntryApplicationBoot.java` excludes Spring Security autoconfig. **No `@ConfigurationProperties("shiro")` or `shiro.*` property binding was found in any in-scope module**, despite a `shiro:` yaml block at `xlyEntry/.../application-local.yml:432-464`. The framework's HTTP auth pattern is documented in [API Reference cross-cutting facts](../../api-reference/index.md#cross-cutting-facts). | | ||
| 96 | +| `shiro-ehcache` | 1.4.2 | `xlyFlow/build.gradle` | No direct Java imports under `xlyFlow/src/`. | | ||
| 97 | +| `shiro-core` | 1.4.2 | `xlyFlow/build.gradle` | (Counted within the 6 `org.apache.shiro` hits above.) | | ||
| 98 | +| `thymeleaf-extras-shiro` | 2.0.0 | `xlyFlow/build.gradle` | 47 `.html` template files reference Shiro tags (xlyApi=5, xlyFlow=42). No Java imports. | | ||
| 99 | +| Bouncy Castle | `bcprov-jdk14:138` | `xlyApi/build.gradle` | 2 files: `xlyApi/src/main/java/com/xly/api/util/RsaEncrypt.java`, `xlyInterface/src/main/java/com/xly/util/RsaEncrypt.java`. | | ||
| 100 | +| commons-codec | 1.16.0 | `xlyPersist/build.gradle`, `xlyApi/build.gradle` | 18 files import `org.apache.commons.codec.*` (xlyApi=6, xlyInterface=6, xlyMsg=4, xlyPersist=2). | | ||
| 101 | + | ||
| 102 | +## 8. Reporting & export | ||
| 103 | + | ||
| 104 | +The framework's print/export surface is the largest single consumer of | ||
| 105 | +third-party code. | ||
| 106 | + | ||
| 107 | +| Library | Version | Where | In-scope source references | | ||
| 108 | +|---|---|---|---| | ||
| 109 | +| iText (5.x branch) | itextpdf 5.5.0 + itext-pdfa 5.5.0 + itext-asian 5.2.0 | `xlyPersist/build.gradle` | 1 file: `xlyPersist/src/main/java/com/xly/jxls/Util/PdfConverUtil.java` imports `com.itextpdf.*`. | | ||
| 110 | +| iText (legacy 2.x via lowagie) | `com.lowagie:itext` 2.1.7 | `xlyPersist/build.gradle` | 1 file in `xlyPersist/src/` imports `com.lowagie.text.*`. Both iText branches coexist on classpath. | | ||
| 111 | +| Aspose Cells | `aspose-cells-21.8.cracked.jar` (local jar) | `xlyPersist/build.gradle` (`api files(...)`) | 6 files in `xlyPersist/src/` import `com.aspose.cells.*`. | | ||
| 112 | +| Aspose Words | `aspose-words-15.8.0-jdk16.jar` (local jar) | `xlyPersist/build.gradle` | 1 file in `xlyPersist/src/` imports `com.aspose.words.*`. | | ||
| 113 | +| Apache POI | 4.1.2 (`xlyPersist`, `xlyFlow`) / 3.15 (`xlyApi`) | `xlyPersist/build.gradle`, `xlyApi/build.gradle`, `xlyFlow/build.gradle` | 36 files import `org.apache.poi.*` (xlyPersist=19, xlyFlow=6, xlyEntry=5, xlyBusinessService=5, xlyApi=1). | | ||
| 114 | +| jxls + jxls-poi | 2.8.1 | `xlyPersist/build.gradle` | 22 files import `org.jxls.*` (xlyPersist=17, xlyEntry=5). | | ||
| 115 | +| jxls-jexcel | 1.0.9 | `xlyPersist/build.gradle` | (Counted within jxls hits above.) | | ||
| 116 | +| commons-jexl3 | 3.1 | `xlyPersist/build.gradle` | (Pulled in by jxls; no direct imports detected.) | | ||
| 117 | +| EasyExcel | 4.0.3 (local jars: `easyexcel-4.0.3.jar` + `-support-4.0.3.jar` + `-core-4.0.3.jar`) | `xlyPersist/build.gradle` | 10 files in `xlyBusinessService/src/` import `com.alibaba.excel.*`. | | ||
| 118 | +| JasperReports | `jasperreports-6.0.0.jar` + `jasperreports-fonts-6.0.0.jar` (local jars) | `xlyPersist/build.gradle` | 11 files import `net.sf.jasperreports.*` (xlyPersist=5, xlyEntry=3, xlyBusinessService=3). | | ||
| 119 | +| OLAP4J | `olap4j-1.2.0.jar` + `olap4j-xmlaserver-1.2.0.jar` (local jars) | `xlyPersist/build.gradle` | 1 file in `xlyPersist/src/` imports `org.olap4j.*`. | | ||
| 120 | +| ZXing | core 3.4.0 + javase 3.4.0 | `xlyPersist/build.gradle` | 5 files import `com.google.zxing.*` (xlyPersist=4, xlyEntry=1). | | ||
| 121 | +| Barcode4J | `barcode4j-light` 2.0 | `xlyPersist/build.gradle` | 1 file in `xlyPersist/src/` imports `org.krysalis.barcode4j.*`. | | ||
| 122 | +| Pinyin4j | 2.5.0 | `xlyPersist/build.gradle` | 1 file: `xlyPersist/src/main/java/com/xly/utils/ChineseCharacterUtil.java`. | | ||
| 123 | +| PDFBox | 2.0.6 | `xlyPersist/build.gradle` | 2 files import `org.apache.pdfbox.*` (xlyPersist=1, xlyBusinessService=1). | | ||
| 124 | +| Thumbnailator | 0.4.8 (`net.coobird`) | `xlyPersist/build.gradle` | 2 files import `net.coobird.*` (xlyPersist=1, xlyEntry=1). | | ||
| 125 | +| jacob | `jacob.jar` (local jar) | `xlyPersist/build.gradle` | 2 files in `xlyPersist/src/` import `com.jacob.*`. | | ||
| 126 | + | ||
| 127 | +## 9. File storage & HTTP clients | ||
| 128 | + | ||
| 129 | +| Library | Version | Where | In-scope source references | | ||
| 130 | +|---|---|---|---| | ||
| 131 | +| Aliyun OSS SDK | `aliyun-sdk-oss` 2.2.0 | `xlyPersist/build.gradle` | 1 file: `xlyPersist/src/main/java/com/xly/utils/OssUtil.java`. | | ||
| 132 | +| commons-fileupload | 1.5 | `xlyFlow/build.gradle` | 1 file in `xlyFlow/src/` imports `org.apache.commons.fileupload.*`. | | ||
| 133 | +| commons-io | 2.5 | `xlyFlow/build.gradle` | 7 files import `org.apache.commons.io.*` (xlyFlow=3, xlyPersist=2, xlyEntry=1, xlyBusinessService=1). | | ||
| 134 | +| OkHttp + Okio | 4.10.0 / 2.10.0 | `xlyPersist/build.gradle` | 2 files in `xlyApi/src/` import `okhttp3.*`. | | ||
| 135 | +| Apache HttpClient | 4.5.5 | `xlyPersist/build.gradle` | 1 file in `xlyBusinessService/src/` imports `org.apache.http.*`. | | ||
| 136 | +| javax.mail | 1.6.2 | `xlyPersist/build.gradle` | 1 file in `xlyPersist/src/` imports `javax.mail.*`. | | ||
| 137 | + | ||
| 138 | +## 10. JSON & general utilities | ||
| 139 | + | ||
| 140 | +| Library | Version | Where | In-scope source references | | ||
| 141 | +|---|---|---|---| | ||
| 142 | +| FastJson | 1.2.15 (`xlyPersist`, `xlyApi`) / 1.2.60 (`xlyFlow`) | `xlyPersist/build.gradle`, `xlyApi/build.gradle`, `xlyFlow/build.gradle` | 84 files import `com.alibaba.fastjson.*` across all in-scope modules (xlyBusinessService=39, xlyEntry=11, xlyInterface=10, xlyPersist=9, xlyFlow=6, xlyMsg=5, xlyApi=4). | | ||
| 143 | +| Jackson | `jackson-databind` 2.9.7 (`xlyFlow` explicit) + transitive via Spring | `xlyFlow/build.gradle` | 22 files import `com.fasterxml.jackson.*` (xlyFlow=8, xlyInterface=9, xlyApi=2, xlyPersist=2, xlyEntry=1). | | ||
| 144 | +| Hutool | `hutool-all` 5.6.5 (`xlyPersist`) / 5.8.5 (`xlyApi`, `xlyFlow`) | `xlyPersist/build.gradle`, `xlyApi/build.gradle`, `xlyFlow/build.gradle` | 271 files import `cn.hutool.*` across every in-scope module (xlyBusinessService=93, xlyFlow=47, xlyApi=37, xlyPersist=33, xlyEntry=25, xlyInterface=23, xlyMsg=10, xlyManage=2, xlyPlc=1). | | ||
| 145 | +| commons-lang3 | 3.6 (`xlyPersist`) / 3.8.1 (`xlyFlow`) | `xlyPersist/build.gradle`, `xlyFlow/build.gradle` | 41 files import `org.apache.commons.lang3.*` (xlyFlow=24, xlyPersist=8, xlyEntry=3, xlyApi=2, xlyBusinessService=3, xlyMsg=1). | | ||
| 146 | +| commons-collections4 | 4.1 | `xlyPersist/build.gradle` | 1 file in `xlyBusinessService/src/`. | | ||
| 147 | +| Groovy | `groovy-all` 3.0.2 | `xlyPersist/build.gradle`, `xlyApi/build.gradle` | 5 Java files import `groovy.util.logging.Slf4j` (xlyPersist=3, xlyApi=2). The annotation is from Groovy's runtime; the Java files using it appear to be vestigial — the import is present but the annotation does not affect Java compilation. | | ||
| 148 | +| Struts2 JSON plugin | 2.5.30 | `xlyPersist/build.gradle` | 1 file: `xlyPersist/src/main/java/com/xly/utils/FeedPage.java`. The framework otherwise runs on Spring MVC. | | ||
| 149 | +| SnakeYAML | 1.27 | `xlyPersist/build.gradle`, `xlyFlow/build.gradle` | 1 file in `xlyFlow/src/` imports `org.yaml.snakeyaml.*`. | | ||
| 150 | +| JDOM | 1.1 | `xlyApi/build.gradle` | 3 files import `org.jdom.*` (xlyApi=1, xlyInterface=1, xlyMsg=1). | | ||
| 151 | +| validation-api | 2.0.1.Final | `xlyFlow/build.gradle` | 2 files in `xlyFlow/src/` import `javax.validation.*`. | | ||
| 152 | + | ||
| 153 | +## 11. Hardware integration | ||
| 154 | + | ||
| 155 | +| Library | Version | Where | In-scope source references | | ||
| 156 | +|---|---|---|---| | ||
| 157 | +| HslCommunication | `HslCommunication.jar` (local jar; no version metadata in filename) | `xlyPersist/build.gradle` | 9 files reference `HslCommunication` (xlyPersist=3, xlyBusinessService=3, xlyPlc=3). xlyPlc is the PLC bridge — see [Slice 6](../../slices/06-hardware.md). | | ||
| 158 | + | ||
| 159 | +## 12. Notifications | ||
| 160 | + | ||
| 161 | +| Library | Version | Where | In-scope source references | | ||
| 162 | +|---|---|---|---| | ||
| 163 | +| Aliyun DingTalk SDK | `com.aliyun:dingtalk` 2.1.14 | `xlyMsg/build.gradle` | 1 file in `xlyMsg/src/main/java/com/xly/dingtalk/`. See [Notifications](../../api-reference/notifications.md). | | ||
| 164 | +| `alibaba-dingtalk-service-sdk` | 2.0.0 | `xlyMsg/build.gradle` | 1 file in `xlyMsg/src/` imports `com.dingtalk.api.*`. | | ||
| 165 | +| Jeewx-API (WeChat) | `jeewx-api-1.3.2.jar` (local jar) | `xlyInterface/build.gradle` | 5 files in `xlyInterface/src/` reference Jeewx packages. | | ||
| 166 | + | ||
| 167 | +## 13. Licensing | ||
| 168 | + | ||
| 169 | +| Library | Version | Where | In-scope source references | | ||
| 170 | +|---|---|---|---| | ||
| 171 | +| TrueLicense | `trueswing.jar` + `truexml.jar` + `turelicense.jar` (local jars) | `xlyBusinessService/build.gradle` | 5 files in `xlyBusinessService/src/main/java/com/xly/license/`: `LicenseManager.java`, `LicenseManagerHolder.java`, `VerifyLicense.java`, `CustomKeyStoreParam.java`, `Resources.java`. yaml: `License:` block at `xlyEntry/.../application-local.yml:80-87` (`checkLic: false` in local). | | ||
| 172 | + | ||
| 173 | +## 14. Logging | ||
| 174 | + | ||
| 175 | +| Library | Version | Where | In-scope source references | | ||
| 176 | +|---|---|---|---| | ||
| 177 | +| Logback | `logback-classic` 1.2.3 | `xlyPersist/build.gradle` | 5 files import `ch.qos.logback.*` across modules. Configuration: `xlyEntry/src/main/resources/logback-spring.xml`. | | ||
| 178 | +| log4j (1.x) | 1.2.17 | `xlyPersist/build.gradle` | 1 file in `xlyFlow/src/` imports `org.apache.log4j.*`. yaml: Druid stat filter `filters: stat,log4j2` at `xlyEntry/.../application-local.yml:282`. | | ||
| 179 | + | ||
| 180 | +## 15. Build & dev | ||
| 181 | + | ||
| 182 | +| Library | Version | Where | What | | ||
| 183 | +|---|---|---|---| | ||
| 184 | +| Gradle wrapper | committed | repo root (`gradlew`, `gradle/`) | Build tool. See [Running locally](running-locally.md). | | ||
| 185 | +| Spring Boot Gradle plugin | 2.2.5.RELEASE | repo-root `build.gradle` | Builds runnable WARs. | | ||
| 186 | +| Spring Boot configuration processor | 2.2.5.RELEASE | `xlyApi/build.gradle` (`annotationProcessor`) | Generates IDE metadata for `@ConfigurationProperties` classes in xlyApi. | | ||
| 187 | + | ||
| 188 | +## Declared but no in-scope source references found | ||
| 189 | + | ||
| 190 | +The following libraries appear in `build.gradle` files but no Java | ||
| 191 | +imports, HTML template references, or yaml property bindings were | ||
| 192 | +found under `xly-src/<in-scope module>/src/`. They may exist on the | ||
| 193 | +classpath as required transitive dependencies, may be consumed via | ||
| 194 | +Spring Boot autoconfiguration, may have been used by code that has | ||
| 195 | +since been removed, or may be vestigial. | ||
| 196 | + | ||
| 197 | +| Library | Declared in | Notes | | ||
| 198 | +|---|---|---| | ||
| 199 | +| Kaptcha (`kaptcha` 2.3.2) | `xlyFlow/build.gradle` | No imports found. Captcha JPEG generator. | | ||
| 200 | +| JNA + jna-platform 4.5.2 | `xlyFlow/build.gradle` | No imports found. Native code access library. | | ||
| 201 | +| oshi-core 3.9.1 | `xlyFlow/build.gradle` | No imports found. (oshi-core depends on JNA.) | | ||
| 202 | +| UserAgentUtils 1.19 | `xlyFlow/build.gradle` | No imports found. | | ||
| 203 | +| Barbecue `1.5-beta1` | `xlyPersist/build.gradle` | No imports found. (Alternate barcode library; Barcode4J + ZXing are the active paths.) | | ||
| 204 | +| Gson 2.8.6 | `xlyPersist/build.gradle` | No `com.google.gson` imports found. FastJson and Jackson are the active JSON paths. | | ||
| 205 | +| commons-pool2 2.8.0 | `xlyPersist/build.gradle` | No direct imports. Likely transitive support for Jedis or similar. | | ||
| 206 | +| Baidu SDK (`baidu-sdk-1.4.5.jar`, local) | `xlyInterface/build.gradle` | No `com.baidu` imports found. | | ||
| 207 | +| `mchange-commons-java` 0.2.11 | `xlyFlow/build.gradle` | No direct imports. | | ||
| 208 | + | ||
| 209 | +## Notable version skew & local jars | ||
| 210 | + | ||
| 211 | +Pulled directly from the `build.gradle` files. Each is a fact, not a recommendation. | ||
| 212 | + | ||
| 213 | +| Item | Detail | | ||
| 214 | +|---|---| | ||
| 215 | +| Shiro | 1.3.2 in `xlyPersist`; 1.4.2 in `xlyApi` and `xlyFlow`. | | ||
| 216 | +| FastJson | 1.2.15 in `xlyPersist` and `xlyApi`; 1.2.60 in `xlyFlow`. | | ||
| 217 | +| Hutool | 5.6.5 in `xlyPersist`; 5.8.5 in `xlyApi` and `xlyFlow`. | | ||
| 218 | +| Apache POI | 4.1.2 in `xlyPersist` and `xlyFlow`; 3.15 in `xlyApi`. | | ||
| 219 | +| Guava | 18.0 in `xlyPersist` and `xlyApi`; 20.0 in `xlyFlow`. | | ||
| 220 | +| commons-lang3 | 3.6 in `xlyPersist`; 3.8.1 in `xlyFlow`. | | ||
| 221 | +| Lombok | 1.18.8 in `xlyPersist` and `xlyFlow`; 1.18.20 in `xlyApi`. | | ||
| 222 | +| iText | `itextpdf` 5.5.0 *and* `com.lowagie:itext` 2.1.7 are both declared in `xlyPersist`. | | ||
| 223 | +| Activiti | engine 5.17.0 (declared in `xlyPersist` and `xlyApi`); rest-api and json-converter 6.0.0 (`xlyFlow`) — see [Activiti integration](activiti.md). | | ||
| 224 | +| Local jars (not from Maven) | `xlyPersist/src/main/java/lib/`: `aspose-cells-21.8.cracked.jar`, `aspose-words-15.8.0-jdk16.jar`, `jacob.jar`, `HslCommunication.jar`, `QRCode.jar`, `olap4j-1.2.0.jar`, `olap4j-xmlaserver-1.2.0.jar`, `jasperreports-6.0.0.jar`, `jasperreports-fonts-6.0.0.jar`, `easyexcel-{,-support-,-core-}4.0.3.jar`. `xlyFlow/src/main/java/lib/`: `mssql-jdbc-6.2.2.jre8.jar`, `ojdbc6-11.2.0.4.jar`. `xlyInterface/src/main/java/lib/`: `mssql-jdbc-6.2.2.jre8.jar`, `baidu-sdk-1.4.5.jar`, `jeewx-api-1.3.2.jar`. `xlyBusinessService/src/main/java/lib/`: `trueswing.jar`, `truexml.jar`, `turelicense.jar`. | | ||
| 225 | +| Spring Boot | 2.2.5.RELEASE — pinned in the root `build.gradle` plugin block and declared at every module that uses Spring Boot starters. | | ||
| 226 | + | ||
| 227 | +## What's intentionally not in this list | ||
| 228 | + | ||
| 229 | +- The plat tier (`xlyPlat*` modules) and dependencies declared only there — out of scope per [index](../../index.md#whats-out-of-scope). | ||
| 230 | +- AI / LLM libraries (`com.theokanning.openai-gpt3-java:service` 0.11.1 and `com.unfbx:chatgpt-java` 1.0.8 in `xlyApi/build.gradle`) — out of scope. | ||
| 231 | +- The MongoDB starter declared in `xlyEntity/build.gradle` (`spring-boot-starter-data-mongodb` 2.2.5). The `xlyEntity` module contains 22 `@Document`-annotated classes under `xlyentity/mongo/`, all named `PLAT_*`. A grep for `MongoTemplate` and `MongoRepository` in in-scope modules returned only `xlyPersist/.../dao/platmongo/BaseMongoDao.java` (which serves the plat tier); no in-scope module invokes Mongo APIs. See the [out-of-scope note in index](../../index.md#whats-out-of-scope). | ||
| 232 | +- `xlyFace` — out of scope. |
en/mkdocs.yml
| @@ -101,6 +101,8 @@ nav: | @@ -101,6 +101,8 @@ nav: | ||
| 101 | - "How to set permissions": reference/builder/permissions.md | 101 | - "How to set permissions": reference/builder/permissions.md |
| 102 | - 4. Reference (Maintainer): | 102 | - 4. Reference (Maintainer): |
| 103 | - reference/maintainer/index.md | 103 | - reference/maintainer/index.md |
| 104 | + - "Running xlyEntry locally": reference/maintainer/running-locally.md | ||
| 105 | + - "Tech stack": reference/maintainer/tech-stack.md | ||
| 104 | - "The runtime: BusinessBaseController & friends": reference/maintainer/runtime.md | 106 | - "The runtime: BusinessBaseController & friends": reference/maintainer/runtime.md |
| 105 | - "Generic procedure dispatch": reference/maintainer/proc-dispatch.md | 107 | - "Generic procedure dispatch": reference/maintainer/proc-dispatch.md |
| 106 | - "Cache invalidation on metadata change": reference/maintainer/cache-invalidation.md | 108 | - "Cache invalidation on metadata change": reference/maintainer/cache-invalidation.md |
| @@ -113,6 +115,7 @@ nav: | @@ -113,6 +115,7 @@ nav: | ||
| 113 | - "External API (xlyApi)": api-reference/external.md | 115 | - "External API (xlyApi)": api-reference/external.md |
| 114 | - "Inbound webhooks (xlyInterface)": api-reference/webhooks.md | 116 | - "Inbound webhooks (xlyInterface)": api-reference/webhooks.md |
| 115 | - "Messaging (ActiveMQ / RocketMQ)": api-reference/messaging.md | 117 | - "Messaging (ActiveMQ / RocketMQ)": api-reference/messaging.md |
| 118 | + - "Notifications (xlyMsg)": api-reference/notifications.md | ||
| 116 | - 6. Auto-Catalog: | 119 | - 6. Auto-Catalog: |
| 117 | - auto-catalog/index.md | 120 | - auto-catalog/index.md |
| 118 | - Tables: auto-catalog/tables/index.md | 121 | - Tables: auto-catalog/tables/index.md |
zh/docs/api-reference/external.md
0 → 100644
| 1 | +# 外部 API(`xlyApi`) | ||
| 2 | + | ||
| 3 | +`xlyApi` 是外部集成方使用的 API 接口面。它作为独立的 Spring Boot WAR 运行(入口类 `xlyApi/src/main/java/com/xly/ApiApplicationBoot.java`),context-path 为 `/xlyApi`,并拥有自己的 `application-*.yml` 文件。 | ||
| 4 | + | ||
| 5 | +它最关键的设计选择是:**大多数外部端点不是硬编码在 Java 里的,而是 `sysapi` 中的数据行**。新的外部 API 和 xly 其他部分一样,是“注册成数据”的。运行时负责查找 `sApiCode`、验证调用方,并执行元数据指定的内容。 | ||
| 6 | + | ||
| 7 | +## 数据驱动分发器:`/api/invoke/{sApiCode}` | ||
| 8 | + | ||
| 9 | +最重要的单个端点: | ||
| 10 | + | ||
| 11 | +```http | ||
| 12 | +POST /xlyApi/api/invoke/{sApiCode} | ||
| 13 | +Authorization: Bearer <token> (or query param ?authorizationt=<token>) | ||
| 14 | +Content-Type: application/json | ||
| 15 | +{ ...request body, passed through as `sBody` to the handler... } | ||
| 16 | +``` | ||
| 17 | + | ||
| 18 | +处理器:`xlyApi/src/main/java/com/xly/api/web/ApiController.java` 中的 `ApiController.invoke()`。 | ||
| 19 | + | ||
| 20 | +流程: | ||
| 21 | + | ||
| 22 | +1. 读取 `Authorization` header(回退:`authorizationt` 查询参数)。 | ||
| 23 | +2. 查找以 `sApiCode` 为键的 `sysapi` 行(通过 `ApiServiceImpl.invoke` → `SELECT … FROM sysapi WHERE sApiCode = #{sApiCode}`)。 | ||
| 24 | +3. 如果该行的 `bHasToken` 标志已设置,就用 `sysapithirdtoken`(或该行指向的等价 token 存储)验证 token。 | ||
| 25 | +4. 使用请求 body 合并出的参数 map,执行 `sysapi.sDataSql` 中存放的 SQL 模板。 | ||
| 26 | +5. 将调用写入 `sysapilog`。 | ||
| 27 | +6. 用 `AjaxResult` 包装结果并返回。 | ||
| 28 | + | ||
| 29 | +因此,新增一个外部 API 是管理 / PM 任务:向 `sysapi` 插入一行,提供 SQL 模板,设置标志,把 `sApiCode` 和 token 给集成方。不需要改 Java 代码。 | ||
| 30 | + | ||
| 31 | +### 需要关注的 `sysapi` 列 | ||
| 32 | + | ||
| 33 | +| 列 | 含义 | | ||
| 34 | +|---|---| | ||
| 35 | +| `sApiCode` | 消费方发送的 path variable。每个租户内必须唯一。 | | ||
| 36 | +| `sApiName` | 人类可读标签。 | | ||
| 37 | +| `sApiUrl` / `sApiUrlRef` | 计算后的 URL,即 `sApiUrlRef + sApiCode`,用于出站分发。 | | ||
| 38 | +| `sMethod` | 此 API 期望的 HTTP 方法(`GET`、`POST` 等)。 | | ||
| 39 | +| `sHeader`、`sBody`、`sBodyNode`、`sBodyType` | 描述入站请求形状的模板。 | | ||
| 40 | +| `sDataSql` | 运行时执行的 SQL 模板。`#{xxx}` 引用会由请求参数填充。 | | ||
| 41 | +| `sDataTest`、`sDataTestNode` | BACK API 测试器(`POST /api/apiTest`)使用的请求 / 响应样例。 | | ||
| 42 | +| `bHasToken` | `1` 表示要求 `Authorization` 中携带 token;`0` 表示公开。 | | ||
| 43 | + | ||
| 44 | +## API 管理端点 | ||
| 45 | + | ||
| 46 | +`/api/list/...`、`/api/data/...`、`/api/add`、`/api/edit`、`/api/remove` 是管理 `sysapi` 行本身的后台接口面(BACK 的“自定义接口”页面会调用这些)。`POST /api/getSqlTemple` 为给定 API 名称生成 SQL 骨架;`POST /api/apiTest` 使用 `sDataTest` 中的测试夹具跑一次端到端 dry-run。 | ||
| 47 | + | ||
| 48 | +## Token 端点:`/token/*` | ||
| 49 | + | ||
| 50 | +| Endpoint | Method | 用途 | | ||
| 51 | +|---|---|---| | ||
| 52 | +| `/token/getToken?corpid=&corpsecret=` | POST | 为集成方的 `(corpid, corpsecret)` 组合签发 bearer token。 | | ||
| 53 | + | ||
| 54 | +返回的 token 就是 `/api/invoke/{sApiCode}` 期望在 `Authorization` 中收到的值。完整实现位于 `xlyApi/src/main/java/com/xly/api/web/TokenController.java` 及其 service。 | ||
| 55 | + | ||
| 56 | +对于 xly 自己获取的**第三方** token(为了代表客户调用集群外 API),见 `/thirdtoken/*`,它由 `sysapithirdtoken` 支撑(表注释:第三方token获取接口)。 | ||
| 57 | + | ||
| 58 | +## 其他收敛后的接口面 | ||
| 59 | + | ||
| 60 | +这些是同一个 WAR 中托管的较小专用 API: | ||
| 61 | + | ||
| 62 | +| Endpoint root | Controller | 用途 | | ||
| 63 | +|---|---|---| | ||
| 64 | +| `/online/api/{sApiCode}` | `OnlineController` | 只读执行某个 `sysapi` 行(不写入)。适合公开数据端点。 | | ||
| 65 | +| `/online/onlineword/{sApiCode}` | `OnlineController` | 返回“word”风格模板载荷的变体。 | | ||
| 66 | +| `/online/onlinelist`, `/online/getToken` | `OnlineController` | 在线 API 列表及其 token 签发。 | | ||
| 67 | +| `/pro/get/{sProName}` | `ProContentController` | 按名称获取存储过程元数据。 | | ||
| 68 | +| `/pro/getData/{sProName}` | `ProContentController` | 执行指定存储过程并返回其结果集。 | | ||
| 69 | +| `/pro/alert/{redisId}`, `/pro/getAlertValue/{redisId}` | `ProContentController` | 按 Redis id 读取预警 / 通知值。 | | ||
| 70 | +| `/pro/executeSql` | `ProContentController` | 执行参数化 SQL 模板(管理级)。 | | ||
| 71 | +| `/thirdparty/*` | `ThirdPartyController` | 第三方 API 定义 CRUD,以及 `checkPartyApi` 校验器。由 `sysapithirdparty` 支撑。 | | ||
| 72 | +| `/thirdtoken/*` | `ThirdTokenController` | 出站 token 配置 CRUD。由 `sysapithirdtoken` 支撑。 | | ||
| 73 | +| `/brand/*` | `BrandController` | 伙伴 / 供应商列表(`sysapibrand`)CRUD。 | | ||
| 74 | +| `/json/*`, `/json/jsonEdit/{sDomId}` | `JsonController` | BACK API 编辑器使用的 JSON 树编辑辅助端点。 | | ||
| 75 | +| `/interfaceDefine/callthirdparty/{interfaceInvoke}` | `InterfaceController` | 分发由 `sysapithirdparty` 定义的出站调用。 | | ||
| 76 | +| `/gpt/chatGpt` | `GptController` | 实验性 GPT/chat 接口的透传;不属于框架 Wiki 范围。 | | ||
| 77 | + | ||
| 78 | +## 支撑表(数据库层接口面) | ||
| 79 | + | ||
| 80 | +这些表保存 API 元数据。所有表都带有 `sBrandsId` / `sSubsidiaryId`,用于租户作用域。 | ||
| 81 | + | ||
| 82 | +| 表 | 角色 | | ||
| 83 | +|---|---| | ||
| 84 | +| `sysapi` | `/api/invoke` 使用的 API 定义。 | | ||
| 85 | +| `sysapilog` | 每次调用的审计日志。 | | ||
| 86 | +| `sysapibrand` | 伙伴 / 供应商目录。 | | ||
| 87 | +| `sysapithirdparty` | 出站第三方端点定义。 | | ||
| 88 | +| `sysapithirdtoken` | 出站第三方 token 配置。 | | ||
| 89 | +| `sysapidbtodb` | DB-to-DB 同步 API 定义。 | | ||
| 90 | +| `sysapidbtodblog` | DB-to-DB 同步运行日志。 | | ||
| 91 | + | ||
| 92 | +## 集成方如何使用 | ||
| 93 | + | ||
| 94 | +典型的首次集成: | ||
| 95 | + | ||
| 96 | +1. **让管理员注册你的 API。** 向 `sysapi` 插入一行(通过 BACK 自助页面或直接写库):选择 `sApiCode`,编写 `sDataSql`,如果需要 token 认证则设置 `bHasToken = 1`,保存。 | ||
| 97 | +2. **获取 token。** `POST /xlyApi/token/getToken?corpid=<your_id>&corpsecret=<your_secret>`。 | ||
| 98 | +3. **调用 API。** 使用 `Authorization` 中的 token 和 JSON body 调用 `POST /xlyApi/api/invoke/<your_sApiCode>`。 | ||
| 99 | +4. **检查日志。** `sysapilog` 会记录每次调用、响应 `iStatus` 和 body。BACK 管理页面也会展示同样的信息。 | ||
| 100 | + | ||
| 101 | +## 这个 API 不是什么 | ||
| 102 | + | ||
| 103 | +- **不是 OpenAPI 描述的接口。** 任意 `sApiCode` 的契约由其 `sysapi.sDataSql` 和 `sBody` 行决定。规格要向注册该 API 的团队获取,而不是从这里的 `/swagger` 端点获取。 | ||
| 104 | +- **不是 `xlyEntry` 内部 API 的薄封装。** 这些是有意分开的接口面。不支持从外部调用 `xlyEntry` 上的 `/business/*`。 | ||
| 105 | +- **不是入站 webhook 接收器。** 第三方推送事件走 [`xlyInterface`](webhooks.md)。 |
zh/docs/api-reference/index.md
0 → 100644
| 1 | +# 5. API 参考 | ||
| 2 | + | ||
| 3 | +xly 暴露了三个不同的 HTTP 接口面,分别由三个独立的 Spring Boot 服务承载。每个接口面都在下面的独立页面中说明;概念总览见[概念 / 三层 API](../concepts/api-surface.md)。 | ||
| 4 | + | ||
| 5 | +| 页面 | 服务 | Context path | 适用场景 | | ||
| 6 | +|---|---|---|---| | ||
| 7 | +| [内部 API](internal.md) | `xlyEntry` | `/xlyEntry` | 你在扩展 SPA,或维护框架运行时。 | | ||
| 8 | +| [外部 API](external.md) | `xlyApi` | `/xlyApi` | 你在接入会从外部调用 xly 的系统。 | | ||
| 9 | +| [Webhook](webhooks.md) | `xlyInterface` | `/xlyInterface` | 第三方系统需要把事件推送进 xly。 | | ||
| 10 | +| [消息](messaging.md) | `xlyEntry` + `xlyErpJms*` | 不适用(ActiveMQ / RocketMQ) | 异步、扇出式集成比同步 HTTP 调用更合适。 | | ||
| 11 | +| [通知](notifications.md) | `xlyMsg`(作为库被 `xlyEntry`、`xlyBusinessService`、`xlyInterface` 使用) | 不适用(钉钉 / 微信 API) | 业务事件需要向用户推送聊天平台消息。 | | ||
| 12 | + | ||
| 13 | +## 阅读顺序 | ||
| 14 | + | ||
| 15 | +如果你是外部集成方,从[外部 API](external.md) 开始。如果你是扩展框架的 Java 开发者,从[内部 API](internal.md) 开始(通用 CRUD 机制的大部分内容在[维护人员运行时章节](../reference/maintainer/runtime.md)中说明;本章会交叉链接到那里)。 | ||
| 16 | + | ||
| 17 | +## 跨接口面的共同事实 | ||
| 18 | + | ||
| 19 | +- **认证。** 内部调用使用 SPA 的 session cookie + `@CurrentUser` 参数解析器。外部调用使用从 `/xlyApi/token/getToken` 获取的 bearer token。Webhook 按通道约定认证方式(签名 header、查询参数密钥等)。 | ||
| 20 | +- **租户作用域。** 每个服务中,所有已认证控制器方法在做任何工作前都会执行 `RequestAddParamUtil.me().addParams(params, userInfo)`;见[多租户概念页](../concepts/multi-tenancy.md)。绕过这一步的请求就是多租户 bug。 | ||
| 21 | +- **日志。** 外部调用写入 `sysapilog`;内部调用使用框架标准的 `syslog4j` 配置;Webhook 由各通道处理器自行决定日志方式。 |
zh/docs/api-reference/internal.md
0 → 100644
| 1 | +# 内部 API(`xlyEntry`) | ||
| 2 | + | ||
| 3 | +`xlyEntry` 服务承载 SPA 的运行时 API。它是三层中最大的一层:控制器和框架的元数据驱动运行时编译到同一个 WAR,大多数调用会落到少数几个可以读写任意模块的通用端点上。 | ||
| 4 | + | ||
| 5 | +这个 API **不是给外部调用方使用的稳定契约**。端点形状会随框架变化而变化。外部集成应该使用[外部 API](external.md)。本页面面向维护人员和 SPA 扩展作者。 | ||
| 6 | + | ||
| 7 | +请求生命周期和代码级 walkthrough 见[维护人员运行时章节](../reference/maintainer/runtime.md)。本页只列 HTTP 入口。 | ||
| 8 | + | ||
| 9 | +## 通用 CRUD 接口面:`/business/*` | ||
| 10 | + | ||
| 11 | +| Endpoint | Method | 用途 | | ||
| 12 | +|---|---|---| | ||
| 13 | +| `/business/getModelBysId/{moduleId}` | GET | 返回某个模块的表单布局,也就是五键组合(`formData`、`gdsformconst`、`gdsjurisdiction`、`billnosetting`、`report`)。 | | ||
| 14 | +| `/business/getBusinessDataByFormcustomId/{formId}` | POST | 返回某个表单的业务数据行,带分页。设置 `sGroupList` 时会分支到 `getBusinessDataByGroup`。 | | ||
| 15 | +| `/business/getBusinessDataByIndex` | POST | 首条 / 末条 / 下一条 / 上一条记录导航。 | | ||
| 16 | +| `/business/addBusinessData` | POST | 单行新增。 | | ||
| 17 | +| `/business/addUpdateDelBusinessData` | POST | 在一个事务调用里组合新增 + 修改 + 删除。前端通过 `sTable` 直接指定目标表。 | | ||
| 18 | +| `/business/getSelectDataBysControlId/{sId}` | POST | 按控件 `sId` 为单个控件加载下拉选项。 | | ||
| 19 | +| `/business/getSelectLimit/{sId}` | POST | 下拉加载调用的分页变体。 | | ||
| 20 | + | ||
| 21 | +这些端点在[切片 1](../slices/01-hello-world.md)(`getModelBysId` + 网格加载 + 保存)和[切片 3](../slices/03-report.md)(基于视图的读取变体)中有更详细说明。处理类位于 `xlyEntry/src/main/java/com/xly/web/businessweb/`。 | ||
| 22 | + | ||
| 23 | +## 元数据管理端点 | ||
| 24 | + | ||
| 25 | +配置侧动作(创建模块、定义表单、声明虚拟表)在 `xlyEntry/src/main/java/com/xly/web/systemweb/` 下有一套并行接口面: | ||
| 26 | + | ||
| 27 | +| Endpoint root | Controller | 用途 | | ||
| 28 | +|---|---|---| | ||
| 29 | +| `/gdsmodule/*` | `GdsmoduleController` | 模块树 CRUD,包括 `getModuleTreePro`、`addGdsmodule`、`updateGdsmodule`。 | | ||
| 30 | +| `/gdsconfigform/*` | `GdsconfigformController` | 表单主表和表单明细元数据 CRUD。 | | ||
| 31 | +| `/gdsconfigtb/*` | `GdsconfigtbController` | 虚拟表主表 / 明细元数据 CRUD。 | | ||
| 32 | + | ||
| 33 | +## 专用运行时端点 | ||
| 34 | + | ||
| 35 | +| Endpoint root | Controller | 用途 | | ||
| 36 | +|---|---|---| | ||
| 37 | +| `/configform/*` | `BusinessConfigformController` | 用户 / 用户组级显示定制。 | | ||
| 38 | +| `/treegrid/*` | `BusinessTreeGridController` | 树表端点(当前分支实现的是存储过程支撑路径)。 | | ||
| 39 | +| `/procedureCall/*` | `GenericProcedureCallController` | 按名称 + 参数通用调用存储过程;见[通用存储过程分发](../reference/maintainer/proc-dispatch.md)。 | | ||
| 40 | +| `/panel/*` | `ConfigformPanelController` | `gdsconfigformpanel` 中的面板布局持久化。 | | ||
| 41 | +| `/checkFlow/*` | `CheckFlowController` | Activiti 工作流接口面(审批 / 驳回 / 查看),只在运行流程引擎的部署中有意义。 | | ||
| 42 | + | ||
| 43 | +## 报表与打印 | ||
| 44 | + | ||
| 45 | +打印接口面位于 `xlyEntry/src/main/java/com/xly/web/report/`: | ||
| 46 | + | ||
| 47 | +- `PrintReportController` — 当前 jxls / iText 打印路径。 | ||
| 48 | +- `PrintReportControllerOld` — 为旧模板保留的历史打印路径。 | ||
| 49 | + | ||
| 50 | +前端的“打印” / “导出”按钮会调用这些控制器,控制器从 `sysreport` 加载模板,执行匹配的视图查询,并把二进制文件流回前端。流程见[切片 3](../slices/03-report.md)。 | ||
| 51 | + | ||
| 52 | +## 认证 | ||
| 53 | + | ||
| 54 | +所有参与业务数据的控制器方法都标注 `@Authorization`,并通过 `@CurrentUser` 接收解析后的 `UserInfo`。session 到 `UserInfo` 的映射由框架自己处理(cookie + Redis 支撑的 session);见[多租户概念页](../concepts/multi-tenancy.md)。 | ||
| 55 | + | ||
| 56 | +如果某个请求未认证却进入了控制器,正常情况下会被 `@Authorization` 拦下;如果没有被拦下(例如某个方法未加注解),这个方法也会绕过 `RequestAddParamUtil` 中的通用租户注入,因此就是多租户 bug。 | ||
| 57 | + | ||
| 58 | +## 这个 API 不是什么 | ||
| 59 | + | ||
| 60 | +- **不是稳定接口。** 端点形状会随框架变化。 | ||
| 61 | +- **不是给外部调用方认证的接口。** 这里没有 API key 流程;cookie/session 不是集成方需要的东西。 | ||
| 62 | +- **不是自助式公开文档。** 这个接口面太大、太通用了,不适合发布成 OpenAPI 文档。外部集成方应该使用经过收敛的[外部 API](external.md)。 |
zh/docs/api-reference/messaging.md
0 → 100644
| 1 | +# 消息(ActiveMQ / RocketMQ) | ||
| 2 | + | ||
| 3 | +xly 中不是所有集成都适合同步 HTTP 调用。框架运行两个消息代理,它们职责不同: | ||
| 4 | + | ||
| 5 | +| Broker | 用途 | Producer | Consumer | | ||
| 6 | +|---|---|---|---| | ||
| 7 | +| **ActiveMQ / JMS** | 缓存失效、集群内扇出事件。元数据变更链路([缓存失效](../reference/maintainer/cache-invalidation.md))依赖它。 | `xlyErpJmsProductor` | `xlyErpJmsConsumer` | | ||
| 8 | +| **RocketMQ** | 其他不适合 ActiveMQ 假设的集成流程。 | `RocketMQServiceImpl`(位于 `xlyBusinessService`) | 因服务而异。 | | ||
| 9 | + | ||
| 10 | +本页只是指针而不是深入说明;准确的队列名和载荷在 `xlyErpJmsConsumer/src/main/java/com/xly/xlyerpjmsconsumer/` 下按 consumer thread 级别记录。 | ||
| 11 | + | ||
| 12 | +## ActiveMQ / JMS:缓存失效通道 | ||
| 13 | + | ||
| 14 | +Producer 侧队列声明位于 `xlyErpJmsProductor/src/main/java/com/xly/xlyerpjmsproductor/config/P2pQueue.java`。当前框架使用的主要 destination(完整列表请读该文件): | ||
| 15 | + | ||
| 16 | +| Constant | 用途 | | ||
| 17 | +|---|---| | ||
| 18 | +| `ERP_JMS_ACTIVEMQ_CHANGE_GDS_MODULE` | “模块元数据已变更”,触发 `ConsumerChangeGdsModuleThread` 清理各节点相关 Redis 缓存。见[元数据变更后的缓存失效](../reference/maintainer/cache-invalidation.md)。 | | ||
| 19 | +| `ERP_JMS_ACTIVEMQ_CHANGE_ELE_CUSTOMER` | 客户主数据变更扇出。 | | ||
| 20 | +| `ERP_JMS_ACTIVEMQ_CHANGE_ELE_EMPLOYEE` | 员工主数据变更扇出。 | | ||
| 21 | +| `ERP_JMS_ACTIVEMQ_CHANGE_ELE_MACHINE` | 车间机台主数据变更扇出。 | | ||
| 22 | +| `ERP_JMS_ACTIVEMQ_UPD_SALE_ORDER`、`ERP_JMS_ACTIVEMQ_UPD_WORK_ORDER`、`ERP_JMS_ACTIVEMQ_UPD_PRODUCTION_REPORT` | “单据已更新”通知,由后台 worker 消费(合计重算、下游失效等)。 | | ||
| 23 | +| `ERP_JMS_ACTIVEMQ_DEL_SALE_ORDER`、`ERP_JMS_ACTIVEMQ_DEL_WORK_ORDER`、`ERP_JMS_ACTIVEMQ_DEL_PRODUCTION_REPORT` | 单据删除通知。 | | ||
| 24 | + | ||
| 25 | +每个 destination 在 `xlyErpJmsConsumer/.../thread/` 下都有对应的 `Consumer*Thread` 类异步处理消息。 | ||
| 26 | + | ||
| 27 | +## RocketMQ:其他流程 | ||
| 28 | + | ||
| 29 | +`RocketMQServiceImpl` 及其配套 `RocketMQService` 接口位于 `xlyBusinessService/src/main/java/com/xly/service/`。它们覆盖非缓存失效流程(例如 `MQCompensateServiceImpl` 处理 ActiveMQ destination 难以表达的补偿 / 重试语义)。RocketMQ topic 按环境配置。 | ||
| 30 | + | ||
| 31 | +## 手动触发缓存失效 | ||
| 32 | + | ||
| 33 | +如果元数据变更是通过原始 SQL 完成的(没有 JMS 事件),各节点缓存不会自动清理。支持的覆盖路径是 `xlyBusinessService/.../service/impl/` 中的 `BusinessCleanRedisDataImpl`,它可以直接发布失效事件。更完整的排查路径见[元数据变更后的缓存失效](../reference/maintainer/cache-invalidation.md)。 | ||
| 34 | + | ||
| 35 | +## 这个机制不是什么 | ||
| 36 | + | ||
| 37 | +- **不是公开集成通道。** 外部集成方不应向这些 broker 发布消息,也不应订阅它们。它们是集群内部的扇出机制。 | ||
| 38 | +- **不是失效缓存的唯一方式。** `xlyEntry` 的 HTTP 写路径已经会在需要时发布 JMS 事件;手动触发只用于边界情况。 |
zh/docs/api-reference/notifications.md
0 → 100644
| 1 | +# 通知(xlyMsg) | ||
| 2 | + | ||
| 3 | +出站通知(钉钉和微信)通过 `xlyMsg` 模块完成。它**不是**调用方直接访问的 HTTP 接口面,而是范围内服务在业务事件需要向聊天平台推送消息时调用的内部 SDK。 | ||
| 4 | + | ||
| 5 | +## 模块内容 | ||
| 6 | + | ||
| 7 | +`xlyMsg/src/main/java/com/xly/`: | ||
| 8 | + | ||
| 9 | +| Package | 角色 | | ||
| 10 | +|---|---| | ||
| 11 | +| `dingtalk/service/DingTalkService` + `dingtalk/util/SendDingTalkUtil`、`DingTalkMsgContentUtil`、`LocalCacheClient` | 钉钉企业消息分发。封装 `com.aliyun:dingtalk:2.1.14` 和 `com.aliyun:alibaba-dingtalk-service-sdk:2.0.0`。 | | ||
| 12 | +| `wechat/service/WechatService` + `wechat/util/SendWxUtil`、`Wx_SignatureUtil`、`JedisMsgUtil`、`MsgContentUtil`、`Xml2JsonUtil` | 微信工作平台分发,包含签名和发送,以及 Redis 支撑的 access-token 缓存。 | | ||
| 13 | +| `notice/service/NoticeService` | 与供应商无关的通知抽象;把“通知用户 X 某事件 Y”的逻辑路由到正确后端。 | | ||
| 14 | + | ||
| 15 | +`xlyMsg/build.gradle` 中唯一的框架依赖是 `xlyPersist`。该模块作为库被消费,不会作为自己的服务部署。 | ||
| 16 | + | ||
| 17 | +## 谁在调用它(范围内调用方) | ||
| 18 | + | ||
| 19 | +这些调用让 `xlyMsg` 成为框架相关内容,而不是 plat 层内容: | ||
| 20 | + | ||
| 21 | +| Caller | 作用 | | ||
| 22 | +|---|---| | ||
| 23 | +| `xlyEntry/.../web/businessweb/TestController.java` | 诊断端点,用于发送测试钉钉消息。 | | ||
| 24 | +| `xlyBusinessService/.../thread/UpdateDingTalkThread.java` | 单据变更后推送钉钉更新的异步 worker。 | | ||
| 25 | +| `xlyBusinessService/.../service/impl/CheckExamineFlowServiceImpl.java` | 工作流审批通知;Activiti 任务被重新分配或完成时,待办人会收到聊天消息。 | | ||
| 26 | +| `xlyBusinessService/.../service/impl/GenericProcedureCallServiceImpl.java` | 通用存储过程 hook:任何选择接入的 `gdsmodule` 存储过程都可以通过这条路径发布通知。 | | ||
| 27 | +| `xlyInterface/.../util/DingTalkUtil.java` + `scheduler/ScheduledTasks.java`、`ErpJobRunStatus.java` | 集成侧的定时任务心跳 / 失败告警。 | | ||
| 28 | + | ||
| 29 | +## 配置 | ||
| 30 | + | ||
| 31 | +凭据(钉钉企业应用 key/secret、微信 AppID、agent ID)从各环境 yaml profile 读取。这里没有全局默认值,每个客户部署会填自己的值,所以框架 Wiki 无法给出规范示例。查看 `xlyEntry/src/main/resources/application-<env>.yml` 下的 active profile yaml,确认实际消费的 key。 | ||
| 32 | + | ||
| 33 | +微信路径使用 Redis 缓存 access token(`wechat/util/JedisMsgUtil.java`),和框架其他部分使用同一个 Redis。哪些服务共享哪些 Redis,见[多服务部署](../reference/maintainer/deployment.md)。 | ||
| 34 | + | ||
| 35 | +## 这个机制不是什么 | ||
| 36 | + | ||
| 37 | +- **不是**入站 webhook 接收器。钉钉回调(例如审批按钮点击)和其他 [webhook](webhooks.md) 一样走 `xlyInterface`。 | ||
| 38 | +- **不是** `xlyPlat*` 的推送通知路径。plat 层有自己的通道(`xlyPlatSmsService`、JPush、App 侧推送),本 Wiki 将其视为范围外。 |
zh/docs/api-reference/webhooks.md
0 → 100644
| 1 | +# 入站 Webhook(`xlyInterface`) | ||
| 2 | + | ||
| 3 | +`xlyInterface` 是三个 Spring Boot WAR 中最小的一个。它的职责是**接收第三方系统推送进来的 HTTP 请求**,例如微信、伙伴工厂、供应商门户,并把它们路由到 xly 处理器。入口类为 `xlyInterface/src/main/java/com/xly/InterfaceApplicationBoot.java`,context-path 为 `/xlyInterface`。 | ||
| 4 | + | ||
| 5 | +这是三个服务里唯一内置 **Swagger UI** 的服务,因为面向伙伴的受众最适合使用可交互的试调文档。构建依赖 `io.springfox:springfox-swagger-ui:2.9.2` 和 `io.springfox:springfox-swagger2:2.9.2`。服务运行后,UI 使用 SpringFox 默认地址: | ||
| 6 | + | ||
| 7 | +```text | ||
| 8 | +http://<host>/xlyInterface/swagger-ui.html | ||
| 9 | +``` | ||
| 10 | + | ||
| 11 | +等价的 JSON 描述位于 `http://<host>/xlyInterface/v2/api-docs`。 | ||
| 12 | + | ||
| 13 | +## 数据驱动接收器:`/interfaceDefine/*` | ||
| 14 | + | ||
| 15 | +它和[外部 API 的 `/api/invoke`](external.md) 模式对应,但用于入站调用: | ||
| 16 | + | ||
| 17 | +| Endpoint | Method | 用途 | | ||
| 18 | +|---|---|---| | ||
| 19 | +| `/interfaceDefine/invoke/{interfaceInvoke}` | POST | 将入站载荷分发给 `{interfaceInvoke}` 命名的处理器。 | | ||
| 20 | +| `/interfaceDefine/callthirdparty/{interfaceInvoke}` | POST | 转发到已配置的出站端点。(对应 `xlyApi` 上同样存在的 `/interfaceDefine/callthirdparty/...` 端点;这里的入站侧和数据驱动入站分发器配套。) | | ||
| 21 | + | ||
| 22 | +处理器:`xlyInterface/src/main/java/com/xly/web/InterfaceController.java`。 | ||
| 23 | + | ||
| 24 | +`{interfaceInvoke}` path variable 会查找一条元数据行,该行声明要运行的 SQL 或存储过程、参数映射和响应形状。它和 xly 其他部分一样遵循数据驱动思路:新增入站端点靠插入数据行,而不是写 Java。 | ||
| 25 | + | ||
| 26 | +## 硬编码的供应商接收器 | ||
| 27 | + | ||
| 28 | +少量接收器不会经过 `/interfaceDefine`,因为它们必须匹配合作方固定的 URL 规格。 | ||
| 29 | + | ||
| 30 | +| Endpoint | Method | 用途 | | ||
| 31 | +|---|---|---| | ||
| 32 | +| `/Push` | POST | 供应商(微信 / 类似系统)推送接收器。 | | ||
| 33 | +| `/Pull` | POST | 供应商拉取模式接收器。 | | ||
| 34 | +| `/getKey/{key}` | GET | 按伙伴命名的 `key` 获取公钥。 | | ||
| 35 | +| `/getKeyTest` | GET | `/getKey` 的测试模式变体。 | | ||
| 36 | +| `/send/sendQw` | POST | 企业微信出站消息。 | | ||
| 37 | + | ||
| 38 | +处理器:`xlyInterface/src/main/java/com/xly/web/WX_VendorWeb.java` 和 `xlyInterface/src/main/java/com/xly/wechat/test/SendQwController.java`。 | ||
| 39 | + | ||
| 40 | +## 认证 | ||
| 41 | + | ||
| 42 | +Webhook 认证方式按伙伴而异。这里没有统一的 token 签发端点(不同于 `xlyApi`)。每个处理器选择自己的方案:签名 header、查询参数 secret,或基于 `sysapibrand` 的预共享 key 校验。接入前需要阅读对应控制器。 | ||
| 43 | + | ||
| 44 | +## 元数据放在哪里 | ||
| 45 | + | ||
| 46 | +`/interfaceDefine/*` 分发器会查询命名入站处理器的元数据行。可检查 `sysapi` 表族(`sysapi`、`sysapibrand`、`sysapithirdparty`)以及当前 schema 自动目录中的任何 `interface*` 表。账本信息和[外部 API](external.md) 有重叠:两个服务共享 API 定义数据,只是暴露在不同 URL 上。 | ||
| 47 | + | ||
| 48 | +## 这个服务不是什么 | ||
| 49 | + | ||
| 50 | +- **不是用 xly 的 session cookie 认证。** 第三方调用方没有用户 session。认证是每个处理器自己的事情,不是框架级统一机制。 | ||
| 51 | +- **不是出站调用通道。** 出站分发(xly 调用伙伴)走 `xlyApi` 的 `/interfaceDefine/callthirdparty/*` 或 `/thirdparty/*` 控制器。这里有重复是有意为之:入站和出站有完全不同的安全姿态。 |
zh/docs/concepts/api-surface.md
0 → 100644
| 1 | +# 三层 API | ||
| 2 | + | ||
| 3 | +xly 不是只有一个 API,而是有**三层**,分别由三个独立的 Spring Boot 服务承载,面向不同受众,也有不同的运行契约。任何集成讨论的第一步,都是先确认你在和哪一层对话。 | ||
| 4 | + | ||
| 5 | +| 层级 | 服务 | Context path | 受众 | | ||
| 6 | +|---|---|---|---| | ||
| 7 | +| **内部** | `xlyEntry` | `/xlyEntry` | xly SPA 自身(BACK + FROUNT)。对外部调用方不是稳定契约。 | | ||
| 8 | +| **外部** | `xlyApi` | `/xlyApi` | 从外部调用 xly 的租户和集成方。数据驱动的公开 API。 | | ||
| 9 | +| **入站 webhook** | `xlyInterface` | `/xlyInterface` | 将事件推送进 xly 的第三方系统。带 Swagger。 | | ||
| 10 | + | ||
| 11 | +每个服务都会构建成自己的 WAR,并在自己的 JVM 中运行。它们不共享进程内状态;它们共享的是**数据库**。正是这个共享数据库让服务拆分成立:内部 API 写入的数据会自动被外部 API 读到,因为两者都连接同一个 schema。 | ||
| 12 | + | ||
| 13 | +## 为什么是三层,而不是一层 | ||
| 14 | + | ||
| 15 | +每一层回答的问题不同,合在一起会牺牲清晰度: | ||
| 16 | + | ||
| 17 | +- **内部层**很大(对所有元数据驱动模块做通用 CRUD)、易变(随框架变化)、且有意保持弱类型(SPA 决定要什么,服务端照元数据执行)。 | ||
| 18 | +- **外部层**是收敛后的接口(只暴露允许集成方使用的端点),按 `sApiCode` 做版本化,并用 bearer token 认证。它能跨框架变化保持稳定,正是因为它小而明确。 | ||
| 19 | +- **入站 webhook 层**接收来自第三方系统的不可信 body,并路由到 xly 处理器。Swagger UI 放在这里,因为这个受众最需要交互式文档。 | ||
| 20 | + | ||
| 21 | +## 每一层在运行时长什么样 | ||
| 22 | + | ||
| 23 | +- **内部层** — 见[四表读取](request-lifecycle.md)。一个端点(`/business/getModelBysId`)返回完整表单布局;另一个端点(`/business/addUpdateDelBusinessData`)写入元数据命名的任意表中的任意行。端点少,形状通用。 | ||
| 24 | +- **外部层** — 大多数调用走 `/api/invoke/{sApiCode}`。`sApiCode` 是 `sysapi` 元数据表中的一行,定义 SQL 模板、参数、认证要求和目标。新的外部 API 是**注册成数据**,不是写成代码;这和框架对自身表单采用的数据驱动基本论点一致。 | ||
| 25 | +- **入站 webhook 层** — `/interfaceDefine/invoke/{interfaceInvoke}` 接收载荷,查找元数据中的匹配处理器,运行配置好的 SQL 或存储过程。此外还有少量为特定伙伴准备的硬编码接收器(`/Push`、`/Pull`、`/send/sendQw`)。 | ||
| 26 | + | ||
| 27 | +## 下一步看哪里 | ||
| 28 | + | ||
| 29 | +- [API 参考(内部)](../api-reference/internal.md) — SPA 使用的 `xlyEntry` 端点;不面向外部调用方。 | ||
| 30 | +- [API 参考(外部)](../api-reference/external.md) — 集成方使用的 `xlyApi` 接口面,以及 `sysapi` 驱动的 `/api/invoke` 模式。 | ||
| 31 | +- [API 参考(Webhook)](../api-reference/webhooks.md) — `xlyInterface` 入站接口面,以及 Swagger UI 的服务地址。 | ||
| 32 | +- [API 参考(消息)](../api-reference/messaging.md) — 补充 HTTP API 的 ActiveMQ / RocketMQ 事件通道。 |
zh/docs/concepts/index.md
| @@ -4,6 +4,59 @@ | @@ -4,6 +4,59 @@ | ||
| 4 | 4 | ||
| 5 | 框架是模块驱动的:PM 创建的每个页面、客户看到的每个页面,都是 `gdsmodule` 中的一行,并与 `gdsconfigformmaster/slave` 中的布局行、`gdsjurisdiction` 中的权限行,以及运行时通过 `BusinessBaseController` 调用的存储过程组合在一起。 | 5 | 框架是模块驱动的:PM 创建的每个页面、客户看到的每个页面,都是 `gdsmodule` 中的一行,并与 `gdsconfigformmaster/slave` 中的布局行、`gdsjurisdiction` 中的权限行,以及运行时通过 `BusinessBaseController` 调用的存储过程组合在一起。 |
| 6 | 6 | ||
| 7 | +## 总览 | ||
| 8 | + | ||
| 9 | +```mermaid | ||
| 10 | +flowchart TB | ||
| 11 | + classDef oos stroke-dasharray:5 5,color:#999 | ||
| 12 | + | ||
| 13 | + BACK["BACK<br/>配置 UI"] | ||
| 14 | + FROUNT["FROUNT<br/>客户 UI"] | ||
| 15 | + EXT([外部集成方]) | ||
| 16 | + HOOKS([第三方 webhook]) | ||
| 17 | + | ||
| 18 | + subgraph framework [框架运行时 - 本 Wiki 覆盖] | ||
| 19 | + XENTRY[xlyEntry] | ||
| 20 | + XAPI[xlyApi] | ||
| 21 | + XIF[xlyInterface] | ||
| 22 | + XFLOW[xlyFlow] | ||
| 23 | + XPLC[xlyPlc] | ||
| 24 | + XMSG[/"xlyMsg<br/>库"/] | ||
| 25 | + end | ||
| 26 | + | ||
| 27 | + DB[("MySQL<br/>xlyweberp")] | ||
| 28 | + REDIS[(Redis)] | ||
| 29 | + AMQ([ActiveMQ]) | ||
| 30 | + XEJMSC[xlyErpJmsConsumer] | ||
| 31 | + PLAT[("xlyPlat* 模块<br/>+ MongoDB")]:::oos | ||
| 32 | + | ||
| 33 | + BACK --> XENTRY | ||
| 34 | + FROUNT --> XENTRY | ||
| 35 | + FROUNT --> XAPI | ||
| 36 | + EXT --> XAPI | ||
| 37 | + HOOKS --> XIF | ||
| 38 | + | ||
| 39 | + XENTRY --> DB | ||
| 40 | + XAPI --> DB | ||
| 41 | + XIF --> DB | ||
| 42 | + XFLOW --> DB | ||
| 43 | + XPLC --> DB | ||
| 44 | + | ||
| 45 | + XENTRY <--> REDIS | ||
| 46 | + XENTRY -- "元数据变更" --> AMQ | ||
| 47 | + AMQ --> XEJMSC | ||
| 48 | + XEJMSC --> REDIS | ||
| 49 | + | ||
| 50 | + XENTRY -. 使用 .-> XMSG | ||
| 51 | + XIF -. 使用 .-> XMSG | ||
| 52 | + | ||
| 53 | + PLAT -.-> DB | ||
| 54 | +``` | ||
| 55 | + | ||
| 56 | +虚线簇(`xlyPlat*` + MongoDB)是 B2B 印刷平台层。它存在于构建中,但在本 Wiki 中[不属于覆盖范围](../index.md)。 | ||
| 57 | + | ||
| 58 | +## 概念页 | ||
| 59 | + | ||
| 7 | 这些页面刻意保持简短:每页解释一个概念,并链接到实际使用该概念的[垂直切片](../slices/index.md)。概念页应该短;如果一页长到超过一屏,通常说明它应该变成一个切片。 | 60 | 这些页面刻意保持简短:每页解释一个概念,并链接到实际使用该概念的[垂直切片](../slices/index.md)。概念页应该短;如果一页长到超过一屏,通常说明它应该变成一个切片。 |
| 8 | 61 | ||
| 9 | - [数据驱动的基本论点](thesis.md) — 框架为什么长成这样。 | 62 | - [数据驱动的基本论点](thesis.md) — 框架为什么长成这样。 |
| @@ -14,3 +67,4 @@ | @@ -14,3 +67,4 @@ | ||
| 14 | - [定制层级](customization-layers.md) — 通道 1 内,基础 / 租户 / 用户覆盖如何合并。 | 67 | - [定制层级](customization-layers.md) — 通道 1 内,基础 / 租户 / 用户覆盖如何合并。 |
| 15 | - [多租户与产品版本](multi-tenancy.md) — 三条作用域轴(`sBrandsId`、`sSubsidiaryId`、`sVersionFlowId`)。 | 68 | - [多租户与产品版本](multi-tenancy.md) — 三条作用域轴(`sBrandsId`、`sSubsidiaryId`、`sVersionFlowId`)。 |
| 16 | - [元数据驱动的请求生命周期](request-lifecycle.md) — 后续会反复回到这张图。 | 69 | - [元数据驱动的请求生命周期](request-lifecycle.md) — 后续会反复回到这张图。 |
| 70 | +- [三层 API](api-surface.md) — 内部(`xlyEntry`)、外部(`xlyApi`)、入站 webhook(`xlyInterface`)。 |
zh/docs/index.md
| @@ -26,6 +26,7 @@ | @@ -26,6 +26,7 @@ | ||
| 26 | - 人脸识别(`xlyFace`),范围较窄。 | 26 | - 人脸识别(`xlyFace`),范围较窄。 |
| 27 | - `xlyweberp_*` 数据库之间的租户级 schema 漂移;本 Wiki 针对一个 schema。 | 27 | - `xlyweberp_*` 数据库之间的租户级 schema 漂移;本 Wiki 针对一个 schema。 |
| 28 | - 备份表(`*_bak`、`*0302` 等)。 | 28 | - 备份表(`*_bak`、`*0302` 等)。 |
| 29 | +- MongoDB 文档存储(yaml profile 中的 `spring.data.mongodb.uri`,以及 `xlyEntity/.../mongo/` 下的文档类)。每个 `@Document` 类都是 `PLAT_*` 命名,每个 `MongoTemplate` 调用方都位于 `xlyPlat*` 模块中,因此 MongoDB 属于上面的 plat 层。本 Wiki 覆盖的框架层只讨论 MySQL。 | ||
| 29 | 30 | ||
| 30 | ## 如何修正这个 Wiki | 31 | ## 如何修正这个 Wiki |
| 31 | 32 |
zh/docs/reference/maintainer/index.md
| @@ -4,6 +4,7 @@ | @@ -4,6 +4,7 @@ | ||
| 4 | 4 | ||
| 5 | 本章服务于会修改 `BusinessBaseController`、向 `gds*` 表族添加元数据表,或接入新第三方集成的人。 | 5 | 本章服务于会修改 `BusinessBaseController`、向 `gds*` 表族添加元数据表,或接入新第三方集成的人。 |
| 6 | 6 | ||
| 7 | +- [本地运行 xlyEntry](running-locally.md) — 开发者首次启动配置(前置条件、profile、DB 覆盖、冒烟检查)。 | ||
| 7 | - [运行时:BusinessBaseController 及相关组件](runtime.md) — 元数据驱动分发循环。 | 8 | - [运行时:BusinessBaseController 及相关组件](runtime.md) — 元数据驱动分发循环。 |
| 8 | - [通用存储过程分发](proc-dispatch.md) — `GenericProcedureCallController` 深入说明。 | 9 | - [通用存储过程分发](proc-dispatch.md) — `GenericProcedureCallController` 深入说明。 |
| 9 | - [元数据变更后的缓存失效](cache-invalidation.md) — `ConsumerChangeGdsModuleThread` 及相关组件。 | 10 | - [元数据变更后的缓存失效](cache-invalidation.md) — `ConsumerChangeGdsModuleThread` 及相关组件。 |
zh/docs/reference/maintainer/running-locally.md
0 → 100644
| 1 | +# 本地运行 xlyEntry | ||
| 2 | + | ||
| 3 | +本页是开发者上手路径:克隆仓库,在本机启动 `xlyEntry`,并访问一个框架端点。配套的[多服务部署](deployment.md)页面覆盖运维视角(多服务、profile 组合、nginx)。 | ||
| 4 | + | ||
| 5 | +## 前置条件 | ||
| 6 | + | ||
| 7 | +| 工具 | 版本说明 | | ||
| 8 | +|---|---| | ||
| 9 | +| JDK 8 | `xly-src/build.gradle` 固定 `sourceCompatibility = 1.8`。JDK 11+ 尚未验证。 | | ||
| 10 | +| Gradle wrapper | 仓库已包含(`./gradlew`)。不要单独安装 Gradle。 | | ||
| 11 | +| MySQL 8 | 驱动为 `com.mysql.cj.jdbc.Driver`。你的 DB schema 必须和 active profile yaml 指向的 schema 匹配;见下面“DB 覆盖”。 | | ||
| 12 | +| Redis | `local` profile 期望 `127.0.0.1:16379`,密码为 `xlyXLY2015`(见 `xlyEntry/src/main/resources/application-local.yml`)。 | | ||
| 13 | +| ActiveMQ + MongoDB | `local` profile 中两者都指向 `t0.xlyprint.com`。如果你的网络能访问该主机,就不需要本地运行它们。 | | ||
| 14 | + | ||
| 15 | +自动目录生成器(`scripts/gen_catalog.py`)和运行 xly 无关;它只通过 `~/.my.cnf` 读取 schema 元数据。该路径见[参与维护](../../contributing/index.md)。 | ||
| 16 | + | ||
| 17 | +## DB 覆盖 | ||
| 18 | + | ||
| 19 | +仓库中的 `xlyEntry/src/main/resources/application-local.yml` 的 `spring.datasource.url` 指向远程开发库。大多数开发者会把它覆盖到本地或个人目标。有两个选择: | ||
| 20 | + | ||
| 21 | +1. **直接编辑 yaml。** 不要提交这个改动。 | ||
| 22 | +2. **通过 JVM 参数覆盖。** 调用 `bootRun` 时传 `-Dspring.datasource.url=...`。 | ||
| 23 | + | ||
| 24 | +Wiki 的侦察脚本通过 `~/.my.cnf` 使用 `xlyweberp_saas_ai`,这和 `application-local.yml` 默认的 `xlyweberp_saas` **不是同一个** schema。选一个 schema,并保持一致。 | ||
| 25 | + | ||
| 26 | +## 运行 | ||
| 27 | + | ||
| 28 | +从 `xly-src/` 目录执行: | ||
| 29 | + | ||
| 30 | +```bash | ||
| 31 | +./gradlew :xlyEntry:bootRun -Dspring.profiles.active=local | ||
| 32 | +``` | ||
| 33 | + | ||
| 34 | +`xlyEntry` 会打成 WAR(见它自己的 `build.gradle`),但开发时 `bootRun` 使用的是 Spring Boot 内嵌 Tomcat,因此不需要外部 Tomcat 部署。 | ||
| 35 | + | ||
| 36 | +## 冒烟检查 | ||
| 37 | + | ||
| 38 | +启动完成后(日志中出现 `Tomcat started on port(s): 8080`): | ||
| 39 | + | ||
| 40 | +| URL | 预期结果 | | ||
| 41 | +|---|---| | ||
| 42 | +| `http://localhost:8080/xlyEntry/` | 框架落地页。未认证页面可以渲染;需要认证的页面会跳到 `/login`。 | | ||
| 43 | +| `http://localhost:8080/xlyEntry/druid/` | Druid 数据源监控。默认凭据 `xly` / `666666` 在 yaml 中;对外暴露端口前必须修改。 | | ||
| 44 | + | ||
| 45 | +如果冒烟检查失败,查看 active profile yaml 中 `logging.dirpath` 配置的日志目录。 | ||
| 46 | + | ||
| 47 | +## `local` 包含什么,不包含什么 | ||
| 48 | + | ||
| 49 | +`local` profile **只**启动框架运行时。它不会启动: | ||
| 50 | + | ||
| 51 | +- `xlyApi` — 如果需要外部 API 接口面,请作为第二个 JVM 启动。 | ||
| 52 | +- `xlyInterface` — 同上。 | ||
| 53 | +- `xlyPlc`、`xlyFlow`、`xlyFace` — 同上;每个服务都有自己的 application class 和 profile。 | ||
| 54 | +- `xlyErpJms*` consumer — 它们是独立的 Spring Boot app。没有它们,JMS 驱动的缓存失效不会跨节点发生(单节点开发机通常可以接受)。 | ||
| 55 | + | ||
| 56 | +多服务本地开发见[多服务部署](deployment.md)。 | ||
| 57 | + | ||
| 58 | +## 启动失败时 | ||
| 59 | + | ||
| 60 | +最常见的两类失败: | ||
| 61 | + | ||
| 62 | +1. **`Communications link failure`** — `spring.datasource.url` 目标在你的机器上不可达。按“DB 覆盖”中的方法覆盖它。 | ||
| 63 | +2. **`Connection refused: t0.xlyprint.com:61616` 或 `:27017`** — 你的网络无法访问共享开发基础设施。你可以接入正确网络,把 yaml 指向本地实例,或在调试期间注释掉相关 bean。 |
zh/mkdocs.yml
| @@ -81,6 +81,7 @@ nav: | @@ -81,6 +81,7 @@ nav: | ||
| 81 | - 定制层级: concepts/customization-layers.md | 81 | - 定制层级: concepts/customization-layers.md |
| 82 | - 多租户与产品版本: concepts/multi-tenancy.md | 82 | - 多租户与产品版本: concepts/multi-tenancy.md |
| 83 | - 元数据驱动的请求生命周期: concepts/request-lifecycle.md | 83 | - 元数据驱动的请求生命周期: concepts/request-lifecycle.md |
| 84 | + - 三层 API: concepts/api-surface.md | ||
| 84 | - 2. 垂直切片: | 85 | - 2. 垂直切片: |
| 85 | - slices/index.md | 86 | - slices/index.md |
| 86 | - "切片 1:CRUD 模块(Hello World)": slices/01-hello-world.md | 87 | - "切片 1:CRUD 模块(Hello World)": slices/01-hello-world.md |
| @@ -98,21 +99,29 @@ nav: | @@ -98,21 +99,29 @@ nav: | ||
| 98 | - "如何设置权限": reference/builder/permissions.md | 99 | - "如何设置权限": reference/builder/permissions.md |
| 99 | - 4. 参考(维护人员): | 100 | - 4. 参考(维护人员): |
| 100 | - reference/maintainer/index.md | 101 | - reference/maintainer/index.md |
| 102 | + - "本地运行 xlyEntry": reference/maintainer/running-locally.md | ||
| 101 | - "运行时:BusinessBaseController 及相关组件": reference/maintainer/runtime.md | 103 | - "运行时:BusinessBaseController 及相关组件": reference/maintainer/runtime.md |
| 102 | - "通用存储过程分发": reference/maintainer/proc-dispatch.md | 104 | - "通用存储过程分发": reference/maintainer/proc-dispatch.md |
| 103 | - "元数据变更后的缓存失效": reference/maintainer/cache-invalidation.md | 105 | - "元数据变更后的缓存失效": reference/maintainer/cache-invalidation.md |
| 104 | - "SQL 模板(xlyEntry/templesql/)": reference/maintainer/sql-templates.md | 106 | - "SQL 模板(xlyEntry/templesql/)": reference/maintainer/sql-templates.md |
| 105 | - "多服务部署": reference/maintainer/deployment.md | 107 | - "多服务部署": reference/maintainer/deployment.md |
| 106 | - "Activiti 集成": reference/maintainer/activiti.md | 108 | - "Activiti 集成": reference/maintainer/activiti.md |
| 107 | - - 5. 自动目录: | 109 | + - 5. API 参考: |
| 110 | + - api-reference/index.md | ||
| 111 | + - "内部 API(xlyEntry)": api-reference/internal.md | ||
| 112 | + - "外部 API(xlyApi)": api-reference/external.md | ||
| 113 | + - "入站 Webhook(xlyInterface)": api-reference/webhooks.md | ||
| 114 | + - "消息(ActiveMQ / RocketMQ)": api-reference/messaging.md | ||
| 115 | + - "通知(xlyMsg)": api-reference/notifications.md | ||
| 116 | + - 6. 自动目录: | ||
| 108 | - auto-catalog/index.md | 117 | - auto-catalog/index.md |
| 109 | - 数据表: auto-catalog/tables/index.md | 118 | - 数据表: auto-catalog/tables/index.md |
| 110 | - 视图: auto-catalog/views/index.md | 119 | - 视图: auto-catalog/views/index.md |
| 111 | - 存储过程: auto-catalog/procedures/index.md | 120 | - 存储过程: auto-catalog/procedures/index.md |
| 112 | - 函数: auto-catalog/functions/index.md | 121 | - 函数: auto-catalog/functions/index.md |
| 113 | - - 6. 术语表: | 122 | + - 7. 术语表: |
| 114 | - glossary/index.md | 123 | - glossary/index.md |
| 115 | - - 7. 参与维护: | 124 | + - 8. 参与维护: |
| 116 | - contributing/index.md | 125 | - contributing/index.md |
| 117 | 126 | ||
| 118 | extra: | 127 | extra: |