chore: 更新Docker和CI配置
- 更新Woodpecker CI配置 - 更新Docker Compose配置 - 更新应用主类配置 - 更新网关路由服务 - 更新审计日志相关代码
This commit is contained in:
@@ -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"]
|
||||
+3
-3
@@ -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
|
||||
|
||||
+9
-15
@@ -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);
|
||||
|
||||
+15
-4
@@ -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) {
|
||||
|
||||
+8
-12
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+26
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+34
@@ -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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user