跳至主要内容

專案結構說明

本文檔說明基於 AppFuse Server 的專案推薦結構,以 app-server 參考實作為範例。

標準專案結構

my-project/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/yourcompany/yourapp/
│ │ │ ├── config/ # 配置類別
│ │ │ ├── entity/ # 領域模型(Entity)
│ │ │ ├── repository/ # 資料存取層
│ │ │ ├── service/ # 業務邏輯層
│ │ │ ├── controller/ # REST API 控制器
│ │ │ └── Application.java # 主程式
│ │ └── resources/
│ │ ├── application.yml # Spring 內建屬性
│ │ └── {app-name}.yml # 應用程式自訂屬性
│ └── test/
│ └── java/
│ └── com/yourcompany/yourapp/
├── build.gradle.kts # Gradle 建置腳本
└── README.md # 專案說明

套件組織

config/ - 配置類別

存放 Spring Configuration 類別:

config/
├── SecurityConfig.java # 安全配置
├── CacheConfig.java # 快取配置
├── JpaAuditingConfig.java # JPA 審計配置
├── MailConfig.java # 郵件配置
├── TenantConfig.java # 多租戶配置
└── WebConfig.java # Web 配置

職責

  • 配置 Spring Beans
  • 整合框架元件
  • 環境特定設定

範例:參考 app-server/config

entity/ - 領域模型

按業務模組組織 Entity:

entity/
├── base/ # 基礎實體
│ ├── AuditableBase.java # 審計基底類別
│ ├── AuditableTenantEntity.java
│ ├── Country.java
│ └── Currency.java
├── tenant/ # 多租戶模組
│ └── Tenant.java
├── auth/ # 認證模組
│ ├── Account.java
│ ├── Role.java
│ └── Authority.java
├── sales/ # 銷售模組(業務範例)
│ ├── Product.java
│ ├── ProductCategory.java
│ └── ProductStatus.java
├── order/ # 訂單模組(業務範例)
│ ├── Order.java
│ ├── OrderItem.java
│ └── OrderStatus.java
└── customer/ # 客戶模組(業務範例)
├── Customer.java
├── Contact.java
└── Address.java

設計原則

  • 按業務領域劃分子套件
  • 基礎類別放在 base/
  • Entity 專注於資料結構定義

範例:參考 app-server/entity

repository/ - 資料存取層

按業務模組組織 Repository:

repository/
├── tenant/
│ └── TenantRepository.java
├── auth/
│ ├── AccountRepository.java
│ └── AuthorityRepository.java
├── sales/
│ ├── ProductRepository.java
│ └── ProductCategoryRepository.java
├── order/
│ └── OrderRepository.java
└── customer/
└── CustomerRepository.java

職責

  • 定義資料存取介面
  • 擴展 Spring Data JPA Repository
  • 自定義查詢方法

範例:參考 app-server/repository

service/ - 業務邏輯層

按業務模組組織 Service:

service/
├── auth/
│ ├── AccountDetailsService.java
│ └── TokenBlacklistService.java
├── sales/
│ ├── ProductService.java
│ └── ProductCategoryService.java
├── order/
│ └── OrderService.java
├── customer/
│ └── CustomerService.java
└── cache/
├── UserCacheService.java
└── SessionCacheService.java

職責

  • 實作業務邏輯
  • 協調多個 Repository 操作
  • 處理交易邊界

範例:參考 app-server/service

controller/ - REST API 控制器

按業務模組組織 REST Controllers:

controller/
├── auth/
│ └── AuthController.java
├── sales/
│ └── ProductController.java
├── order/
│ └── OrderController.java
├── customer/
│ └── CustomerController.java
└── base/
├── ReferenceDataController.java
└── StagingFileController.java

職責

  • 處理 HTTP 請求/回應
  • 參數驗證
  • 呼叫 Service 執行業務邏輯
  • 建構 HATEOAS 連結

範例:參考 app-server/controller

配置檔案組織

AppFuse 採用配置檔分離策略,將 Spring 內建屬性與應用程式自訂屬性分開管理:

