This commit is contained in:
2025-11-26 16:03:06 +08:00
parent ba53dc9c20
commit 04eb85e1dc
46 changed files with 186 additions and 23 deletions

View File

@@ -0,0 +1,14 @@
# 数据库配置
MYSQL_ROOT_PASSWORD=123456
MYSQL_DATABASE=school_news
MYSQL_USER=schoolnews
MYSQL_PASSWORD=123456
MYSQL_PORT=3306
# Redis配置
REDIS_PASSWORD=123456
REDIS_PORT=6379
# 服务端口配置
SERV_PORT=8081
WEB_PORT=8080

View File

@@ -0,0 +1,61 @@
# ====================================
# 后端基础镜像 - Base Serv
# 包含JRE + Python + 系统工具 + 爬虫依赖
# 用途:作为后端服务镜像的基础,避免每次都安装依赖
# ====================================
FROM eclipse-temurin:21-jre
# 设置环境变量
ENV LANG=C.UTF-8 \
LC_ALL=C.UTF-8 \
TZ=Asia/Shanghai
# 安装系统依赖和工具
RUN apt-get update && \
apt-get install -y \
# Python环境
python3 \
python3-pip \
python3-venv \
# 网络和诊断工具
netcat-traditional \
curl \
wget \
# MySQL客户端
default-mysql-client \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# 临时复制requirements.txt用于安装依赖
COPY schoolNewsCrawler/requirements.txt /tmp/requirements.txt
# 安装Python爬虫依赖一次性安装到基础镜像
RUN echo "========================================" && \
echo "安装Python爬虫依赖到基础镜像" && \
echo "========================================" && \
# 配置pip使用国内镜像源清华源
python3 -m pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple && \
python3 -m pip --version && \
echo "" && \
# Python 3.12 引入了 PEP 668 规范,需要添加 --break-system-packages
python3 -m pip install --no-cache-dir --break-system-packages -r /tmp/requirements.txt && \
echo "" && \
echo "✅ 爬虫依赖安装完成" && \
python3 -m pip list | grep -E "(beautifulsoup4|crawl4ai|selenium|pydantic|requests|loguru)" && \
# 清理临时文件
rm -f /tmp/requirements.txt
# 创建应用目录结构
WORKDIR /app
RUN mkdir -p /app/config /app/logs /app/uploads /app/crawler
# 镜像元数据
LABEL maintainer="School News Team" \
description="Base image for school-news backend service with Python dependencies" \
version="1.0"
# 暴露端口(文档用途)
EXPOSE 8081
# 默认命令(会被子镜像覆盖)
CMD ["echo", "This is base image, please use school-news-serv image"]

View File

