简介:这份文档面向正在使用若依(RuoYi)前后端分离框架的Java开发者与运维人员,聚焦项目上线部署环节,把从本地打包到服务器运行、再到访问异常的完整链路整理成可照做的操作说明,适合已具备Spring Boot与Vue基础、希望独立完成环境搭建的中级开发者。资源共1个docx文件,压缩包约223KB,内容分为三部分:Linux环境下Nginx代理前后端服务的部署流程、Windows环境下Tomcat免Nginx的war包部署方式,以及调用百度地图等第三方API时的跨域处理思路,并附有部署后页面404、登录后空白等常见故障的排查与配置修正方法。已有7766人学习下载,说明其在实战场景中具备较高参考价值。读者可据此掌握jar与war两种打包产物的落地方式、Nginx与Tomcat的代理配置差异、前端打包路径的易错点,以及通过CORS、前端proxy与反向代理解决跨域的三条路径,减少上线反复试错的成本。
1. 一份部署文档能省多少事:若依前后端分离要装的四样东西
本地npm run dev跑得好好的,mvn spring-boot:run也没报错,一传到服务器就白屏、登录 404、菜单点不开——这是若依前后端分离项目上线时最典型的翻车现场。这份部署文档的价值不在于讲 Spring Boot 是什么,而在于它把 Linux+Nginx 和 Windows+Tomcat 两条完全不同的路子都趟了一遍,还顺手记下了跨域和刷新 404 这两个高频坑点。它适合三类人:第一次把若依项目往生产环境搬的新手、接手了别人半成品项目要补部署文档的中间层、以及需要在没有 Nginx 的内网 Windows 机器上跑 Demo 的开发者。读完之后你至少能判断:手上这台服务器该走哪条路、jar 和 war 的差别在哪、nginx.conf里那两段 location 少一行会出什么事。
2. 打包:mvn clean package 与 npm run build:prod 的产物核对
部署出问题,一半以上不是服务器配错,是包本身就打错了。我见过太多人把target目录整个压缩上传,或者把前端源码目录当成 dist 传上去,然后在服务器上排查半天。这一章只干一件事:把两个包打对,并且在上传之前就知道产物长什么样、放在哪。
2.1 后端 jar:pom 里 packaging 一行决定产物形态
若依是多模块结构,真正能跑的是ruoyi-admin这个启动模块,其余ruoyi-common、ruoyi-framework、ruoyi-system都是被依赖的库。所以打包命令必须在根目录执行,产出的 jar 在ruoyi-admin/target/下,而不是根目录的target。
# 在项目根目录执行,跳过测试类编译与执行 mvn clean package -Dmaven.test.skip=true # 打包完成后确认产物 ls -lh ruoyi-admin/target/*.jar # 期望看到类似 ruoyi-admin.jar 的文件,体积通常几十 MB-Dmaven.test.skip=true和-DskipTests不是一回事:前者连测试代码都不编译,后者只跳过执行。服务器上没有测试数据库、没有单测依赖的环境下,用前者更省事,能避免因为src/test里连了本地 MySQL 而打包失败。
若依的 pom 里通常带dev/prod两个 profile,控制日志级别和配置文件激活。我一般会显式指定:
mvn clean package -P prod -Dmaven.test.skip=true-P prod会激活application-prod.yml相关的资源过滤,日志输出到文件而不是控制台。如果你不指定,打出来的包里激活的可能是 dev 配置,日志级别是 DEBUG,上线后磁盘很快被日志写满——这个坑不显眼但很致命。
提示:打包前先确认
application.yml里的spring.profiles.active,以及数据库、Redis 的连接地址是不是要走外部配置。若依支持通过--spring.profiles.active=prod在启动时覆盖,比改配置文件再打包更灵活。
2.2 前端 dist:publicPath 与那个被去掉的点
前端打包命令是npm run build:prod,后面的--report是可选参数,会额外生成一个report.html用于分析依赖体积,生产部署用不上但排查「包为什么 8MB」时很好用。
# 前端项目根目录执行 npm install npm run build:prod --report # 产物目录 ls -lh dist/ # 期望看到 index.html、static/ 目录真正的坑在vue.config.js。默认配置里publicPath常见写法是'/',但有些模板会写成'./'——多了一个点,代表相对路径。相对路径在 history 路由模式下会出事:访问/system/user这种二级路由时,浏览器会按「当前目录」去解析./static/js/app.js,实际请求变成/system/static/js/app.js,服务器上没有这个文件,页面直接白屏。
// vue.config.js module.exports = { // 生产环境必须用绝对路径 '/',不能是 './' publicPath: process.env.NODE_ENV === 'production' ? '/' : '/', outputDir: 'dist', assetsDir: 'static', // 路由模式为 history 时必配,否则刷新 404 // 这一项由 Nginx 的 try_files 兜底,前端不处理 }部署文档里那句「去掉 / 之前的 .」说的就是这件事。很多人第一次部署成功,后来改了菜单重新打包又出问题,本质是某次合并代码把publicPath改回了'./'。这类问题排查起来很玄学,因为构建不报错、访问首页也正常,只有深层路由才炸。
另一个高频问题是 Node 版本。若依前端依赖sass-loader/node-sass,Node 16 以上版本很容易在npm install阶段报Node Sass does not yet support your current environment。常见做法是用 nvm 锁到 Node 14 或 16,或者把依赖切到sass(dart-sass)版本。别在生产服务器上折腾编译工具链,本地打好包传 dist 就行。
2.3 上传目录约定:先定路径,再谈配置
打好的两个包上传到服务器,路径最好提前约定死,后面所有配置都围绕这两个路径写。我一般用这套:
| 产物 | 服务器路径 | 说明 |
|---|---|---|
| 后端 jar | /opt/app/ruoyi-admin.jar | 独立目录,方便日志和重启脚本 |
| 前端 dist | /usr/share/nginx/html/ | Nginx 默认站点根目录,或自定义路径 |
| 后端日志 | /opt/app/msg.log | nohup 输出重定向文件 |
| Nginx 配置 | /etc/nginx/conf.d/ruoyi.conf | 不直接改主配置,便于回滚 |
# 上传示例 scp ruoyi-admin/target/ruoyi-admin.jar root@server:/opt/app/ scp -r dist/* root@server:/usr/share/nginx/html/用scp -r dist/*而不是scp -r dist,差别在于前者把 dist 里的内容铺到目标目录,后者会多套一层dist/目录,导致 Nginx 的root指向和实际文件位置差一级——访问首页直接 403 或 404。这个细节看着小,实际排查起来要翻 Nginx 的error.log才能定位。
3. Linux + Nginx:两段 location 与 nohup 启动的落点
Linux 这条路是若依官方最推荐的部署方式,结构清晰:Nginx 扛静态资源和反向代理,jar 包跑在 8080,Redis 存 token 和缓存。看起来只有三步,但每一步都有能让你卡两小时的细节。这一章按「依赖先起、后端再起、Nginx 最后起」的顺序推进,因为倒过来做,你的错误日志会互相干扰,根本分不清是谁的问题。
3.1 Redis 先起来,别让后端启动就报连接拒绝
若依的登录态、验证码、字典缓存都走 Redis,后端启动时会尝试建立连接。Redis 没起来,Spring Boot 可能在启动阶段就抛RedisConnectionFailureException,或者起来之后所有登录请求 500。
# CentOS / RHEL 系 yum install -y redis systemctl enable redis systemctl start redis # 验证 redis-cli ping # 期望返回 PONG如果是 Ubuntu/Debian,包名是redis-server。装完之后必须检查两件事:bind配置和protected-mode。默认bind 127.0.0.1只允许本机访问,这在「后端和 Redis 同机」的场景下是对的,不要为了图省事改成0.0.0.0且关掉保护模式——那是把自己家的门敞开。
# 确认监听端口 ss -lntp | grep 6379 # 期望看到 127.0.0.1:6379后端application.yml里对应配置:
spring: redis: host: 127.0.0.1 port: 6379 database: 0 password: # 无密码留空 timeout: 10sdatabase这一项容易被忽略。同一台机器上如果跑了多个项目,都用 db 0 会互相污染缓存,出现「登录了但一直提示未授权」的诡异现象。我的习惯是每个项目分配独立 db 编号,并在部署文档里写死。
3.2 后端 nohup 启动与日志落点
java -jar前台启动,一按 Ctrl+C 服务就停,SSH 断开连接也会挂。所以生产环境必须后台启动。
cd /opt/app # 后台启动,标准输出和错误都重定向到 msg.log nohup java -jar ruoyi-admin.jar > msg.log 2>&1 & # 记录进程号,方便后续重启 echo $! > app.pid # 确认启动成功 sleep 10 tail -n 50 msg.log这段命令有三个点要讲清楚。nohup让进程忽略挂断信号,SSH 断开不会杀掉它。> msg.log把标准输出重定向到文件,2>&1把标准错误也并进去——只写前者的话,异常堆栈会丢,出问题时日志里只有正常输出,等于黑匣子没录到关键画面。末尾的&才是真正让命令进后台,少了它前面的重定向都白搭。
msg.log落在执行命令时的当前目录,不是 jar 所在目录,也不是/opt/app以外的任何地方。所以先cd再执行,别在/root下随手一敲,回头找不到日志。
启动参数上,我一般还会加内存限制,避免 JVM 按物理内存比例吃掉整台机器:
nohup java -Xms512m -Xmx1024m -jar ruoyi-admin.jar \ --spring.profiles.active=prod > msg.log 2>&1 &-Xms是初始堆,-Xmx是最大堆。小内存机器(2G)上如果不限制,JVM 默认最大堆可能到 1/4 物理内存,再叠上 MySQL 和 Redis,很容易触发 OOM Killer。这个参数没有标准答案,按机器规格调,但一定要显式写。
3.3 nginx.conf 的 root、location /prod-api 与 try_files
Nginx 配置是整条链路的中枢,配置错一个斜杠,前端能打开但接口全 404。若依前端打包时通过.env.production里的VUE_APP_BASE_API = '/prod-api'给所有请求加了统一前缀,Nginx 要做的就是把这个前缀剥掉,转发给后端。
server { listen 80; server_name _; # 前端静态资源根目录,指向 dist 内容所在位置 root /usr/share/nginx/html; index index.html; # 关键一:history 路由兜底 location / { try_files $uri $uri/ /index.html; } # 关键二:接口反向代理 location /prod-api/ { proxy_set_header Host $http_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_pass http://127.0.0.1:8080/; proxy_read_timeout 300s; } }try_files $uri $uri/ /index.html是 history 路由能刷新的根本原因。用户直接访问/system/user时,磁盘上并没有这个文件,前两个参数都匹配失败,最后回退到index.html,由前端路由接管。少这一行,刷新页面就是 404。
proxy_pass结尾那个斜杠是全文最容易翻车的地方,值得单独说:
| 写法 | 请求/prod-api/login实际转发到 | 结果 |
|---|---|---|
proxy_pass http://127.0.0.1:8080/; | http://127.0.0.1:8080/login | 正确,前缀被剥掉 |
proxy_pass http://127.0.0.1:8080; | http://127.0.0.1:8080/prod-api/login | 后端无此路径,404 |
规则是:proxy_pass后面带 URI(哪怕只是一个/),Nginx 就用它替换掉 location 匹配的部分;不带 URI,则原样透传完整路径。若依后端默认没有/prod-api这个 context-path,所以必须带斜杠。
改完配置不要急着重启,先测:
nginx -t # 输出 syntax is ok / test is successful 才继续 systemctl reload nginx用reload而不是restart,前者平滑加载,不断开现有连接。生产环境上restart会造成短暂 502。
3.4 从 ip 到登录接口的四步验证
配置写完,别急着开浏览器。按这四步走,能把问题定位到具体环节:
# 第一步:后端进程在不在 ps -ef | grep ruoyi-admin | grep -v grep # 第二步:后端端口通不通(本机自测,绕过 Nginx) curl -i http://127.0.0.1:8080/captchaImage # 第三步:Nginx 转发通不通(走代理前缀) curl -i http://127.0.0.1/prod-api/captchaImage # 第四步:首页静态资源 curl -I http://127.0.0.1/index.html第二步返回 200 且带 JSON,说明后端没问题;第三步失败但第二步成功,问题在 Nginx 的proxy_pass或防火墙;第四步 404,说明root指错了或者 dist 没铺对。这四步的价值在于把「前后端分离部署」这个大黑盒拆成三段,每段单独验证,比对着浏览器 F12 猜要快得多。
4. Windows + Tomcat:war 改名 prod-api 与 404 兜底
有些内网环境就是没有 Linux,也不允许装 Nginx,只能在一台 Windows 机器上用 Tomcat 跑。这条路比 Linux 麻烦,因为 Tomcat 既是 Servlet 容器又要兼任静态资源服务器,配置项分散在pom.xml、server.xml、web.xml三个地方,少配一处就是一个特定的故障现象。这一章按「改包型 → 定上下文 → 兜 404 → 对齐前缀」的顺序讲。
4.1 pom 改 war 与 finalName
Spring Boot 默认打 jar,要部署到外部 Tomcat 必须改成 war,并且排除内置 Tomcat 的干扰。
<!-- ruoyi-admin/pom.xml --> <packaging>war</packaging> <build> <finalName>prod-api</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <!-- 关键:不指定 mainClass 时,war 包需要这一步排除内置容器 --> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <!-- 关键:provided,运行期由外部 Tomcat 提供 --> <scope>provided</scope> </dependency> </dependencies><finalName>prod-api</finalName>决定了打出来的 war 包名。Tomcat 部署时用 war 文件名作为 context path,所以prod-api.war部署后访问前缀就是/prod-api,正好和前端.env.production里的VUE_APP_BASE_API对上,前端代码一行不用改。
如果不设finalName,打出来是ruoyi-admin.war,context path 变成/ruoyi-admin,前端所有请求 404。这时候要么改 war 名,要么改前端配置重新打包——当然是前者便宜。
spring-boot-starter-tomcat的provided作用域也不能忘。不排除的话,war 里会带着内置 Tomcat 的类,和外部 Tomcat 冲突,启动时可能报ClassNotFoundException或者端口占用。这是 Spring Boot 部署外部容器的标准动作,但若依原始模板是 jar 打包,改的时候很容易漏。
4.2 server.xml 的 Context、docBase 与端口
war 包扔进webapps目录,Tomcat 会自动解压部署,这一步不用配。真正要配的是前端 dist 的访问路径。
<!-- conf/server.xml --> <!-- 1. 改端口,避免和已有服务冲突 --> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> <!-- 2. 在 Host 节点内添加 Context,把根路径指向前端 dist --> <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Context path="/" docBase="D:/tomcat/webapps/dist" reloadable="true" crossContext="true" /> </Host>path="/"表示根路径访问,用户输入ip:8080直接到前端。docBase是 dist 内容的绝对路径,也可以写相对于webapps的相对路径(比如直接写dist)。reloadable="true"会在 class 文件变化时重载,开发期方便,生产环境建议改false省资源。
这里有个容易忽略的点:path="/"和prod-api.war会共存。war 部署后占用/prod-api,Context 占用/,两者不冲突,正好对应「前端走根路径、接口走 /prod-api」的结构。
4.3 WEB-INF/web.xml 把 404 打回 index.html
Tomcat 没有 Nginx 的try_files,前端 history 路由刷新会直接 404。解决办法是在 dist 目录下建WEB-INF/web.xml,把 404 错误页指向index.html。
# dist 根目录下创建 mkdir -p WEB-INF<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1" metadata-complete="true"> <display-name>Router for Tomcat</display-name> <error-page> <error-code>404</error-code> <location>/index.html</location> </error-page> </web-app>这段配置的作用等价于 Nginx 的try_files:任何找不到的路径都返回index.html,由 Vue Router 接管。metadata-complete="true"告诉 Tomcat 不用扫描注解,启动快一点。
放的位置必须是dist/WEB-INF/web.xml,也就是和index.html同级目录下的WEB-INF文件夹。放到 tomcat 的conf目录下是无效的,那是全局配置,作用域不一样。这个细节部署文档里没强调,但放错位置的人不少。
4.4 前端请求前缀与 context path 对齐
Tomcat 方案下,前端.env.production的VUE_APP_BASE_API必须等于后端 war 的 context path,也就是/prod-api。如果之前为了 Linux+Nginx 部署改成了别的值,这里要重新打包。
# .env.production # 与 tomcat webapps 下 war 包名保持一致 VUE_APP_BASE_API = '/prod-api'改完必须重新npm run build:prod,因为环境变量是在构建期注入的,改完不重新打包等于没改。我见过有人在服务器上直接编辑 dist 里的 js 文件找这个字符串替换——能生效,但下次打包就丢了,属于给自己埋雷。
启动 Tomcat 后验证顺序和 Linux 类似:先ip:8080/prod-api/captchaImage确认后端,再ip:8080/确认前端,最后在浏览器里实际登录一次。
5. 部署避坑排查:五条现象、原因与解法
前面几章讲的是「怎么配」,这一章讲「配完还是不对怎么办」。下面五条是我在不同环境里反复遇到的,每条都按现象、原因、解决三步写,你可以当成一个排查索引,对号入座。
5.1 首页能打开,点菜单报 404 或白屏
现象:浏览器输入 IP 能正常看到登录页,登录进去之后点左侧菜单,右侧空白,F12 里看到若干 js/css 请求 404,路径类似/system/static/js/chunk-xxx.js。
原因:publicPath被写成了'./',浏览器按当前路由路径解析静态资源。访问/system/user时,相对路径./static/...被解析成/system/static/...,服务器上没有这个文件。
解决:把vue.config.js里的publicPath改成'/',重新打包上传。验证方法是打包后打开dist/index.html,看里面引用的资源路径是不是以/static/开头,是就对了。
5.2 刷新页面 404,但从首页点进去正常
现象:在系统里点来点去都没问题,一按 F5 刷新当前页面就 404,Nginx 的error.log里能看到open() "/usr/share/nginx/html/system/user" failed。
原因:history 路由模式下,前端路由是浏览器端行为,服务器上并不存在/system/user这个物理路径。没有兜底规则时,Nginx 老老实实去磁盘找文件,当然找不到。
解决:Nginx 加try_files $uri $uri/ /index.html;;Tomcat 方案加WEB-INF/web.xml的 404 error-page。两个方案本质是同一件事:把所有未匹配路径交还给index.html。改完记得nginx -t && nginx -s reload。
5.3 登录接口通了,但登录后跳回登录页
现象:/prod-api/login返回 200 且带 token,前端也存了 token,但页面一跳转就被踢回登录页,Network 里后续请求全是 401。
原因:多半是 Redis 里存的 token 和请求头里的对不上。常见触发点是后端重启后 Redis 数据被清、或者多个环境共用同一个 Redis db 导致 key 覆盖,也可能是application.yml里的token.secret在两次打包之间变了(有些模板会随机生成)。
解决:先redis-cli keys '*'看有没有业务 key;再确认token.secret是否固定写在配置文件里;最后检查是不是同一台 Redis 被多个环境共用。若依的 token 是以 JWT 形式下发的,secret 变了等于所有旧 token 失效,这个排查方向很多人想不到。
5.4 后端起来了,Nginx 转发却报 502
现象:curl http://127.0.0.1:8080/captchaImage正常返回,但curl http://127.0.0.1/prod-api/captchaImage返回 502 Bad Gateway。
原因:502 的含义是 Nginx 连不上上游。可能是proxy_pass的地址写错(比如写了公网 IP 但后端只监听 127.0.0.1)、端口不对、或者 SELinux 阻止了 Nginx 发起网络连接。
解决:先看 Nginx 错误日志tail -f /var/log/nginx/error.log,里面会明确写connect() failed (111: Connection refused)。确认proxy_pass指向127.0.0.1:8080;如果后端application.yml里配了server.address,检查是不是绑死了某个网卡。SELinux 环境下执行setsebool -P httpd_can_network_connect 1。
5.5 改了配置重启,行为却没变
现象:明明改了nginx.conf或者重新传了 jar,重启之后表现和之前一模一样,日志里也看不到新配置生效的痕迹。
原因:三种可能。一是 Nginx 有多个配置文件,改的那个没被include进去;二是 jar 包启动时加载的是外部配置文件(config/application.yml优先级高于包内),改包内配置无效;三是进程没真正杀掉,旧进程还在跑。
解决:nginx -T可以打印最终生效的完整配置,比看单个文件靠谱;Spring Boot 的外部配置优先级从高到低是命令行参数 > 当前目录/config/ > 当前目录/ > classpath:/config/ > classpath:/,确认没有外部文件覆盖;用ps -ef | grep java确认只有一个进程,重启脚本里加上kill -9兜底。
注意:
kill -9是最后手段,会跳过 Spring 的优雅关闭,连接池、定时任务都不会正常收尾。正常重启应该先kill(发 SIGTERM),等 10 秒还没退再-9。
6. 第三方 API 跨域:CORS、Nginx 反代与 devServer proxy 的取舍
调用第三方地图、短信、OSS 这类开放接口时,浏览器控制台报has been blocked by CORS policy,这是部署完成后最常遇到的一类问题。三条路各有适用场景,选错会让后面维护很痛苦。
| 方案 | 生效范围 | 适用场景 | 主要代价 |
|---|---|---|---|
| 后端全局 CORS | 生产 + 开发 | 自己的前后端分离项目 | 配置不当会放开所有来源 |
| Nginx 反向代理 | 仅生产 | 第三方接口不支持 CORS,或需要隐藏 key | 多一层转发,需要维护 location |
| devServer proxy | 仅开发 | 本地联调 | 打包后失效,不能带到生产 |
后端全局 CORS 是最省事的做法,Spring Boot 里加一个配置类即可:
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") // Spring Boot 2.4+ 必须用 allowedOriginPatterns // allowedOrigins("*") 与 allowCredentials(true) 不能共存 .allowedOriginPatterns("http://your-domain") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .allowCredentials(true) .maxAge(3600); } }allowCredentials(true)是为了让浏览器带上 Cookie 和自定义的 Authorization 头,若依的 JWT 就在请求头里。这一项为 true 时,allowedOrigins不能写"*",必须写具体域名或者用allowedOriginPatterns,否则启动直接报错。maxAge(3600)让浏览器缓存预检结果一小时,减少 OPTIONS 请求。
但要注意:CORS 只对「浏览器发起的跨域请求」有意义。如果第三方接口本身不支持跨域,你在自己后端加 CORS 是没用的——浏览器拦的是第三方域名的响应。这时候正确做法是在 Nginx 里做一层反向代理,让浏览器以为请求的是同源地址:
# 把 /map-api/ 前缀的请求转发到第三方服务 location /map-api/ { proxy_pass https://third-party-api.example.com/; proxy_set_header Host third-party-api.example.com; proxy_ssl_server_name on; # 第三方 key 放在这里,前端不再暴露 proxy_set_header X-Api-Key "your-key"; }proxy_ssl_server_name on在代理 HTTPS 上游且对方用了 SNI 时是必须的,不加可能握手失败。把 key 放在 Nginx 层还有个额外好处:前端打包产物里搜不到密钥,避免泄露。
至于devServer.proxy,它只在npm run dev时生效,是本地联调用的。很多人本地调通了就以为上线也没问题,结果一打包部署全是跨域报错——因为 proxy 配置根本不会进 dist。
说个我自己的教训:早年图省事,在 CORS 配置里写了allowedOriginPatterns("*")加allowCredentials(true),本地测试一切正常,上线后安全扫描直接标红。从那以后我每次配 CORS,都强制把来源写成白名单常量,哪怕只有一条,也不留通配符。第三方接口的代理同理,能收窄到具体路径就别用location /。这套习惯多花十分钟,省的是后面被人找上门的麻烦。希望帮到你。
本文还有配套的精品资源,点击获取