简介:基于Java的宠物领养系统毕业设计资源包,面向计算机相关专业学生与Java开发者,提供一套已通过验收、可稳定运行的完整项目方案。资源包含源代码、数据库脚本、部署文档及演示录像,可帮助读者快速搭建系统环境,并理解从需求分析到编码实现的完整流程。
包内共44个文件,主要包括Java源代码压缩包、SQL数据库脚本、PPT演示文稿、mp4操作演示与部署视频,以及大量png页面截图和jpg设计图(如系统流程图、E-R图等),整体大小约176.67MB,目录结构清晰,适合按模块查阅学习。
目前该项目已有250位用户学习下载。通过这份资源,读者可以获得宠物领养系统的完整实现细节,覆盖用户注册登录、宠物信息展示与检索、领养申请与审核、管理员后台管理、评论互动、志愿者申请等核心业务模块;同时,部署视频与PPT资料能帮助快速复现项目、梳理答辩思路,是毕业设计、课程设计及Java实战练习的优质参考。
1. 基于Java的宠物领养系统设计与实现:这份压缩包能帮你省掉多少开发量?
毕业设计季遇到“基于Java的宠物领养系统设计与实现”这类题目的同学,大概率都搜过源码。一个人从零搭Spring、写宠物发布、做领养审核,再把图片上传和状态流转调顺,没两三周下不来。而这个压缩包把源代码、数据库脚本、部署文档、演示录像四样东西一起打包,目的很直接:让你不用重新造轮子,拿到手能在本地把系统跑起来。实际用起来的情况是:下载了这份资源的人,一半卡在环境配置,另一半卡在数据库导不进,能顺利跑通并且把代码逻辑讲清楚的人反而最少。这篇笔记就按“先认结构、再跑环境、后改代码、最后答辩”的顺序,把这条落地路径完整走一遍。
2. 解压后别急着启动:先搞清项目结构与环境版本怎么选
2.1 压缩包里的五部分:先分清源码、SQL、文档、录像各自干什么
拿到压缩包,先别急着解压双击,按标题里的描述,这份资源里面至少有四类内容:源代码工程、数据库脚本、部署文档、演示录像。我的习惯是解压后先建一个文件夹,按这四个维度把内容归类,再开始动手。
源代码部分通常只有一个工程目录。先看根目录下有没有pom.xml,有就说明是 Maven 工程,导入 IDE 时要用“导入 Maven 项目”的入口,而不是当成普通文件夹打开。如果没有pom.xml,但存在.classpath和.project,那是早期 Eclipse 工程,导入方式和 Maven 工程完全不同,连 lib 目录下的 jar 包都得手动引入,这一步判断错了,后面全乱。
SQL 脚本一般是一个.sql文件,也可能叫 init.sql 或 pet_adoption.sql,注意看脚本里有几类语句:建库语句、建表语句、插入的初始数据。有些脚本里还带着DROP TABLE IF EXISTS开头,这类脚本是可以重复导入的,但要注意它可能会清掉你之前的数据。
部署文档是 pdf、doc 或 Markdown 格式,里面写的启动步骤往往对应作者当时的机器环境,端口号、数据库密码、JDK 版本都可能和你的环境不一样,所以部署文档只能当作参考底稿。演示录像则是 mp4 格式,是作者跑系统时录的屏幕视频,我建议把录像完整看一遍再动代码,它能告诉你这套系统完成度有多高:页面长什么样、哪些功能点真的有实现,哪些只是摆了个按钮。
提示:解压后先看目录,再读文档,最后开 IDE。这一步的 10 分钟能避免后面两小时的无效操作。
2.2 JDK、MySQL、Tomcat 版本选型:照着这套组合搭环境最稳
版本选型是跑通老项目时最容易翻车的一环。这类基于 Java 的毕设项目,最常见的代码风格是 SSM(Spring + Spring MVC + MyBatis)或者 Spring Boot + MyBatis,无论哪种,JDK 1.8 都是最稳的基线。很多老代码里用了 JDK 8 的 lambda 表达式,也有不少用了过期的 API,你直接上 JDK 17 或更高版本,编译时会出现一堆不兼容错误,处理成本远高于装一个 JDK 1.8。
数据库固定用 MySQL,版本选 5.7 或 8.0 都行,但这两个版本对驱动的依赖不同,后面第 5 章会专门讲连接失败的坑。Tomcat 建议 8.5 或 9,如果项目里用到的是 javax.servlet 包,Tomcat 10 是 jakarta.servlet,直接跑会报 ClassNotFoundException。记住这条组合:JDK 8 + MySQL 5.7/8.0 + Tomcat 8.5/9 + Maven 3.6,能覆盖九成以上此类项目。
Maven 环境也要提前确认好。环境变量配完后,在命令行执行mvn -v,能看到版本信息说明配置成功。多数情况下,项目里的 pom.xml 会从中央仓库拉依赖,首次构建时耗时较长是正常的。如果你在公司内网或校园网,可能需要改镜像地址,最常见的做法是用阿里云镜像替换 central 仓库地址,这一步能省下大量等待时间。
2.3 改 jdbc.properties 三处配置:让项目连上你本地的数据库
跑通系统的第一步不是启动项目,而是把数据库连接配置改成你自己的。这类项目里,数据库连接信息一般集中在src/main/resources/jdbc.properties或application.yml中。打开后你大概率会看到这样的内容:
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/pet_adoption?useUnicode=true&characterEncoding=utf8 jdbc.username=root jdbc.password=123456需要改的地方只有三处:jdbc.url里的数据库名pet_adoption换成你的 SQL 脚本实际创建的库名;jdbc.username换成你的 MySQL 用户名;jdbc.password换成你的 MySQL 密码。如果你用的是 MySQL 5.7,驱动类和 URL 保持不变就能跑;如果换成 MySQL 8.0,驱动类要改成com.mysql.cj.jdbc.Driver,URL 末尾还需要追加serverTimezone=Asia/Shanghai,否则会报时区错误。
改完配置后,先在命令行确认 MySQL 服务已启动。Windows 下用net start mysql查看服务状态,或者打开服务管理器确认 mysql 服务处于“正在运行”。很多第一次跑项目的人,代码改了半天发现数据库服务都没启动,这个基础动作最容易被忽略。接着再打开 IDE,等 Maven 把依赖下载完,启动 Tomcat,看到控制台输出Started或Tomcat started on port(s): 8080才说明应用真正起来了。
3. 数据库设计与脚本导入:五张核心表如何撑起领养全流程
3.1 宠物、用户、申请三张主表:字段设计与类型选择
做这类系统,数据库设计决定了整个业务能不能闭环。以最常见的需求为基准,核心表至少要有用户表、宠物表、领养申请表、公告表、管理员表这五张。用户表和管理员表负责角色区分,宠物表存储待领养的动物信息,领养申请表关联用户与宠物,公告表做站内通知。五张表之间的关系很清晰:一个用户可以提交多条领养申请,一只宠物也会被多个用户申请,所以申请表的定位就是关联表加审核字段。
宠物表的字段设计最值得细看,它直接决定功能能做多细。我一般建议至少包含这些字段:
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | int(11) | 主键,自增 |
| name | varchar(30) | 宠物名称 |
| species | varchar(20) | 猫 / 狗 / 其他 |
| breed | varchar(50) | 品种 |
| age | int(4) | 年龄,按年存 |
| gender | tinyint(1) | 0 表示公,1 表示母 |
| health_status | varchar(255) | 健康描述,如已驱虫、已打疫苗 |
| image_url | varchar(255) | 宠物图片路径 |
| status | tinyint(1) | 0 待领养,1 已申请,2 已领养 |
| description | text | 详细描述 |
| create_time | datetime | 发布时间 |
注意status字段用的是tinyint(1)而不是字符串。毕设里很多人图省事把状态直接存中文,比如“待领养”“已领养”,这样做的后果是后期做状态统计时要写一堆模糊匹配,而且代码里到处是魔法字符串,改一个状态名要全局替换。用数字状态值,配合代码里的枚举或常量类,改起来只动一处。
申请表则要关联三个核心字段:pet_id、user_id、apply_status。其中apply_status建议用 0 待审核、1 已通过、2 已驳回。申请表里还要留apply_reason和phone两个字段,前者是申请理由,后者是联系方式,不然后端拿不到申请人的真实信息,审核逻辑就断了一环。
3.2 导入 SQL 脚本:字符集与时区两个参数必须改
SQL 脚本导入看似简单,但踩过坑的人都知道,字符集和时区不理顺,后面全是对不上盘的乱码。标准做法是先建库,再导入。
用命令行执行时,分两步走:
mysql -u root -p -e "CREATE DATABASE pet_adoption DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;" mysql -u root -p --default-character-set=utf8mb4 pet_adoption < pet_adoption.sql第一步先建数据库,并明确指定使用utf8mb4字符集。这里有个大众容易忽略的点:utf8mb4是 MySQL 8.0 的默认字符集,但在 MySQL 5.7 里不是,如果建库时不显式声明,脚本里的中文默认用utf8存,遇到 emoji 表情之类的四个字节字符,后期写入时会报Incorrect string value错误。所以无论你的 MySQL 是哪个版本,建库时都把DEFAULT CHARACTER SET utf8mb4加上是最保险的。
第二步导入时用--default-character-set=utf8mb4参数,是让命令行客户端与服务器之间的连接也使用 utf8mb4 编码。如果这一步不加,客户端可能按latin1或gbk发送字符,导致表结构里的中文注释和初始数据全变问号。导入完成后,你可以用下面这条命令快速验证数据是否正常:
SELECT pet_id, name, species FROM pet LIMIT 5;如果你的结果里中文显示正常,说明字符集链路是通的;如果还是乱码,问题就出在建库语句或连接层。还有一个容易被忽略的点:脚本里如果有CREATE DATABASE语句,导入时就不要再用-e建库,直接指定库名导入即可,避免重复建库报错。
3.3 状态字段的流转逻辑:待审核、已通过、已领养怎么串起来
领养系统的核心业务逻辑不是增删改查,而是状态流转,尤其是宠物状态与申请状态的联动。整个流程可以这样理解:管理员先在后台发布一只宠物,宠物初始status=0(待领养);用户在前台看到后提交领养申请,申请表产生一条记录且apply_status=0(待审核)。管理员审核通过时,不仅要改申请表的apply_status=1,还要同步把对应宠物的status改成 1(已申请)或直接改成 2(已领养)。
我在项目中看到过一种常见设计:宠物表的状态只分“待领养”和“已领养”,申请通过后直接把宠物状态置为 2。这种简化可行,但少了中间态“已申请”的语义,当多个人同时申请同一只宠物时,管理员审核完第一个通过,剩下几个还没审核的申请就容易产生误判。所以更稳妥的状态机是:
-- 宠物状态:0=待领养,1=已申请,2=已领养 -- 申请状态:0=待审核,1=已通过,2=已驳回 -- 管理员通过一条申请时,同时更新两张表 UPDATE apply SET apply_status = 1 WHERE id = #{applyId} AND apply_status = 0; UPDATE pet SET status = 1 WHERE id = #{petId} AND status = 0;注意这里两个 UPDATE 都带上了状态条件,AND apply_status = 0和AND status = 0是防止并发操作的。如果两个人几乎同时提交申请,管理员又同时点了两个通过,不带条件的更新可能会让同一只宠物被领养两次。这种并发场景在答辩时不一定会被问到,但如果面试官或评委有经验,一定会盯着这个细节问。
状态流转的另一种实现策略是直接在申请通过时把宠物状态改成 2(已领养),不再经过“已申请”这一步。如果你的需求明确是“审核通过即领养完成”,用这条策略代码更少,但要在宠物详情页加上“该宠物已被领养,去看看其他小伙伴吧”之类的提示,避免用户看到已领养宠物却还能提交申请。
4. 后端代码看懂三处就能改:发布、上传、审核的核心流程
4.1 Controller-Service-Mapper:一次列表查询从 URL 到数据库的完整路径
大部分刚接触这套代码的同学,打开工程后面对几十个 Java 文件会发懵,不知道该从哪里下手。我的建议是从一次完整请求的链路开始看。比如宠物列表页,浏览器请求/pet/list,代码处理顺序是:Controller 接收请求并取参数,Service 写业务逻辑或调用事务,Mapper 对着数据库执行 SQL,最后返回视图名,由视图解析器找到对应 JSP 或 Thymeleaf 模板渲染页面。
Controller 层的代码通常长这样:
@Controller @RequestMapping("/pet") public class PetController { @Autowired private PetService petService; @RequestMapping("/list") public String list(Model model, @RequestParam(defaultValue = "1") int pageNum) { // 调用 service 层分页查询,pageNum 是当前页码 PageInfo<Pet> pageInfo = petService.queryPetPage(pageNum, 6); model.addAttribute("pageInfo", pageInfo); return "pet/list"; } }这段代码里,Model model是 Spring MVC 用来携带数据到视图的容器,@RequestParam(defaultValue = "1")表示前端不传页码时默认取第 1 页,return "pet/list"返回的是视图名,最终会映射到 webapp 目录下的/WEB-INF/views/pet/list.jsp或/templates/pet/list.html。如果你的项目中视图文件找不到,大概率是返回的字符串和目录结构对不上。
Service 层的作用是承载业务逻辑,比如分页条件的组装、状态判断、事务控制。在列表查询这个场景里,Service 层通常只做一层透传,把 Mapper 的查询结果包进PageInfo返回。真正值得研究的是领养申请这类多表联动逻辑,因为那里才会体现出 Service 层存在的意义。如果只写增删改查,Service 层完全可以被 Controller 替代,但代码就会变得越来越难维护,这也是为什么面试时会反复问三层架构的意义。
4.2 宠物发布与图片上传:本地路径配置决定页面能不能出图
宠物发布是整个系统里功能最完整的模块,它涉及表单绑定、图片上传、数据落库三个环节。图片上传这块很典型,处理不好会出现“添加成功但页面不显示图片”这种令人抓狂的问题。常见的实现是用 Spring 的CommonsMultipartResolver做文件接收,代码里通过transferTo把上传文件写入磁盘。
这类老项目中,图片存储路径有几种写法。一种是把图片保存到项目运行目录的/upload文件夹下,用相对路径;另一种是保存到 D 盘或 Linux 服务器上的某个绝对路径。直接影响页面能否显示的关键配置在这里:
# application.properties 或 spring-mvc.xml 中的配置 spring.servlet.multipart.max-file-size=5MB spring.servlet.multipart.max-request-size=10MB file.upload-dir=/data/pet_adoption/uploadspring.servlet.multipart.max-file-size限制单张图片大小,max-request-size限制一次请求的总大小,这两个参数在毕设项目里经常被忽略,一旦传了稍大一点的图片就会报MaxUploadSizeExceededException。file.upload-dir是自定义的存储路径,推荐设置成绝对路径。上传代码里拿到原始文件名后,一般要用 UUID 重命名,防止两张图同名互相覆盖。
避坑的关键在于:页面显示图片用的是<img src="${pet.imageUrl}">,这个 imageUrl 存的值如果是/upload/xxx.jpg,那请求会被 Tomcat 交给当前工程去找/upload目录。如果你把文件写到 D 盘某个目录,而 web 应用里没有对应的映射关系,图片一定 404。正确的做法是给静态资源加一个虚拟路径映射,把/upload/**映射到磁盘实际目录,这样页面的请求路径和磁盘存储路径脱钩,不管是本地 Windows 还是部署到 Linux 都能正常出图。
4.3 领养审核的状态更新:@Transactional 保证两个表同步改
审核领养申请是系统里唯一涉及双表联动的写操作,也是最具代表性的代码片段。管理员点击“通过”按钮,后台要同时更新宠物状态和申请状态,这两次更新必须保证原子性:要么一起成功,要么一起失败。如果只改申请状态,宠物还是“待领养”,下一个用户申请时依然能看到这只宠物;如果只改宠物状态,申请记录还挂在“待审核”,管理员看到这个列表会无所适从。
典型的 Service 层代码是这样:
@Service public class ApplyServiceImpl implements ApplyService { @Autowired private ApplyMapper applyMapper; @Autowired private PetMapper petMapper; @Transactional // 开启事务,保证两个 update 同时提交或同时回滚 public void approveApply(Integer applyId, Integer petId) { // 第一步:把申请状态改成已通过 int applyRows = applyMapper.updateStatus(applyId, 1); if (applyRows == 0) { throw new RuntimeException("申请记录不存在或已被处理"); } // 第二步:把宠物状态改成已领养 int petRows = petMapper.updateStatus(petId, 2); if (petRows == 0) { throw new RuntimeException("宠物状态已变更,请刷新后重试"); } } }@Transactional注解是 Spring 声明式事务的关键。加上它之后,这两个 UPDATE 语句会放在同一个数据库事务里执行,任何一个失败都会触发回滚,另一个已经执行的更新也会撤销。这个注解背后是 Spring AOP 的代理机制,实现原理不需要深入,但你要知道它只对 public 方法生效,并且同类内部调用this.approveApply()会绕开代理,事务不生效。
这里还有一个业务细节值得展开:applyMapper.updateStatus(applyId, 1)返回的applyRows如果为 0,说明该申请已经被处理过,此时抛出异常让事务回滚,比直接往下走更安全。很多毕设代码忽略了这个检查,导致重复提交时宠物状态被二次修改,页面显示和数据库就产生了不一致。这一处判断,既是工程经验的体现,也是答辩时能讲出来的亮点。
5. 部署运行常见避坑:五条翻车现场与排查顺序
5.1 启动后访问 404:项目名或部署目录没对上
现象:Tomcat 正常启动,控制台没有报错,但浏览器访问http://localhost:8080/显示 Tomcat 默认首页,或者访问http://localhost:8080/pet/list直接 404。
原因:大多数情况下,项目没有部署到 Tomcat 的webapps目录下。IDE 启动时如果不配置 Deployment 的 Application context,Tomcat 不会自动加载你的工程;即使加载了,上下文路径(context path)也可能带了项目名,比如http://localhost:8080/pet_adoption_war_exploded/,和你预期的访问路径不一致。
解决:先看 Tomcat 启动日志里有没有Deploying web application archive这行记录,没有说明根本没部署。IDEA 中确认 Run Configuration 里的Deployment标签页已经将 artifact 添加进去,并把Application context改为/pet_adoption。如果你的部署文档里写的是http://localhost:8080/pet_adoption/login,那就把所有访问地址都带上项目名,而不是只用根路径。
5.2 导入 SQL 后中文乱码:字符集一路都要是 utf8mb4
现象:表结构和初始数据里的中文全部变成??,或者只有一部分是正常的,另一部分乱码。
原因:建库时没有指定字符集,MySQL 沿用了服务器默认字符集,可能是latin1。命令行的连接也默认按系统字符集传输,这种多重不确定叠加在一块,最常见的就是“建库字符集、客户端连接字符集、SQL 文件保存编码”三处不一致。
解决:先确认 SQL 文件的编码格式,用 Notepad++ 或 VS Code 打开,看状态栏显示的是 UTF-8 还是 GBK,如果文件本身是 GBK,导入前先转成 UTF-8。建库语句显式用DEFAULT CHARACTER SET utf8mb4。已经用错字符集建好的库,用ALTER DATABASE pet_adoption CHARACTER SET utf8mb4;改回来,但库里的旧数据可能已经是乱码,最省事的做法是删库重导。
5.3 MySQL 8 连接失败:驱动版本与 serverTimezone 没跟上
现象:启动项目时控制台报Communications link failure或The server time zone value '�й���ʱ��' is unrecognized。
原因:项目里的数据库驱动是 5.x 版本,而你的 MySQL 是 8.0。MySQL 8 默认认证插件是caching_sha2_password,老驱动无法兼容;同时 8.0 的时区处理更严格,URL 里不带serverTimezone参数就会报错。
解决:pom.xml 里把 mysql 驱动版本改成 8.0.x,同时把驱动类从com.mysql.jdbc.Driver换成com.mysql.cj.jdbc.Driver,URL 追加serverTimezone=Asia/Shanghai&useSSL=false。改完驱动后记得在 Maven 面板刷新依赖,不然 IDE 还是用旧 jar 包启动项目。
5.4 图片上传成功但页面不显示:相对路径在 Linux 上不成立
现象:本地 Windows 环境图片正常显示,把项目打成 war 包部署到云服务器后,上传图片成功,但所有图片请求都 404。
原因:本地开发时,上传目录被解析到 Tomcat 的临时目录或工程目录下,页面能正常访问;部署到 Linux 后,Tomcat 的临时目录每次重启会清理,写入的文件直接消失。如果代码里用的是request.getServletContext().getRealPath("/upload/"),返回的路径在 war 包环境下可能是空目录或者指向临时目录。
解决:把file.upload-dir改成 Linux 下的固定目录,例如/data/pet_adoption/upload,然后配置静态资源虚拟映射。Spring Boot 项目在application.yml里加spring.web.resources.static-locations,SSM 项目则在 spring-mvc.xml 里配<mvc:resources mapping="/upload/**" location="file:/data/pet_adoption/upload/"/>,让页面的/upload/**请求映射到磁盘真实路径。
5.5 演示录像和本地操作步调不一致:答辩前一定要自我复核
现象:看演示录像时作者操作得很顺,但自己按录像里的步骤跑一遍,发现某个页面路径不对,或者某个功能点击后没有反应。
原因:录像里的项目可能和压缩包里的源码不是同一版本。这类资源在流传过程中,经常存在“录像属于 V2 版本、代码修改后没重新录”的情况;或者录像用的数据库初始数据带有一条特定记录,而你自己导入的脚本里没这条数据,导致页面展示不同。
解决:不要拿录像直接当验收标准。先把录像完整看一遍,记下录像中出现的所有菜单名称和操作顺序,再对照自己跑起来的系统逐一核对。对不上的地方,以代码为准——查 Controller 里的 RequestMapping、查导航栏页面的菜单配置,把实际系统的操作路径重新写一份给自己。答辩演示时如果用的是本地实际运行效果,提前走三遍完整流程比背录像台词靠谱得多。
6. 把系统改成你自己的:换名换色、验证核心链路与演示技巧
6.1 三步完成个性化改造:全局替换、改 logo、调整种子数据
拿到手的代码不管是谁的,毕设要求都得让它看起来像自己的作品,这一步花两小时就能完成。第一步是全局替换系统名称和标题,用 IDE 的全局搜索功能,把整个工程里的“宠物领养系统”换成你的命名,涉及的地方包括页面<title>标签、导航栏、登录页的欢迎语。JSP 页面和 JS 文件中可能还有硬编码的站点名,搜索时注意把文件类型覆盖范围放开,别只搜 Java 文件。
第二步是改视觉标识。最常见的做法是替换static目录下的 logo 图片和登录页背景图,同时改 CSS 里的主色调。多数毕设项目用的 Bootstrap,你只需要在bootstrap.min.css之外加一个自己的custom.css,里面写两行覆盖主色变量,就能明显改变观感。
第三步是调整数据库初始数据。把公告表里的公告内容、管理员账号、预设的宠物记录,都换成你自己设计的内容。这一步特别重要,答辩评委打开系统时最先看到的就是这些数据,如果里面还残留着作者原版的名字或无关的宠物信息,很容易被追问来源。
6.2 五分钟验证核心链路:登录到领养确认的九步闭环
改完代码后不能只是“能启动”就算完,得验证整条业务闭环。我建议你把系统重置到初始状态,按这个顺序走一遍:管理员登录、进入后台、发布一只新宠物、退出登录;切换普通用户登录、在列表页找到刚发布的宠物、提交领养申请;切回管理员账号、查看申请列表、审核通过;再切到用户视角确认宠物状态已变为已领养。
这九个步骤覆盖了系统的所有核心模块:登录认证、后台管理、宠物发布、图片上传、申请提交、状态流转。每一步出现报错都记下来,按第 5 章的排查顺序处理。演示时如果时间紧张,至少保证这三个画面能顺畅跑出来:宠物列表页的正常展示、领养申请的成功提交、管理员审核后的状态变化。
6.3 演示录像的用法:照着录一遍,不如按现场环境录新的
录像资源在答辩环节扮演另一个角色,它是预先准备的“后悔药”。现场演示最常见的风险是网络异常或数据库端口被占用,导致系统启动不了。我自己经历过一次答辩前半小时发现 MySQL 密码不匹配,当场手忙脚乱,后来凡是演示前必做三件事:把数据库服务置为开机自启、关闭防火墙对 3306 和 8080 端口的拦截、把演示用账号密码抄在记事本里备用。
更稳妥的做法是,用你改完后的系统重新录一段 3 分钟的演示视频,按照 6.2 的九步闭环走一遍,录的时候用 OBS 或 EV 录屏都可以,画面里开一个系统时间显示窗,证明这段录像是你自己操作的。现场演示翻车时,直接播放这段录像并继续讲解,比对着报错日志解释要体面得多。希望帮到你。
本文还有配套的精品资源,点击获取