Docker Compose 部署若依前后端分离版

devtools/2024/9/28 21:15:12/

准备一台服务器

本次使用虚拟机,虚拟机系统 Ubuntu20.04,内存 4G,4核。
确保虚拟机能连接互联网。

Ubuntu20.04 安装 Docker

添加 Docker 的官方 GPG key:

sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

添加仓库到 apt 中:

echo \"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \sudo tee /etc/apt/sources.list.d/docker.list > /dev/nullsudo apt-get update

安装最新版本的 Docker:

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

docker-compose-plugin 就是 Docker Compose,上面的命令就安装了 Docker Compose

配置 Docker 镜像仓库:

sudo mkdir -p /etc/dockersudo tee /etc/docker/daemon.json <<-'EOF'
{"registry-mirrors": ["https://mirror.baidubce.com"]
}
EOFsudo systemctl daemon-reloadsudo systemctl restart docker# 使用 Docker info 命令查看配置的加速仓库
docker info

启动一个 Hello World 容器测试 Docker 是否安装成功:

sudo docker run hello-world

看到如下内容就是安装成功:
image.png

使用如下命令查看 Docker 的版本以及 Docker Compose 的版本:

docker version
docker compose version

配置 Docker 命令可以使用非 Root 用户使用:

# 创建名为 docker 的用户组
sudo groupadd docker# 将当前用户添加到 docker 用户组中
sudo usermod -aG docker $USER# 激活
newgrp docker# 验证非 Root 用户是否能使用 Docker 命令
docker run hello-world

配置 Docker 开机自启:

sudo systemctl enable docker.service
sudo systemctl enable containerd.service# 关闭 Docker 开机自启
sudo systemctl disable docker.service
sudo systemctl disable containerd.service

ruoyi__81">打 ruoyi 后端的镜像

做必要的配置修改

image.png
image.png

master:url: jdbc:mysql://mysql-service:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&connectTimeout=1000&socketTimeout=30000&autoReconnect=true&failOverReadOnly=falseusername: ruoyipassword: 123456

image.png

编写 Dockerfile 文件

# 使用官方的 OpenJDK 8 镜像作为基础镜像
FROM openjdk:8-jdk-alpine
# 创建存放上传文件的目录
RUN mkdir -p /opt/project/ruoyi/ruoyi-backend/upload-file-path
# 创建存放日志的目录
RUN mkdir -p /opt/project/ruoyi/ruoyi-backend/logs
# 安装字体文件
RUN mkdir -p /etc/apk/
RUN touch /etc/apk/repositories
RUN echo -e 'https://mirrors.aliyun.com/alpine/v3.6/main/\nhttps://mirrors.aliyun.com/alpine/v3.6/community/' > /etc/apk/repositories
RUN apk --no-cache add ttf-dejavu fontconfig
RUN set -xe && apk --no-cache add ttf-dejavu fontconfig
# 设置工作目录
WORKDIR /opt/project/ruoyi/ruoyi-backend
# 将构建好的 JAR 文件复制到容器
COPY ./ruoyi-admin/target/ruoyi-admin.jar ruoyi-admin.jar
# 暴露应用程序端口
EXPOSE 8080
# 启动应用程序
CMD ["nohup","java","-jar","/opt/project/ruoyi/ruoyi-backend/ruoyi-admin.jar", ">", "/opt/project/ruoyi/ruoyi-backend/logs/nohup.log", "&"]

IDEA 连接虚拟机中的 Docker 并打镜像

首先,检查 IDEA 是否安装了 Docker 插件:
image.png
版本比较新的 IDEA 默认都安装了这个插件,如果没有安装,安装一下。
确保我们虚拟机上安装了 Docker 和 Docker-compose,并启动了 Docker。
找到 IDEA 下方的 Services tab 栏,按照如下操作新建一个 Docker 连接:
image.png
配置连接 Docker 的 SSH 连接:
image.png
如果按照下面通过 password 认证连接 docker,idea 会显示 “Only key-pair ssh auth type is supported for docker connectons”:
image.png

