# rain-novel **Repository Path**: rainbrookx/rain-novel ## Basic Information - **Project Name**: rain-novel - **Description**: 本项目是参照小说精品屋(https://docs.xxyopen.com/)开发的练习项目。✏我从 controller、service、缓存(Redis、Caffeine)、dao 逐个接口、逐层开发。原始仓库:https://gitee.com/novel_dev_team/novel - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: https://docs.xxyopen.com/ - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-07-05 - **Last Updated**: 2025-10-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # README 项目运行地址: ## 开发过程 1. 尽可能使用最新版本的各种依赖,尝试解决遇到的兼容问题、API变动问题等情况。 2. 原作者使用旧版的 `MyBatis-Plus 代码生成器` ,升级到新版本后,发现部分配置的API已经修改,经过AI尝试发现,AI不能很好地按照新版本的MP生成器文档修改原始代码,所以,我自己根据文档完成修改。 3. `MyBatis-Plus 代码生成器` 适合生成 entity、mapper,但不适合生成 controller、service 4. 在浏览器中,这个项目 API 结果的数据格式是 XML,不是JSON(shardingsphere-jdbc 引入的jackson-dataformat-xml)。但是,如果“Content-Type=application/json”,那么就会返回 JSON 5. SecureRandom 类 6. lombok @Builder,生成的构造器是没有 public 修饰的 7. 问题 2025.07.05 redis 做缓存的功能,应该配置了redis,另外验证码redis没有生效 - ==> 2025.07.06 BUG原因:`Duration.ofMillis(5)` 5 毫秒的过期时间 (◞‸◟) 8. 验证了 `CacheManager` 是生效的(包括 redis 和 caffeine) 9. RespDto 适合加上 @Data @Builder,ReqDto 只用加 @Data 10. 原作者的 JWT 没有过期时间,每次生成的 JWT 是一样的 11. UserHolder.getUserId(),在拦截器中 解析 JWT 获得userId, 并 UserHolder.setUserId() 12. redis 序列化出现问题,清空 redis 服务器中的数据后,就没有报错了 - 原因:redis使用 java serializable 序列化,缓存的数据结构(类),我的包名是 `xyz.csmemo.novel`,原作者的是 `io.github.xxyopen.novel`,先后运行我的或者原作者,然后再运行另一个(反序列化),就会报错 - 缓存没命中存入的过程是序列化,缓存命中取出的过程是反序列 ## 部署过程 ### 原作者的文档 > 单纯使用 docker 部署数据库、中间件,相对来说,比较麻烦 - MySQL、Redis、Nginx 单独使用 docker 部署 - JDK 安装到服务器 (主机)上 - 使用 `nohup java -jar novel-<版本号>.jar &` 启动 jar ### 我的部署方式 - 使用 docker compose 部署数据库、中间件、后端服务、前端服务 - 使用 Spring Boot 的外部配置文件,配置数据库、中间件 - Redis、RabbitMQ 没有开放对外访问的端口,保证数据安全。为了方便设置定时器重置数据库,所以开放了 MySQL 的端口(云服务器安全组禁用3306) #### docker-compose.yml ```yml services: mysql: image: mysql:8.0.42 container_name: novel-mysql restart: always command: --default-authentication-plugin=mysql_native_password environment: MYSQL_ROOT_PASSWORD: 123456 MYSQL_DATABASE: novel volumes: - mysql-data:/var/lib/mysql - ./mysql/init:/docker-entrypoint-initdb.d ports: - "3306:3306" networks: - novel-network redis: image: redis:7.0-alpine3.20 container_name: novel-redis restart: always volumes: - redis-data:/data networks: - novel-network rabbitmq: image: rabbitmq:3.10.25-management container_name: novel-rabbitmq restart: always environment: RABBITMQ_DEFAULT_USER: novel RABBITMQ_DEFAULT_PASS: novel networks: - novel-network backend: build: context: ./backend dockerfile: Dockerfile container_name: novel-backend restart: always volumes: - backend-data:/app/upload depends_on: - mysql - redis - rabbitmq ports: - "8888:8888" networks: - novel-network frontend: build: context: ./frontend dockerfile: Dockerfile container_name: novel-frontend restart: always depends_on: - backend ports: - "81:80" networks: - novel-network networks: novel-network: driver: bridge volumes: mysql-data: redis-data: backend-data: ``` #### backend/Dockerfile ```dockerfile # 使用官方 OpenJDK 21 镜像(精简版,减小体积) FROM openjdk:21-slim-bullseye # 创建文件上传目录(与配置文件中的 /app/upload 对应) RUN mkdir -p /app/upload && chmod -R 755 /app/upload # 确保上传目录有读写权限 # 设置工作目录 WORKDIR /app RUN apt-get update -y && \ apt-get install -y libfreetype6 fontconfig && \ rm -rf /var/lib/apt/lists/* # 清理缓存,减小镜像体积 # 复制应用 jar 包到容器内(使用更规范的文件名) COPY novel-3.5.1-SNAPSHOT.jar app.jar COPY application.yml application.yml # 暴露应用端口(与配置文件中的 server.port=8888 对应) EXPOSE 8888 # 启动命令(优化 JVM 参数,适应容器环境) CMD ["java", "-jar", "app.jar"] ``` #### frontend/Dockerfile ```dockerfile FROM nginx:mainline-alpine3.22-slim COPY . /usr/share/nginx/html EXPOSE 81 CMD ["nginx", "-g", "daemon off;"] ```