diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..93bb823
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,80 @@
+# 资金服务平台 - 统一 Dockerfile
+# 多阶段构建:Maven 构建 + JRE 运行
+
+# ==================== 构建阶段 ====================
+FROM maven:3.9-eclipse-temurin-21-alpine AS builder
+
+WORKDIR /build
+
+# 复制 Maven 配置文件(利用缓存加速构建)
+COPY pom.xml .
+COPY fund-common/pom.xml fund-common/
+COPY fund-gateway/pom.xml fund-gateway/
+COPY fund-sys/pom.xml fund-sys/
+COPY fund-cust/pom.xml fund-cust/
+COPY fund-proj/pom.xml fund-proj/
+COPY fund-req/pom.xml fund-req/
+COPY fund-exp/pom.xml fund-exp/
+COPY fund-receipt/pom.xml fund-receipt/
+COPY fund-report/pom.xml fund-report/
+COPY fund-file/pom.xml fund-file/
+
+# 下载依赖(利用 Docker 缓存)
+RUN mvn dependency:go-offline -B || true
+
+# 复制源代码
+COPY fund-common/ fund-common/
+COPY fund-gateway/ fund-gateway/
+COPY fund-sys/ fund-sys/
+COPY fund-cust/ fund-cust/
+COPY fund-proj/ fund-proj/
+COPY fund-req/ fund-req/
+COPY fund-exp/ fund-exp/
+COPY fund-receipt/ fund-receipt/
+COPY fund-report/ fund-report/
+COPY fund-file/ fund-file/
+
+# 构建参数:指定要构建的模块
+ARG MODULE=fund-sys
+RUN mvn clean package -pl ${MODULE} -am -DskipTests -B
+
+# ==================== 运行阶段 ====================
+FROM eclipse-temurin:21-jre-alpine
+
+# 安装必要工具
+RUN apk add --no-cache curl tzdata && \
+ cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
+ echo "Asia/Shanghai" > /etc/timezone && \
+ apk del tzdata
+
+# 创建非 root 用户
+RUN addgroup -S appgroup && adduser -S appuser -G appgroup
+
+WORKDIR /app
+
+# 构建参数
+ARG MODULE=fund-sys
+ARG VERSION=0.0.1-SNAPSHOT
+
+# 从构建阶段复制 JAR 包
+COPY --from=builder /build/${MODULE}/target/${MODULE}-${VERSION}.jar app.jar
+
+# 设置权限
+RUN chown -R appuser:appgroup /app
+
+# 切换非 root 用户
+USER appuser
+
+# JVM 参数
+ENV JAVA_OPTS="-Xms256m -Xmx512m -XX:+UseG1GC -XX:+HeapDumpOnOutOfMemoryError"
+ENV SPRING_PROFILES_ACTIVE="docker"
+
+# 暴露端口(默认 8080,实际端口由服务决定)
+EXPOSE 8080
+
+# 健康检查
+HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
+ CMD curl -f http://localhost:${SERVER_PORT:-8080}/actuator/health || exit 1
+
+# 启动命令
+ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar app.jar"]
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..fdc3531
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,436 @@
+# 资金服务平台 - Docker Compose 编排配置
+# 版本: 1.0
+
+version: '3.8'
+
+services:
+ # ==================== 基础设施服务 ====================
+
+ # MySQL 数据库
+ mysql:
+ image: mysql:8.0
+ container_name: fund-mysql
+ restart: unless-stopped
+ environment:
+ MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-root123}
+ MYSQL_DATABASE: fund_platform
+ TZ: Asia/Shanghai
+ ports:
+ - "3306:3306"
+ volumes:
+ - mysql_data:/var/lib/mysql
+ - ./docker/mysql/init:/docker-entrypoint-initdb.d:ro
+ command:
+ - --character-set-server=utf8mb4
+ - --collation-server=utf8mb4_unicode_ci
+ - --default-authentication-plugin=mysql_native_password
+ healthcheck:
+ test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+ networks:
+ - fund-network
+
+ # Redis 缓存
+ redis:
+ image: redis:7-alpine
+ container_name: fund-redis
+ restart: unless-stopped
+ ports:
+ - "6379:6379"
+ volumes:
+ - redis_data:/data
+ command: redis-server --appendonly yes
+ healthcheck:
+ test: ["CMD", "redis-cli", "ping"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+ networks:
+ - fund-network
+
+ # Nacos 注册中心 & 配置中心
+ nacos:
+ image: nacos/nacos-server:v3.0.0
+ container_name: fund-nacos
+ restart: unless-stopped
+ environment:
+ MODE: standalone
+ SPRING_DATASOURCE_PLATFORM: mysql
+ MYSQL_SERVICE_HOST: mysql
+ MYSQL_SERVICE_PORT: 3306
+ MYSQL_SERVICE_DB_NAME: nacos_config
+ MYSQL_SERVICE_USER: root
+ MYSQL_SERVICE_PASSWORD: ${MYSQL_ROOT_PASSWORD:-root123}
+ NACOS_AUTH_TOKEN: SecretKey012345678901234567890123456789012345678901234567890123456789
+ NACOS_AUTH_IDENTITY_KEY: serverIdentity
+ NACOS_AUTH_IDENTITY_VALUE: security
+ ports:
+ - "8848:8848"
+ - "9848:9848"
+ - "9849:9849"
+ volumes:
+ - nacos_data:/home/nacos/logs
+ depends_on:
+ mysql:
+ condition: service_healthy
+ healthcheck:
+ test: ["CMD", "curl", "-f", "http://localhost:8848/nacos/v1/console/health/readiness"]
+ interval: 30s
+ timeout: 10s
+ retries: 10
+ start_period: 60s
+ networks:
+ - fund-network
+
+ # ==================== 监控服务 ====================
+
+ # Prometheus 监控
+ prometheus:
+ image: prom/prometheus:v2.48.0
+ container_name: fund-prometheus
+ restart: unless-stopped
+ ports:
+ - "9090:9090"
+ volumes:
+ - ./docker/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
+ - ./docker/prometheus/rules:/etc/prometheus/rules:ro
+ - prometheus_data:/prometheus
+ command:
+ - '--config.file=/etc/prometheus/prometheus.yml'
+ - '--storage.tsdb.path=/prometheus'
+ - '--storage.tsdb.retention.time=15d'
+ - '--web.enable-lifecycle'
+ networks:
+ - fund-network
+
+ # Grafana 可视化
+ grafana:
+ image: grafana/grafana:10.2.0
+ container_name: fund-grafana
+ restart: unless-stopped
+ environment:
+ GF_SECURITY_ADMIN_USER: admin
+ GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD:-admin123}
+ GF_USERS_ALLOW_SIGN_UP: "false"
+ GF_SERVER_ROOT_URL: http://localhost:3000
+ ports:
+ - "3000:3000"
+ volumes:
+ - grafana_data:/var/lib/grafana
+ - ./docker/grafana/provisioning:/etc/grafana/provisioning:ro
+ - ./docker/grafana/dashboards:/var/lib/grafana/dashboards:ro
+ depends_on:
+ - prometheus
+ networks:
+ - fund-network
+
+ # ==================== 业务微服务 ====================
+
+ # API 网关
+ gateway:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ args:
+ MODULE: fund-gateway
+ container_name: fund-gateway
+ restart: unless-stopped
+ environment:
+ SERVER_PORT: 8000
+ SPRING_PROFILES_ACTIVE: docker
+ NACOS_SERVER_ADDR: nacos:8848
+ NACOS_USERNAME: nacos
+ NACOS_PASSWORD: nacos
+ JAVA_OPTS: -Xms256m -Xmx512m
+ ports:
+ - "8000:8000"
+ depends_on:
+ nacos:
+ condition: service_healthy
+ healthcheck:
+ test: ["CMD", "curl", "-f", "http://localhost:8000/actuator/health"]
+ interval: 30s
+ timeout: 10s
+ retries: 5
+ start_period: 120s
+ networks:
+ - fund-network
+
+ # 系统服务
+ fund-sys:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ args:
+ MODULE: fund-sys
+ container_name: fund-sys
+ restart: unless-stopped
+ environment:
+ SERVER_PORT: 8100
+ SPRING_PROFILES_ACTIVE: docker
+ NACOS_SERVER_ADDR: nacos:8848
+ NACOS_USERNAME: nacos
+ NACOS_PASSWORD: nacos
+ MYSQL_HOST: mysql
+ MYSQL_PORT: 3306
+ MYSQL_DB: fund_platform
+ MYSQL_USER: root
+ MYSQL_PASSWORD: ${MYSQL_ROOT_PASSWORD:-root123}
+ REDIS_HOST: redis
+ REDIS_PORT: 6379
+ JAVA_OPTS: -Xms256m -Xmx512m
+ ports:
+ - "8100:8100"
+ depends_on:
+ nacos:
+ condition: service_healthy
+ mysql:
+ condition: service_healthy
+ redis:
+ condition: service_healthy
+ healthcheck:
+ test: ["CMD", "curl", "-f", "http://localhost:8100/actuator/health"]
+ interval: 30s
+ timeout: 10s
+ retries: 5
+ start_period: 120s
+ networks:
+ - fund-network
+
+ # 客户服务
+ fund-cust:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ args:
+ MODULE: fund-cust
+ container_name: fund-cust
+ restart: unless-stopped
+ environment:
+ SERVER_PORT: 8200
+ SPRING_PROFILES_ACTIVE: docker
+ NACOS_SERVER_ADDR: nacos:8848
+ NACOS_USERNAME: nacos
+ NACOS_PASSWORD: nacos
+ MYSQL_HOST: mysql
+ MYSQL_PORT: 3306
+ MYSQL_DB: fund_platform
+ MYSQL_USER: root
+ MYSQL_PASSWORD: ${MYSQL_ROOT_PASSWORD:-root123}
+ JAVA_OPTS: -Xms256m -Xmx512m
+ ports:
+ - "8200:8200"
+ depends_on:
+ nacos:
+ condition: service_healthy
+ mysql:
+ condition: service_healthy
+ networks:
+ - fund-network
+
+ # 项目服务
+ fund-proj:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ args:
+ MODULE: fund-proj
+ container_name: fund-proj
+ restart: unless-stopped
+ environment:
+ SERVER_PORT: 8300
+ SPRING_PROFILES_ACTIVE: docker
+ NACOS_SERVER_ADDR: nacos:8848
+ NACOS_USERNAME: nacos
+ NACOS_PASSWORD: nacos
+ MYSQL_HOST: mysql
+ MYSQL_PORT: 3306
+ MYSQL_DB: fund_platform
+ MYSQL_USER: root
+ MYSQL_PASSWORD: ${MYSQL_ROOT_PASSWORD:-root123}
+ JAVA_OPTS: -Xms256m -Xmx512m
+ ports:
+ - "8300:8300"
+ depends_on:
+ nacos:
+ condition: service_healthy
+ mysql:
+ condition: service_healthy
+ networks:
+ - fund-network
+
+ # 需求工单服务
+ fund-req:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ args:
+ MODULE: fund-req
+ container_name: fund-req
+ restart: unless-stopped
+ environment:
+ SERVER_PORT: 8400
+ SPRING_PROFILES_ACTIVE: docker
+ NACOS_SERVER_ADDR: nacos:8848
+ NACOS_USERNAME: nacos
+ NACOS_PASSWORD: nacos
+ MYSQL_HOST: mysql
+ MYSQL_PORT: 3306
+ MYSQL_DB: fund_platform
+ MYSQL_USER: root
+ MYSQL_PASSWORD: ${MYSQL_ROOT_PASSWORD:-root123}
+ JAVA_OPTS: -Xms256m -Xmx512m
+ ports:
+ - "8400:8400"
+ depends_on:
+ nacos:
+ condition: service_healthy
+ mysql:
+ condition: service_healthy
+ networks:
+ - fund-network
+
+ # 支出服务
+ fund-exp:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ args:
+ MODULE: fund-exp
+ container_name: fund-exp
+ restart: unless-stopped
+ environment:
+ SERVER_PORT: 8500
+ SPRING_PROFILES_ACTIVE: docker
+ NACOS_SERVER_ADDR: nacos:8848
+ NACOS_USERNAME: nacos
+ NACOS_PASSWORD: nacos
+ MYSQL_HOST: mysql
+ MYSQL_PORT: 3306
+ MYSQL_DB: fund_platform
+ MYSQL_USER: root
+ MYSQL_PASSWORD: ${MYSQL_ROOT_PASSWORD:-root123}
+ JAVA_OPTS: -Xms256m -Xmx512m
+ ports:
+ - "8500:8500"
+ depends_on:
+ nacos:
+ condition: service_healthy
+ mysql:
+ condition: service_healthy
+ networks:
+ - fund-network
+
+ # 收款服务
+ fund-receipt:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ args:
+ MODULE: fund-receipt
+ container_name: fund-receipt
+ restart: unless-stopped
+ environment:
+ SERVER_PORT: 8600
+ SPRING_PROFILES_ACTIVE: docker
+ NACOS_SERVER_ADDR: nacos:8848
+ NACOS_USERNAME: nacos
+ NACOS_PASSWORD: nacos
+ MYSQL_HOST: mysql
+ MYSQL_PORT: 3306
+ MYSQL_DB: fund_platform
+ MYSQL_USER: root
+ MYSQL_PASSWORD: ${MYSQL_ROOT_PASSWORD:-root123}
+ JAVA_OPTS: -Xms256m -Xmx512m
+ ports:
+ - "8600:8600"
+ depends_on:
+ nacos:
+ condition: service_healthy
+ mysql:
+ condition: service_healthy
+ networks:
+ - fund-network
+
+ # 报表服务
+ fund-report:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ args:
+ MODULE: fund-report
+ container_name: fund-report
+ restart: unless-stopped
+ environment:
+ SERVER_PORT: 8700
+ SPRING_PROFILES_ACTIVE: docker
+ NACOS_SERVER_ADDR: nacos:8848
+ NACOS_USERNAME: nacos
+ NACOS_PASSWORD: nacos
+ MYSQL_HOST: mysql
+ MYSQL_PORT: 3306
+ MYSQL_DB: fund_platform
+ MYSQL_USER: root
+ MYSQL_PASSWORD: ${MYSQL_ROOT_PASSWORD:-root123}
+ JAVA_OPTS: -Xms256m -Xmx512m
+ ports:
+ - "8700:8700"
+ depends_on:
+ nacos:
+ condition: service_healthy
+ mysql:
+ condition: service_healthy
+ networks:
+ - fund-network
+
+ # 文件服务
+ fund-file:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ args:
+ MODULE: fund-file
+ container_name: fund-file
+ restart: unless-stopped
+ environment:
+ SERVER_PORT: 8800
+ SPRING_PROFILES_ACTIVE: docker
+ NACOS_SERVER_ADDR: nacos:8848
+ NACOS_USERNAME: nacos
+ NACOS_PASSWORD: nacos
+ MYSQL_HOST: mysql
+ MYSQL_PORT: 3306
+ MYSQL_DB: fund_platform
+ MYSQL_USER: root
+ MYSQL_PASSWORD: ${MYSQL_ROOT_PASSWORD:-root123}
+ JAVA_OPTS: -Xms256m -Xmx512m
+ ports:
+ - "8800:8800"
+ depends_on:
+ nacos:
+ condition: service_healthy
+ mysql:
+ condition: service_healthy
+ networks:
+ - fund-network
+
+# ==================== 网络配置 ====================
+networks:
+ fund-network:
+ driver: bridge
+ name: fund-network
+
+# ==================== 数据卷 ====================
+volumes:
+ mysql_data:
+ name: fund-mysql-data
+ redis_data:
+ name: fund-redis-data
+ nacos_data:
+ name: fund-nacos-data
+ prometheus_data:
+ name: fund-prometheus-data
+ grafana_data:
+ name: fund-grafana-data
diff --git a/docker/.env b/docker/.env
new file mode 100644
index 0000000..7a0789b
--- /dev/null
+++ b/docker/.env
@@ -0,0 +1,18 @@
+# 资金服务平台 - Docker 环境配置
+# 复制为 .env 使用
+
+# ==================== 数据库配置 ====================
+MYSQL_ROOT_PASSWORD=root123
+
+# ==================== Nacos 配置 ====================
+NACOS_AUTH_TOKEN=SecretKey012345678901234567890123456789012345678901234567890123456789
+
+# ==================== Grafana 配置 ====================
+GRAFANA_PASSWORD=admin123
+
+# ==================== 服务配置 ====================
+# JVM 参数
+JAVA_OPTS=-Xms256m -Xmx512m -XX:+UseG1GC
+
+# 日志级别
+LOG_LEVEL=INFO
diff --git a/docker/grafana/dashboards/fund-platform-dashboard.json b/docker/grafana/dashboards/fund-platform-dashboard.json
new file mode 100644
index 0000000..0c052cd
--- /dev/null
+++ b/docker/grafana/dashboards/fund-platform-dashboard.json
@@ -0,0 +1,662 @@
+{
+ "annotations": {
+ "list": []
+ },
+ "editable": true,
+ "fiscalYearStartMonth": 0,
+ "graphTooltip": 0,
+ "id": null,
+ "links": [],
+ "liveNow": false,
+ "panels": [
+ {
+ "collapsed": false,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 0
+ },
+ "id": 1,
+ "panels": [],
+ "title": "服务概览",
+ "type": "row"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "prometheus"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "red",
+ "value": 0
+ }
+ ]
+ },
+ "unit": "none"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 6,
+ "w": 6,
+ "x": 0,
+ "y": 1
+ },
+ "id": 2,
+ "options": {
+ "colorMode": "background",
+ "graphMode": "none",
+ "justifyMode": "auto",
+ "orientation": "horizontal",
+ "reduceOptions": {
+ "calcs": ["lastNotNull"],
+ "fields": "",
+ "values": false
+ },
+ "textMode": "auto"
+ },
+ "pluginVersion": "10.2.0",
+ "targets": [
+ {
+ "expr": "count(up{job=~\"fund-.*\"})",
+ "refId": "A",
+ "legendFormat": "总服务数"
+ },
+ {
+ "expr": "count(up{job=~\"fund-.*\"} == 1)",
+ "refId": "B",
+ "legendFormat": "在线服务"
+ },
+ {
+ "expr": "count(up{job=~\"fund-.*\"} == 0)",
+ "refId": "C",
+ "legendFormat": "离线服务"
+ }
+ ],
+ "title": "服务状态",
+ "type": "stat"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "prometheus"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "lineInterpolation": "smooth",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": true,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ }
+ ]
+ },
+ "unit": "reqps"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 6,
+ "w": 10,
+ "x": 6,
+ "y": 1
+ },
+ "id": 3,
+ "options": {
+ "legend": {
+ "calcs": ["mean", "max"],
+ "displayMode": "table",
+ "placement": "right",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "expr": "sum(rate(http_server_requests_seconds_count{application=~\"$application\"}[5m])) by (application)",
+ "legendFormat": "{{application}}",
+ "refId": "A"
+ }
+ ],
+ "title": "请求速率 (QPS)",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "prometheus"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "lineInterpolation": "smooth",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": true,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ }
+ ]
+ },
+ "unit": "s"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 6,
+ "w": 8,
+ "x": 16,
+ "y": 1
+ },
+ "id": 4,
+ "options": {
+ "legend": {
+ "calcs": ["mean", "max"],
+ "displayMode": "table",
+ "placement": "right",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "expr": "histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{application=~\"$application\"}[5m])) by (le, application))",
+ "legendFormat": "{{application}} P95",
+ "refId": "A"
+ },
+ {
+ "expr": "histogram_quantile(0.99, sum(rate(http_server_requests_seconds_bucket{application=~\"$application\"}[5m])) by (le, application))",
+ "legendFormat": "{{application}} P99",
+ "refId": "B"
+ }
+ ],
+ "title": "响应时间 (P95/P99)",
+ "type": "timeseries"
+ },
+ {
+ "collapsed": false,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 7
+ },
+ "id": 10,
+ "panels": [],
+ "title": "JVM 内存",
+ "type": "row"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "prometheus"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "lineInterpolation": "smooth",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": true,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ }
+ ]
+ },
+ "unit": "bytes"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 12,
+ "x": 0,
+ "y": 8
+ },
+ "id": 11,
+ "options": {
+ "legend": {
+ "calcs": ["mean", "max"],
+ "displayMode": "table",
+ "placement": "right",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "expr": "jvm_memory_used_bytes{application=~\"$application\", area=\"heap\"}",
+ "legendFormat": "{{application}} - Used",
+ "refId": "A"
+ },
+ {
+ "expr": "jvm_memory_max_bytes{application=~\"$application\", area=\"heap\"}",
+ "legendFormat": "{{application}} - Max",
+ "refId": "B"
+ }
+ ],
+ "title": "JVM 堆内存使用",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "prometheus"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "lineInterpolation": "smooth",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": true,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ }
+ ]
+ },
+ "unit": "s"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 8,
+ "w": 12,
+ "x": 12,
+ "y": 8
+ },
+ "id": 12,
+ "options": {
+ "legend": {
+ "calcs": ["mean", "max"],
+ "displayMode": "table",
+ "placement": "right",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "expr": "rate(jvm_gc_pause_seconds_sum{application=~\"$application\"}[5m])",
+ "legendFormat": "{{application}} - {{action}}",
+ "refId": "A"
+ }
+ ],
+ "title": "GC 时间",
+ "type": "timeseries"
+ },
+ {
+ "collapsed": false,
+ "gridPos": {
+ "h": 1,
+ "w": 24,
+ "x": 0,
+ "y": 16
+ },
+ "id": 20,
+ "panels": [],
+ "title": "数据库连接池",
+ "type": "row"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "prometheus"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "palette-classic"
+ },
+ "custom": {
+ "axisCenteredZero": false,
+ "axisColorMode": "text",
+ "axisLabel": "",
+ "axisPlacement": "auto",
+ "barAlignment": 0,
+ "drawStyle": "line",
+ "fillOpacity": 10,
+ "gradientMode": "none",
+ "hideFrom": {
+ "legend": false,
+ "tooltip": false,
+ "viz": false
+ },
+ "lineInterpolation": "smooth",
+ "lineWidth": 1,
+ "pointSize": 5,
+ "scaleDistribution": {
+ "type": "linear"
+ },
+ "showPoints": "never",
+ "spanNulls": true,
+ "stacking": {
+ "group": "A",
+ "mode": "none"
+ },
+ "thresholdsStyle": {
+ "mode": "off"
+ }
+ },
+ "mappings": [],
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ }
+ ]
+ },
+ "unit": "short"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 6,
+ "w": 12,
+ "x": 0,
+ "y": 17
+ },
+ "id": 21,
+ "options": {
+ "legend": {
+ "calcs": ["mean", "max"],
+ "displayMode": "table",
+ "placement": "right",
+ "showLegend": true
+ },
+ "tooltip": {
+ "mode": "multi",
+ "sort": "none"
+ }
+ },
+ "targets": [
+ {
+ "expr": "hikaricp_connections_active{application=~\"$application\"}",
+ "legendFormat": "{{application}} - Active",
+ "refId": "A"
+ },
+ {
+ "expr": "hikaricp_connections_idle{application=~\"$application\"}",
+ "legendFormat": "{{application}} - Idle",
+ "refId": "B"
+ },
+ {
+ "expr": "hikaricp_connections_max{application=~\"$application\"}",
+ "legendFormat": "{{application}} - Max",
+ "refId": "C"
+ }
+ ],
+ "title": "HikariCP 连接池状态",
+ "type": "timeseries"
+ },
+ {
+ "datasource": {
+ "type": "prometheus",
+ "uid": "prometheus"
+ },
+ "fieldConfig": {
+ "defaults": {
+ "color": {
+ "mode": "thresholds"
+ },
+ "mappings": [],
+ "max": 100,
+ "min": 0,
+ "thresholds": {
+ "mode": "absolute",
+ "steps": [
+ {
+ "color": "green",
+ "value": null
+ },
+ {
+ "color": "yellow",
+ "value": 70
+ },
+ {
+ "color": "red",
+ "value": 85
+ }
+ ]
+ },
+ "unit": "percent"
+ },
+ "overrides": []
+ },
+ "gridPos": {
+ "h": 6,
+ "w": 12,
+ "x": 12,
+ "y": 17
+ },
+ "id": 22,
+ "options": {
+ "orientation": "horizontal",
+ "reduceOptions": {
+ "calcs": ["lastNotNull"],
+ "fields": "",
+ "values": false
+ },
+ "showThresholdLabels": false,
+ "showThresholdMarkers": true
+ },
+ "pluginVersion": "10.2.0",
+ "targets": [
+ {
+ "expr": "(hikaricp_connections_active{application=~\"$application\"} / hikaricp_connections_max{application=~\"$application\"}) * 100",
+ "legendFormat": "{{application}}",
+ "refId": "A"
+ }
+ ],
+ "title": "连接池使用率",
+ "type": "gauge"
+ }
+ ],
+ "refresh": "5s",
+ "schemaVersion": 38,
+ "style": "dark",
+ "tags": ["fundplatform", "springboot", "jvm"],
+ "templating": {
+ "list": [
+ {
+ "current": {
+ "selected": true,
+ "text": "All",
+ "value": "$__all"
+ },
+ "datasource": {
+ "type": "prometheus",
+ "uid": "prometheus"
+ },
+ "definition": "label_values(up{job=~\"fund-.*\"}, application)",
+ "hide": 0,
+ "includeAll": true,
+ "label": "Application",
+ "multi": true,
+ "name": "application",
+ "options": [],
+ "query": {
+ "query": "label_values(up{job=~\"fund-.*\"}, application)",
+ "refId": "PrometheusVariableQueryEditor-VariableQuery"
+ },
+ "refresh": 1,
+ "regex": "",
+ "skipUrlSync": false,
+ "sort": 1,
+ "type": "query"
+ }
+ ]
+ },
+ "time": {
+ "from": "now-1h",
+ "to": "now"
+ },
+ "timepicker": {},
+ "timezone": "",
+ "title": "资金服务平台监控",
+ "uid": "fund-platform-dashboard",
+ "version": 1,
+ "weekStart": ""
+}
diff --git a/docker/grafana/provisioning/dashboards/dashboards.yml b/docker/grafana/provisioning/dashboards/dashboards.yml
new file mode 100644
index 0000000..38da075
--- /dev/null
+++ b/docker/grafana/provisioning/dashboards/dashboards.yml
@@ -0,0 +1,14 @@
+# Grafana Dashboard 自动导入配置
+apiVersion: 1
+
+providers:
+ - name: 'FundPlatform'
+ orgId: 1
+ folder: 'FundPlatform'
+ folderUid: 'fundplatform'
+ type: file
+ disableDeletion: false
+ updateIntervalSeconds: 30
+ allowUiUpdates: true
+ options:
+ path: /var/lib/grafana/dashboards
diff --git a/docker/grafana/provisioning/datasources/prometheus.yml b/docker/grafana/provisioning/datasources/prometheus.yml
new file mode 100644
index 0000000..f2d8eee
--- /dev/null
+++ b/docker/grafana/provisioning/datasources/prometheus.yml
@@ -0,0 +1,15 @@
+# Grafana 数据源配置
+apiVersion: 1
+
+datasources:
+ # Prometheus 数据源
+ - name: Prometheus
+ type: prometheus
+ access: proxy
+ url: http://prometheus:9090
+ isDefault: true
+ editable: false
+ jsonData:
+ httpMethod: POST
+ manageAlerts: true
+ prometheusType: Prometheus
diff --git a/docker/mysql/init/01-init.sql b/docker/mysql/init/01-init.sql
new file mode 100644
index 0000000..695f3cb
--- /dev/null
+++ b/docker/mysql/init/01-init.sql
@@ -0,0 +1,144 @@
+-- 资金服务平台 - MySQL 初始化脚本
+-- 执行顺序: 01
+
+-- 设置字符集
+SET NAMES utf8mb4;
+SET CHARACTER SET utf8mb4;
+
+-- 创建 Nacos 配置数据库
+CREATE DATABASE IF NOT EXISTS `nacos_config`
+ DEFAULT CHARACTER SET utf8mb4
+ COLLATE utf8mb4_unicode_ci;
+
+-- 创建业务数据库
+CREATE DATABASE IF NOT EXISTS `fund_platform`
+ DEFAULT CHARACTER SET utf8mb4
+ COLLATE utf8mb4_unicode_ci;
+
+-- 授权(如果需要创建专用用户)
+-- CREATE USER 'fund_user'@'%' IDENTIFIED BY 'fund123';
+-- GRANT ALL PRIVILEGES ON fund_platform.* TO 'fund_user'@'%';
+-- FLUSH PRIVILEGES;
+
+USE `fund_platform`;
+
+-- 用户表
+CREATE TABLE IF NOT EXISTS `sys_user` (
+ `id` BIGINT NOT NULL COMMENT '用户ID',
+ `username` VARCHAR(50) NOT NULL COMMENT '用户名',
+ `password` VARCHAR(100) NOT NULL COMMENT '密码',
+ `real_name` VARCHAR(50) COMMENT '真实姓名',
+ `phone` VARCHAR(20) COMMENT '手机号',
+ `email` VARCHAR(100) COMMENT '邮箱',
+ `dept_id` BIGINT COMMENT '部门ID',
+ `tenant_id` BIGINT NOT NULL DEFAULT 1 COMMENT '租户ID',
+ `status` TINYINT DEFAULT 1 COMMENT '状态:0禁用 1启用',
+ `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
+ `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ `deleted` TINYINT DEFAULT 0 COMMENT '是否删除',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_username` (`username`, `tenant_id`),
+ KEY `idx_tenant_id` (`tenant_id`),
+ KEY `idx_dept_id` (`dept_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
+
+-- 角色表
+CREATE TABLE IF NOT EXISTS `sys_role` (
+ `id` BIGINT NOT NULL COMMENT '角色ID',
+ `role_name` VARCHAR(50) NOT NULL COMMENT '角色名称',
+ `role_code` VARCHAR(50) NOT NULL COMMENT '角色编码',
+ `tenant_id` BIGINT NOT NULL DEFAULT 1 COMMENT '租户ID',
+ `status` TINYINT DEFAULT 1 COMMENT '状态',
+ `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
+ `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ `deleted` TINYINT DEFAULT 0,
+ PRIMARY KEY (`id`),
+ KEY `idx_tenant_id` (`tenant_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表';
+
+-- 菜单表
+CREATE TABLE IF NOT EXISTS `sys_menu` (
+ `id` BIGINT NOT NULL COMMENT '菜单ID',
+ `parent_id` BIGINT DEFAULT 0 COMMENT '父菜单ID',
+ `menu_name` VARCHAR(50) NOT NULL COMMENT '菜单名称',
+ `menu_type` TINYINT DEFAULT 1 COMMENT '类型:1目录 2菜单 3按钮',
+ `path` VARCHAR(200) COMMENT '路由路径',
+ `component` VARCHAR(200) COMMENT '组件路径',
+ `perms` VARCHAR(100) COMMENT '权限标识',
+ `sort` INT DEFAULT 0 COMMENT '排序',
+ `icon` VARCHAR(100) COMMENT '图标',
+ `status` TINYINT DEFAULT 1 COMMENT '状态',
+ `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
+ `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ `deleted` TINYINT DEFAULT 0,
+ PRIMARY KEY (`id`),
+ KEY `idx_parent_id` (`parent_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='菜单表';
+
+-- 用户角色关联表
+CREATE TABLE IF NOT EXISTS `sys_user_role` (
+ `id` BIGINT NOT NULL AUTO_INCREMENT,
+ `user_id` BIGINT NOT NULL,
+ `role_id` BIGINT NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_user_role` (`user_id`, `role_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户角色关联表';
+
+-- 角色菜单关联表
+CREATE TABLE IF NOT EXISTS `sys_role_menu` (
+ `id` BIGINT NOT NULL AUTO_INCREMENT,
+ `role_id` BIGINT NOT NULL,
+ `menu_id` BIGINT NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_role_menu` (`role_id`, `menu_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色菜单关联表';
+
+-- 部门表
+CREATE TABLE IF NOT EXISTS `sys_dept` (
+ `id` BIGINT NOT NULL COMMENT '部门ID',
+ `parent_id` BIGINT DEFAULT 0 COMMENT '父部门ID',
+ `dept_name` VARCHAR(50) NOT NULL COMMENT '部门名称',
+ `tenant_id` BIGINT NOT NULL DEFAULT 1 COMMENT '租户ID',
+ `sort` INT DEFAULT 0,
+ `status` TINYINT DEFAULT 1,
+ `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
+ `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ `deleted` TINYINT DEFAULT 0,
+ PRIMARY KEY (`id`),
+ KEY `idx_tenant_id` (`tenant_id`),
+ KEY `idx_parent_id` (`parent_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='部门表';
+
+-- 租户表
+CREATE TABLE IF NOT EXISTS `sys_tenant` (
+ `id` BIGINT NOT NULL COMMENT '租户ID',
+ `tenant_name` VARCHAR(100) NOT NULL COMMENT '租户名称',
+ `tenant_code` VARCHAR(50) NOT NULL COMMENT '租户编码',
+ `contact_name` VARCHAR(50) COMMENT '联系人',
+ `contact_phone` VARCHAR(20) COMMENT '联系电话',
+ `status` TINYINT DEFAULT 1 COMMENT '状态',
+ `expire_time` DATETIME COMMENT '过期时间',
+ `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
+ `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ `deleted` TINYINT DEFAULT 0,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_tenant_code` (`tenant_code`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='租户表';
+
+-- 插入默认租户
+INSERT INTO `sys_tenant` (`id`, `tenant_name`, `tenant_code`, `contact_name`, `status`)
+VALUES (1, '默认租户', 'DEFAULT', '系统管理员', 1) ON DUPLICATE KEY UPDATE `tenant_name` = VALUES(`tenant_name`);
+
+-- 插入默认管理员用户 (密码: admin123,使用 BCrypt 加密)
+INSERT INTO `sys_user` (`id`, `username`, `password`, `real_name`, `tenant_id`, `status`)
+VALUES (1, 'admin', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9lBOsl7iAt6Z5EH', '系统管理员', 1, 1)
+ON DUPLICATE KEY UPDATE `real_name` = VALUES(`real_name`);
+
+-- 插入默认角色
+INSERT INTO `sys_role` (`id`, `role_name`, `role_code`, `tenant_id`)
+VALUES (1, '管理员', 'ADMIN', 1), (2, '普通用户', 'USER', 1)
+ON DUPLICATE KEY UPDATE `role_name` = VALUES(`role_name`);
+
+-- 分配管理员角色
+INSERT INTO `sys_user_role` (`user_id`, `role_id`) VALUES (1, 1)
+ON DUPLICATE KEY UPDATE `role_id` = VALUES(`role_id`);
diff --git a/docker/prometheus/prometheus.yml b/docker/prometheus/prometheus.yml
new file mode 100644
index 0000000..13b897d
--- /dev/null
+++ b/docker/prometheus/prometheus.yml
@@ -0,0 +1,159 @@
+# Prometheus 配置文件
+# 资金服务平台监控配置
+
+global:
+ scrape_interval: 15s # 抓取间隔
+ evaluation_interval: 15s # 规则评估间隔
+ external_labels:
+ monitor: 'fund-platform'
+
+# 告警管理器配置(可选)
+# alerting:
+# alertmanagers:
+# - static_configs:
+# - targets:
+# - alertmanager:9093
+
+# 规则文件
+rule_files:
+ - /etc/prometheus/rules/*.yml
+
+# 抓取配置
+scrape_configs:
+ # ==================== 基础设施监控 ====================
+
+ # Prometheus 自身监控
+ - job_name: 'prometheus'
+ static_configs:
+ - targets: ['localhost:9090']
+ labels:
+ instance: 'prometheus'
+
+ # MySQL 监控 (需要 mysqld_exporter)
+ # - job_name: 'mysql'
+ # static_configs:
+ # - targets: ['mysql-exporter:9104']
+
+ # Redis 监控 (需要 redis_exporter)
+ # - job_name: 'redis'
+ # static_configs:
+ # - targets: ['redis-exporter:9121']
+
+ # ==================== Spring Boot 微服务监控 ====================
+
+ # API 网关
+ - job_name: 'fund-gateway'
+ metrics_path: '/actuator/prometheus'
+ static_configs:
+ - targets: ['gateway:8000']
+ labels:
+ application: 'fund-gateway'
+ service: 'gateway'
+ relabel_configs:
+ - source_labels: [__address__]
+ target_label: instance
+ replacement: 'fund-gateway'
+
+ # 系统服务
+ - job_name: 'fund-sys'
+ metrics_path: '/actuator/prometheus'
+ static_configs:
+ - targets: ['fund-sys:8100']
+ labels:
+ application: 'fund-sys'
+ service: 'business'
+ relabel_configs:
+ - source_labels: [__address__]
+ target_label: instance
+ replacement: 'fund-sys'
+
+ # 客户服务
+ - job_name: 'fund-cust'
+ metrics_path: '/actuator/prometheus'
+ static_configs:
+ - targets: ['fund-cust:8200']
+ labels:
+ application: 'fund-cust'
+ service: 'business'
+ relabel_configs:
+ - source_labels: [__address__]
+ target_label: instance
+ replacement: 'fund-cust'
+
+ # 项目服务
+ - job_name: 'fund-proj'
+ metrics_path: '/actuator/prometheus'
+ static_configs:
+ - targets: ['fund-proj:8300']
+ labels:
+ application: 'fund-proj'
+ service: 'business'
+ relabel_configs:
+ - source_labels: [__address__]
+ target_label: instance
+ replacement: 'fund-proj'
+
+ # 需求工单服务
+ - job_name: 'fund-req'
+ metrics_path: '/actuator/prometheus'
+ static_configs:
+ - targets: ['fund-req:8400']
+ labels:
+ application: 'fund-req'
+ service: 'business'
+ relabel_configs:
+ - source_labels: [__address__]
+ target_label: instance
+ replacement: 'fund-req'
+
+ # 支出服务
+ - job_name: 'fund-exp'
+ metrics_path: '/actuator/prometheus'
+ static_configs:
+ - targets: ['fund-exp:8500']
+ labels:
+ application: 'fund-exp'
+ service: 'business'
+ relabel_configs:
+ - source_labels: [__address__]
+ target_label: instance
+ replacement: 'fund-exp'
+
+ # 收款服务
+ - job_name: 'fund-receipt'
+ metrics_path: '/actuator/prometheus'
+ static_configs:
+ - targets: ['fund-receipt:8600']
+ labels:
+ application: 'fund-receipt'
+ service: 'business'
+ relabel_configs:
+ - source_labels: [__address__]
+ target_label: instance
+ replacement: 'fund-receipt'
+
+ # 报表服务
+ - job_name: 'fund-report'
+ metrics_path: '/actuator/prometheus'
+ static_configs:
+ - targets: ['fund-report:8700']
+ labels:
+ application: 'fund-report'
+ service: 'business'
+ relabel_configs:
+ - source_labels: [__address__]
+ target_label: instance
+ replacement: 'fund-report'
+
+ # 文件服务
+ - job_name: 'fund-file'
+ metrics_path: '/actuator/prometheus'
+ static_configs:
+ - targets: ['fund-file:8800']
+ labels:
+ application: 'fund-file'
+ service: 'business'
+ relabel_configs:
+ - source_labels: [__address__]
+ target_label: instance
+ replacement: 'fund-file'
diff --git a/docker/prometheus/rules/alerts.yml b/docker/prometheus/rules/alerts.yml
new file mode 100644
index 0000000..88fd2e9
--- /dev/null
+++ b/docker/prometheus/rules/alerts.yml
@@ -0,0 +1,128 @@
+# Prometheus 告警规则
+# 资金服务平台
+
+groups:
+ # ==================== 服务可用性告警 ====================
+ - name: service_availability
+ rules:
+ # 服务宕机告警
+ - alert: ServiceDown
+ expr: up == 0
+ for: 1m
+ labels:
+ severity: critical
+ annotations:
+ summary: "服务 {{ $labels.job }} 宕机"
+ description: "服务 {{ $labels.instance }} 已经宕机超过 1 分钟"
+
+ # 健康检查失败
+ - alert: HealthCheckFailed
+ expr: spring_boot_health_status{status="DOWN"} == 1
+ for: 30s
+ labels:
+ severity: warning
+ annotations:
+ summary: "服务健康检查失败"
+ description: "服务 {{ $labels.application }} 健康状态为 DOWN"
+
+ # ==================== JVM 内存告警 ====================
+ - name: jvm_memory
+ rules:
+ # 堆内存使用率过高
+ - alert: HeapMemoryUsageHigh
+ expr: (jvm_memory_used_bytes{area="heap"} / jvm_memory_max_bytes{area="heap"}) * 100 > 85
+ for: 5m
+ labels:
+ severity: warning
+ annotations:
+ summary: "JVM 堆内存使用率过高"
+ description: "服务 {{ $labels.application }} 堆内存使用率 {{ $value | printf \"%.2f\" }}%"
+
+ # 堆内存即将耗尽
+ - alert: HeapMemoryCritical
+ expr: (jvm_memory_used_bytes{area="heap"} / jvm_memory_max_bytes{area="heap"}) * 100 > 95
+ for: 1m
+ labels:
+ severity: critical
+ annotations:
+ summary: "JVM 堆内存即将耗尽"
+ description: "服务 {{ $labels.application }} 堆内存使用率 {{ $value | printf \"%.2f\" }}%,请立即处理"
+
+ # GC 时间过长
+ - alert: GCTimeTooHigh
+ expr: rate(jvm_gc_pause_seconds_sum[5m]) > 0.5
+ for: 5m
+ labels:
+ severity: warning
+ annotations:
+ summary: "GC 时间过长"
+ description: "服务 {{ $labels.application }} GC 时间占比过高,可能影响性能"
+
+ # ==================== HTTP 请求告警 ====================
+ - name: http_requests
+ rules:
+ # 高错误率
+ - alert: HighErrorRate
+ expr: sum(rate(http_server_requests_seconds_count{status=~"5.."}[5m])) by (application) / sum(rate(http_server_requests_seconds_count[5m])) by (application) > 0.05
+ for: 5m
+ labels:
+ severity: warning
+ annotations:
+ summary: "HTTP 请求错误率过高"
+ description: "服务 {{ $labels.application }} 5xx 错误率 {{ $value | printf \"%.2f\" }}%"
+
+ # 响应时间过长
+ - alert: HighResponseTime
+ expr: histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket[5m])) by (le, application)) > 2
+ for: 5m
+ labels:
+ severity: warning
+ annotations:
+ summary: "HTTP 响应时间过长"
+ description: "服务 {{ $labels.application }} P95 响应时间 {{ $value | printf \"%.2f\" }} 秒"
+
+ # ==================== 数据库连接池告警 ====================
+ - name: database_connections
+ rules:
+ # HikariCP 连接池使用率过高
+ - alert: HikariPoolUsageHigh
+ expr: (hikaricp_connections_active / hikaricp_connections_max) * 100 > 80
+ for: 5m
+ labels:
+ severity: warning
+ annotations:
+ summary: "数据库连接池使用率过高"
+ description: "服务 {{ $labels.application }} 连接池使用率 {{ $value | printf \"%.2f\" }}%"
+
+ # 连接池等待
+ - alert: HikariPoolPending
+ expr: hikaricp_connections_pending > 0
+ for: 2m
+ labels:
+ severity: warning
+ annotations:
+ summary: "数据库连接池存在等待"
+ description: "服务 {{ $labels.application }} 有 {{ $value }} 个连接请求在等待"
+
+ # ==================== 系统资源告警 ====================
+ - name: system_resources
+ rules:
+ # CPU 使用率过高
+ - alert: HighCPUUsage
+ expr: system_cpu_usage * 100 > 80
+ for: 5m
+ labels:
+ severity: warning
+ annotations:
+ summary: "CPU 使用率过高"
+ description: "服务 {{ $labels.application }} CPU 使用率 {{ $value | printf \"%.2f\" }}%"
+
+ # 进程打开文件描述符过多
+ - alert: HighFileDescriptorUsage
+ expr: process_files_open_files / process_files_max_files * 100 > 80
+ for: 5m
+ labels:
+ severity: warning
+ annotations:
+ summary: "文件描述符使用率过高"
+ description: "服务 {{ $labels.application }} 文件描述符使用率 {{ $value | printf \"%.2f\" }}%"
diff --git a/fund-gateway/src/main/resources/application-docker.yml b/fund-gateway/src/main/resources/application-docker.yml
new file mode 100644
index 0000000..56b4b87
--- /dev/null
+++ b/fund-gateway/src/main/resources/application-docker.yml
@@ -0,0 +1,113 @@
+# Docker 环境配置 - Gateway
+server:
+ port: ${SERVER_PORT:8000}
+
+spring:
+ application:
+ name: fund-gateway
+ profiles:
+ active: ${SPRING_PROFILES_ACTIVE:docker}
+
+ cloud:
+ nacos:
+ server-addr: ${NACOS_SERVER_ADDR:nacos:8848}
+ username: ${NACOS_USERNAME:nacos}
+ password: ${NACOS_PASSWORD:nacos}
+ discovery:
+ namespace: ${NACOS_NAMESPACE:}
+ group: DEFAULT_GROUP
+ enabled: true
+
+ gateway:
+ discovery:
+ locator:
+ enabled: true
+ lower-case-service-id: true
+ routes:
+ - id: fund-sys
+ uri: lb://fund-sys
+ predicates:
+ - Path=/api/sys/**
+ filters:
+ - StripPrefix=1
+ - id: fund-cust
+ uri: lb://fund-cust
+ predicates:
+ - Path=/api/cust/**
+ filters:
+ - StripPrefix=1
+ - id: fund-proj
+ uri: lb://fund-proj
+ predicates:
+ - Path=/api/proj/**
+ filters:
+ - StripPrefix=1
+ - id: fund-req
+ uri: lb://fund-req
+ predicates:
+ - Path=/api/req/**
+ filters:
+ - StripPrefix=1
+ - id: fund-exp
+ uri: lb://fund-exp
+ predicates:
+ - Path=/api/exp/**
+ filters:
+ - StripPrefix=1
+ - id: fund-receipt
+ uri: lb://fund-receipt
+ predicates:
+ - Path=/api/receipt/**
+ filters:
+ - StripPrefix=1
+ - id: fund-report
+ uri: lb://fund-report
+ predicates:
+ - Path=/api/report/**
+ filters:
+ - StripPrefix=1
+ - id: fund-file
+ uri: lb://fund-file
+ predicates:
+ - Path=/api/file/**
+ filters:
+ - StripPrefix=1
+
+# JWT 配置
+jwt:
+ secret: YourSecretKeyForJWTTokenGenerationMustBeAtLeast256BitsLong
+ expiration: 86400000
+
+# Actuator 监控端点配置
+management:
+ endpoints:
+ web:
+ exposure:
+ include: health,info,metrics,prometheus
+ base-path: /actuator
+ endpoint:
+ health:
+ show-details: always
+ probes:
+ enabled: true
+ health:
+ livenessstate:
+ enabled: true
+ readinessstate:
+ enabled: true
+ metrics:
+ tags:
+ application: ${spring.application.name}
+ distribution:
+ percentiles-histogram:
+ http.server.requests: true
+ percentiles:
+ http.server.requests: 0.5,0.95,0.99
+
+# 日志配置
+logging:
+ level:
+ root: INFO
+ com.fundplatform: DEBUG
+ pattern:
+ console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId}] %-5level %logger{36} - %msg%n"
diff --git a/fund-sys/src/main/resources/application-docker.yml b/fund-sys/src/main/resources/application-docker.yml
new file mode 100644
index 0000000..642df80
--- /dev/null
+++ b/fund-sys/src/main/resources/application-docker.yml
@@ -0,0 +1,84 @@
+# Docker 环境配置
+server:
+ port: ${SERVER_PORT:8100}
+
+spring:
+ application:
+ name: fund-sys
+ profiles:
+ active: ${SPRING_PROFILES_ACTIVE:docker}
+
+ # 数据源配置
+ datasource:
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://${MYSQL_HOST:mysql}:${MYSQL_PORT:3306}/${MYSQL_DB:fund_platform}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
+ username: ${MYSQL_USER:root}
+ password: ${MYSQL_PASSWORD:root123}
+ hikari:
+ pool-name: FundSysHikariPool
+ minimum-idle: 5
+ maximum-pool-size: 20
+ idle-timeout: 30000
+ max-lifetime: 1800000
+ connection-timeout: 30000
+
+ # Redis 配置
+ data:
+ redis:
+ host: ${REDIS_HOST:redis}
+ port: ${REDIS_PORT:6379}
+
+ # Nacos 配置
+ cloud:
+ nacos:
+ server-addr: ${NACOS_SERVER_ADDR:nacos:8848}
+ username: ${NACOS_USERNAME:nacos}
+ password: ${NACOS_PASSWORD:nacos}
+ discovery:
+ namespace: ${NACOS_NAMESPACE:}
+ group: DEFAULT_GROUP
+ enabled: true
+
+# MyBatis Plus 配置
+mybatis-plus:
+ mapper-locations: classpath*:/mapper/**/*.xml
+ global-config:
+ db-config:
+ id-type: ASSIGN_ID
+ logic-delete-field: deleted
+ logic-delete-value: 1
+ logic-not-delete-value: 0
+
+# Actuator 监控端点配置
+management:
+ endpoints:
+ web:
+ exposure:
+ include: health,info,metrics,prometheus
+ base-path: /actuator
+ endpoint:
+ health:
+ show-details: always
+ probes:
+ enabled: true
+ health:
+ livenessstate:
+ enabled: true
+ readinessstate:
+ enabled: true
+ metrics:
+ tags:
+ application: ${spring.application.name}
+ distribution:
+ percentiles-histogram:
+ http.server.requests: true
+ percentiles:
+ http.server.requests: 0.5,0.95,0.99
+
+# 日志配置
+logging:
+ level:
+ root: INFO
+ com.fundplatform: DEBUG
+ pattern:
+ console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId}] %-5level %logger{36} - %msg%n"
diff --git a/pom.xml b/pom.xml
index e80688c..4f11f21 100644
--- a/pom.xml
+++ b/pom.xml
@@ -60,6 +60,21 @@
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+
+
+ io.micrometer
+ micrometer-registry-prometheus
+
+
+