所以需要改为 key-pair 的认证方式:
image.png
点击 OK。
移除路径映射后点击 OK:
image.png
右键我们创建的 Docker 连接,点击 “connection”,就连接成功了:
image.png
找到我们的 Dockerfile,右键这个文件,点击"Modify Run Configuration":
image.png
这里我们只需要修改 Image tag,也就是镜像名称,再点击 OK:
image.png
在打镜像前将我们的项目打包:
image.png
image.png
在 Dockerfile 文件的头部左侧的箭头位置点击 “Build image for dockerfile”,就会自动按照 Dockerfile 为我们打镜像:
image.png
打镜像完成后,就可以看到我们打的镜像了:
image.png

ruoyi__147">打 ruoyi 前端的镜像

编写 Dockerfile

在项目的根目录下创建 nginx.conf 配置文件,这个配置文件会拷贝到 ruoyi 前端镜像中,作为 Nginx 的配置文件:

user root;
worker_processes 1;events {worker_connections 1024;
}http {include mime.types;default_type application/octet-stream;sendfile on;keepalive_timeout 65;server {listen 80;server_name 127.0.0.1;charset utf-8;location / {root /opt/project/ruoyi/ruoyi-front-code;try_files $uri $uri/ /index.html;index index.html index.htm;}location /prod-api/ {proxy_set_header Host $http_host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header REMOTE-HOST $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_pass http://ruoyi-backend-service:8080/;}error_page 500 502 503 504 /50x.html;location = /50x.html {root html;}}
}
# 使用 Nginx 作为基础镜像
FROM nginx:1.12.2
# 将 nginx.conf 拷贝到容器
COPY nginx.conf /etc/nginx/nginx.conf
# 创建存放前端编译后代码的目录
RUN mkdir -p /opt/project/ruoyi/ruoyi-front-code
# 将构建好的应用拷贝到 Nginx 的默认 web 目录
COPY dist /opt/project/ruoyi/ruoyi-front-code
# Expose 端口
EXPOSE 80
# 启动 Nginx 服务器
CMD ["nginx", "-g", "daemon off;"]

WebStorm 连接虚拟机中的 Docker 打镜像

连接和打包步骤和 IDEA 连接虚拟机 Docker 的步骤一模一样。

docker_compose__207">准备 docker compose 启动的所有容器需要的文件以及文件夹

准备 Redis 容器需要的配置文件

找到本次部署的 Redis 7.2.0 的 redis.conf 文件,编辑其中的以下内容:


# 修改连接 redis 的密码为 123456
requirepass 123456# 注释掉 bind 127.0.0.1,bind 用于限制访问 Redis 的机器 ip,直接关掉
# bind 127.0.0.1

准备 MySQL 容器需要的初始化 SQL 文件

初始化的 SQL 文件在 Ruoyi 后端项目的如下位置:
image.png
容器首次启动的时候,我们需要执行这些初始化文件来建表、导入数据。
我们还需要一个创建数据库并创建一个用户的 sql 文件(create-database-user.sql):

-- 创建数据库
CREATE DATABASE  `ry-vue` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 创建普通用户
grant all PRIVILEGES on ry-vue.* to ruoyi@'%' identified by '123456';
flush privileges;
use ry-vue;

我们编写一个初始化的 sql 文件,在这个 sql 文件中再调用 create-database-user.sql、quartz.sql 和 ry_20231130.sql 这三个文件:

source /opt/mysql-service/create-database-user.sql;
use ry-vue;
source /opt/mysql-service/quartz.sql;
source /opt/mysql-service/ry_20231130.sql;

注意:这里的路径都是容器中的路径,就是容器首次启动时会调用这些命令

在宿主机中创建文件夹以及上传需要文件

/opt/project 目录的目录结构如下:

project/
└── ruoyi├── docker-compose.yml -- 下面我们要编写的 docker-compose 文件├── mysql-service -- 存放 mysql-service 相关文件的目录│   ├── other│   │   ├── children-sql -- 子 sql 文件存放目录│   │   │   ├── create-database-user.sql│   │   │   ├── quartz.sql│   │   │   └── ry_20231130.sql│   │   └── init -- mysql 初始化执行目录,会挂载到 docker-entrypoint-initdb.d│   │       └── arrange-sql.sql -- sql 编排文件,会依次调用 children-sql 文件夹中的 sql 文件│   └── volumes -- mysql-service 挂载的容器卷│       └── mysql└── redis-service└── volumes -- redis-service 挂载的容器卷└── redis.conf

准备 SQL 文件

quartz.sql 和 ry_20231130.sql 在 ruoyi 后端代码根目录的 sql 文件夹中就有,直接拷贝即可,但是,需要在这两个 SQL 文件的第一行添加一行使用指定数据库的 SQL 语句:

use ry-vue;

create-database-user.sql 负责创建用户、数据库和为用户赋权:

-- 创建数据库
CREATE DATABASE  `ry-vue` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 应先创建新用户
create user 'ruoyi'@'%' identified by '123456';
-- 执行授权
GRANT ALL PRIVILEGES ON `ry-vue`.* TO 'ruoyi'@'%';
-- 刷新
flush privileges;
-- 授权远程
ALTER USER 'ruoyi'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
-- 刷新
flush privileges;

arrange-sql.sql 负责调用其他 SQL 文件,起到对 SQL 文件进行编排的作用:

source /opt/mysql-service/create-database-user.sql;
SET NAMES utf8;
source /opt/mysql-service/quartz.sql;
source /opt/mysql-service/ry_20231130.sql;

dockercomposeyml__292">编写 docker-compose.yml 文件

version: '3.8'
services:mysql-service:image: mysql:8.0restart: alwaysenvironment:MYSQL_ROOT_PASSWORD: 123456ports:- "3306:3306"volumes:- /opt/project/ruoyi/mysql-service/volumes/mysql:/var/lib/mysql- /opt/project/ruoyi/mysql-service/other/init:/docker-entrypoint-initdb.d/- /opt/project/ruoyi/mysql-service/other/children-sql:/opt/mysql-service/redis-service:image: redis:7.2.0-alpine3.18restart: alwaysports:- "6379:6379"volumes:- /opt/project/ruoyi/redis-service/volumes/redis.conf:/usr/local/etc/redis/redis.confcommand: [ "redis-server", "/usr/local/etc/redis/redis.conf" ]ruoyi-backend-service:image: ruoyi-backend:1.0networks:- ruoyi-networkports:- "8080:8080"depends_on:- mysql-service- redis-serviceruoyi-frontend-service:image: ruoyi-frontend:1.0networks:- ruoyi-networkports:- "80:80"depends_on:- ruoyi-backend-servicenetworks:ruoyi-network:driver: bridge

使用如下命令启动 docker-compose 文件中的容器

docker compose up -d

遇到的问题

后端连接到 MySQL 错误

13:55:01.882 [main] ERROR c.a.d.p.DruidDataSource - [init,942] - init datasource error, url: jdbc:mysql://mysql-service:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT&connectTimeout=1000&socketTimeout=30000
com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failureThe last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.at com.mysql.cj.jdbc.exceptions.SQLError.createCommunicationsException(SQLError.java:175)at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:64)at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:825)at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:446)at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:239)at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:188)at com.alibaba.druid.filter.FilterChainImpl.connection_connect(FilterChainImpl.java:118)at com.alibaba.druid.filter.stat.StatFilter.connection_connect(StatFilter.java:232)at com.alibaba.druid.filter.FilterChainImpl.connection_connect(FilterChainImpl.java:112)at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1706)at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1801)at com.alibaba.druid.pool.DruidDataSource.init(DruidDataSource.java:938)at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:1462)at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:1458)at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:83)at org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource.getConnection(AbstractRoutingDataSource.java:194)at org.springframework.jdbc.datasource.DataSourceUtils.fetchConnection(DataSourceUtils.java:159)at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:117)at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:80)at org.mybatis.spring.transaction.SpringManagedTransaction.openConnection(SpringManagedTransaction.java:80)at org.mybatis.spring.transaction.SpringManagedTransaction.getConnection(SpringManagedTransaction.java:67)at org.apache.ibatis.executor.BaseExecutor.getConnection(BaseExecutor.java:345)at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:89)at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:64)at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:333)at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:158)at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:110)at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:90)at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:154)at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:147)at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:142)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:425)at com.sun.proxy.$Proxy100.selectList(Unknown Source)at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224)at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:147)at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:80)at org.apache.ibatis.binding.MapperProxy$PlainMethodInvoker.invoke(MapperProxy.java:142)at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:86)at com.sun.proxy.$Proxy101.selectConfigList(Unknown Source)at com.ruoyi.system.service.impl.SysConfigServiceImpl.loadingConfigCache(SysConfigServiceImpl.java:177)at com.ruoyi.system.service.impl.SysConfigServiceImpl.init(SysConfigServiceImpl.java:40)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:389)at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:333)at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:157)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:440)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1796)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276)at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1391)at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1311)at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:657)at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640)at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119)at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1431)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:619)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:955)at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:920)at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:780)at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:453)at org.springframework.boot.SpringApplication.run(SpringApplication.java:343)at org.springframework.boot.SpringApplication.run(SpringApplication.java:1370)at org.springframework.boot.SpringApplication.run(SpringApplication.java:1359)at com.ruoyi.RuoYiApplication.main(RuoYiApplication.java:18)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)at org.springframework.boot.loader.Launcher.launch(Launcher.java:108)at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)
Caused by: com.mysql.cj.exceptions.CJCommunicationsException: Communications link failure

