重构项目结构,将分散在各模块的领域模型统一移动到manage-common模块 更新相关依赖和引用路径 调整docker-compose配置和测试标记 添加新的Playwright测试配置 优化Dockerfile构建过程
64 KiB
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 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
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
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
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
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 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
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
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
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
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 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
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
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 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
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 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
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 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
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 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
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:
<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
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:
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;toimport cn.novalon.manage.common.util.SnowflakeId;import cn.novalon.manage.sys.config.JwtProperties;toimport 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
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/*tonovalon-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/*tonovalon-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:
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.*;toimport cn.novalon.manage.db.entity.*;import cn.novalon.manage.sys.infrastructure.db.repository.*;toimport cn.novalon.manage.db.repository.*;
Step 6: Compile and verify
Run: cd novalon-manage-api && mvn clean compile
Expected: BUILD SUCCESS
Step 7: Commit
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:
<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:
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
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.javatonovalon-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.javatonovalon-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.javatonovalon-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.javatonovalon-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
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.javatonovalon-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.javatonovalon-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.javatonovalon-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.javatonovalon-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.javatonovalon-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.javatonovalon-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
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.javatonovalon-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.javatonovalon-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.javatonovalon-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
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
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
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
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
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
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
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:
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
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
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
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
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
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
# 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
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
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
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