ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于Spring Boot的宠物领养系统设计与实现全解析

基于Spring Boot的宠物领养系统设计与实现全解析 简介本资源是一套完整的本科毕业设计项目——基于Spring Boot的宠物领养系统面向计算机类专业学生及Java Web初学者解决毕业设计选题难、技术栈整合复杂、文档材料不全等实际问题。系统采用前后端分离架构后端基于Spring Boot MySQLJDK 1.8前端管理界面使用Vue用户端为HTML静态页面功能覆盖用户管理、宠物领养/认领全流程、审核机制、教学视频与公告发布、感谢信归档等核心业务模块。压缩包共含源码、开题报告、论文全文、答辩PPT、数据库脚本、演示视频、环境工具包及同框架项目安装教程等关键材料文件类型涵盖Java工程、SQL脚本、PDF文档、MP4视频及Markdown说明整体大小67.46MB。目前已有109人学习下载内容结构清晰、部署路径明确配套教程可快速完成本地环境搭建与功能验证特别适合缺乏企业级项目经验的学生开展实战复现与答辩准备。1. 项目整体设计与技术选型1.1 宠物领养系统的核心需求拆解先说结论宠物领养系统这个选题在毕业设计里属于麻雀虽小五脏俱全的典型代表。它不像电商系统那样涉及复杂的支付和库存也不像社交平台那样需要处理高并发消息推送但它却几乎覆盖了 Java Web 开发的所有核心知识点用户认证与权限管理、业务状态流转、文件上传、数据关联查询、前后端交互、报表统计等等。你把这些东西吃透了不仅仅是交一个毕设而是把 Spring Boot 的常用套路走了一遍。我当时接到这个题目的时候第一件事不是急着写代码而是先把需求理清楚。正规的宠物领养系统至少要包含两类角色访客或者叫普通用户和管理员。访客可以浏览宠物列表、查看宠物详情、提交领养申请、管理个人信息、查看申请进度管理员则负责宠物信息的上下架、审核领养申请、管理用户、处理领养回访记录。有些系统还会加入宠物走失发布寻主启事志愿者申请这些功能但核心业务始终是宠物信息管理 领养申请审核这条主线。如果你想把这个系统做得有亮点我建议在基础需求上增加以下几个模块宠物健康档案疫苗接种记录、驱虫记录、领养协议在线签署至少是电子确认流程、领养回访计划比如定期回访提醒。这些功能在答辩时非常加分因为评审老师会看到你不仅仅是在做 CRUD而是有业务思考在里面。1.2 技术栈选型及理由技术选型是毕业设计的第一步也是答辩时老师必问的问题。我的建议是不要为了炫技去用一些冷门框架而是选择生态最成熟、资料最丰富的方案。当时我的选型是这样的后端框架Spring Boot 2.7.x前端框架Vue 2 Element UI如果你时间充裕也可以考虑 Vue 3 Element Plus数据库MySQL 8.0ORM 框架MyBatis-Plus权限认证Spring Security JWT文件存储本地存储通过 Nginx 映射静态资源路径接口文档Swagger / Knife4j项目管理MavenSpring Boot 的选择理由不用多说它已经成为 Java 后端开发的事实标准。我特意选了 2.7.x 而不是最新的 3.x原因有两个一是 2.7.x 的生态兼容性最好网上搜到的资料几乎都是基于这个版本的遇到问题容易找到解决方案二是很多学校的课程和企业项目还在用 Java 8 Spring Boot 2.x你用这个版本在答辩时更有说服力不会因为版本太高被老师质疑。如果你用的 JDK 版本较高确实会遇到 Spring Boot 2.x 不兼容的问题但 Java 8 环境下基本没有坑。前端选 Vue 2 Element UI是因为它的中文文档完善、组件丰富特别适合快速搭建后台管理界面。你不需要是前端高手照着 Element UI 的组件文档就能把页面拼出来。而且 Vue 2 的双向绑定机制对后端出身的同学更友好比 React 的受控组件思维更直观。1.3 系统架构与模块划分整个系统的架构并不复杂就是标准的前后端分离方案。后端只负责提供 RESTful API前端通过 Axios 发起 HTTP 请求获取数据并渲染页面。这样做的好处是职责清晰后端专注于业务逻辑和数据处理前端专注于页面交互和展示。我把后端模块划分成五个层次每个层次有明确的职责Controller 层接收前端请求进行参数校验调用 Service 层处理业务Service 层核心业务逻辑包括数据校验、状态流转、事务控制Mapper 层Dao数据库操作使用 MyBatis-Plus 简化 CRUDEntity 层与数据库表结构对应的实体类DTO/VO 层数据传输对象用于前后端数据交互避免直接暴露实体结构模块上我拆分为用户模块、宠物模块、领养申请模块、审核模块、回访模块、公告模块、统计模块。每个模块都是一套完整的 Controller-Service-Mapper 结构后期维护和扩展都很方便。这种划分方式在文档里也很好写每个模块一节逻辑清晰论文排版都省心。2. 核心功能模块设计与数据库建模2.1 用户角色权限设计权限设计是整个系统的基础如果这里没做好后面所有功能都会乱。我采用的是基于角色的访问控制RBAC模型也就是用户-角色-权限三层关系。系统中定义了三种角色普通用户ROLE_USER浏览宠物、提交领养申请、管理个人信息管理员ROLE_ADMIN宠物管理、领养审核、用户管理、回访管理超级管理员ROLE_SUPER_ADMIN在管理员的基础上增加管理员账号的配置权限在 Spring Security 中我通过 JWT 令牌保存用户的角色信息。前端登录成功后拿到 token每次请求在请求头中携带Authorization: Bearer token。后端通过一个拦截器解析 token获取用户 ID 和角色信息然后根据注解判断接口是否允许当前角色访问。这样设计的优点是接口权限是通过注解直接声明在 Controller 方法上的例如PreAuthorize(hasRole(ADMIN))代码可读性好权限配置一目了然。实际开发中我建议你建一张user表、一张role表、一张user_role关联表。虽然毕业设计规模不大但如果你用用户表里直接加一个 role 字段的做法虽然简单答辩时容易被追问扩展性问题。用标准的三张表设计前后端取角色信息时稍微多一点代码量但整体架构更正规文档也有内容可写。2.2 宠物信息管理模块细节宠物信息管理是系统的核心数据这部分的设计直接影响用户体验。我的宠物表pet中包含了以下主要字段id主键name宠物名称type宠物类型猫/狗/其他breed品种age年龄gender性别health_status健康状况已驱虫、已打疫苗等description详细描述cover_image封面图URLimages图片列表用 JSON 数组存储status状态0-待审核、1-已上架、2-已下架、3-已被领养create_time、update_time时间戳这里有个关键设计点宠物状态机。管理员发布宠物信息后状态为待审核审核通过后变为已上架用户提交领养申请并审核通过后状态变为已被领养如果长期无人领养管理员可以手动下架。这个状态流转是整个系统的业务核心答辩时一定要能讲清楚。图片上传功能我采用的是本地存储方案。前端通过 Element UI 的 Upload 组件选择图片以 multipart 文件流的形式传给后端。后端接收后将文件保存到服务器的/upload/pet/目录文件名用 UUID 重命名防止重复然后把可访问的 URL 存到数据库。生产环境部署时通过 Nginx 将这个目录映射为静态资源路径前端就能通过 URL 直接访问图片了。这里有一个坑必须限制上传文件的大小和类型建议在 yml 配置中设置spring.servlet.multipart.max-file-size10MB并且在后端做一次文件类型的扩展名校验否则容易被提交恶意文件。2.3 领养申请与审核流程领养申请是整个系统的核心业务闭环也是最容易在答辩时被深入提问的模块。流程是这样的用户在前端点击申请领养填写领养申请表包括居住环境、养宠经验、领养原因等系统创建一条领养申请记录状态为待审核管理员在后台看到待审核列表点击查看申请详情可以通过或拒绝通过后宠物状态更新为已被领养同时生成一条回访计划记录用户可以在个人中心查看申请进度我用一张adoption_application表来存储申请记录字段包括id、user_id、pet_id、reason、experience、address、status0-待审核、1-已通过、2-已拒绝、audit_remark、audit_time、create_time。同时一张visit_plan表存储回访记录字段包括id、application_id、visit_time、visit_content、visitor、create_time。这个流程用了一个很关键的技巧事务控制。当管理员审核通过时需要同时更新申请状态和宠物状态如果这两步只成功了一步就会出现数据不一致所以必须在 Service 方法上加Transactional注解。这是后端开发的基本功也是答辩的高频考点我在代码注释里专门标注了这一点方便文档中讲解。2.4 数据库表结构设计要点数据库设计直接决定了后续开发的工作量和系统性能。我梳理一下所有表的关系一共 10 张核心表表名用途备注user用户表含用户名、密码BCrypt加密、手机号role角色表角色名称、描述user_role用户角色关联表多对多关系pet宠物信息表含状态字段数据库索引pet_image宠物图片表一对多也可用JSON字段存数组adoption_application领养申请表核心业务表visit_plan回访计划表与申请表一对一notice公告表管理员发布站内公告feedback用户反馈表用户提交建议或举报sys_log操作日志表记录关键操作便于追溯设计时我特意给pet表的status、type字段加了索引给adoption_application表的user_id、pet_id加了外键索引。原因是这两个字段是高频查询条件加索引能显著提升查询效率。这个细节在答辩时写进 PPT会显得你考虑问题非常全面。另外所有表都加了create_time和update_time字段。MyBatis-Plus 的自动填充功能可以直接在插入和更新时自动给这两个字段赋值不需要在代码里手动 set。这个功能很实用建议在演示时提一下也是一个加分项。3. 关键代码实现与实操过程3.1 快速搭建 Spring Boot 项目骨架我使用的是 Spring Initializr 方式创建项目。你可以直接在 IDEA 的 New Project 中选择 Spring Initializr然后在界面中选择需要的依赖。这里列出我选的依赖Spring Web提供 REST API 支持Spring Security用户认证和权限控制MyBatis-Plus Framework数据库 ORM 框架MySQL Driver数据库驱动Lombok简化实体类代码Validation参数校验创建完成后项目会自动生成一个主启动类例如PetAdoptionApplication.java。然后在application.yml中配置数据源和 MyBatis-Plus 相关的设置。我的核心配置如下server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/pet_adoption?useUnicodetruecharacterEncodingutf-8useSSLfalseserverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver servlet: multipart: max-file-size: 10MB max-request-size: 20MB mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl map-underscore-to-camel-case: true global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0这里有几件事必须注意serverTimezoneAsia/Shanghai必须加否则高版本 MySQL 连不上会报时区错误。map-underscore-to-camel-case开启后数据库的下划线字段create_time会自动映射到 Java 的驼峰属性createTime省去一堆繁琐的映射配置。逻辑删除配置是我特意留的这样删除数据时实际上是执行 UPDATE 操作把deleted字段置为 1数据不会真正的物理删除避免误删后无法恢复。毕业设计里这个功能非常实用写文档的时候也可以作为亮点。3.2 核心接口实现以宠物列表和领养申请为例代码实现部分是整个项目的重头戏。我挑两个最核心的接口拿出来讲讲一个是宠物列表查询一个是领养申请提交。宠物列表接口的设计要考虑三个场景首页展示所有已上架的宠物、搜索筛选按类型、品种、年龄、分页加载。MyBatis-Plus 的分页插件把这块做得非常简洁Controller 层接收当前页码和每页数量传给 Service 层查询结果直接通过Page对象返回。代码大致如下RestController RequestMapping(/api/pet) public class PetController { Autowired private PetService petService; GetMapping(/list) public ResultPagePetVO getPetList(RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 10) Integer pageSize, PetQuery query) { PagePetVO page petService.getPetPage(pageNum, pageSize, query); return Result.success(page); } GetMapping(/detail/{id}) public ResultPetVO getPetDetail(PathVariable Long id) { return Result.success(petService.getPetDetail(id)); } }在 Service 实现中关键是通过 LambdaQueryWrapper 动态拼接查询条件。比如用户不传类型就查全部传了类型就在 SQL 中加入type ?条件。这种方式比手写 XML 灵活很多代码量也少非常适合快速开发。领养申请的接口稍微复杂一些因为它涉及事务和状态校验。我贴一段核心代码思路Transactional public void submitAdoption(AdoptionApplicationDTO dto, Long userId) { // 1. 校验宠物是否存在且处于可领养状态 Pet pet petMapper.selectById(dto.getPetId()); if (pet null || pet.getStatus() ! 1) { throw new BusinessException(该宠物不存在或不可领养); } // 2. 防止重复申请同一只宠物 LambdaQueryWrapperAdoptionApplication wrapper new LambdaQueryWrapper(); wrapper.eq(AdoptionApplication::getUserId, userId) .eq(AdoptionApplication::getPetId, dto.getPetId()) .in(AdoptionApplication::getStatus, 0, 1); if (adoptionApplicationMapper.selectCount(wrapper) 0) { throw new BusinessException(您已申请过该宠物请勿重复提交); } // 3. 创建申请记录 AdoptionApplication application new AdoptionApplication(); BeanUtils.copyProperties(dto, application); application.setUserId(userId); application.setStatus(0); adoptionApplicationMapper.insert(application); }这段代码里有两个非常重要的业务判断一是宠物当前是否可领养二是用户是否已经申请过同一只宠物。这两个校验缺一不可否则会出现用户同时申请十几只宠物、或者对一只已被领养的宠物反复申请的情况。真实项目中业务校验永远放在事务里并且优先执行这个习惯一定要养成。3.3 前端管理页面的实现思路前端界面我用 Vue 2 Element UI 实现。页面结构大致分为首页宠物展示墙、宠物详情页、登录/注册页、个人中心、后台管理界面。这些页面的核心是复用组件比如宠物卡片组件、分页组件、状态标签组件。后台管理界面是核心因为管理员的所有操作都在这里完成。我把管理页面拆成几个模块页面宠物管理页表格展示宠物信息支持搜索、上下架、编辑、删除领养审核页待审核列表 申请详情抽屉 通过/拒绝按钮回访管理页回访计划列表 新增回访记录用户管理页用户列表 角色分配公告管理页公告发布与列表我前后端对接时的核心原则是统一返回结果格式。我定义了一个通用的Result类结构为{ code: 200, message: success, data: {...} }。前端在 Axios 的响应拦截器中统一判断code是否为 200否则弹出错误提示。这样一来任何时候后端抛出业务异常前端都能统一弹 Toast不需要每个接口单独写错误处理逻辑省了很多事。// axios 拦截器示例 service.interceptors.response.use( (response) { const res response.data; if (res.code ! 200) { this.$message.error(res.message || 请求失败); return Promise.reject(new Error(res.message)); } return res; }, (error) { this.$message.error(网络异常请稍后重试); return Promise.reject(error); } );这种统一的响应格式和拦截器在后端开发中已经是标配了。你写文档的时候把这个设计单独拿出来讲能体现出工程化思维。3.4 环境配置与项目运行全流程我给你梳理一套从零到能跑起来的完整流程照着做基本不会有问题安装 JDK 8或 11、Maven 3.6、MySQL 8.0、Node.js 14在 MySQL 中创建数据库pet_adoption导入项目附带的pet_adoption.sql脚本修改application.yml中的数据库用户名和密码启动后端项目确认控制台不报错端口 8080 正常监听在 IDEA 中打开前端目录打开终端执行npm install安装依赖执行npm run serve启动前端开发服务器默认端口 8081浏览器访问http://localhost:8081使用管理员账号登录后台如果前端和后端端口不一致需要在前端项目中配置代理。在 Vue 项目的vue.config.js中添加module.exports { devServer: { port: 8081, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } };这里有个细节如果后端接口前缀带有/api那么代理规则直接匹配/api即可如果后端接口路径没有统一前缀我建议你在后端的 Controller 上加一个全局的RequestMapping(/api)的路径前缀这样前后端联调时非常方便也方便后续做网关统一前缀。4. 常见问题与部署避坑记录4.1 版本兼容性引发的各种问题这一节我集中整理一下实际开发中遇到的、大概率你也会踩到的坑。第一个坑是 Spring Boot 版本太高导致的兼容性问题。如果你用了 Spring Boot 3.x 或 Spring Boot 2.7 以上版本MyBatis-Plus 需要引入专门的适配包mybatis-plus-spring-boot3-starter否则启动会报错。同理Swagger 也是一个重灾区Spring Boot 2.6 及以上版本默认不启用 Spring MVC 的路径匹配策略Swagger 2.x 会出现空指针异常。解决办法是在application.yml中加一行配置spring: mvc: pathmatch: matching-strategy: ant_path_matcher如果你用的 JDK 版本比较高比如 JDK 17 或更高而 Spring Boot 是 2.x 系列那么运行时会报模块访问控制相关错误。我当时调试了半天最后实测下来最省事的办法是直接把 JDK 版本切到 8 或 11不要和高版本 JDK 纠缠毕业设计没必要在这里消耗时间。第二个坑是mapper-locations配置错误。MyBatis-Plus 默认扫描classpath*:mapper/**/*.xml如果你的 XML 文件放在src/main/resources/mapper/目录下但配置没有指定扫描路径启动时会报Invalid bound statement (not found)。解决方法是在 yml 中配置mybatis-plus.mapper-locations: classpath*:mapper/**/*.xml。第三个坑是跨域问题。前后端分离开发时前端在localhost:8081后端在localhost:8080如果不配置跨域浏览器会直接拦截请求。解决办法是写一个全局配置类实现WebMvcConfigurer接口重写addCorsMappings方法允许http://localhost:8081的跨域请求。或者像我上面说的直接在前端 vue.config.js 中配置代理开发环境下用代理更省心。4.2 数据库连接和账号管理的问题数据库连接报错也是高频问题常见的有两种。一种是Access denied for user说明数据库密码和配置对不上或者当前用户没有远程访问权限。解决办法是登录 MySQL执行授权语句GRANT ALL PRIVILEGES ON pet_adoption.* TO rootlocalhost IDENTIFIED BY 你的密码; FLUSH PRIVILEGES;另一种是时区报错错误信息类似The server time zone value Öйú±ê׼ʱ¼ä is unrecognized。这就是我前面强调的在 JDBC URL 后加上serverTimezoneAsia/Shanghai即可解决。另外导入 SQL 脚本时务必确认 Spring Boot 配置中的数据库名和脚本里的数据库名一致。很多同学明明导入了数据启动后却查不到任何表十有八九是连接到了错误的数据库。4.3 部署环境中的关键问题汇总项目完成后你需要把系统部署到服务器上供演示和答辩使用。我特别整理了一个问题速查表你可以直接参考问题现象根本原因解决方案前端页面 404路由模式用了 history且 Web 服务器未配置 fallback改成 hash 模式或配置 Nginx location try_files图片无法访问上传目录没有映射为静态资源Nginx 配置location /upload/ { alias /opt/pet/upload/; }后端接口超时数据库连接池太小或 SQL 慢查询排查 SQL 是否走索引调整max-active参数服务器运行一段时间后内存溢出JVM 参数未优化启动脚本中显式指定-Xms256m -Xmx512m数据库乱码连接字符集未配置URL 后追加characterEncodingutf-8端口被占用服务器上已有其他进程占用启动前先lsof -i:8080检查端口关于部署方式如果你会使用 Docker我强烈推荐用 Docker Compose 来一键启动 MySQL 后端 Nginx 服务。写一个docker-compose.yml把 MySQL 数据卷挂载到宿主机后端构建成镜像Nginx 负责代理前端静态文件和反向代理后端接口整个过程在文档里写清楚导师看了会觉得你工程能力很强。4.4 从 GitHub 下载源码后的使用建议如果你想基于下载的源码进行二次开发我给你几个建议能帮你少走弯路。第一拿到源码后不要急着运行先看 README 文档。如果文档中写了环境要求比如 JDK 版本、Node 版本一定要满足否则编译阶段就会卡住。第二仔细检查数据库脚本是否完整导入。很多源码虽然附带了.sql文件但有些表数据是空的会导致系统运行没有初始数据。建议在导入后跑几个查询确认admin账号能查到。第三注意源码中的配置项。如果application.yml里配置了你的本地环境不存在的路径比如 Linux 服务器路径需要改成你自己的本地路径。还有 Redis 相关的配置如果项目里集成了 Redis 而你的机器没有安装启动时会一直报连接失败这时候要么先安装 Redis要么把 Redis 相关配置注释掉。第四不要相信没有任何注释的项目文档。真正靠谱的源码包除了代码外至少应该包含项目结构说明、数据库导入脚本、运行步骤、答辩常见问题整理。如果缺少这些你自己调试的时间成本会非常高。5. 毕业设计文档与答辩准备5.1 与源码配套的说明书写作指南毕业设计文档是个重头戏这块工作量不比写代码小。我建议文档按下面的结构组织绪论背景、意义、国内外现状相关技术介绍Spring Boot、MyBatis-Plus、Vue.js 等系统分析可行性分析、需求分析、用例图系统设计架构设计、功能模块设计、数据库设计系统实现核心功能页面截图 代码讲解系统测试功能性测试、性能测试总结与展望文档中最重要的部分是系统设计和系统实现。在设计部分画出系统架构图、功能模块图、ER 图是基本操作在实现部分不要贴大段完整代码而是选择核心代码片段配以文字说明这段代码实现了什么逻辑为什么这样实现。写文档有一个技巧把每个功能模块的业务流程图画清楚。比如领养审核流程从用户提交申请到管理员审核再到回访每一步画清楚文字说明再跟上这份文档的专业度立刻提升一个档次。5.2 答辩前必须演练的五个核心问题答辩环节是评审老师了解你真实水平的窗口。我有几个经验整理出来供你参考第一讲 PPT 时不要照着念功能列表要挑一个核心功能展开讲完整业务闭环。比如专门讲领养申请审核这个流程从表结构到接口设计到前端交互一条线讲透比罗列十个功能都有说服力。第二准备几个为什么选这个方案的答案。比如为什么用 JWT 而不是 Session为什么用 MyBatis-Plus 而不是原生 MyBatis为什么用前后端分离这些都是高频问题提前想好答案。第三展示代码时可以提前在 IDEA 里定位好核心位置答辩现场直接按快捷键跳到代码再快速讲解逻辑。不要现场现找容易手忙脚乱。第四准备好数据库设计说明。老师最喜欢问的就是你这个字段为什么这样设计、这张表为什么加这个索引你如果能答上来status 字段加索引是因为它是高频查询条件基本就稳了。第五一定要准备好测试用例。提前用 Postman 演示接口调用准备好登录、查询、提交申请的管理员账号答辩时现场走通一个完整流程比任何口头描述都有效。5.3 源码之后还能怎么扩展如果做完基础功能后还有富余时间我建议有选择地加一些亮点功能接入短信或邮件通知审核通过后自动给用户发送通知推荐用阿里云短信或 QQ 邮箱 SMTP增加数据可视化大屏用 ECharts 做宠物领养统计、品种分布、成功领养率展示视觉效果拉满实现收藏功能用户把喜欢的宠物加入收藏便于后期再次查看增加领养回访提醒定时任务用 Spring 的Scheduled注解每天定时检查是否有到期的回访计划这些功能不需要全部做挑一两个你最有把握的就行。加一个亮点功能答辩时主动展示效果比被动回答要好得多。6. 实操心得与个人体会聊了这么多技术细节最后说说我做完这个项目后的一些真实感受。宠物领养系统作为毕业设计它的难度定位是非常合适的。项目规模不大不小核心业务明确涉及的 Spring Boot 技术点覆盖面广但又不会像微服务那样复杂到失控。如果你认真把每一行代码都读懂了、每一张表都弄清楚为什么这样设计那么做完这个项目后你对 Spring Boot 的掌握程度绝对能达到入职初级开发的水平。我在实际开发中最大的体会是最快的开发方式不是直接写代码而是先把数据库表设计好。表结构定了实体类就出来了Service 流程也就清晰了。很多同学做到一半返工问题基本都出在数据库设计没想清楚。还有一个小技巧把项目的文档和注释当成代码的一部分来写。我在整个项目里保持了非常详细的代码注释每个 Service 方法上都写了业务逻辑说明。写文档时直接把这些注释整理成文本效率提高了不少。更重要的是正式项目中这个习惯非常加分答辩时老师翻你的代码看到每段业务逻辑都有注释印象分一定不会低。最后多提一句拿到这个项目后千万别只是把代码跑通就了事。先删掉几个模块试着不看源码自己重新实现一遍再对照源码找差距。这个过程可能比找 100 个教程都管用。技术这东西看一百遍不如自己动手写一遍。本文还有配套的精品资源点击获取
返回列表