修改 application-durid.yml 中的如下配置:

url: jdbc:mysql://mysql-service:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT&connectTimeout=1000&socketTimeout=30000&autoReconnect=true&failOverReadOnly=falsetestOnBorrow: true

开启代理软件会导致访问虚拟机前端页面出现问题

image.png

访问后端接口报错

image.png
后端的报错日志:

15:38:29.831 [http-nio-8080-exec-8] ERROR c.r.f.w.e.GlobalExceptionHandler - [handleRuntimeException,93] - 请求地址'/captchaImage',发生未知异常.
java.lang.NullPointerException: nullat sun.awt.FontConfiguration.getVersion(FontConfiguration.java:1264)at sun.awt.FontConfiguration.readFontConfigFile(FontConfiguration.java:219)at sun.awt.FontConfiguration.init(FontConfiguration.java:107)at sun.awt.X11FontManager.createFontConfiguration(X11FontManager.java:774)at sun.font.SunFontManager$2.run(SunFontManager.java:431)at java.security.AccessController.doPrivileged(Native Method)at sun.font.SunFontManager.<init>(SunFontManager.java:376)at sun.awt.FcFontManager.<init>(FcFontManager.java:35)at sun.awt.X11FontManager.<init>(X11FontManager.java:57)at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)at java.lang.reflect.Constructor.newInstance(Constructor.java:423)at java.lang.Class.newInstance(Class.java:442)at sun.font.FontManagerFactory$1.run(FontManagerFactory.java:83)at java.security.AccessController.doPrivileged(Native Method)at sun.font.FontManagerFactory.getInstance(FontManagerFactory.java:74)at java.awt.Font.getFont2D(Font.java:491)at java.awt.Font.access$000(Font.java:224)at java.awt.Font$FontAccessImpl.getFont2D(Font.java:228)at sun.font.FontUtilities.getFont2D(FontUtilities.java:180)at sun.font.StandardGlyphVector.initFontData(StandardGlyphVector.java:1126)at sun.font.StandardGlyphVector.init(StandardGlyphVector.java:1115)at sun.font.StandardGlyphVector.<init>(StandardGlyphVector.java:167)at java.awt.Font.createGlyphVector(Font.java:2545)at com.google.code.kaptcha.text.impl.DefaultWordRenderer.renderWord(DefaultWordRenderer.java:67)at com.google.code.kaptcha.impl.DefaultKaptcha.createImage(DefaultKaptcha.java:43)at com.ruoyi.web.controller.common.CaptchaController.getCode(CaptchaController.java:70)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1072)at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:965)at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)at javax.servlet.http.HttpServlet.service(HttpServlet.java:529)at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)at javax.servlet.http.HttpServlet.service(HttpServlet.java:623)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:209)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:111)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:111)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:114)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)at com.ruoyi.common.filter.RepeatableFilter.doFilter(RepeatableFilter.java:39)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:327)at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115)at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:121)at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:115)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126)at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:105)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at com.ruoyi.framework.security.filter.JwtAuthenticationTokenFilter.doFilterInternal(JwtAuthenticationTokenFilter.java:42)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:111)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110)at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211)at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183)at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354)at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:481)at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:130)at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390)at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:926)at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1791)at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)at java.lang.Thread.run(Thread.java:748)

