技術棧
| 項目 |
技術 |
| Language |
Java 21 |
| Framework |
Spring Boot 3.4 |
| Database |
PostgreSQL |
| Security |
JWT(jjwt 0.12) |
| API Documentation |
Swagger / OpenAPI 3(springdoc 2.8) |
| Build Tool |
Gradle 8.12 |
| Password Hashing |
BCrypt |
專案結構(22 個原始碼檔案)
Baasid/
├── build.gradle
├── settings.gradle
├── gradlew
├── .gitignore
├── README.md # 啟動說明
├── DELIVERABLES.md # 本文件
├── sql/
│ └── init.sql # CREATE TABLE + INSERT 腳本
├── gradle/wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
└── src/main/
├── resources/
│ ├── application.yml # 主設定
│ └── application-dev.yml # dev profile(自動建表)
└── java/com/baasid/
├── BaasidApplication.java # 啟動入口
├── config/
│ ├── SecurityConfig.java # Spring Security 設定
│ ├── OpenApiConfig.java # Swagger 設定
│ └── DataInitializer.java # 測試資料初始化(dev profile)
├── controller/
│ ├── AuthController.java # 認證 API
│ └── GoodsController.java # 商品 CRUD API
├── dto/
│ ├── LoginRequest.java # 登入請求
│ ├── LoginResponse.java # 登入回應
│ ├── GoodsRequest.java # 商品請求(goods_name)
│ ├── GoodsResponse.java # 商品回應(_id, goods_name)
│ └── ErrorResponse.java # 錯誤回應
├── entity/
│ ├── SystemUser.java # 使用者 Entity
│ └── Goods.java # 商品 Entity
├── exception/
│ ├── GlobalExceptionHandler.java# 全域例外處理
│ ├── UnauthorizedException.java
│ └── ResourceNotFoundException.java
├── repository/
│ ├── SystemUserRepository.java
│ └── GoodsRepository.java
├── security/
│ ├── JwtUtil.java # JWT 產生 / 驗證
│ └── JwtAuthenticationFilter.java # JWT 請求過濾器
└── service/
├── AuthService.java # 認證服務
└── GoodsService.java # 商品服務
API 端點
| Method |
Path |
說明 |
認證 |
成功 |
錯誤 |
| POST |
/auth/login |
登入,JWT 回傳於 Response Header Authorization |
不需要 |
200 |
401 / 500 |
| POST |
/goods/add |
新增商品 |
Bearer Token |
200 |
403 / 500 |
| GET |
/goods |
取得所有商品 |
Bearer Token |
200 |
403 / 500 |
| GET |
/goods/{id} |
取得指定商品 |
Bearer Token |
200 |
403 / 500 |
| PUT |
/goods/{id} |
更新商品 |
Bearer Token |
200 |
403 / 500 |
| DELETE |
/goods/{id} |
刪除商品 |
Bearer Token |
200 |
403 / 500 |
資料庫設計
system_user
| 英文名稱 |
資料型態 |
長度 |
允許空值 |
Key |
欄位說明 |
| _id |
UUID |
|
N |
PK |
UUID 主鍵 |
| account |
VARCHAR |
128 |
N |
UK |
帳號(唯一) |
| password |
VARCHAR |
128 |
|
|
密碼(BCrypt 雜湊) |
| name |
VARCHAR |
128 |
|
|
名稱 |
goods
| 英文名稱 |
資料型態 |
長度 |
允許空值 |
Key |
欄位說明 |
| _id |
UUID |
|
N |
PK |
UUID 主鍵 |
| name |
VARCHAR |
128 |
N |
|
商品名稱 |
| cr_user |
UUID |
|
N |
FK |
創建者(system_user._id) |
| cr_datetime |
TIMESTAMP |
|
|
|
創建時間(預設現在) |
| up_user |
UUID |
|
N |
FK |
更新者(system_user._id) |
| up_datetime |
TIMESTAMP |
|
|
|
更新時間(預設現在) |
繳交文件清單
| # |
要求 |
對應檔案 |
| 1 |
程式碼 |
src/main/java/com/baasid/ 下完整 Spring Boot 專案 |
| 2 |
專案啟動方式 |
README.md(含兩種啟動方式) |
| 3 |
資料庫 CREATE script |
sql/init.sql(CREATE TABLE 區段) |
| 4 |
資料庫 INSERT script |
sql/init.sql(INSERT 區段) |
快速啟動
# 1. 建立 PostgreSQL 資料庫
psql -U postgres -c "CREATE DATABASE baasid;"
# 2. 方式 A — 使用 SQL 腳本初始化後啟動
psql -U postgres -d baasid -f sql/init.sql
./gradlew bootRun
# 2. 方式 B — 使用 dev profile 自動建表 + 植入測試資料
./gradlew bootRun --args='--spring.profiles.active=dev'
# 3. 開啟 Swagger UI
open http://localhost:8080/swagger-ui.html
測試帳號
| 帳號 |
密碼 |
名稱 |
| admin |
password123 |
管理員 |
| user01 |
password123 |
測試用戶 |
設計決策
| 決策 |
說明 |
| JWT 存放位置 |
依規格放在 Response Header Authorization,格式為 Bearer <token> |
| 密碼儲存 |
使用 BCrypt 雜湊,不儲存明碼 |
| JSON 欄位名稱 |
透過 @JsonProperty 對應規格要求的 _id、goods_name |
| Session 管理 |
Stateless,完全透過 JWT 驗證,不使用 Session |
| Entity 時間戳 |
使用 JPA @PrePersist / @PreUpdate 自動填入建立與更新時間 |
| 例外處理 |
@RestControllerAdvice 統一處理,回傳對應 HTTP Status Code |
| Profile 分離 |
application.yml 為主設定(ddl-auto: validate),application-dev.yml 啟用自動建表 |