@@ -0,0 +1,112 @@
# 校园新闻管理系统 - MySQL数据库镜像
# 基于reInit.sh的数据库初始化方案
FROM mysql:8.0
# 设置环境变量
ENV LANG=C.UTF-8 \
TZ=Asia/Shanghai
# 注意MySQL配置有两种方式
# 1. 通过docker-compose.yml的command参数基础配置
# 2. 通过挂载my.cnf文件高级配置可选
# docker-compose.yml中可以取消注释: ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf
# 创建SQL目录
RUN mkdir -p /docker-entrypoint-initdb.d /opt/sql
# 复制所有SQL文件保持目录结构
COPY schoolNewsServ/.bin/mysql/sql/ /opt/sql/
# 复制并调整reInit.sh为Docker环境设置执行权限
COPY schoolNewsServ/.bin/mysql/sql/reInit.sh /opt/sql/
RUN sed -i 's/DB_HOST="localhost"/DB_HOST="localhost"/' /opt/sql/reInit.sh && \
sed -i 's/DB_PORT="3306"/DB_PORT="3306"/' /opt/sql/reInit.sh && \
sed -i 's/DB_USER="root"/DB_USER="root"/' /opt/sql/reInit.sh && \
sed -i 's/DB_PASSWORD="123456"/DB_PASSWORD="${MYSQL_ROOT_PASSWORD}"/' /opt/sql/reInit.sh && \
sed -i 's/DB_NAME="school_news"/DB_NAME="${MYSQL_DATABASE}"/' /opt/sql/reInit.sh && \
sed -i 's|LOG_FILE="$SCRIPT_DIR/reInit.log"|LOG_FILE="/tmp/reInit.log"|' /opt/sql/reInit.sh && \
chmod +x /opt/sql/reInit.sh && \
chmod +x /opt/sql/sensitiveData/importSensitiveWords.sh
# 创建Docker初始化适配脚本
RUN cat > /docker-entrypoint-initdb.d/01-init-database.sh <<'EOF'
#!/bin/bash
set -e
echo "=========================================="
echo "校园新闻管理系统 - 数据库初始化"
echo "使用 reInit.sh + Docker配置更新"
echo "=========================================="
# 等待MySQL完全启动
echo "等待MySQL启动..."
until mysql -uroot -p"${MYSQL_ROOT_PASSWORD}" -e "SELECT 1" >/dev/null 2>&1; do
sleep 1
done
echo "MySQL已就绪"
# 切换到SQL目录
cd /opt/sql
# 设置环境变量供reInit.sh使用
export DB_HOST="localhost"
export DB_PORT="3306"
export DB_USER="root"
export DB_PASSWORD="${MYSQL_ROOT_PASSWORD}"
export DB_NAME="${MYSQL_DATABASE}"
export MYSQL_PWD="${MYSQL_ROOT_PASSWORD}"
# Source reInit.sh并调用其初始化函数
echo "执行数据库初始化使用reInit.sh..."
source reInit.sh
# 调用reInit.sh的核心函数跳过备份和删除
execute_init_script # 执行initAll.sql
import_sensitive_words # 导入敏感词
# Docker环境特定配置更新爬虫路径并标记初始化状态
echo "更新Docker环境配置..."
mysql -uroot "${MYSQL_DATABASE}" <<EOSQL
-- 确保初始化标记表存在
CREATE TABLE IF NOT EXISTS _db_init_status (
id INT PRIMARY KEY AUTO_INCREMENT,
script_name VARCHAR(255) NOT NULL UNIQUE,
executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
status VARCHAR(50) DEFAULT 'init'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 确保有一条当前脚本的记录
INSERT IGNORE INTO _db_init_status (script_name) VALUES ('01-init-database.sql');
-- 更新爬虫配置为Docker容器内路径
UPDATE tb_sys_config
SET config_value = '/usr/bin/python3'
WHERE config_key = 'crawler.pythonPath';
UPDATE tb_sys_config
SET config_value = '/app/crawler'
WHERE config_key = 'crawler.basePath';
-- 将初始化状态标记为 success供 healthcheck 使用
UPDATE _db_init_status
SET status = 'success'
WHERE script_name = '01-init-database.sql';
SELECT '✅ 数据库初始化完成!' AS message;
SELECT '默认用户: admin, 密码: 123456' AS tip;
SELECT '爬虫配置已更新为Docker容器路径' AS docker_config;
EOSQL
echo "=========================================="
echo "✅ 初始化完成!"
echo "=========================================="
EOF
# 设置执行权限
RUN chmod +x /docker-entrypoint-initdb.d/01-init-database.sh
# 暴露端口
EXPOSE 3306
# 健康检查
HEALTHCHECK --interval=10s --timeout=5s --retries=5 --start-period=30s \
CMD mysqladmin ping -h localhost -p${MYSQL_ROOT_PASSWORD} || exit 1

View File

@@ -0,0 +1,30 @@
# ====================================
# 后端服务镜像 - School News Serv
# 基于school-news-base-serv已包含Python依赖
# 注意jar包需要在主机中先编译好
# ====================================
FROM school-news-base-serv:latest
# 从主机复制已编译的jar包
COPY schoolNewsServ/admin/target/admin-1.0.0.jar /app/app.jar
# 复制爬虫脚本(基础镜像已安装依赖,这里只需复制脚本)
COPY schoolNewsCrawler/ /app/crawler/
# 复制默认配置文件(作为备份)
COPY schoolNewsServ/admin/src/main/resources/application.yml /app/config/application.yml.template
COPY schoolNewsServ/admin/src/main/resources/log4j2-spring.xml /app/config/log4j2-spring.xml.template
# 复制启动脚本
COPY schoolNewsServ/docker/start.sh /app/start.sh
RUN chmod +x /app/start.sh
# 暴露端口
EXPOSE 8081
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -f http://localhost:8081/schoolNewsServ/actuator/health || exit 1
# 启动应用
CMD ["/app/start.sh"]

View File

@@ -0,0 +1,56 @@
# ====================================
# 前端服务镜像 - School News Web
# 使用Node运行Vite预览服务器
# 注意dist目录需要在主机中先构建好
# ====================================
FROM node:20-alpine
# 设置环境变量
ENV TZ=Asia/Shanghai \
NODE_ENV=production
# 配置国内镜像源并安装基础工具
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories && \
apk update && \
apk add --no-cache tzdata bash curl && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone
# 创建应用目录
WORKDIR /app
# 创建必要目录
RUN mkdir -p /app/dist /app/config /app/logs
# 复制package.json和package-lock.json
COPY schoolNewsWeb/package*.json ./
# 安装生产依赖包括vite用于preview
RUN npm config set registry https://registry.npmmirror.com && \
npm ci --only=production && \
npm install -g vite
# 从主机复制已构建的dist目录
COPY schoolNewsWeb/dist/ /app/dist/
# 复制配置文件模板(可整个替换)
COPY schoolNewsWeb/public/app-config.js /app/config/app-config.js.template
# 确保dist中有默认配置文件
RUN if [ ! -f /app/dist/app-config.js ]; then \
cp /app/config/app-config.js.template /app/dist/app-config.js; \
fi
# 复制启动脚本
COPY schoolNewsWeb/docker/start.sh /app/start.sh
RUN chmod +x /app/start.sh
# 暴露端口Vite preview默认4173
EXPOSE 4173
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=20s --retries=3 \
CMD curl -f http://localhost:4173/ || exit 1
# 启动应用
CMD ["/app/start.sh"]

View File

@@ -0,0 +1,184 @@
server:
port: 8081
servlet:
context-path: /schoolNewsServ
encoding:
charset: UTF-8
enabled: true
force: true
spring:
application:
name: school-news-admin
# 数据源配置 - Docker环境
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://${MYSQL_HOST:mysql}:${MYSQL_PORT:3306}/${MYSQL_DATABASE:school_news}?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
username: ${MYSQL_USER:root}
password: ${MYSQL_PASSWORD:123456}
hikari:
maximum-pool-size: 30
minimum-idle: 10
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
# Redis配置 - Docker环境
data:
redis:
host: ${REDIS_HOST:redis}
port: ${REDIS_PORT:6379}
password: ${REDIS_PASSWORD:123456}
database: 0
timeout: 10000
lettuce:
pool:
max-active: 50
max-wait: 3000
max-idle: 20
min-idle: 5
shutdown-timeout: 100ms
# 邮件配置
mail:
host: smtp.qq.com
port: 587
username: 3223905473@qq.com
password: xmdmxvtjumxocicc
default-encoding: UTF-8
properties:
mail:
smtp:
auth: true
starttls:
enable: true
required: true
# 短信服务配置
sms:
enabled: true
provider: aliyun
access-key-id: LTAI5t68do3qVXx5Rufugt3X
access-key-secret: 2vD9ToIff49Vph4JQXsn0Cy8nXQfzA
sign-name: 星洋智慧
template-code: SMS_491985030
region-id: cn-hangzhou
endpoint: dysmsapi.aliyuncs.com
# 认证配置
school-news:
auth:
jwt-secret: schoolNewsSecretKeyForJWT2025SecureEnough
jwt-expiration: 86400
max-login-attempts: 5
lockout-duration: 30
white-list:
- "/auth/login"
- "/auth/logout"
- "/auth/register"
- "/auth/captcha"
- "/auth/send-sms-code"
- "/auth/send-email-code"
- "/auth/health"
- "/actuator/**"
- "/swagger-ui/**"
- "/v3/api-docs/**"
- "/favicon.ico"
- "/error"
- "/public/**"
- "/static/**"
- "/file/download/**"
- "/ai/chat/stream/**"
# 爬虫配置 - Docker环境
crawler:
# 容器内Python路径
pythonPath: /usr/bin/python3
# 容器内爬虫脚本根目录
basePath: /app/crawler
crontab:
items:
- name: 人民日报新闻爬取
methods:
- name: 关键字搜索爬取
clazz: newsCrewerTask
excuete_method: execute
path: crawler/RmrbSearch.py
params:
- name: query
description: 搜索关键字
type: String
value: ""
- name: total
description: 总新闻数量
type: Integer
value: 10
- name: 排行榜爬取
clazz: newsCrewerTask
excuete_method: execute
path: crawler/RmrbHotPoint.py
- name: 往日精彩头条爬取
clazz: newsCrewerTask
excuete_method: execute
path: crawler/RmrbTrending.py
params:
- name: startDate
description: 开始日期
type: String
value: ""
- name: endDate
description: 结束日期
type: String
value: ""
- name: yesterday
description: 是否是昨天
type: Boolean
value: true
# dify
dify:
knowledgeApiKey: dataset-nupqKP4LONpzdXmGthIrbjeJ
# 文件存储配置
file:
storage:
storages:
- type: local
enabled: true
base-path: /app/uploads
# MyBatis Plus配置
mybatis-plus:
type-aliases-package: org.xyzh.common.dto
mapper-locations: classpath*:mapper/*.xml
global-config:
db-config:
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
insert-strategy: not_null
update-strategy: not_null
select-strategy: not_empty
configuration:
map-underscore-to-camel-case: true
cache-enabled: true
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
# 日志配置
logging:
config: classpath:log4j2-spring.xml
charset:
console: UTF-8
file: UTF-8
# 管理端点配置
management:
endpoints:
web:
exposure:
include: health,info,metrics,env
endpoint:
health:
show-details: when-authorized
debug: false

View File

@@ -0,0 +1,208 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
校园新闻管理系统 - Admin模块日志配置
-->
<configuration status="WARN" monitorInterval="30">
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--变量配置-->
<Properties>
<!-- 格式化输出:%date表示日期%thread表示线程名%-5level级别从左显示5个字符宽度 %msg日志消息%n是换行符-->
<!-- %logger{36} 表示 Logger 名字最长36个字符 -->
<property name="LOG_PATTERN" value="%date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" />
<!-- 定义日志存储的路径 -->
<property name="FILE_PATH" value="./logs" />
<!-- Admin模块日志文件名 -->
<property name="FILE_NAME" value="school-news-admin" />
<!-- 设置系统属性 -->
<property name="file.encoding" value="UTF-8" />
<property name="console.encoding" value="UTF-8" />
<property name="stdout.encoding" value="UTF-8" />
<property name="stderr.encoding" value="UTF-8" />
</Properties>
<appenders>
<console name="Console" target="SYSTEM_OUT">
<!--输出日志的格式-->
<PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/>
<!--控制台输出debug及以上级别的信息-->
<ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY"/>
</console>
<!--文件会打印出所有信息这个log每次运行程序会自动清空由append属性决定适合临时测试用-->
<File name="Filelog" fileName="${FILE_PATH}/${FILE_NAME}-test.log" append="false">
<PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/>
</File>
<!-- 这个会打印出所有的info及以下级别的信息每次大小超过size则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
<RollingFile name="RollingFileInfo" fileName="${FILE_PATH}/${FILE_NAME}-info.log" filePattern="${FILE_PATH}/${FILE_NAME}-INFO-%d{yyyy-MM-dd}_%i.log.gz">
<!--控制台只输出level及以上级别的信息onMatch其他的直接拒绝onMismatch-->
<ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/>
<Policies>
<!--interval属性用来指定多久滚动一次默认是1 hour-->
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<!-- DefaultRolloverStrategy属性如不设置则默认为最多同一文件夹下7个文件开始覆盖-->
<DefaultRolloverStrategy max="15"/>
</RollingFile>
<!-- 这个会打印出所有的warn及以下级别的信息每次大小超过size则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
<RollingFile name="RollingFileWarn" fileName="${FILE_PATH}/${FILE_NAME}-warn.log" filePattern="${FILE_PATH}/${FILE_NAME}-WARN-%d{yyyy-MM-dd}_%i.log.gz">
<!--控制台只输出level及以上级别的信息onMatch其他的直接拒绝onMismatch-->
<ThresholdFilter level="warn" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/>
<Policies>
<!--interval属性用来指定多久滚动一次默认是1 hour-->
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<!-- DefaultRolloverStrategy属性如不设置则默认为最多同一文件夹下7个文件开始覆盖-->
<DefaultRolloverStrategy max="15"/>
</RollingFile>
<!-- 这个会打印出所有的error及以下级别的信息每次大小超过size则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档-->
<RollingFile name="RollingFileError" fileName="${FILE_PATH}/${FILE_NAME}-error.log" filePattern="${FILE_PATH}/${FILE_NAME}-ERROR-%d{yyyy-MM-dd}_%i.log.gz">
<!--控制台只输出level及以上级别的信息onMatch其他的直接拒绝onMismatch-->
<ThresholdFilter level="error" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/>
<Policies>
<!--interval属性用来指定多久滚动一次默认是1 hour-->
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<!-- DefaultRolloverStrategy属性如不设置则默认为最多同一文件夹下7个文件开始覆盖-->
<DefaultRolloverStrategy max="15"/>
</RollingFile>
<!-- 数据库日志Appender - 异步写入DEBUG级别及以上的日志到数据库 -->
<DatabaseAppender name="DatabaseAppender" ignoreExceptions="false">
<ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY"/>
</DatabaseAppender>
</appenders>
<!--Logger节点用来单独指定日志的形式比如要为指定包下的class指定不同的日志级别等。-->
<!--然后定义loggers只有定义了logger并引入的appenderappender才会生效-->
<loggers>
<!--过滤掉spring的一些无用的DEBUG信息-->
<logger name="org.mybatis" level="debug" additivity="false">
<AppenderRef ref="Console"/>
</logger>
<!--监控系统信息-->
<!--若是additivity设为false则 子Logger 只会在自己的appender里输出不会在 父Logger 的appender里输出。-->
<Logger name="org.springframework" level="info" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
<!-- MyBatis Mapper 日志配置 - 打印SQL -->
<Logger name="org.xyzh.achievement.mapper" level="debug" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
<Logger name="org.xyzh.ai.mapper" level="debug" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
<Logger name="org.xyzh.system.mapper" level="debug" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
<Logger name="org.xyzh.news.mapper" level="debug" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
<Logger name="org.xyzh.study.mapper" level="debug" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
<Logger name="org.xyzh.crontab.mapper" level="debug" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
<Logger name="org.xyzh.message.mapper" level="debug" additivity="false">
<AppenderRef ref="Console"/>
</Logger>
<!-- 项目包日志配置 - Auth模块 -->
<Logger name="org.xyzh.auth" level="debug" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="Filelog"/>
<AppenderRef ref="RollingFileInfo"/>
<AppenderRef ref="RollingFileWarn"/>
<AppenderRef ref="RollingFileError"/>
<AppenderRef ref="DatabaseAppender"/>
</Logger>
<!-- 项目包日志配置 - System模块 -->
<Logger name="org.xyzh.system" level="debug" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="Filelog"/>
<AppenderRef ref="RollingFileInfo"/>
<AppenderRef ref="RollingFileWarn"/>
<AppenderRef ref="RollingFileError"/>
<AppenderRef ref="DatabaseAppender"/>
</Logger>
<!-- 项目包日志配置 - News模块 -->
<Logger name="org.xyzh.news" level="debug" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="Filelog"/>
<AppenderRef ref="RollingFileInfo"/>
<AppenderRef ref="RollingFileWarn"/>
<AppenderRef ref="RollingFileError"/>
<AppenderRef ref="DatabaseAppender"/>
</Logger>
<!-- 项目包日志配置 - Common模块 -->
<Logger name="org.xyzh.common" level="debug" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="Filelog"/>
<AppenderRef ref="RollingFileInfo"/>
<AppenderRef ref="RollingFileWarn"/>
<AppenderRef ref="RollingFileError"/>
<AppenderRef ref="DatabaseAppender"/>
</Logger>
<!-- 项目包日志配置 - Achievement模块 -->
<Logger name="org.xyzh.achievement" level="debug" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="Filelog"/>
<AppenderRef ref="RollingFileInfo"/>
<AppenderRef ref="RollingFileWarn"/>
<AppenderRef ref="RollingFileError"/>
<AppenderRef ref="DatabaseAppender"/>
</Logger>
<Logger name="org.xyzh.crontab" level="debug" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="Filelog"/>
<AppenderRef ref="RollingFileInfo"/>
<AppenderRef ref="RollingFileWarn"/>
<AppenderRef ref="RollingFileError"/>
<AppenderRef ref="DatabaseAppender"/>
</Logger>
<Logger name="org.xyzh.message" level="debug" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="Filelog"/>
<AppenderRef ref="RollingFileInfo"/>
<AppenderRef ref="RollingFileWarn"/>
<AppenderRef ref="RollingFileError"/>
<AppenderRef ref="DatabaseAppender"/>
</Logger>
<Logger name="org.xyzh.sensitive" level="debug" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="Filelog"/>
<AppenderRef ref="RollingFileInfo"/>
<AppenderRef ref="RollingFileWarn"/>
<AppenderRef ref="RollingFileError"/>
<AppenderRef ref="DatabaseAppender"/>
</Logger>
<root level="info">
<appender-ref ref="Console"/>
<appender-ref ref="Filelog"/>
<appender-ref ref="RollingFileInfo"/>
<appender-ref ref="RollingFileWarn"/>
<appender-ref ref="RollingFileError"/>
<appender-ref ref="DatabaseAppender"/>
</root>
</loggers>
</configuration>

View File

@@ -0,0 +1,74 @@
/**
* 前端应用配置文件
*
* 此文件用于Docker部署时的配置外挂
* 挂载方式docker-compose.yml 中配置
* volumes:
* - ./config/web-app-config.js:/app/config/app-config.js
*
* 修改步骤:
* 1. 编辑此文件
* 2. 重启容器docker-compose restart school-news-web
* 3. 刷新浏览器即可生效
*
* 注意:此文件结构必须与 schoolNewsWeb/public/app-config.js 保持一致
*/
(function() {
'use strict';
window.APP_RUNTIME_CONFIG = {
// 环境标识
env: 'production',
// API 配置
api: {
baseUrl: '/schoolNewsServ', // API基础路径
timeout: 30000 // 请求超时时间(毫秒)
},
// 应用基础路径
baseUrl: '/schoolNewsWeb/',
// 文件配置
file: {
downloadUrl: '/schoolNewsServ/file/download/',
uploadUrl: '/schoolNewsServ/file/upload/',
maxSize: {
image: 5, // MB
video: 100, // MB
document: 10 // MB
},
acceptTypes: {
image: 'image/*',
video: 'video/*',
document: '.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx'
}
},
// Token 配置
token: {
key: 'token',
refreshThreshold: 300000 // 5分钟毫秒
},
// 公共路径
publicImgPath: '/schoolNewsWeb/img',
publicWebPath: '/schoolNewsWeb',
// 功能开关(可自由扩展)
features: {
enableDebug: false, // 是否启用调试模式
enableMockData: false // 是否启用Mock数据
}
};
// 配置加载完成标记
window.__CONFIG_LOADED__ = true;
// 控制台输出配置信息
if (console && console.log) {
console.log('%c[配置]%c Docker配置已加载', 'color: green; font-weight: bold', 'color: inherit');
console.log('[配置] 环境:', window.APP_RUNTIME_CONFIG.env);
console.log('[配置] API地址:', window.APP_RUNTIME_CONFIG.api.baseUrl);
}
})();

View File

@@ -0,0 +1,57 @@
/**
* @description 应用配置 - Docker生产环境
* @author yslg
* @since 2025-10-18
*/
// 生产环境配置
const isDev = false;
// API 基础路径 - Docker环境使用相对路径
export const API_BASE_URL = '/schoolNewsServ';
// 文件下载路径
export const FILE_DOWNLOAD_URL = `${API_BASE_URL}/file/download/`;
// 应用配置
export const APP_CONFIG = {
// 应用标题
title: '校园新闻管理系统',
// 基础路径
baseUrl: '/schoolNewsWeb/',
// API 配置
api: {
baseUrl: API_BASE_URL,
timeout: 30000
},
// 文件配置
file: {
downloadUrl: FILE_DOWNLOAD_URL,
uploadUrl: `${API_BASE_URL}/file/upload`,
maxSize: {
image: 5, // MB
video: 100, // MB
document: 10 // MB
},
acceptTypes: {
image: 'image/*',
video: 'video/*',
document: '.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx'
}
},
// Token 配置
token: {
key: 'token',
refreshThreshold: 5 * 60 * 1000 // 提前5分钟刷新
}
};
// 公共资源路径 - Docker环境
export const PUBLIC_IMG_PATH = '/schoolNewsWeb/img';
export const PUBLIC_WEB_PATH = '/schoolNewsWeb';
export default APP_CONFIG;

View File

@@ -0,0 +1,81 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { VitePWA } from 'vite-plugin-pwa'
import { resolve } from 'path'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
VitePWA({
registerType: 'autoUpdate',
workbox: {
cleanupOutdatedCaches: true,
skipWaiting: true,
clientsClaim: true
}
})
],
// 基础路径
base: '/schoolNewsWeb/',
file: {
downloadUrl: "http://school-news-serv:8081/schoolNewsServ/file/download/"
},
// 输出目录
build: {
outDir: 'dist',
assetsDir: 'static',
sourcemap: false,
chunkSizeWarningLimit: 1500,
rollupOptions: {
output: {
manualChunks: {
'vue-vendor': ['vue', 'vue-router', 'vuex'],
'element-plus': ['element-plus']
}
}
}
},
// 路径别名
resolve: {
alias: {
'@': resolve(__dirname, 'src')
},
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
},
// 环境变量
define: {
'process.env.BASE_URL': JSON.stringify('/schoolNewsWeb/'),
'process.env.VITE_API_BASE_URL': JSON.stringify('/api'),
'process.env.VITE_APP_TITLE': JSON.stringify('校园新闻管理系统')
},
// 开发服务器配置(生产环境无效)
server: {
host: '0.0.0.0',
port: 8080,
open: '/schoolNewsWeb/',
// 代理配置
proxy: {
'/api': {
target: 'http://school-news-serv:8081/schoolNewsServ',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
},
// CSS 配置
css: {
preprocessorOptions: {
scss: {
additionalData: ''
}
}
}
})

