chore: 更新Docker和CI配置

- 更新Woodpecker CI配置
- 更新Docker Compose配置
- 更新应用主类配置
- 更新网关路由服务
- 更新审计日志相关代码
This commit is contained in:
张翔
2026-04-15 23:38:03 +08:00
parent 38dc055a27
commit 60fb84e306
11 changed files with 398 additions and 204 deletions
+33 -6
View File
@@ -1,22 +1,49 @@
FROM maven:3.9-eclipse-temurin-17 AS builder
# 多阶段构建优化Dockerfile
FROM maven:3.9-eclipse-temurin-21 AS builder
WORKDIR /app
# 复制Maven配置文件和源码
COPY pom.xml .
COPY mvnw .
COPY mvnw.cmd .
COPY .mvn .mvn
COPY src ./src
RUN chmod +x mvnw
# 下载依赖(利用Docker缓存层)
RUN ./mvnw dependency:go-offline -B
# 复制源码并构建
COPY src ./src
RUN ./mvnw clean package -DskipTests
FROM openjdk:17-slim
# 运行时镜像
FROM eclipse-temurin:21-jre-jammy
# 设置时区和语言环境
RUN apt-get update && apt-get install -y \
curl \
&& rm -rf /var/lib/apt/lists/*
# 创建非root用户运行应用
RUN groupadd -r novalon && useradd -r -g novalon novalon
WORKDIR /app
COPY --from=builder /app/target/*.jar app.jar
# 复制构建产物
COPY --from=builder --chown=novalon:novalon /app/target/*.jar app.jar
# 设置JVM参数优化
ENV JAVA_OPTS="-Xmx512m -Xms256m -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:+UseContainerSupport -Djava.security.egd=file:/dev/./urandom"
# 暴露端口
EXPOSE 8084
ENTRYPOINT ["java", "-jar", "app.jar"]
# 切换用户
USER novalon
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
CMD curl -f http://localhost:8084/actuator/health || exit 1
# 启动命令
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
@@ -9,9 +9,7 @@ import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;
@SpringBootApplication(exclude = {ReactiveUserDetailsServiceAutoConfiguration.class})
@ConfigurationPropertiesScan(basePackages = "cn.novalon.manage")
@ComponentScan(basePackages = "cn.novalon.manage")
@SpringBootApplication(scanBasePackages = "cn.novalon.manage", exclude = {ReactiveUserDetailsServiceAutoConfiguration.class})
@EnableR2dbcRepositories(basePackages = {"cn.novalon.manage.db.dao", "cn.novalon.manage.sys.audit.repository"})
public class ManageApplication {
@@ -20,6 +18,8 @@ public class ManageApplication {
public static void main(String[] args) {
logger.info("应用程序启动中...");
logger.info("包扫描路径: cn.novalon.manage");
// 使用简单的启动方式,避免自动配置问题
SpringApplication.run(ManageApplication.class, args);
logger.info("应用程序启动完成");
}
@@ -20,7 +20,11 @@ spring:
password: ${DB_PASSWORD:postgres}
driver-class-name: org.postgresql.Driver
flyway:
enabled: false
enabled: true
locations: classpath:db/migration
baseline-on-migrate: true
baseline-version: 0
validate-on-migrate: true
security:
user:
name: disabled
@@ -74,11 +74,9 @@ public class DynamicRouteService implements IDynamicRouteService {
logger.info("Adding route: {}", routeId);
return routeDefinitionWriter.save(Mono.just(routeDefinition))
.then(Mono.fromRunnable(() -> {
routeCache.put(routeId, routeDefinition);
refreshRoutes();
logger.info("Route added successfully: {}", routeId);
}))
.then(Mono.fromRunnable(() -> routeCache.put(routeId, routeDefinition)))
.then(refreshRoutes())
.then(Mono.fromRunnable(() -> logger.info("Route added successfully: {}", routeId)))
.thenReturn(true)
.onErrorResume(error -> {
logger.error("Failed to add route: {}", routeId, error);
@@ -104,11 +102,9 @@ public class DynamicRouteService implements IDynamicRouteService {
return routeDefinitionWriter.delete(Mono.just(routeId))
.then(routeDefinitionWriter.save(Mono.just(routeDefinition)))
.then(Mono.fromRunnable(() -> {
routeCache.put(routeId, routeDefinition);
refreshRoutes();
logger.info("Route updated successfully: {}", routeId);
}))
.then(Mono.fromRunnable(() -> routeCache.put(routeId, routeDefinition)))
.then(refreshRoutes())
.then(Mono.fromRunnable(() -> logger.info("Route updated successfully: {}", routeId)))
.thenReturn(true)
.onErrorResume(error -> {
logger.error("Failed to update route: {}", routeId, error);
@@ -131,11 +127,9 @@ public class DynamicRouteService implements IDynamicRouteService {
logger.info("Deleting route: {}", routeId);
return routeDefinitionWriter.delete(Mono.just(routeId))
.then(Mono.fromRunnable(() -> {
routeCache.remove(routeId);
refreshRoutes();
logger.info("Route deleted successfully: {}", routeId);
}))
.then(Mono.fromRunnable(() -> routeCache.remove(routeId)))
.then(refreshRoutes())
.then(Mono.fromRunnable(() -> logger.info("Route deleted successfully: {}", routeId)))
.thenReturn(true)
.onErrorResume(error -> {
logger.error("Failed to delete route: {}", routeId, error);
@@ -1,5 +1,6 @@
package cn.novalon.manage.gateway.route;
import cn.novalon.manage.gateway.service.impl.DynamicRouteService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -25,7 +26,7 @@ import static org.mockito.Mockito.*;
* 涉及业务:路由增删改查、路由刷新
*
* @author 张翔
* @date 2026-03-26
* @date 2026-04-14
*/
@ExtendWith(MockitoExtension.class)
class DynamicRouteServiceTest {
@@ -78,7 +79,15 @@ class DynamicRouteServiceTest {
@Test
void testDeleteRoute_Success() {
String routeId = "test-route";
RouteDefinition routeDefinition = createRouteDefinition(routeId);
// 先添加路由到缓存中
when(routeDefinitionWriter.save(any())).thenReturn(Mono.empty());
StepVerifier.create(dynamicRouteService.addRoute(routeDefinition))
.expectNext(true)
.verifyComplete();
// 然后删除路由
when(routeDefinitionWriter.delete(any())).thenReturn(Mono.empty());
StepVerifier.create(dynamicRouteService.deleteRoute(routeId))
@@ -86,7 +95,7 @@ class DynamicRouteServiceTest {
.verifyComplete();
verify(routeDefinitionWriter).delete(any());
verify(publisher).publishEvent(any(RefreshRoutesEvent.class));
verify(publisher, times(2)).publishEvent(any(RefreshRoutesEvent.class));
}
@Test
@@ -113,7 +122,7 @@ class DynamicRouteServiceTest {
.expectNext(true)
.verifyComplete();
StepVerifier.create(dynamicRouteService.getAllRoutes().collectList())
StepVerifier.create(dynamicRouteService.getRoutes().collectList())
.assertNext(routes -> {
assertNotNull(routes);
assertTrue(routes.size() >= 2);
@@ -131,7 +140,9 @@ class DynamicRouteServiceTest {
.expectNext(true)
.verifyComplete();
assertTrue(dynamicRouteService.getRouteCount() >= 1);
StepVerifier.create(dynamicRouteService.getRouteCount())
.assertNext(count -> assertTrue(count >= 1))
.verifyComplete();
}
private RouteDefinition createRouteDefinition(String id) {
@@ -47,9 +47,8 @@ public class AuditLogController {
public Flux<AuditLog> query(AuditLogQueryRequest request) {
if (request.getEntityType() != null && request.getEntityId() != null) {
return auditLogService.findByEntityTypeAndEntityId(
request.getEntityType(),
request.getEntityId()
);
request.getEntityType(),
request.getEntityId());
} else if (request.getEntityType() != null) {
return auditLogService.findByEntityType(request.getEntityType());
} else if (request.getOperator() != null) {
@@ -58,11 +57,10 @@ public class AuditLogController {
return auditLogService.findByOperationType(request.getOperationType());
} else if (request.getStartTime() != null && request.getEndTime() != null) {
return auditLogService.findByOperationTimeBetween(
request.getStartTime(),
request.getEndTime()
);
request.getStartTime(),
request.getEndTime());
}
return Flux.empty();
}
@@ -97,10 +95,8 @@ public class AuditLogController {
@GetMapping("/time-range")
@Operation(summary = "按时间范围查询", description = "根据时间范围查询审计日志")
public Flux<AuditLog> findByTimeRange(
@Parameter(description = "开始时间")
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startTime,
@Parameter(description = "结束时间")
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endTime) {
@Parameter(description = "开始时间") @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startTime,
@Parameter(description = "结束时间") @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endTime) {
return auditLogService.findByOperationTimeBetween(startTime, endTime);
}
@@ -108,7 +104,7 @@ public class AuditLogController {
@Operation(summary = "审计日志统计", description = "获取审计日志的统计信息")
public Mono<AuditLogStatistics> getStatistics() {
AuditLogStatistics statistics = new AuditLogStatistics();
return Mono.just(statistics);
}
@@ -138,4 +138,30 @@ public class AuditLog extends BaseDomain {
public void setDescription(String description) {
this.description = description;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
AuditLog auditLog = (AuditLog) o;
return java.util.Objects.equals(entityType, auditLog.entityType) &&
java.util.Objects.equals(entityId, auditLog.entityId) &&
java.util.Objects.equals(operationType, auditLog.operationType) &&
java.util.Objects.equals(operator, auditLog.operator) &&
java.util.Objects.equals(operationTime, auditLog.operationTime) &&
java.util.Objects.equals(beforeData, auditLog.beforeData) &&
java.util.Objects.equals(afterData, auditLog.afterData) &&
java.util.Arrays.equals(changedFields, auditLog.changedFields) &&
java.util.Objects.equals(ipAddress, auditLog.ipAddress) &&
java.util.Objects.equals(userAgent, auditLog.userAgent) &&
java.util.Objects.equals(description, auditLog.description);
}
@Override
public int hashCode() {
return java.util.Objects.hash(super.hashCode(), entityType, entityId, operationType, operator,
operationTime, beforeData, afterData, java.util.Arrays.hashCode(changedFields),
ipAddress, userAgent, description);
}
}
@@ -100,4 +100,38 @@ public class AuditLogQueryRequest {
public void setSize(Integer size) {
this.size = size;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AuditLogQueryRequest that = (AuditLogQueryRequest) o;
return java.util.Objects.equals(entityType, that.entityType) &&
java.util.Objects.equals(entityId, that.entityId) &&
java.util.Objects.equals(operationType, that.operationType) &&
java.util.Objects.equals(operator, that.operator) &&
java.util.Objects.equals(startTime, that.startTime) &&
java.util.Objects.equals(endTime, that.endTime) &&
java.util.Objects.equals(page, that.page) &&
java.util.Objects.equals(size, that.size);
}
@Override
public int hashCode() {
return java.util.Objects.hash(entityType, entityId, operationType, operator, startTime, endTime, page, size);
}
@Override
public String toString() {
return "AuditLogQueryRequest{" +
"entityType='" + entityType + '\'' +
", entityId=" + entityId +
", operationType='" + operationType + '\'' +
", operator='" + operator + '\'' +
", startTime=" + startTime +
", endTime=" + endTime +
", page=" + page +
", size=" + size +
'}';
}
}