EMS4J is a Spring Boot multi-module energy management system that supports both prepaid operations and energy-consumption analytics. It provides remote device control and multiple billing modes (pay-as-you-go, consolidated, monthly), supports both WeChat Pay and offline payments, and includes peak/off-peak metering, tiered pricing, account management, and financial accounting. It is compatible with multi-protocol device access, and can be adapted to typical scenarios such as campus dormitory prepaid systems and industrial park prepaid systems. The codebase is cleanly structured for easy extension. It is also an open-source project for learning complex business modeling and Spring Boot multi-module architecture design. If this project helps you, please consider giving it a ⭐️.
- Multi-protocol device access
- Billing models (pay-as-you-go / consolidated billing / monthly subscription)
- Metering and billing (peak/off-peak/valley / tiered rates)
- Account management (opening / closing / recharge)
- Remote control (switch on/off, multi-rate configuration)
- Financial accounting (bills, transactions, reconciliation)
cp deploy/env.example .env
docker compose -f deploy/compose/docker-compose.full.yml up -d --buildDefault access URLs:
- Frontend app:
http://127.0.0.1:4173 - Backend API docs:
http://127.0.0.1:8080/doc.html
Default credentials:
- Username:
admin - Password:
Abc123!@#
Notes:
docker-compose.full.ymlstarts the frontend, backend, MySQL, Redis, and RabbitMQ together- The first startup may take longer because images need to be built and dependencies initialized
- If you prefer running frontend and backend separately, see the
Development & Deploymentsection below
-
A complete prepaid business loop
Covers account opening, recharge, charging, warnings, account settlement, order payment, and remote control beyond a simple CRUD admin system. -
Clear multi-module layering
Built with a Spring Boot multi-module structure where domains such asdevice / account / billing / order / lease / plan / aggregationstay explicit and readable. -
Useful for studying complex business modeling
Includes pay-as-you-go, consolidated, and monthly billing models, plus the collaboration between accounts, meters, orders, and accounting flows. -
Includes the IoT access path, not just the business backend
The standaloneems-iotmodule covers multi-protocol access, packet parsing, command dispatch, and event publishing. -
Solid async and idempotency practices
Covers MQ-based processing, transactional messaging, duplicate report handling, and unique-index-backed protection. -
Runnable locally, not just a conceptual repository
Includes frontend and backend projects, Docker-based dependencies, SQL bootstrap scripts, and runtime documentation.
| Page | Screenshot |
|---|---|
| Account Detail | ![]() |
| Account Settlement | ![]() |
| Order List | ![]() |
| Order Creation | ![]() |
| Page | Screenshot |
|---|---|
| Meter Detail | ![]() |
| Price Plan Detail | ![]() |
| Warning Plan Detail | ![]() |
The system supports three billing types: pay-as-you-go, consolidated, and monthly. In pay-as-you-go and consolidated modes, balance is deducted based on actual usage. In pay-as-you-go mode, each water/electric meter is settled independently. In consolidated mode, the balance is recharged on one water/electric meter and other meters use that balance. Monthly is settled at a fixed amount per cycle.
The typical flow is recharge after account opening, usage generates charges and continuously updates the balance, and when the balance is insufficient or reaches the warning threshold it can trigger notifications and remote disconnect. Full account closure will be settled and a settlement order will be generated, resulting in refunds or additional payment.
| Component | Version | Required |
|---|---|---|
| JDK | 17+ | Yes |
| Maven | 3.8+ | Yes |
| MySQL | 8.0+ | Yes |
| Redis | 6.0+ | Yes |
| RabbitMQ | 4.1+ | No |
| Node.js | 18.18+ | Required for frontend development/build |
| pnpm | 10.32+ | Required for frontend development/build |
Clone the repository first:
git clone <repository-url>
cd ems4jBackend middleware dependencies can be started with Docker Compose:
cp deploy/env.example .env
docker compose -f deploy/compose/docker-compose.infra.yml up -dThen start backend and frontend separately:
# backend
mvn clean package -DskipTests
java -jar ems-bootstrap/target/ems-0.2.0.jar --spring.profiles.active=dev
# frontend
cd frontend-web
pnpm install
pnpm devDefault access URLs:
- Backend API docs:
http://127.0.0.1:8080/doc.html - Frontend app:
http://127.0.0.1:4173
cp deploy/env.example .env
# full container mode uses: ems-bootstrap/src/main/resources/application-docker.yml
docker compose -f deploy/compose/docker-compose.full.yml up -d --buildNotes:
deploy/compose/docker-compose.infra.yml: MySQL / Redis / RabbitMQ onlydeploy/compose/docker-compose.full.yml: backend / frontend / middleware- RabbitMQ image already includes the
x-delayed-messageplugin
# import database
mysql -u <user> -p <db> < sql/ems.sql
# install RabbitMQ x-delayed-message plugin
# @see https://github.com/rabbitmq/rabbitmq-delayed-message-exchangeEdit ems-bootstrap/src/main/resources/application-dev.yml:
- Database connection (
spring.datasource) - Redis connection (
spring.data.redis) - RabbitMQ connection (
spring.rabbitmq, optional)
Frontend proxy target defaults to http://127.0.0.1:8080 and can be overridden:
cd frontend-web
VITE_PROXY_TARGET=http://127.0.0.1:18080 pnpm devBuild and run:
mvn clean package -DskipTests
java -jar ems-bootstrap/target/ems-0.2.0.jar --spring.profiles.active=dev# Full build (skip tests)
mvn clean install -DskipTests
# Run tests
mvn test
# Module build/test (example)
mvn -pl ems-business/ems-business-device -am test
# Frontend
cd frontend-web
pnpm typecheck
pnpm test:unit
pnpm test:unit:coverage
pnpm test:e2e| Category | Technology |
|---|---|
| Language/Framework | Java 17 / Spring Boot 3.5 |
| Persistence | MyBatis-Plus / MySQL 8.0 |
| Cache | Redis / Redisson |
| Message Queue | RabbitMQ (optional) |
| IoT Access | Netty |
| Auth | Sa-Token + JWT |
| API Doc | Knife4j / SpringDoc OpenAPI |
+-------------------------------+ +-------------------------------+
| ems-bootstrap | | ems-iot |
| (Web Service Entry) | | (IoT Service Standalone) |
+-------------------------------+ +-------------------------------+
| |
+-----------+-----------+-----------+ |
| | | | |
+--v-----+ +---v----+ +----v-------+ | |
| ems-web| | ems-mq | |ems-schedule| | |
|(HTTP | | (Msg) | | (Schedule)| | |
| API) | | | | | | |
+--+-----+ +---+----+ +-----+------+ | |
| | | | |
+-----------+------------+----------+------------------+
|
+------------------------------------------------------------------+
| ems-business |
| +------------+ +------------+ +------------+ +------------+ |
| | device | | account | | billing | | order | |
| | (Device Mgmt)| | (Account | | (Balance & | | (Trade & | |
| | | | Mgmt) | | Consume) | | Payment) | |
| +------------+ +------------+ +------------+ +------------+ |
| | lease | | plan | | aggregation| |
| | (Owner & | | (Pricing | | (Cross- | |
| | Space) | | Plan) | | domain) | |
| +------------+ +------------+ +------------+ |
+------------------------------------------------------------------+
|
+-----------+-----------+
| |
+--v-------------------+ +v-----------------------+
| ems-foundation | | ems-components |
| +------+ +---------+ | | +----------+ +------+ |
| | user | |integrat.| | | |datasource| | lock | |
| +------+ +---------+ | | +----------+ +------+ |
| +------+ +---------+ | | +---------+ +-------+ |
| | space| | system | | | | context | | redis | |
| +------+ +---------+ | | +---------+ +-------+ |
| +------+ +---------+ | +------------------------+
| | org | | notifi. | |
| +------+ +---------+ |
+----------------------+
|
+-------v-------+
| ems-common |
| (Common Utils)|
+---------------+
Notes:
- ems-web can depend on both ems-business and ems-foundation (user/org/space/system, etc.).
- ems-web should depend on service/dto only; avoid direct repository/entity/mapper access.
- ems-foundation should not depend on ems-business/ems-web to keep base domains reusable.
+----------+ Command Send +----------+ Protocol Conv +----------+
| ems-web |----------------->| ems-iot |----------------->| Device |
+----------+ +----------+ +----------+
^ | |
| | Data Report |
| v |
| +----------+ |
+-----------------------| Business |<------------------------+
API Result | Layer |
+----------+
|
v
+----------+
| MySQL |
+----------+
Notes:
- ems-mq-api provides message contracts and base messaging services (infrastructure layer).
- ems-mq-rabbitmq is the business messaging app layer, hosting message listeners and orchestration.
- Frontend details are maintained in
frontend-web/README.md.
| Vendor | Type |
|---|---|
| Acrel (安科瑞) | Meter / Gateway |
| Sfere (斯菲尔) | Meter |
| Yige (仪歌) | Meter |
| Yke (燕赵) | Meter |
There are two integration approaches:
- Direct device access (in-house platform)
- Implement protocol access, parsing, command translation, and event publishing in
ems-iot. - References:
- Third-party IoT platforms
- Implement platform adapters under
ems-foundation/integrationand coordinate withems-iotand business modules. - Reference:
For detailed platform integration solutions, see:
| Document | Description |
|---|---|
| Development Practices Guide | Code style, naming conventions and development practices |
| Business Module Documentation | Business modules documentation (device, account, billing, order, lease, plan) |
| Foundation Module Documentation | Foundation modules documentation (user, organization, space, system, integration) |
| IoT Module Documentation | IoT module documentation for device access and protocol integration |
| Test Guidelines | Unit and integration test standards and best practices |
This project grew out of an ongoing effort to reorganize and refactor a real-world complex business system.
In a prepaid energy domain, devices, accounts, billing, orders, permissions, and remote control are tightly coupled. As the business evolves, unclear module boundaries quickly make the code harder to maintain and harder to extend.
EMS4J is not only about making the features work. It is about making those relationships explicit: what belongs to device, what belongs to billing, what should be split out of account, and what logic should remain in upper-layer orchestration.
That is why this repository is both a runnable prepaid energy system and a practical reference for complex domain modeling, module-boundary governance, and engineering maintainability.
This project is licensed under the MIT License. See LICENSE.