View File

@@ -0,0 +1,259 @@
version: '3.8'
services:
# MySQL数据库
mysql:
image: school-news-mysql:latest
container_name: school-news-mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-123456}
MYSQL_DATABASE: ${MYSQL_DATABASE:-school_news}
MYSQL_USER: ${MYSQL_USER:-schoolnews}
MYSQL_PASSWORD: ${MYSQL_PASSWORD:-123456}
TZ: Asia/Shanghai
ports:
- "${MYSQL_PORT:-3307}:3306"
volumes:
# 数据持久化(命名卷)
- mysql-data:/var/lib/mysql
# 自定义配置文件(可选,取消注释以启用)
# 如需自定义MySQL配置取消下面的注释并修改mysql/my.cnf
# - ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
- --default-authentication-plugin=mysql_native_password
- --max_connections=1000
- --max_allowed_packet=64M
- --local-infile=1
networks:
- school-news-network
healthcheck:
# 只有当 MySQL 可访问且敏感词表中至少有一条 deny 记录时,才认为 healthy
test: ["CMD-SHELL", "mysql -uroot -p${MYSQL_ROOT_PASSWORD:-123456} -D ${MYSQL_DATABASE:-school_news} -e \"SELECT 'ok' FROM _db_init_status WHERE script_name='01-init-database.sql' AND status='success' LIMIT 1;\" 2>/dev/null | grep -q ok"]
interval: 10s
timeout: 10s
retries: 10
start_period: 60s
# Redis缓存
redis:
image: redis:7-alpine
container_name: school-news-redis
restart: always
environment:
TZ: Asia/Shanghai
ports:
- "${REDIS_PORT:-6379}:6379"
volumes:
# 数据持久化(命名卷)
- redis-data:/data
# Redis配置文件命名卷
- redis-config:/usr/local/etc/redis
command: redis-server /usr/local/etc/redis/redis.conf --requirepass ${REDIS_PASSWORD:-123456}
networks:
- school-news-network
healthcheck:
test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
interval: 10s
timeout: 3s
retries: 5
# 后端服务
school-news-serv:
image: school-news-serv:latest
container_name: school-news-serv
restart: always
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_healthy
environment:
# 数据库配置
MYSQL_HOST: mysql
MYSQL_PORT: 3306
MYSQL_DATABASE: ${MYSQL_DATABASE:-school_news}
MYSQL_USER: ${MYSQL_USER:-root}
MYSQL_PASSWORD: ${MYSQL_PASSWORD:-123456}
# Redis配置
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_PASSWORD: ${REDIS_PASSWORD:-123456}
# JVM配置
JAVA_OPTS: "-Xms512m -Xmx1g -XX:+UseG1GC"
TZ: Asia/Shanghai
ports:
- "${SERV_PORT:-8081}:8081"
volumes:
# 配置文件(命名卷)
- serv-config:/app/config
# 日志目录(命名卷)
- serv-logs:/app/logs
# 上传文件目录(命名卷)
- serv-uploads:/app/uploads
# 爬虫脚本目录(默认不挂载,保留在镜像内)
# 注意:挂载会覆盖镜像内容,如需运行时更新爬虫脚本可取消注释
- serv-crawler:/app/crawler
networks:
- school-news-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8081/schoolNewsServ/actuator/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
# 前端服务Node + Vite Preview
school-news-web:
image: school-news-web:latest
container_name: school-news-web
restart: always
depends_on:
- school-news-serv
environment:
TZ: Asia/Shanghai
NODE_ENV: production
# 不直接暴露端口通过nginx反向代理访问
expose:
- "4173"
volumes:
# 运行时配置文件(命名卷)
- web-config:/app/config
# 日志目录(命名卷)
- web-logs:/app/logs
networks:
- school-news-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:4173/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 20s
# Nginx反向代理
nginx:
image: nginx:alpine # 直接使用官方镜像,无需自定义构建
container_name: school-news-nginx
restart: always
depends_on:
- school-news-web
- school-news-serv
environment:
TZ: Asia/Shanghai
ports:
- "${NGINX_PORT:-80}:80"
volumes:
# 仅挂载自定义 Nginx 主配置文件
- ./volumes/nginx/config/nginx.conf:/etc/nginx/nginx.conf
# 仅挂载站点配置目录conf.d保留镜像内的 mime.types 等其他文件
- nginx-conf-d:/etc/nginx/conf.d:ro
# 日志目录(命名卷)
- nginx-logs:/var/log/nginx
networks:
- school-news-network
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
networks:
school-news-network:
driver: bridge
# 命名卷定义数据存储在当前目录下的volumes/子目录)
# 使用前请先运行初始化脚本:./init-volumes.sh 或 init-volumes.bat
volumes:
# ===== MySQL =====
mysql-data:
driver: local
driver_opts:
type: none
o: bind
device: ./volumes/mysql/data
# ===== Redis =====
redis-data:
driver: local
driver_opts:
type: none
o: bind
device: ./volumes/redis/data
redis-config:
driver: local
driver_opts:
type: none
o: bind
device: ./volumes/redis/config
# ===== 后端服务 =====
serv-config:
driver: local
driver_opts:
type: none
o: bind
device: ./volumes/serv/config
serv-logs:
driver: local
driver_opts:
type: none
o: bind
device: ./volumes/serv/logs
serv-uploads:
driver: local
driver_opts:
type: none
o: bind
device: ./volumes/serv/uploads
# 爬虫脚本目录(可选,默认不启用)
# 注意启用后会覆盖镜像内的爬虫脚本需先复制镜像内容到volumes/serv/crawler
serv-crawler:
driver: local
driver_opts:
type: none
o: bind
device: ./volumes/serv/crawler
# ===== 前端服务 =====
web-config:
driver: local
driver_opts:
type: none
o: bind
device: ./volumes/web/config
web-logs:
driver: local
driver_opts:
type: none
o: bind
device: ./volumes/web/logs
# ===== Nginx =====
nginx-conf-file:
driver: local
driver_opts:
type: none
o: bind
device: ./volumes/nginx/config/nginx.conf
nginx-conf-d:
driver: local
driver_opts:
type: none
o: bind
device: ./volumes/nginx/config/conf.d
nginx-logs:
driver: local
driver_opts:
type: none
o: bind
device: ./volumes/nginx/logs