http://doc.ruoyi.vip/ruoyi/other/faq.html#linux%E7%B3%BB%E7%BB%9F%E9%AA%8C%E8%AF%81%E7%A0%81%E4%B9%B1%E7%A0%81%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95

image.png


http://www.ppmy.cn/devtools/32083.html

相关文章

1、FreeCAD概述与架构

FreeCAD介绍 FreeCAD的诞生&#xff1a;2002年10月29日&#xff0c;由Jrgen Riegel上传了版本0.0.1的初始上传。FreeCAD的维基百科页面显示&#xff0c;FreeCAD基本上是由不同强大的库组成的集合&#xff0c;其中最重要的是openCascade&#xff0c;用于管理和构建几何体&#x…

Docker:centos7安装docker

官网&#xff1a;https://www.docker.com/官网 文档地址 - 确认centos7及其以上的版本 查看当前系统版本 cat /etc/redhat-release- 卸载旧版本 依照官网执行 - yum安装gcc相关 yum -y install gccyum -y install gcc-c- 安装需要的软件包 yum install -y yum-utils- 设置s…

[学习笔记] Android综合_2024-4-30

数据库注意&#xff1a; 前端与后端之间 要有事务、锁。 要用innodb才支持事务。 记得使用接口测试工具测试&#xff08;HTTP ResuestListener&#xff09;。 后端给前端发返回的数据类型一定要是map。 为了简洁&#xff0c;后端所有参数用post接口&#xff0c;别用get接口…