配置檔命名慣例

檔案內容說明
application.ymlSpring 內建屬性server、spring、management、logging 等
{app-name}.yml應用程式自訂屬性app.* 等自訂配置

檔名 {app-name} 對應 spring.application.name,例如 app-server 專案使用 app-server.yml

配置載入順序

appfuse-server 的 Environ 模組支援外部配置,載入順序如下(後者覆蓋前者):

1. classpath:application.yml        ← Spring 內建屬性
2. classpath:{app-name}.yml ← 應用程式自訂屬性
3. ${app.home}/conf/{app-name}.yml ← 外部配置(部署時覆蓋)

application.yml(Spring 內建屬性)

存放 Spring 框架相關配置:

server:
servlet:
context-path: /app-server

spring:
application:
name: app-server
datasource:
url: jdbc:h2:file:${user.home}/var/data/appdb
jpa:
hibernate:
ddl-auto: update

logging:
level:
io.leandev.app: DEBUG

{app-name}.yml(應用程式自訂屬性)

存放應用程式特定的配置:

app:
storage:
type: database
jwt:
expiration: 900000
cors:
allowed-origins: "http://localhost:*"

外部配置(部署環境)

部署時可在 ${app.home}/conf/ 放置外部配置檔覆蓋預設值:

# 設定 app.home
export APP_HOME=/opt/app-server

# 建立外部配置
mkdir -p $APP_HOME/conf
cat > $APP_HOME/conf/app-server.yml << EOF
app:
cors:
allowed-origins: "https://app.example.com"
EOF

外部配置優先於 classpath 內的配置,適合管理環境特定設定。

Schema 管理

app-server 參考實作使用 Hibernate ddl-auto: update 自動管理 Schema:

spring:
jpa:
hibernate:
ddl-auto: update

ddl-auto 選項

說明適用環境
update自動新增欄位/表,不刪除開發環境
validate僅驗證 Schema 一致性生產環境(搭配遷移工具)
create-drop啟動時建立、關閉時刪除測試環境
none不做任何操作由遷移工具管理
生產環境建議

生產環境建議使用 FlywayLiquibase 管理 Schema 遷移, 搭配 ddl-auto: validate 確保 Entity 與實際 Schema 一致。

測試結構

測試目錄鏡射 main 的套件結構:

test/java/com/yourcompany/yourapp/
├── entity/
│ └── sales/
│ └── ProductTest.java # 單元測試
├── repository/
│ └── sales/
│ └── ProductRepositoryTest.java # Repository 測試
├── service/
│ └── sales/
│ └── ProductServiceTest.java
└── controller/
└── sales/
└── ProductControllerTest.java # API 整合測試

架構設計原則

分層架構

app-server 採用分層架構(Layered Architecture),將程式碼按技術職責分層:

┌─────────────────────────────────────┐
│ controller/ │ ← HTTP 請求處理
├─────────────────────────────────────┤
│ service/ │ ← 業務邏輯
├─────────────────────────────────────┤
│ repository/ │ ← 資料存取
├─────────────────────────────────────┤
│ entity/ │ ← 領域模型
└─────────────────────────────────────┘

優點

  • 職責清晰,易於理解
  • 各層可獨立測試
  • 符合 Spring 生態系慣例

業務模組劃分

在每一層內,按業務模組(如 sales/order/customer/)組織程式碼:

entity/
├── sales/ # 銷售相關 Entity
├── order/ # 訂單相關 Entity
└── customer/ # 客戶相關 Entity

service/
├── sales/ # 銷售相關 Service
├── order/ # 訂單相關 Service
└── customer/ # 客戶相關 Service

這種「分層 + 模組」的組織方式兼顧了:

  • 技術層面:清晰的依賴方向(controller → service → repository → entity)
  • 業務層面:相關功能集中在同一子套件

配置分離

  • Spring 內建屬性 → application.yml
  • 應用程式自訂屬性 → {app-name}.yml
  • 部署環境覆蓋 → ${app.home}/conf/{app-name}.yml
  • 敏感資訊 → 環境變數

下一步

參考資源