Files
novalon-manage-system/docs/plans/2026-03-13-multi-module-refactor-implementation-plan.md
T
张翔 dc53a233b9 refactor(domain): 将领域模型移动到common模块
重构项目结构,将分散在各模块的领域模型统一移动到manage-common模块
更新相关依赖和引用路径
调整docker-compose配置和测试标记
添加新的Playwright测试配置
优化Dockerfile构建过程
2026-03-13 19:58:57 +08:00

2025 lines
64 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Multi-Module Architecture Refactor Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** 将 novalon-manage-api 从单体模块重构为网关 + 单体多模块架构,实现模块化、统一认证授权、独立部署和性能优化。
**Architecture:** 采用网关(manage-gateway+ 应用层(manage-app+ 业务模块(manage-sys、manage-audit、manage-notify、manage-file+ 公共模块(manage-common、manage-db)的分层架构。网关统一处理JWT认证、RBAC权限和限流熔断,应用层聚合所有业务模块,通过Caffeine缓存优化性能,使用Docker容器化部署。
**Tech Stack:** Java 21, Spring Boot 3.4.1, Spring WebFlux, Spring Security, R2DBC, PostgreSQL, JWT, Caffeine, Docker, Maven
---
## Phase 1: Preparation (1-2 days)
### Task 1: Create manage-gateway module structure
**Files:**
- Create: `novalon-manage-api/manage-gateway/pom.xml`
- Create: `novalon-manage-api/manage-gateway/src/main/java/cn/novalon/manage/gateway/GatewayApplication.java`
- Create: `novalon-manage-api/manage-gateway/src/main/resources/application.yml`
- Create: `novalon-manage-api/manage-gateway/src/main/resources/application-dev.yml`
- Create: `novalon-manage-api/manage-gateway/src/main/resources/application-prod.yml`
- Create: `novalon-manage-api/manage-gateway/Dockerfile`
**Step 1: Create manage-gateway pom.xml**
```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.novalon.manage</groupId>
<artifactId>novalon-manage-api</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>manage-gateway</artifactId>
<packaging>jar</packaging>
<name>Manage Gateway</name>
<description>Gateway module for Novalon Manage API</description>
<dependencies>
<dependency>
<groupId>cn.novalon.manage</groupId>
<artifactId>manage-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>cn.novalon.manage.gateway.GatewayApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
```
**Step 2: Create GatewayApplication.java**
```java
package cn.novalon.manage.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("manage-app", r -> r
.path("/api/**")
.uri("http://manage-app:8081"))
.build();
}
}
```
**Step 3: Create application.yml**
```yaml
server:
port: 8080
spring:
application:
name: manage-gateway
cloud:
gateway:
routes:
- id: manage-app
uri: http://manage-app:8081
predicates:
- Path=/api/**
default-filters:
- name: Retry
args:
retries: 3
statuses: BAD_GATEWAY,SERVICE_UNAVAILABLE
methods: GET,POST
backoff:
firstBackoff: 10ms
maxBackoff: 50ms
factor: 2
basedOnPreviousValue: false
management:
endpoints:
web:
exposure:
include: health,info,metrics
base-path: /actuator
endpoint:
health:
show-details: always
metrics:
tags:
application: ${spring.application.name}
logging:
level:
cn.novalon.manage: DEBUG
org.springframework.cloud.gateway: DEBUG
```
**Step 4: Create Dockerfile**
```dockerfile
FROM openjdk:21-jdk-slim
WORKDIR /app
COPY manage-gateway/target/manage-gateway-1.0.0.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
```
**Step 5: Compile and verify**
Run: `cd novalon-manage-api && mvn clean compile -pl manage-gateway -am`
Expected: BUILD SUCCESS
**Step 6: Commit**
```bash
git add novalon-manage-api/manage-gateway/
git commit -m "feat: create manage-gateway module structure"
```
---
### Task 2: Create manage-app module structure
**Files:**
- Create: `novalon-manage-api/manage-app/pom.xml`
- Create: `novalon-manage-api/manage-app/src/main/java/cn/novalon/manage/app/ManageApplication.java`
- Create: `novalon-manage-api/manage-app/src/main/resources/application.yml`
- Create: `novalon-manage-api/manage-app/src/main/resources/application-dev.yml`
- Create: `novalon-manage-api/manage-app/src/main/resources/application-prod.yml`
- Create: `novalon-manage-api/manage-app/Dockerfile`
**Step 1: Create manage-app pom.xml**
```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.novalon.manage</groupId>
<artifactId>novalon-manage-api</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>manage-app</artifactId>
<packaging>jar</packaging>
<name>Manage App</name>
<description>Application module for Novalon Manage API</description>
<dependencies>
<dependency>
<groupId>cn.novalon.manage</groupId>
<artifactId>manage-sys</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>cn.novalon.manage</groupId>
<artifactId>manage-audit</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>cn.novalon.manage</groupId>
<artifactId>manage-notify</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>cn.novalon.manage</groupId>
<artifactId>manage-file</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>cn.novalon.manage</groupId>
<artifactId>manage-db</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>cn.novalon.manage</groupId>
<artifactId>manage-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>r2dbc-postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-database-postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>cn.novalon.manage.app.ManageApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
```
**Step 2: Create ManageApplication.java**
```java
package cn.novalon.manage.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ConfigurationPropertiesScan(basePackages = "cn.novalon.manage")
@ComponentScan(basePackages = "cn.novalon.manage")
public class ManageApplication {
public static void main(String[] args) {
SpringApplication.run(ManageApplication.class, args);
}
}
```
**Step 3: Create application.yml**
```yaml
server:
port: 8081
spring:
application:
name: manage-app
r2dbc:
url: r2dbc:postgresql://${DB_HOST:localhost}:${DB_PORT:5432}/${DB_NAME:novalon_manage}
username: ${DB_USERNAME:postgres}
password: ${DB_PASSWORD:postgres}
pool:
initial-size: 10
max-size: 50
max-idle-time: 30m
max-life-time: 1h
acquire-timeout: 5s
flyway:
enabled: true
locations: classpath:db/migration
management:
endpoints:
web:
exposure:
include: health,info,metrics,env,loggers
base-path: /actuator
endpoint:
health:
show-details: always
metrics:
tags:
application: ${spring.application.name}
environment: ${spring.profiles.active}
logging:
level:
cn.novalon.manage: DEBUG
org.springframework.r2dbc: DEBUG
```
**Step 4: Create Dockerfile**
```dockerfile
FROM openjdk:21-jdk-slim
WORKDIR /app
COPY manage-app/target/manage-app-1.0.0.jar app.jar
EXPOSE 8081
ENTRYPOINT ["java", "-jar", "app.jar"]
```
**Step 5: Compile and verify**
Run: `cd novalon-manage-api && mvn clean compile -pl manage-app -am`
Expected: BUILD SUCCESS
**Step 6: Commit**
```bash
git add novalon-manage-api/manage-app/
git commit -m "feat: create manage-app module structure"
```
---
### Task 3: Create manage-common module structure
**Files:**
- Create: `novalon-manage-api/manage-common/pom.xml`
- Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/`
- Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/util/`
- Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/config/`
- Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/filter/`
- Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/exception/`
**Step 1: Create manage-common pom.xml**
```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.novalon.manage</groupId>
<artifactId>novalon-manage-api</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>manage-common</artifactId>
<packaging>jar</packaging>
<name>Manage Common</name>
<description>Common module for Novalon Manage API</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>
```
**Step 2: Create package structure**
Run: `mkdir -p novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/{util,config,filter,exception,dto}`
Expected: Directories created successfully
**Step 3: Create common exception classes**
Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/exception/BusinessException.java`
```java
package cn.novalon.manage.common.exception;
public class BusinessException extends RuntimeException {
private final String code;
private final String message;
public BusinessException(String code, String message) {
super(message);
this.code = code;
this.message = message;
}
public String getCode() {
return code;
}
@Override
public String getMessage() {
return message;
}
}
```
**Step 4: Compile and verify**
Run: `cd novalon-manage-api && mvn clean compile -pl manage-common -am`
Expected: BUILD SUCCESS
**Step 5: Commit**
```bash
git add novalon-manage-api/manage-common/
git commit -m "feat: create manage-common module structure"
```
---
### Task 4: Create manage-db module structure
**Files:**
- Create: `novalon-manage-api/manage-db/pom.xml`
- Create: `novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/`
- Create: `novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/entity/`
- Create: `novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/repository/`
- Create: `novalon-manage-api/manage-db/src/main/resources/db/migration/`
**Step 1: Create manage-db pom.xml**
```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.novalon.manage</groupId>
<artifactId>novalon-manage-api</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>manage-db</artifactId>
<packaging>jar</packaging>
<name>Manage DB</name>
<description>Database module for Novalon Manage API</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>r2dbc-postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-database-postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.5.5.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.5.5.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>
```
**Step 2: Copy migration scripts**
Run: `cp -r novalon-manage-api/manage-sys/src/main/resources/db/migration/* novalon-manage-api/manage-db/src/main/resources/db/migration/`
Expected: Migration scripts copied successfully
**Step 3: Compile and verify**
Run: `cd novalon-manage-api && mvn clean compile -pl manage-db -am`
Expected: BUILD SUCCESS
**Step 4: Commit**
```bash
git add novalon-manage-api/manage-db/
git commit -m "feat: create manage-db module structure"
```
---
### Task 5: Create manage-audit module structure
**Files:**
- Create: `novalon-manage-api/manage-audit/pom.xml`
- Create: `novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/`
- Create: `novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/handler/`
- Create: `novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/service/`
- Create: `novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/dto/`
**Step 1: Create manage-audit pom.xml**
```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.novalon.manage</groupId>
<artifactId>novalon-manage-api</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>manage-audit</artifactId>
<packaging>jar</packaging>
<name>Manage Audit</name>
<description>Audit module for Novalon Manage API</description>
<dependencies>
<dependency>
<groupId>cn.novalon.manage</groupId>
<artifactId>manage-db</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>cn.novalon.manage</groupId>
<artifactId>manage-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>
```
**Step 2: Compile and verify**
Run: `cd novalon-manage-api && mvn clean compile -pl manage-audit -am`
Expected: BUILD SUCCESS
**Step 3: Commit**
```bash
git add novalon-manage-api/manage-audit/
git commit -m "feat: create manage-audit module structure"
```
---
### Task 6: Create manage-notify module structure
**Files:**
- Create: `novalon-manage-api/manage-notify/pom.xml`
- Create: `novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/`
- Create: `novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/handler/`
- Create: `novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/service/`
- Create: `novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/config/`
**Step 1: Create manage-notify pom.xml**
```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.novalon.manage</groupId>
<artifactId>novalon-manage-api</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>manage-notify</artifactId>
<packaging>jar</packaging>
<name>Manage Notify</name>
<description>Notify module for Novalon Manage API</description>
<dependencies>
<dependency>
<groupId>cn.novalon.manage</groupId>
<artifactId>manage-db</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>cn.novalon.manage</groupId>
<artifactId>manage-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>
```
**Step 2: Compile and verify**
Run: `cd novalon-manage-api && mvn clean compile -pl manage-notify -am`
Expected: BUILD SUCCESS
**Step 3: Commit**
```bash
git add novalon-manage-api/manage-notify/
git commit -m "feat: create manage-notify module structure"
```
---
### Task 7: Create manage-file module structure
**Files:**
- Create: `novalon-manage-api/manage-file/pom.xml`
- Create: `novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/`
- Create: `novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/handler/`
- Create: `novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/service/`
- Create: `novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/config/`
**Step 1: Create manage-file pom.xml**
```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.novalon.manage</groupId>
<artifactId>novalon-manage-api</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>manage-file</artifactId>
<packaging>jar</packaging>
<name>Manage File</name>
<description>File module for Novalon Manage API</description>
<dependencies>
<dependency>
<groupId>cn.novalon.manage</groupId>
<artifactId>manage-db</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>cn.novalon.manage</groupId>
<artifactId>manage-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>
```
**Step 2: Compile and verify**
Run: `cd novalon-manage-api && mvn clean compile -pl manage-file -am`
Expected: BUILD SUCCESS
**Step 3: Commit**
```bash
git add novalon-manage-api/manage-file/
git commit -m "feat: create manage-file module structure"
```
---
### Task 8: Update parent pom.xml with new modules
**Files:**
- Modify: `novalon-manage-api/pom.xml`
**Step 1: Update modules section**
Read: `novalon-manage-api/pom.xml`
Find: `<modules>` section and replace with:
```xml
<modules>
<module>manage-gateway</module>
<module>manage-app</module>
<module>manage-sys</module>
<module>manage-audit</module>
<module>manage-notify</module>
<module>manage-file</module>
<module>manage-common</module>
<module>manage-db</module>
</modules>
```
**Step 2: Verify build**
Run: `cd novalon-manage-api && mvn clean compile`
Expected: BUILD SUCCESS
**Step 3: Commit**
```bash
git add novalon-manage-api/pom.xml
git commit -m "feat: update parent pom.xml with new modules"
```
---
## Phase 2: Module Extraction (3-5 days)
### Task 9: Extract common utilities to manage-common
**Files:**
- Modify: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/utils/SnowflakeId.java`
- Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/util/SnowflakeId.java`
- Modify: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/config/JwtProperties.java`
- Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/config/JwtProperties.java`
**Step 1: Move SnowflakeId to manage-common**
Read: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/utils/SnowflakeId.java`
Copy content to: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/util/SnowflakeId.java`
Update package declaration: `package cn.novalon.manage.common.util;`
**Step 2: Move JwtProperties to manage-common**
Read: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/config/JwtProperties.java`
Copy content to: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/config/JwtProperties.java`
Update package declaration: `package cn.novalon.manage.common.config;`
**Step 3: Update manage-sys imports**
Find all files in manage-sys that import SnowflakeId or JwtProperties and update imports:
```bash
cd novalon-manage-api/manage-sys
find src -name "*.java" -exec grep -l "SnowflakeId\|JwtProperties" {} \;
```
Update imports from:
- `import cn.novalon.manage.sys.utils.SnowflakeId;` to `import cn.novalon.manage.common.util.SnowflakeId;`
- `import cn.novalon.manage.sys.config.JwtProperties;` to `import cn.novalon.manage.common.config.JwtProperties;`
**Step 4: Remove old files from manage-sys**
Run: `rm novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/utils/SnowflakeId.java`
Run: `rm novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/config/JwtProperties.java`
**Step 5: Compile and verify**
Run: `cd novalon-manage-api && mvn clean compile`
Expected: BUILD SUCCESS
**Step 6: Commit**
```bash
git add novalon-manage-api/manage-common/ novalon-manage-api/manage-sys/
git commit -m "refactor: extract common utilities to manage-common"
```
---
### Task 10: Extract database entities to manage-db
**Files:**
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/infrastructure/db/entity/*` to `novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/entity/`
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/infrastructure/db/repository/*` to `novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/repository/`
**Step 1: Move entity classes**
Run: `mkdir -p novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/entity`
Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/infrastructure/db/entity/* novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/entity/`
**Step 2: Update entity package declarations**
For each entity file in manage-db/entity, update package declaration:
From: `package cn.novalon.manage.sys.infrastructure.db.entity;`
To: `package cn.novalon.manage.db.entity;`
**Step 3: Move repository interfaces**
Run: `mkdir -p novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/repository`
Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/infrastructure/db/repository/* novalon-manage-api/manage-db/src/main/java/cn/novalon/manage/db/repository/`
**Step 4: Update repository package declarations**
For each repository file in manage-db/repository, update package declaration:
From: `package cn.novalon.manage.sys.infrastructure.db.repository;`
To: `package cn.novalon.manage.db.repository;`
**Step 5: Update imports in manage-sys**
Find all files in manage-sys that import entities or repositories and update imports:
```bash
cd novalon-manage-api/manage-sys
find src -name "*.java" -exec grep -l "cn.novalon.manage.sys.infrastructure.db" {} \;
```
Update imports from:
- `import cn.novalon.manage.sys.infrastructure.db.entity.*;` to `import cn.novalon.manage.db.entity.*;`
- `import cn.novalon.manage.sys.infrastructure.db.repository.*;` to `import cn.novalon.manage.db.repository.*;`
**Step 6: Compile and verify**
Run: `cd novalon-manage-api && mvn clean compile`
Expected: BUILD SUCCESS
**Step 7: Commit**
```bash
git add novalon-manage-api/manage-db/ novalon-manage-api/manage-sys/
git commit -m "refactor: extract database entities to manage-db"
```
---
### Task 11: Refactor manage-sys module
**Files:**
- Modify: `novalon-manage-api/manage-sys/pom.xml`
- Modify: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/ManageSysApplication.java`
**Step 1: Update manage-sys pom.xml dependencies**
Read: `novalon-manage-api/manage-sys/pom.xml`
Replace dependencies section with:
```xml
<dependencies>
<dependency>
<groupId>cn.novalon.manage</groupId>
<artifactId>manage-db</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>cn.novalon.manage</groupId>
<artifactId>manage-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webflux-ui</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
```
**Step 2: Update ManageSysApplication.java**
Read: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/ManageSysApplication.java`
Update package scan to include new packages:
```java
package cn.novalon.manage.sys;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ConfigurationPropertiesScan(basePackages = "cn.novalon.manage")
@ComponentScan(basePackages = "cn.novalon.manage")
public class ManageSysApplication {
public static void main(String[] args) {
SpringApplication.run(ManageSysApplication.class, args);
}
}
```
**Step 3: Compile and verify**
Run: `cd novalon-manage-api && mvn clean compile -pl manage-sys -am`
Expected: BUILD SUCCESS
**Step 4: Commit**
```bash
git add novalon-manage-api/manage-sys/
git commit -m "refactor: update manage-sys module dependencies"
```
---
### Task 12: Migrate audit functionality to manage-audit
**Files:**
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/handler/log/SysLogHandler.java` to `novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/handler/`
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/OperationLogService.java` to `novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/service/impl/`
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/SysLoginLogService.java` to `novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/service/impl/`
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/SysExceptionLogService.java` to `novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/service/impl/`
**Step 1: Move audit handlers**
Run: `mkdir -p novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/handler`
Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/handler/log/SysLogHandler.java novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/handler/`
**Step 2: Move audit services**
Run: `mkdir -p novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/service/impl`
Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/OperationLogService.java novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/service/impl/`
Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/SysLoginLogService.java novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/service/impl/`
Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/SysExceptionLogService.java novalon-manage-api/manage-audit/src/main/java/cn/novalon/manage/audit/service/impl/`
**Step 3: Update package declarations**
For each moved file, update package declaration:
From: `package cn.novalon.manage.sys.handler.log;` to `package cn.novalon.manage.audit.handler;`
From: `package cn.novalon.manage.sys.core.service.impl;` to `package cn.novalon.manage.audit.service.impl;`
**Step 4: Compile and verify**
Run: `cd novalon-manage-api && mvn clean compile -pl manage-audit -am`
Expected: BUILD SUCCESS
**Step 5: Commit**
```bash
git add novalon-manage-api/manage-audit/ novalon-manage-api/manage-sys/
git commit -m "refactor: migrate audit functionality to manage-audit"
```
---
### Task 13: Migrate notify functionality to manage-notify
**Files:**
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/handler/notice/SysNoticeHandler.java` to `novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/handler/`
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/handler/message/SysUserMessageHandler.java` to `novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/handler/`
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/SysNoticeService.java` to `novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/service/impl/`
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/SysUserMessageService.java` to `novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/service/impl/`
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/WebSocketServiceImpl.java` to `novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/service/impl/`
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/config/WebSocketConfig.java` to `novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/config/`
**Step 1: Move notify handlers**
Run: `mkdir -p novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/handler`
Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/handler/notice/SysNoticeHandler.java novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/handler/`
Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/handler/message/SysUserMessageHandler.java novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/handler/`
**Step 2: Move notify services**
Run: `mkdir -p novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/service/impl`
Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/SysNoticeService.java novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/service/impl/`
Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/SysUserMessageService.java novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/service/impl/`
Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/WebSocketServiceImpl.java novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/service/impl/`
**Step 3: Move notify config**
Run: `mkdir -p novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/config`
Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/config/WebSocketConfig.java novalon-manage-api/manage-notify/src/main/java/cn/novalon/manage/notify/config/`
**Step 4: Update package declarations**
For each moved file, update package declaration:
From: `package cn.novalon.manage.sys.handler.notice;` to `package cn.novalon.manage.notify.handler;`
From: `package cn.novalon.manage.sys.handler.message;` to `package cn.novalon.manage.notify.handler;`
From: `package cn.novalon.manage.sys.core.service.impl;` to `package cn.novalon.manage.notify.service.impl;`
From: `package cn.novalon.manage.sys.config;` to `package cn.novalon.manage.notify.config;`
**Step 5: Compile and verify**
Run: `cd novalon-manage-api && mvn clean compile -pl manage-notify -am`
Expected: BUILD SUCCESS
**Step 6: Commit**
```bash
git add novalon-manage-api/manage-notify/ novalon-manage-api/manage-sys/
git commit -m "refactor: migrate notify functionality to manage-notify"
```
---
### Task 14: Migrate file functionality to manage-file
**Files:**
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/handler/file/SysFileHandler.java` to `novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/handler/`
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/SysFileService.java` to `novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/service/impl/`
- Move: `novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/config/MultipartConfig.java` to `novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/config/`
**Step 1: Move file handler**
Run: `mkdir -p novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/handler`
Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/handler/file/SysFileHandler.java novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/handler/`
**Step 2: Move file service**
Run: `mkdir -p novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/service/impl`
Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/core/service/impl/SysFileService.java novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/service/impl/`
**Step 3: Move file config**
Run: `mkdir -p novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/config`
Run: `mv novalon-manage-api/manage-sys/src/main/java/cn/novalon/manage/sys/config/MultipartConfig.java novalon-manage-api/manage-file/src/main/java/cn/novalon/manage/file/config/`
**Step 4: Update package declarations**
For each moved file, update package declaration:
From: `package cn.novalon.manage.sys.handler.file;` to `package cn.novalon.manage.file.handler;`
From: `package cn.novalon.manage.sys.core.service.impl;` to `package cn.novalon.manage.file.service.impl;`
From: `package cn.novalon.manage.sys.config;` to `package cn.novalon.manage.file.config;`
**Step 5: Compile and verify**
Run: `cd novalon-manage-api && mvn clean compile -pl manage-file -am`
Expected: BUILD SUCCESS
**Step 6: Commit**
```bash
git add novalon-manage-api/manage-file/ novalon-manage-api/manage-sys/
git commit -m "refactor: migrate file functionality to manage-file"
```
---
## Phase 3: Gateway and Application Layer (2-3 days)
### Task 15: Implement JWT authentication filter in manage-gateway
**Files:**
- Create: `novalon-manage-api/manage-gateway/src/main/java/cn/novalon/manage/gateway/filter/JwtAuthenticationFilter.java`
- Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/util/JwtTokenProvider.java`
- Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/dto/JwtUser.java`
**Step 1: Create JwtUser DTO**
Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/dto/JwtUser.java`
```java
package cn.novalon.manage.common.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class JwtUser {
private String userId;
private String username;
private List<String> roles;
private List<String> permissions;
}
```
**Step 2: Create JwtTokenProvider**
Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/util/JwtTokenProvider.java`
```java
package cn.novalon.manage.common.util;
import cn.novalon.manage.common.config.JwtProperties;
import cn.novalon.manage.common.dto.JwtUser;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
import java.util.Date;
import java.util.List;
@Component
public class JwtTokenProvider {
private final JwtProperties jwtProperties;
private final SecretKey key;
public JwtTokenProvider(JwtProperties jwtProperties) {
this.jwtProperties = jwtProperties;
this.key = Keys.hmacShaKeyFor(jwtProperties.getSecret().getBytes());
}
public String generateToken(JwtUser user) {
Date now = new Date();
Date expiryDate = new Date(now.getTime() + jwtProperties.getExpiration() * 1000);
return Jwts.builder()
.subject(user.getUserId())
.claim("username", user.getUsername())
.claim("roles", user.getRoles())
.claim("permissions", user.getPermissions())
.issuedAt(now)
.expiration(expiryDate)
.signWith(key)
.compact();
}
public JwtUser parseToken(String token) {
Claims claims = Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token)
.getBody();
JwtUser user = new JwtUser();
user.setUserId(claims.getSubject());
user.setUsername(claims.get("username", String.class));
user.setRoles(claims.get("roles", List.class));
user.setPermissions(claims.get("permissions", List.class));
return user;
}
public boolean validateToken(String token) {
try {
Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token);
return true;
} catch (Exception e) {
return false;
}
}
}
```
**Step 3: Create JwtAuthenticationFilter**
Create: `novalon-manage-api/manage-gateway/src/main/java/cn/novalon/manage/gateway/filter/JwtAuthenticationFilter.java`
```java
package cn.novalon.manage.gateway.filter;
import cn.novalon.manage.common.dto.JwtUser;
import cn.novalon.manage.common.util.JwtTokenProvider;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class JwtAuthenticationFilter extends AbstractGatewayFilterFactory<JwtAuthenticationFilter.Config> {
private final JwtTokenProvider jwtTokenProvider;
public JwtAuthenticationFilter(JwtTokenProvider jwtTokenProvider) {
super(Config.class);
this.jwtTokenProvider = jwtTokenProvider;
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
String path = request.getPath().value();
if (isPublicPath(path)) {
return chain.filter(exchange);
}
String token = extractToken(request);
if (token == null || !jwtTokenProvider.validateToken(token)) {
return unauthorized(exchange.getResponse());
}
JwtUser user = jwtTokenProvider.parseToken(token);
addHeaders(exchange, user);
return chain.filter(exchange);
};
}
private boolean isPublicPath(String path) {
return path.startsWith("/api/auth/login") || path.startsWith("/api/auth/register");
}
private String extractToken(ServerHttpRequest request) {
String bearerToken = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
return null;
}
private void addHeaders(ServerWebExchange exchange, JwtUser user) {
ServerHttpRequest mutatedRequest = exchange.getRequest().mutate()
.header("X-User-Id", user.getUserId())
.header("X-User-Username", user.getUsername())
.header("X-User-Roles", String.join(",", user.getRoles()))
.header("X-User-Permissions", String.join(",", user.getPermissions()))
.build();
exchange.mutate().request(mutatedRequest).build();
}
private Mono<Void> unauthorized(ServerHttpResponse response) {
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
public static class Config {
}
}
```
**Step 4: Compile and verify**
Run: `cd novalon-manage-api && mvn clean compile -pl manage-gateway,manage-common -am`
Expected: BUILD SUCCESS
**Step 5: Commit**
```bash
git add novalon-manage-api/manage-gateway/ novalon-manage-api/manage-common/
git commit -m "feat: implement JWT authentication filter in manage-gateway"
```
---
### Task 16: Implement RBAC authorization filter in manage-gateway
**Files:**
- Create: `novalon-manage-api/manage-gateway/src/main/java/cn/novalon/manage/gateway/filter/RbacAuthorizationFilter.java`
- Create: `novalon-manage-api/manage-gateway/src/main/java/cn/novalon/manage/gateway/config/PermissionConfig.java`
**Step 1: Create PermissionConfig**
Create: `novalon-manage-api/manage-gateway/src/main/java/cn/novalon/manage/gateway/config/PermissionConfig.java`
```java
package cn.novalon.manage.gateway.config;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class PermissionConfig {
public static final Map<String, String> PATH_PERMISSIONS = new HashMap<>();
static {
PATH_PERMISSIONS.put("/api/sys/users", "user:read");
PATH_PERMISSIONS.put("/api/sys/users/**", "user:write");
PATH_PERMISSIONS.put("/api/sys/roles", "role:read");
PATH_PERMISSIONS.put("/api/sys/roles/**", "role:write");
PATH_PERMISSIONS.put("/api/sys/menus", "menu:read");
PATH_PERMISSIONS.put("/api/sys/menus/**", "menu:write");
PATH_PERMISSIONS.put("/api/sys/config", "config:read");
PATH_PERMISSIONS.put("/api/sys/config/**", "config:write");
PATH_PERMISSIONS.put("/api/audit/logs", "audit:read");
PATH_PERMISSIONS.put("/api/notify/notices", "notice:read");
PATH_PERMISSIONS.put("/api/notify/notices/**", "notice:write");
PATH_PERMISSIONS.put("/api/file/files", "file:read");
PATH_PERMISSIONS.put("/api/file/files/**", "file:write");
}
public static String getRequiredPermission(String path, String method) {
String permissionKey = path;
if (!PATH_PERMISSIONS.containsKey(path)) {
permissionKey = path.substring(0, path.lastIndexOf('/'));
}
return PATH_PERMISSIONS.get(permissionKey);
}
}
```
**Step 2: Create RbacAuthorizationFilter**
Create: `novalon-manage-api/manage-gateway/src/main/java/cn/novalon/manage/gateway/filter/RbacAuthorizationFilter.java`
```java
package cn.novalon.manage.gateway.filter;
import cn.novalon.manage.gateway.config.PermissionConfig;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Arrays;
import java.util.List;
@Component
public class RbacAuthorizationFilter extends AbstractGatewayFilterFactory<RbacAuthorizationFilter.Config> {
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
String path = request.getPath().value();
String method = request.getMethod().name();
if (isPublicPath(path)) {
return chain.filter(exchange);
}
List<String> permissions = request.getHeaders().get("X-User-Permissions");
List<String> roles = request.getHeaders().get("X-User-Roles");
if (permissions == null || roles == null) {
return forbidden(exchange.getResponse());
}
String requiredPermission = PermissionConfig.getRequiredPermission(path, method);
if (requiredPermission != null && !hasPermission(permissions, requiredPermission)) {
return forbidden(exchange.getResponse());
}
return chain.filter(exchange);
};
}
private boolean isPublicPath(String path) {
return path.startsWith("/api/auth/login") || path.startsWith("/api/auth/register");
}
private boolean hasPermission(List<String> permissions, String requiredPermission) {
return permissions.contains(requiredPermission) || permissions.contains("*:*");
}
private Mono<Void> forbidden(ServerHttpResponse response) {
response.setStatusCode(HttpStatus.FORBIDDEN);
return response.setComplete();
}
public static class Config {
}
}
```
**Step 3: Update GatewayApplication to register filters**
Read: `novalon-manage-api/manage-gateway/src/main/java/cn/novalon/manage/gateway/GatewayApplication.java`
Update to include filters:
```java
package cn.novalon.manage.gateway;
import cn.novalon.manage.gateway.filter.JwtAuthenticationFilter;
import cn.novalon.manage.gateway.filter.RbacAuthorizationFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("manage-app", r -> r
.path("/api/**")
.filters(f -> f
.filter(new JwtAuthenticationFilter.Config())
.filter(new RbacAuthorizationFilter.Config()))
.uri("http://manage-app:8081"))
.build();
}
}
```
**Step 4: Compile and verify**
Run: `cd novalon-manage-api && mvn clean compile -pl manage-gateway -am`
Expected: BUILD SUCCESS
**Step 5: Commit**
```bash
git add novalon-manage-api/manage-gateway/
git commit -m "feat: implement RBAC authorization filter in manage-gateway"
```
---
### Task 17: Configure Caffeine cache in manage-common
**Files:**
- Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/config/CacheConfig.java`
- Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/service/TokenBlacklistService.java`
**Step 1: Create CacheConfig**
Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/config/CacheConfig.java`
```java
package cn.novalon.manage.common.config;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.TimeUnit;
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCaffeine(caffeineCacheBuilder());
return cacheManager;
}
@Bean
public com.github.benmanes.caffeine.cache.Cache<Object, Object> caffeineCache() {
return Caffeine.newBuilder()
.maximumSize(10000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build();
}
private Caffeine<Object, Object> caffeineCacheBuilder() {
return Caffeine.newBuilder()
.maximumSize(10000)
.expireAfterWrite(10, TimeUnit.MINUTES);
}
}
```
**Step 2: Create TokenBlacklistService**
Create: `novalon-manage-api/manage-common/src/main/java/cn/novalon/manage/common/service/TokenBlacklistService.java`
```java
package cn.novalon.manage.common.service;
import com.github.benmanes.caffeine.cache.Cache;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Service
public class TokenBlacklistService {
private final Cache<String, Boolean> tokenBlacklistCache;
public TokenBlacklistService() {
this.tokenBlacklistCache = com.github.benmanes.caffeine.cache.Caffeine.newBuilder()
.maximumSize(10000)
.expireAfterWrite(2, TimeUnit.HOURS)
.build();
}
public void addToBlacklist(String tokenId) {
tokenBlacklistCache.put(tokenId, true);
}
public boolean isBlacklisted(String tokenId) {
return tokenBlacklistCache.getIfPresent(tokenId) != null;
}
}
```
**Step 3: Compile and verify**
Run: `cd novalon-manage-api && mvn clean compile -pl manage-common -am`
Expected: BUILD SUCCESS
**Step 4: Commit**
```bash
git add novalon-manage-api/manage-common/
git commit -m "feat: configure Caffeine cache in manage-common"
```
---
### Task 18: Create Docker Compose configuration
**Files:**
- Create: `novalon-manage-system/docker-compose.yml`
- Create: `novalon-manage-system/.env.example`
**Step 1: Create docker-compose.yml**
Create: `novalon-manage-system/docker-compose.yml`
```yaml
version: '3.8'
services:
postgres:
image: postgres:15-alpine
container_name: novalon-postgres
environment:
POSTGRES_DB: novalon_manage
POSTGRES_USER: ${DB_USERNAME:-postgres}
POSTGRES_PASSWORD: ${DB_PASSWORD:-postgres}
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
- ./docs/sql:/docker-entrypoint-initdb.d
networks:
- novalon-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
manage-gateway:
build:
context: ./novalon-manage-api
dockerfile: manage-gateway/Dockerfile
container_name: novalon-gateway
ports:
- "8080:8080"
environment:
SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-prod}
JWT_SECRET: ${JWT_SECRET}
JWT_EXPIRATION: ${JWT_EXPIRATION:-7200}
APP_SERVICE_URL: http://manage-app:8081
depends_on:
manage-app:
condition: service_healthy
networks:
- novalon-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 10s
retries: 3
manage-app:
build:
context: ./novalon-manage-api
dockerfile: manage-app/Dockerfile
container_name: novalon-app
ports:
- "8081:8081"
environment:
SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-prod}
DB_HOST: postgres
DB_PORT: 5432
DB_NAME: novalon_manage
DB_USERNAME: ${DB_USERNAME:-postgres}
DB_PASSWORD: ${DB_PASSWORD:-postgres}
JWT_SECRET: ${JWT_SECRET}
depends_on:
postgres:
condition: service_healthy
networks:
- novalon-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8081/actuator/health"]
interval: 30s
timeout: 10s
retries: 3
volumes:
postgres_data:
networks:
novalon-network:
driver: bridge
```
**Step 2: Create .env.example**
Create: `novalon-manage-system/.env.example`
```bash
# Database Configuration
DB_USERNAME=postgres
DB_PASSWORD=your_secure_password
# JWT Configuration
JWT_SECRET=your_jwt_secret_key_minimum_256_bits
JWT_EXPIRATION=7200
# Spring Profile
SPRING_PROFILES_ACTIVE=prod
```
**Step 3: Commit**
```bash
git add novalon-manage-system/docker-compose.yml novalon-manage-system/.env.example
git commit -m "feat: add Docker Compose configuration"
```
---
## Phase 4: Testing and Optimization (2-3 days)
### Task 19: Write unit tests for manage-common
**Files:**
- Create: `novalon-manage-api/manage-common/src/test/java/cn/novalon/manage/common/util/JwtTokenProviderTest.java`
- Create: `novalon-manage-api/manage-common/src/test/java/cn/novalon/manage/common/service/TokenBlacklistServiceTest.java`
**Step 1: Write JwtTokenProviderTest**
Create: `novalon-manage-api/manage-common/src/test/java/cn/novalon/manage/common/util/JwtTokenProviderTest.java`
```java
package cn.novalon.manage.common.util;
import cn.novalon.manage.common.config.JwtProperties;
import cn.novalon.manage.common.dto.JwtUser;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
class JwtTokenProviderTest {
private JwtTokenProvider jwtTokenProvider;
private JwtProperties jwtProperties;
@BeforeEach
void setUp() {
jwtProperties = new JwtProperties();
jwtProperties.setSecret("test-secret-key-for-testing-purposes-only");
jwtProperties.setExpiration(7200);
jwtTokenProvider = new JwtTokenProvider(jwtProperties);
}
@Test
void testGenerateToken() {
JwtUser user = new JwtUser();
user.setUserId("user123");
user.setUsername("testuser");
user.setRoles(Arrays.asList("ADMIN"));
user.setPermissions(Arrays.asList("user:read", "user:write"));
String token = jwtTokenProvider.generateToken(user);
assertNotNull(token);
assertFalse(token.isEmpty());
}
@Test
void testParseToken() {
JwtUser originalUser = new JwtUser();
originalUser.setUserId("user123");
originalUser.setUsername("testuser");
originalUser.setRoles(Arrays.asList("ADMIN"));
originalUser.setPermissions(Arrays.asList("user:read", "user:write"));
String token = jwtTokenProvider.generateToken(originalUser);
JwtUser parsedUser = jwtTokenProvider.parseToken(token);
assertEquals(originalUser.getUserId(), parsedUser.getUserId());
assertEquals(originalUser.getUsername(), parsedUser.getUsername());
assertEquals(originalUser.getRoles(), parsedUser.getRoles());
assertEquals(originalUser.getPermissions(), parsedUser.getPermissions());
}
@Test
void testValidateToken() {
JwtUser user = new JwtUser();
user.setUserId("user123");
user.setUsername("testuser");
user.setRoles(Arrays.asList("ADMIN"));
user.setPermissions(Arrays.asList("user:read"));
String validToken = jwtTokenProvider.generateToken(user);
assertTrue(jwtTokenProvider.validateToken(validToken));
String invalidToken = "invalid.token.here";
assertFalse(jwtTokenProvider.validateToken(invalidToken));
}
}
```
**Step 2: Write TokenBlacklistServiceTest**
Create: `novalon-manage-api/manage-common/src/test/java/cn/novalon/manage/common/service/TokenBlacklistServiceTest.java`
```java
package cn.novalon.manage.common.service;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class TokenBlacklistServiceTest {
private TokenBlacklistService tokenBlacklistService;
@BeforeEach
void setUp() {
tokenBlacklistService = new TokenBlacklistService();
}
@Test
void testAddToBlacklist() {
String tokenId = "token123";
tokenBlacklistService.addToBlacklist(tokenId);
assertTrue(tokenBlacklistService.isBlacklisted(tokenId));
}
@Test
void testIsBlacklisted() {
String tokenId = "token456";
assertFalse(tokenBlacklistService.isBlacklisted(tokenId));
tokenBlacklistService.addToBlacklist(tokenId);
assertTrue(tokenBlacklistService.isBlacklisted(tokenId));
}
@Test
void testMultipleTokens() {
String token1 = "token1";
String token2 = "token2";
String token3 = "token3";
tokenBlacklistService.addToBlacklist(token1);
tokenBlacklistService.addToBlacklist(token2);
tokenBlacklistService.addToBlacklist(token3);
assertTrue(tokenBlacklistService.isBlacklisted(token1));
assertTrue(tokenBlacklistService.isBlacklisted(token2));
assertTrue(tokenBlacklistService.isBlacklisted(token3));
}
}
```
**Step 3: Run tests**
Run: `cd novalon-manage-api && mvn test -pl manage-common`
Expected: All tests pass
**Step 4: Commit**
```bash