View File

@@ -0,0 +1,29 @@
-- ========================================
-- 校园新闻管理系统数据库初始化脚本
--
-- 注意:
-- 1. 本脚本仅在数据库首次创建时执行
-- 2. 如果数据库已存在请手动执行或使用02-check-init.sh
-- ========================================
-- 创建数据库(如果不存在)
-- 创建数据库使用utf8mb4字符集
CREATE DATABASE IF NOT EXISTS `school_news` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 使用数据库
USE `school_news`;
-- 检查表是否已存在,避免重复初始化
-- 创建一个标记表记录初始化状态
CREATE TABLE IF NOT EXISTS _db_init_status (
id INT PRIMARY KEY AUTO_INCREMENT,
script_name VARCHAR(255) NOT NULL UNIQUE,
executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
status VARCHAR(50) DEFAULT 'init'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 记录初始化标记
INSERT IGNORE INTO _db_init_status (script_name) VALUES ('01-init-database.sql');
-- 提示信息
SELECT CONCAT('数据库 school_news 初始化完成。请将您的表结构脚本放在 02-create-tables.sql 中') AS message;

View File

@@ -0,0 +1,334 @@
# 数据库初始化脚本说明
## 📋 概述
本目录包含数据库初始化脚本用于Docker容器首次启动时自动初始化数据库。
**基于**: `schoolNewsServ/.bin/mysql/sql/reInit.sh` 的实现逻辑
## 📂 脚本文件
| 文件 | 说明 | 状态 |
|------|------|------|
| `01-init-database.sql` | 创建数据库和初始化标记表 | ✅ 已就绪 |
| `02-create-tables.sql` | 创建所有业务表50+张) | ⚠️ 需准备 |
| `03-init-data.sql` | 导入初始数据(用户、菜单等) | ⚠️ 需准备 |
| `prepare-sql.sh` | 自动准备脚本 | ✅ 已就绪 |
| `数据库初始化指南.md` | 详细说明文档 | ✅ 已就绪 |
## 🚀 快速开始
### 方式1: 使用自动脚本(推荐)
```bash
cd docker/init-db
chmod +x prepare-sql.sh
./prepare-sql.sh
```
脚本会自动:
1. ✅ 从 `schoolNewsServ/.bin/mysql/sql/` 读取所有SQL文件
2. ✅ 合并所有 `createTable*.sql``02-create-tables.sql`
3. ✅ 合并所有 `init*.sql``03-init-data.sql`
4. ✅ 添加Docker环境特定配置爬虫路径等
5. ✅ 生成统计信息
### 方式2: 手动准备
参见 [数据库初始化指南.md](数据库初始化指南.md)
## 📊 脚本执行顺序
MySQL容器会按照文件名的字母顺序自动执行此目录下的`.sql`文件:
```
容器启动
01-init-database.sql
├─ 创建数据库 school_news
└─ 创建初始化标记表 _db_init_status
02-create-tables.sql
├─ 创建用户模块表3+张)
├─ 创建权限模块表10+张)
├─ 创建资源模块表5+张)
├─ 创建学习模块表8+张)
├─ 创建AI模块表5+张)
├─ 创建系统模块表5+张)
├─ 创建成就模块表5+张)
├─ 创建定时任务模块表3+张)
├─ 创建消息模块表3+张)
└─ 创建敏感词模块表1+张)
03-init-data.sql
├─ 导入菜单和权限数据
├─ 导入默认用户和角色
├─ 导入系统配置
└─ 导入Docker环境配置爬虫路径
数据库就绪 ✓
```
## 🎯 初始化特性
### 幂等性设计
所有脚本支持重复执行,不会导致错误:
```sql
-- 表创建使用IF NOT EXISTS
CREATE TABLE IF NOT EXISTS tb_user (...);
-- 数据插入使用INSERT IGNORE
INSERT IGNORE INTO tb_sys_config VALUES (...);
-- 使用_db_init_status表跟踪执行状态
INSERT IGNORE INTO _db_init_status (script_name) VALUES ('02-create-tables.sql');
```
### 避免重复初始化
系统使用 `_db_init_status` 表来跟踪已执行的脚本:
```bash
# 查看已执行的脚本
docker exec school-news-mysql mysql -uroot -p123456 school_news -e \
"SELECT * FROM _db_init_status ORDER BY executed_at;"
```
## 🗄️ 数据库结构
### 模块组成
| 模块 | 表数量 | 说明 |
|------|--------|------|
| 用户管理 | 3+ | 用户、部门、角色 |
| 权限管理 | 10+ | 菜单、权限、角色权限映射 |
| 资源管理 | 5+ | 资源、标签、分类、评论 |
| 课程管理 | 3+ | 课程、章节、课件 |
| 学习管理 | 5+ | 学习记录、笔记、错题 |
| 个人中心 | 3+ | 收藏、历史、个人信息 |
| AI智能体 | 5+ | AI对话、知识库 |
| 系统配置 | 5+ | 配置、日志、文件管理 |
| 成就系统 | 5+ | 成就、徽章、等级 |
| 定时任务 | 3+ | 任务、执行记录、元数据 |
| 消息通知 | 3+ | 消息、通知、模板 |
| 敏感词 | 1+ | 敏感词过滤 |
**总计**: 50+ 张表
### 默认数据
#### 默认用户
- **用户名**: admin
- **密码**: admin123
- **角色**: 管理员(拥有所有权限)
#### 系统配置
- `crawler.pythonPath`: /usr/bin/python3
- `crawler.basePath`: /app/crawler
## 🔄 重新初始化
### 完全重新初始化(会删除所有数据)
```bash
# 停止并删除容器和数据卷
cd docker
docker-compose down -v
# 重新启动
docker-compose up -d
```
### 只重置初始化标记
```bash
# 清空标记表,下次重启时重新执行脚本
docker exec school-news-mysql mysql -uroot -p123456 -e \
"TRUNCATE TABLE school_news._db_init_status;"
# 重启MySQL容器
docker-compose restart mysql
```
## 🧪 验证初始化
### 1. 查看初始化日志
```bash
docker logs school-news-mysql 2>&1 | grep -i "init\|sql"
```
### 2. 检查数据库和表
```bash
# 检查数据库
docker exec school-news-mysql mysql -uroot -p123456 -e "SHOW DATABASES;"
# 检查表数量
docker exec school-news-mysql mysql -uroot -p123456 school_news -e \
"SELECT COUNT(*) AS table_count FROM information_schema.tables WHERE table_schema='school_news';"
# 查看所有表
docker exec school-news-mysql mysql -uroot -p123456 school_news -e "SHOW TABLES;"
```
### 3. 验证默认数据
```bash
# 检查默认用户
docker exec school-news-mysql mysql -uroot -p123456 school_news -e \
"SELECT username, nickname, status FROM tb_sys_user WHERE username='admin';"
# 检查系统配置
docker exec school-news-mysql mysql -uroot -p123456 school_news -e \
"SELECT config_key, config_value FROM tb_sys_config WHERE config_key LIKE 'crawler.%';"
# 检查菜单数量
docker exec school-news-mysql mysql -uroot -p123456 school_news -e \
"SELECT COUNT(*) AS menu_count FROM tb_sys_menu;"
```
### 4. 检查初始化状态
```bash
docker exec school-news-mysql mysql -uroot -p123456 school_news -e \
"SELECT script_name, executed_at, status FROM _db_init_status ORDER BY executed_at;"
```
## ⚠️ 注意事项
### 1. SOURCE语句不支持
Docker的mysql镜像**不支持** `SOURCE` 语句需要将所有SQL合并到一个文件
```sql
-- ❌ 不支持
SOURCE createTableUser.sql;
-- ✅ 需要合并
-- 将createTableUser.sql的内容直接复制过来
CREATE TABLE tb_user (...);
```
### 2. 文件执行顺序
文件按字母顺序执行,命名规范:
```
01-xxx.sql (最先执行)
02-xxx.sql (其次执行)
03-xxx.sql (最后执行)
04-xxx.sql (可选:迁移脚本)
```
### 3. 字符集配置
确保使用UTF8MB4字符集
```sql
CREATE TABLE tb_xxx (
...
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```
### 4. 安全性
生产环境必须:
- ✅ 修改默认密码
- ✅ 使用强密码策略
- ✅ 限制数据库访问权限
- ✅ 定期备份数据
## 🗂️ 数据持久化
数据库数据持久化在Docker数据卷中
```yaml
volumes:
mysql-data:
driver: local
```
### 查看和管理数据卷
```bash
# 查看所有数据卷
docker volume ls
# 查看数据卷详情
docker volume inspect docker_mysql-data
# 备份数据卷
docker run --rm -v docker_mysql-data:/data -v $(pwd):/backup \
alpine tar czf /backup/mysql-backup.tar.gz /data
# 恢复数据卷
docker run --rm -v docker_mysql-data:/data -v $(pwd):/backup \
alpine tar xzf /backup/mysql-backup.tar.gz -C /
```
## 🐛 故障排查
### 问题1: 脚本未执行
**症状**: 数据库创建了但没有表
**排查**:
```bash
# 查看MySQL日志
docker logs school-news-mysql
# 检查SQL文件
ls -l docker/init-db/*.sql
```
**解决**:
- 确保SQL文件有读权限
- 检查SQL语法是否正确
### 问题2: 初始化失败
**症状**: 容器启动失败或反复重启
**排查**:
```bash
# 查看错误日志
docker logs school-news-mysql 2>&1 | grep -i error
# 进入容器检查
docker exec -it school-news-mysql bash
```
**解决**:
- 检查SQL语法错误
- 确保表之间的依赖关系正确
- 验证数据格式是否正确
### 问题3: 重复执行导致错误
**解决**: 使用幂等性设计
- 使用 `CREATE TABLE IF NOT EXISTS`
- 使用 `INSERT IGNORE`
- 使用 `_db_init_status` 表跟踪
## 📚 相关文档
- [数据库初始化指南](数据库初始化指南.md) - 详细的准备和使用说明
- [reInit.sh](../../schoolNewsServ/.bin/mysql/sql/reInit.sh) - 原始初始化脚本
- [Docker README](../README.md) - Docker部署文档
## 💡 最佳实践
1.**自动化** - 使用 `prepare-sql.sh` 自动准备SQL文件
2.**幂等性** - 确保脚本可以重复执行
3.**版本控制** - SQL文件纳入Git管理注意敏感信息
4.**文档同步** - 表结构变更同步更新SQL文件
5.**定期备份** - 重要数据定期备份
6.**测试验证** - 在测试环境充分验证后再部署生产
---
**更新时间**: 2025-11-24
**基于**: schoolNewsServ/.bin/mysql/sql/reInit.sh v1.1.0

