Spring Boot – Gradle 多模組架構
本文件透過商業智慧研究中心 – 後台系統來說明商智中心的Spring Boot架構
版本:0.1.0
最後更新時間:06/10/2026
最後更新人員:陳泓毓
1. 專案概覽
| 項目 | 說明 |
|---|---|
| 框架 | Spring Boot 2.6.6 |
| 語言 | Java 11 |
| 建置工具 | Gradle(多模組專案) |
| 資料庫 | MySQL 8 |
本專案為 RESTful API 後端,供前端管理介面(React 等 SPA)呼叫
2. 系統架構
2.1 整體拓撲
┌─────────────────┐ HTTPS/HTTP ┌──────────────────────────────┐
│ 前端 SPA │ ──────────────────────▶ │ birc-management-backend │
│ (React 等) │ Authorization: Bearer │ Spring Boot (port 8080) │
│ │ ◀────────────────────── │ │
└─────────────────┘ JSON 回應 └──────────┬───────────────────┘
│
┌──────────────────────────┼──────────────────────┐
│ │ │
▼ ▼ ▼
┌────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ MySQL 資料庫 │ │ 本機檔案系統 │ │ 內部 Maven Repo │
│ schema: events │ │ image/ file 目錄 │ │ (共用函式庫) │
└────────────────┘ └─────────────────┘ └─────────────────┘Code language: JavaScript (javascript)
2.2 職責劃分
| 層級 | 職責 |
|---|---|
| 前端 | UI 呈現、表單驗證、攜帶 JWT Token 發送 API 請求 |
| Controller | 接收 HTTP 請求、參數驗證、組裝 JSON 回應 |
| Service | 商業邏輯、交易控制、Entity ↔ Bean 轉換協調 |
| DAO(Repository) | 資料庫 CRUD,基於 Spring Data JPA |
| Entity | 對應資料庫資料表結構(JPA 映射) |
| Bean | API 傳輸物件,用於接收前端輸入或回傳資料 |
| Transformer | Entity 與 Bean 之間的轉換邏輯 |
2.3 設計原則
- Entity 不直接暴露給前端:Controller 透過 Bean 或手動組裝
ObjectData回傳,避免洩漏密碼等敏感欄位。 - 讀寫分離的 Service 基底類別:唯讀操作繼承
BaseViewServiceImpl,含寫入操作繼承BaseServiceImpl。 - 設定與資料庫映射分離為獨立 Gradle 子模組,方便維護與重用。
3. Gradle 多模組結構
birc-management/ ← 根專案(主應用程式)
├── build.gradle
├── settings.gradle
├── src/main/java/.../management/ ← 業務邏輯主程式
│ ├── BircManagementApplication.java ← 啟動類別
│ ├── controller/
│ ├── service/
│ ├── bean/
│ ├── dto/
│ ├── exception/
│ ├── schedule/
│ └── util/
├── src/main/resources/
│ ├── application.yml
│ └── application-local.yml ← 本地設定(需自行建立,不進版控)
└── modules/
├── birc-management-config/ ← 安全、Swagger、靜態資源等設定
│ └── config/
│ ├── SecurityConfig.java
│ ├── filter/ ← JWT、登入 Filter
│ ├── handler/ ← 登入成功/失敗處理
│ └── properties/ ← 設定檔屬性綁定
└── birc-management-database-config/ ← 資料庫層
└── databaseconfig/
├── entity/ ← JPA Entity
├── dao/ ← Spring Data JPA Repository
├── dto/ ← 分頁等資料傳輸物件
└── entity/listener/ ← JPA 生命週期監聽器Code language: PHP (php)
模組依賴關係
birc-management (主模組)
├── modules:birc-management-config
├── modules:birc-management-database-config
└── tw.edu.ntub.birc:common:1.1.0 ← 校內共用函式庫Code language: CSS (css)
4. Spring Boot 分層架構
4.1 啟動類別
BircManagementApplication 是整個應用程式的進入點:
@EnableScheduling
@SpringBootApplication(exclude = {UserDetailsServiceAutoConfiguration.class})
public class BircManagementApplication extends SpringBootServletInitializer { ... }Code language: JavaScript (javascript)
重點說明:
@EnableScheduling:啟用排程任務(如自動簽退)。- 排除
UserDetailsServiceAutoConfiguration:使用自訂的UserDetailsServiceImpl。 - 繼承
SpringBootServletInitializer:支援打包成 WAR 部署至外部 Tomcat(目前war { enabled = false },以 JAR 方式執行)。
4.2 各層職責與命名慣例
| 套件 | 命名慣例 | 說明 |
|---|---|---|
controller | XxxController | @RestController + @RequestMapping,處理 HTTP |
service | XxxService(介面)、XxxServiceImpl(實作) | @Service,商業邏輯 |
service.transformer | XxxTransformer、XxxTransformerImpl | Entity ↔ Bean 轉換 |
bean | XxxBean | 前端傳入/傳出的資料物件,可加 @Valid 驗證 |
databaseconfig.entity | 與資料表同名 | JPA @Entity |
databaseconfig.dao | XxxDAO | 繼承 BaseDAO 或 BaseViewDAO |
exception | XxxException | 自訂商業例外 |
schedule | XxxSchedule | @Component + @Scheduled |
4.3 Service 繼承體系
BaseViewService<B, ID> ← 唯讀介面(get、search)
└── BaseService<B, ID> ← 加入 update、delete
BaseViewServiceImpl<B, E, ID> ← 唯讀實作(泛型:Bean, Entity, 主鍵型別)
└── BaseServiceImpl<B, E, ID>← 加入寫入實作Code language: HTML, XML (xml)
泛型參數說明:
B:Bean(API 層物件)E:Entity(資料庫物件)ID:主鍵型別(如String、Integer)
範例:UserServiceImpl extends BaseServiceImpl<UserBean, User, String>
4.4 Transformer 模式
BeanEntityTransformer<B, E> 定義雙向轉換:
E transferToEntity(B b); // Bean → Entity(新增/更新時)
B transferToBean(E e); // Entity → Bean(查詢回傳時)Code language: JavaScript (javascript)
每個業務領域有獨立的 Transformer 實作(如 UserTransformerImpl),由 Spring 自動注入至對應的 Service。
5. 請求處理流程
以 GET /user/{account} 為例:
HTTP Request
│
▼
JwtAuthenticationFilter ← 解析 Authorization: Bearer <token>
│ 設定 SecurityContext
▼
UserController.getUser() ← @GetMapping,呼叫 Service
│
▼
UserServiceImpl.getByAccount() ← 商業邏輯
│
▼
UserDAO.findByAccount() ← Spring Data JPA 查詢
│
▼
MySQL (events.user 資料表)
│
▼ (回傳路徑)
User Entity → 手動組裝 ObjectData → ResponseEntityBuilder → JSON 字串Code language: CSS (css)
Controller 撰寫慣例
- 使用
@AllArgsConstructor(Lombok)進行建構子注入,不使用@Autowired欄位注入。 - 回傳型別為
ResponseEntity<String>(JSON 字串),透過ResponseEntityBuilder統一格式。 - 需要權限的端點加上
@PreAuthorize("hasAnyAuthority('Manager')")。 - 表單驗證使用
@Valid+BindingResultUtils.validate(bindingResult)。
6. 安全與認證(Spring Security + JWT)
6.1 認證流程
1. 前端 POST /login(JSON 或 form-data)
account + password
│
▼
2. CustomLoginFilter 攔截登入請求
│
▼
3. CustomAuthenticationProvider 驗證帳密
│
▼
4. CustomAuthenticationSuccessHandler 產生 JWT
│
▼
5. 回應 Header: X-Auth-Token: <jwt>
6. 後續請求帶入 Authorization: Bearer <jwt>
│
▼
7. JwtAuthenticationFilter 解析 Token,設定 SecurityContextCode language: HTML, XML (xml)
6.2 權限角色
權限透過 UserRole 資料表管理,常見角色:
| Authority | 說明 |
|---|---|
Manager | 管理員,可存取多數管理功能 |
| (其他角色依資料庫設定) | 一般成員等 |
使用 @PreAuthorize 在方法層級控制存取:
@PreAuthorize("hasAnyAuthority('Manager')")
@GetMapping(path = "")
public ResponseEntity<String> searchUsers() { ... }Code language: JavaScript (javascript)
6.3 公開端點
以下路徑不需認證(定義於 SecurityConfig):
- Swagger 文件:
/api、/v3/**、/swagger-ui/** - 靜態資源:
/static/**、/webjars/** - 圖片/檔案:
/image/**、/file/**(依設定)
6.4 Session 策略
設定為 SessionCreationPolicy.STATELESS,不依賴伺服器端 Session,完全以 JWT 進行無狀態認證。
7. 資料存取層(JPA)
7.1 Entity
Entity 位於 modules/birc-management-database-config/.../entity/,使用標準 JPA 註解:
@Table(name = "user", schema = Config.DATABASE_NAME) // schema = "events"
@Entity
@Data
@EntityListeners(UserListener.class)
public class User {
@Id
@Column(name = "account")
private String account;
@ManyToOne
@JoinColumn(name = "user_role", referencedColumnName = "role_id")
private UserRole userRole;
// ...
}Code language: PHP (php)
注意事項:
- 資料庫 schema 名稱統一定義在
Config.DATABASE_NAME = "events"。 ddl-auto: none,不自動建表,資料表結構由 DBA 或 migration 腳本維護。- 部分 Entity 有
@EntityListeners,在 persist/update 前後執行自訂邏輯(如自動填入時間戳)。
7.2 DAO(Repository)
public interface UserDAO extends BaseDAO<User, String> {
Optional<User> findByAccount(String account);
String findChineseNameByAccount(String account);
}Code language: PHP (php)
BaseDAO繼承JpaRepository,提供標準 CRUD。BaseViewDAO僅提供唯讀操作,用於 View 或統計查詢。- 自訂查詢方法依 Spring Data JPA 命名規則(
findByXxx)或@Query撰寫。
7.3 交易管理
交易透過兩種機制控制:
- AOP 攔截器(
databaseconfig.Config):依方法名稱前綴自動套用交易屬性。
save*、update*、delete*、create*→ 需要交易(REQUIRED)get*、search*、find*→ 唯讀(NOT_SUPPORTED)
@Transactional註解:在 Service 方法上明確標示(如UserServiceImpl.updatePassword)。
主應用程式中另有 AOP 設定,對 BaseViewService 套件下的所有方法套用 transactionInterceptor。
8. API 回應格式與例外處理
8.1 統一回應格式
所有 API 回傳統一的 JSON 結構(由 ResponseEntityBuilder 產生):
{
"result": true,
"errorCode": "",
"message": "查詢成功",
"data": { ... }
}Code language: JavaScript (javascript)
失敗時 result 為 false,errorCode 與 message 說明錯誤原因。
8.2 例外處理
ExceptionHandleController(@ControllerAdvice)集中處理所有例外:
| 例外類型 | 處理方式 |
|---|---|
ProjectException(含子類別) | 回傳對應 errorCode 與 message |
AccessDeniedException | 權限不足提示 |
BindException | 表單驗證錯誤訊息 |
MaxUploadSizeExceededException | 檔案過大 |
Exception(兜底) | 包裝為 UnknownException |
自訂商業例外應繼承 ProjectException(來自 tw.edu.ntub.birc.common),以確保被統一處理。
9. 檔案上傳與靜態資源
9.1 上傳流程
- Controller 接收
MultipartFile(通常透過 Bean 的List<MultipartFile> images欄位)。 - 呼叫
UploadFileService.uploadFile()儲存至本機目錄。 - 檔案資訊寫入
upload_file資料表。 - 透過靜態資源路徑對外提供存取。
9.2 靜態資源映射
birc-management-config 的 Config.java 將 URL 路徑映射至本機目錄:
| URL 路徑 | 本機目錄(由 application-local.yml 設定) |
|---|---|
/image/** | server.image.path |
/file/** | server.file.path |
9.3 檔案大小限制
application.yml 設定:
spring.servlet.multipart:
max-file-size: 200MB
max-request-size: 250MBCode language: CSS (css)
10. 排程任務
排程類別位於 src/.../schedule/,以 @Component + @Scheduled 實作:
| 類別 | Cron 表達式 | 功能 |
|---|---|---|
ClockInSchedule | 0 0 3 * * *(每日凌晨 3 點) | 自動簽退未打卡離開的紀錄 |
OnDutySchedule | 0 0 0 * * *(每日午夜) | 值班相關自動作業 |
時區統一使用 Asia/Taipei。
11. 開發環境設定
11.1 必要條件
- Java 11(OpenJDK 11.0.2 或以上)
- Gradle(或使用專案內建的 Gradle Wrapper)
- MySQL 8 資料庫(schema:
events)
11.2 本地設定檔
- 複製
src/main/resources/application-local-example.yml - 重新命名為
application-local.yml - 修改以下項目:
server:
path: http://localhost:8080
image:
path: 'D:\birc-management\UploadFile\image\'
file:
path: 'D:\birc-management\UploadFile\file\'
birc-management:
database:
url: jdbc:log4jdbc:mysql://localhost:3306/events?serverTimezone=Asia/Taipei
account: 你的帳號
password: 你的密碼Code language: PHP (php)
application-local.yml含敏感資訊,不應提交至版控。
11.3 啟動應用程式
# Windows
gradlew bootRun
# 或直接執行 main
# BircManagementApplication.main()Code language: PHP (php)
啟動後:
- API 服務:
http://localhost:8080 - Swagger UI:
http://localhost:8080/api
11.4 日誌
使用 Log4j2(排除預設的 Logback),設定檔為 src/main/resources/log4j2.yml。
SQL 偵錯可透過 log4jdbc 在 application-local.yml 開啟 sqltiming: DEBUG。
12. 新增功能開發指南
假設要新增「公告(Announcement)」功能,建議依以下順序開發:
Step 1:建立 Entity 與 DAO
在 modules/birc-management-database-config 中:
entity/Announcement.java ← 對應資料表
dao/AnnouncementDAO.java ← extends BaseDAO<Announcement, Integer>Code language: HTML, XML (xml)
Step 2:建立 Bean 與 Transformer
在主模組 src/main/java/.../management 中:
bean/AnnouncementBean.java
service/transformer/AnnouncementTransformer.java
service/transformer/impl/AnnouncementTransformerImpl.java
Step 3:建立 Service
service/AnnouncementService.java ← 介面
service/impl/AnnouncementServiceImpl.java ← extends BaseServiceImpl<...>Code language: HTML, XML (xml)
Step 4:建立 Controller
controller/AnnouncementController.java
@RestController
@AllArgsConstructor
@RequestMapping(path = "announcement")
public class AnnouncementController {
private final AnnouncementService announcementService;
@GetMapping
public ResponseEntity<String> searchAll() { ... }
}Code language: PHP (php)
Step 5:視需要加入權限與例外
- 管理端點加上
@PreAuthorize - 自訂例外繼承
ProjectException
開發檢查清單
- [ ] Entity 欄位與資料表一致,
schema = Config.DATABASE_NAME - [ ] DAO 方法命名符合 Spring Data JPA 規則
- [ ] Service 寫入方法有
@Transactional或由 AOP 攔截器涵蓋 - [ ] Controller 使用
ResponseEntityBuilder回傳統一格式 - [ ] 敏感操作有
@PreAuthorize保護 - [ ] 表單輸入有
@Valid驗證
13. 常用套件與外部依賴
| 套件 | 用途 |
|---|---|
spring-boot-starter-web | REST API、內嵌 Tomcat |
spring-boot-starter-security | 認證與授權 |
spring-boot-starter-data-jpa | ORM 與 Repository |
spring-boot-starter-validation | Bean Validation(@Valid、@NotNull 等) |
springdoc-openapi-ui | Swagger / OpenAPI 文件 |
lombok | 減少樣板程式碼(@Data、@AllArgsConstructor) |
log4j2 + log4jdbc | 日誌與 SQL 偵錯 |
tw.edu.ntub.birc:common | 校內共用工具(JavaBeanUtils、CollectionUtils 等) |
commons-beanutils | Bean 屬性複製 |
jackson | JSON 序列化/反序列化 |