【后端】RabbitMQ的常见使用问题

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、RabbitMQ 常见问题二、RabbitMQ 常见报错三、总结 前言 例如&#xff1a;随着人工智能的不断发展&#xff0c;机器学习这门技术也越来越重要&#xff0c;很…

一、Mysql索引的底层数据结构与算法

Mysql索引的底层数据结构与算法 前言一、索引数据结构为什么 MySQL 的索引要使用 B 树而不是其他树形结构?比如 B 树?为什么InnoDB存储引擎选择使用Btree索引结构&#xff1f; 二、索引分类思考&#xff1a;以下SQL语句&#xff0c;那个执行效率高&#xff1f;为什么&#xf…

C++基础之条件判断语句

条件判断语句是一种编程语言中的控制结构用于根据给定的条件来执行不同的代码块。它允许程序根据条件的真假来选择性地执行不同的代码分支。 一、if语句 形式如下&#xff1a; if(表达式)语句 表达式一般为关系表达式&#xff0c;表达式的运算结果应该是真或假(true或false)。…

[力扣]——387.字符串中的第一个唯一字符

. - 力扣&#xff08;LeetCode&#xff09; class Solution {public int firstUniqChar(String s) {int[] count new int[256];// 统计每个字符出现的次数for(int i 0; i < s.length(); i){count[s.charAt(i)];}// 找第一个只出现一次的字符for(int i 0; i < s.lengt…

MySql体系架构

一、MySql体系架构 1.1 网络连接层 客户端连接器&#xff08;Client Connectors&#xff09;&#xff1a;提供与MySQL服务器建立的支持。目前几乎支持所有主流的服务器编程技术&#xff0c;例如常见的Java、C、Python、.NET等&#xff0c;它们通过各自的API技术与MySQL建立连接…