View File

@@ -0,0 +1,65 @@
@echo off
REM ============================================
REM 初始化 Docker Volumes 目录 (Windows)
REM ============================================
echo ========================================
echo 初始化 Docker Volumes 目录
echo ========================================
echo.
REM 创建所有卷目录(分层结构)
echo 创建数据目录...
if not exist "volumes" mkdir "volumes"
if not exist "volumes\mysql\data" mkdir "volumes\mysql\data"
if not exist "volumes\redis\data" mkdir "volumes\redis\data"
if not exist "volumes\redis\config" mkdir "volumes\redis\config"
if not exist "volumes\serv\config" mkdir "volumes\serv\config"
if not exist "volumes\serv\logs" mkdir "volumes\serv\logs"
if not exist "volumes\serv\uploads" mkdir "volumes\serv\uploads"
REM if not exist "volumes\serv\crawler" mkdir "volumes\serv\crawler" REM 可选,如需运行时更新爬虫可取消注释
if not exist "volumes\web\config" mkdir "volumes\web\config"
if not exist "volumes\web\logs" mkdir "volumes\web\logs"
if not exist "volumes\nginx\config" mkdir "volumes\nginx\config"
if not exist "volumes\nginx\logs" mkdir "volumes\nginx\logs"
REM 复制配置文件模板
echo 复制配置文件模板...
if exist "redis\redis.conf" (copy /Y "redis\redis.conf" "volumes\redis\config\" >nul) else (echo ⚠️ redis.conf 不存在)
if exist "config\application.yml" (copy /Y "config\application.yml" "volumes\serv\config\" >nul) else (echo ⚠️ application.yml 不存在)
if exist "config\log4j2-spring.xml" (copy /Y "config\log4j2-spring.xml" "volumes\serv\config\" >nul) else (echo ⚠️ log4j2-spring.xml 不存在)
if exist "config\web-app-config.js" (copy /Y "config\web-app-config.js" "volumes\web\config\app-config.js" >nul) else (echo ⚠️ web-app-config.js 不存在)
if exist "nginx\nginx.conf" (xcopy /E /Y "nginx\*" "volumes\nginx\config\" >nul) else (echo ⚠️ nginx配置 不存在)
REM if exist "..\schoolNewsCrawler" (xcopy /E /Y "..\schoolNewsCrawler\*" "volumes\serv\crawler\" >nul) else (echo ⚠️ 爬虫脚本 不存在) REM 可选
echo.
echo ✅ 目录创建完成:
dir /b volumes
echo.
echo ========================================
echo 目录结构说明:
echo ========================================
echo volumes\
echo ├── mysql\
echo │ └── data\ - MySQL数据库数据
echo ├── redis\
echo │ ├── data\ - Redis缓存数据
echo │ └── config\ - Redis配置文件
echo ├── serv\
echo │ ├── config\ - 后端配置文件
echo │ ├── logs\ - 后端服务日志
echo │ ├── uploads\ - 后端上传文件
echo │ └── crawler\ - 爬虫脚本(可选,默认在镜像内)
echo ├── web\
echo │ ├── config\ - 前端配置文件
echo │ └── logs\ - 前端服务日志
echo └── nginx\
echo ├── config\ - Nginx配置文件
echo └── logs\ - Nginx访问日志
echo.
echo ✅ 初始化完成!现在可以启动服务了:
echo docker-compose up -d
echo ========================================
pause

View File

@@ -0,0 +1,70 @@
#!/bin/bash
##############################################
# 初始化 Docker Volumes 目录
# 用途:创建所有命名卷需要的本地目录
##############################################
echo "========================================"
echo "初始化 Docker Volumes 目录"
echo "========================================"
# 获取脚本所在目录
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
VOLUMES_DIR="${SCRIPT_DIR}/volumes"
echo "创建目录: ${VOLUMES_DIR}"
# 创建所有卷目录(分层结构)
echo "创建数据目录..."
mkdir -p "${VOLUMES_DIR}/mysql/data"
mkdir -p "${VOLUMES_DIR}/redis/data"
mkdir -p "${VOLUMES_DIR}/redis/config"
mkdir -p "${VOLUMES_DIR}/serv/config"
mkdir -p "${VOLUMES_DIR}/serv/logs"
mkdir -p "${VOLUMES_DIR}/serv/uploads"
mkdir -p "${VOLUMES_DIR}/serv/crawler" # 可选,如需运行时更新爬虫可取消注释
mkdir -p "${VOLUMES_DIR}/web/config"
mkdir -p "${VOLUMES_DIR}/web/logs"
mkdir -p "${VOLUMES_DIR}/nginx/config"
mkdir -p "${VOLUMES_DIR}/nginx/logs"
# 复制配置文件模板
echo "复制配置文件模板..."
[ -f "${SCRIPT_DIR}/redis/redis.conf" ] && cp "${SCRIPT_DIR}/redis/redis.conf" "${VOLUMES_DIR}/redis/config/" || echo " ⚠️ redis.conf 不存在"
[ -f "${SCRIPT_DIR}/mysql/my.cnf" ] && cp "${SCRIPT_DIR}/mysql/my.cnf" "${VOLUMES_DIR}/mysql/" || echo " ⚠️ my.cnf 不存在"
[ -f "${SCRIPT_DIR}/config/application.yml" ] && cp "${SCRIPT_DIR}/config/application.yml" "${VOLUMES_DIR}/serv/config/" || echo " ⚠️ application.yml 不存在"
[ -f "${SCRIPT_DIR}/config/log4j2-spring.xml" ] && cp "${SCRIPT_DIR}/config/log4j2-spring.xml" "${VOLUMES_DIR}/serv/config/" || echo " ⚠️ log4j2-spring.xml 不存在"
[ -f "${SCRIPT_DIR}/config/web-app-config.js" ] && cp "${SCRIPT_DIR}/config/web-app-config.js" "${VOLUMES_DIR}/web/config/app-config.js" || echo " ⚠️ web-app-config.js 不存在"
[ -f "${SCRIPT_DIR}/nginx/nginx.conf" ] && cp -r "${SCRIPT_DIR}/nginx"/* "${VOLUMES_DIR}/nginx/config/" || echo " ⚠️ nginx配置 不存在"
[ -d "${SCRIPT_DIR}/crawler/" ] && cp -r "${SCRIPT_DIR}/crawler"/* "${VOLUMES_DIR}/serv/crawler/" || echo " ⚠️ 爬虫脚本 不存在"
echo ""
echo "✅ 目录创建完成:"
tree -L 2 "${VOLUMES_DIR}" 2>/dev/null || ls -la "${VOLUMES_DIR}"
echo ""
echo "========================================"
echo "目录结构说明:"
echo "========================================"
echo "volumes/"
echo "├── mysql/"
echo "│ └── data/ - MySQL数据库数据"
echo "├── redis/"
echo "│ ├── data/ - Redis缓存数据"
echo "│ └── config/ - Redis配置文件"
echo "├── serv/"
echo "│ ├── config/ - 后端配置文件"
echo "│ ├── logs/ - 后端服务日志"
echo "│ ├── uploads/ - 后端上传文件"
echo "│ └── crawler/ - 爬虫脚本(可选,默认在镜像内)"
echo "├── web/"
echo "│ ├── config/ - 前端配置文件"
echo "│ └── logs/ - 前端服务日志"
echo "└── nginx/"
echo " ├── config/ - Nginx配置文件"
echo " └── logs/ - Nginx访问日志"
echo ""
echo "✅ 初始化完成!现在可以启动服务了:"
echo " docker-compose up -d"
echo "========================================"

View File

@@ -0,0 +1,40 @@
[mysqld]
# 基本设置
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
default-authentication-plugin=mysql_native_password
# 连接设置
max_connections=1000
max_connect_errors=100
max_allowed_packet=64M
# 性能优化
innodb_buffer_pool_size=256M
innodb_log_file_size=64M
innodb_flush_log_at_trx_commit=2
innodb_flush_method=O_DIRECT
# 查询缓存
query_cache_type=0
query_cache_size=0
# 慢查询日志
slow_query_log=1
slow_query_log_file=/var/log/mysql/slow.log
long_query_time=2
# 二进制日志
log_bin=mysql-bin
binlog_format=ROW
expire_logs_days=7
max_binlog_size=100M
# 时区设置
default-time-zone='+08:00'
[mysql]
default-character-set=utf8mb4
[client]
default-character-set=utf8mb4

View File

@@ -0,0 +1,74 @@
# ====================================
# 校园新闻系统 - Nginx反向代理配置
# ====================================
# 上游服务定义
upstream web_backend {
server school-news-web:4173;
}
upstream api_backend {
server school-news-serv:8081;
}
server {
listen 80;
server_name localhost;
# 日志配置
access_log /var/log/nginx/school-news-access.log;
error_log /var/log/nginx/school-news-error.log;
# 客户端上传大小限制
client_max_body_size 100M;
# 根路径重定向到前端
location = / {
return 301 /schoolNewsWeb/;
}
# 前端应用代理Node Vite Preview
location /schoolNewsWeb/ {
proxy_pass http://web_backend/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket支持如果需要HMR
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 超时设置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# 后端API代理
location /schoolNewsServ/ {
proxy_pass http://api_backend/schoolNewsServ/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 超时设置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# 缓冲设置
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
}
# 错误页面
error_page 404 /schoolNewsWeb/;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

View File

@@ -0,0 +1,32 @@
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}

View File

@@ -0,0 +1,41 @@
# Redis配置文件 - Docker环境
# 网络配置
bind 0.0.0.0
protected-mode yes
port 6379
# 持久化配置
# RDB快照
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /data
# AOF持久化
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# 内存管理
maxmemory 512mb
maxmemory-policy allkeys-lru
# 日志
loglevel notice
logfile ""
# 客户端
maxclients 10000
timeout 300
# 慢查询日志
slowlog-log-slower-than 10000
slowlog-max-len 128