每年到了四五月份,都能在技术社区刷到一批被毕设折磨得焦头烂额的计算机专业学生,其中 “java迎新网管理系统” 这个题目出现的频率相当高。说实话,我当时选这个题的时候也没觉得它有多特别,就觉得高校迎新这业务听着挺实在的,不至于像“图书管理系统”那样烂大街,也比“网上商城”这类纯CRUD的项目要稍微有点业务深度。
结果真正动手做起来才发现,迎新管理这件事远没有想象中那么简单——它不是一个单点的信息发布页面,而是横跨新生数据导入、报到流程引导、宿舍分配、缴费状态确认、院系接待等多个角色的协同流程。整个系统做下来,等于把Spring Boot、MyBatis、MySQL、Redis、Vue这些Java后端常用的技术栈全部过了一遍,而且每个环节都有真实业务约束,不是那种为了用技术而用技术的玩具项目。
这篇就把我当时从选题、设计、编码到部署答辩的全过程拆开揉碎讲一遍,包括数据库表结构怎么设计才能避免后期返工、Excel批量导入新生数据时最容易踩的坑、以及答辩时老师最喜欢追问的几个点该怎么应对。所有内容都基于我实际开发时的真实经历,希望能给正在做类似课题或者准备做Java毕设的同学一点参考。
1. 项目定位与整体设计思路
1.1 为什么“迎新管理”比想象中更适合做毕设
先聊聊这个课题本身的定位。很多同学在选毕设题目时有个误区,觉得功能越花哨越好,恨不得把微服务、中间件、分布式事务全堆上去。但对于本科毕设来说,评委老师看重的不是技术栈有多新,而是你能不能把一个真实业务场景完整地抽象成数据模型和功能模块,并且代码实现是干净、可运行的。
“迎新管理系统”恰恰是一个非常适合的课题,原因有三:第一,业务流程清晰,新生从录取到入住的路径是固定的,不存在模糊的业务边界;第二,参与者角色多样,至少有管理员、院系老师、新生三种角色,这就涉及权限管理和多端交互,系统的复杂度自然就上来了;第三,数据操作类型完整,既有基础信息的增删改查,也有导入导出、状态流转、统计报表,几乎覆盖了JavaWeb开发的所有基础操作。
我自己在做需求分析时,先把整个迎新流程画了一遍:新生被录取后,学校先导入新生名单;新生在报到前登录系统查看入学须知、填写个人信息、预约报到时间;报到当天到校后,在院系接待点进行资格审核,然后办理宿舍入住、领取校园卡、确认缴费状态;最后院系辅导员可以在后台查看本院的报到进度。整个流程走下来,系统的功能边界就非常清楚了。
1.2 功能模块划分:不是简单的新生注册
确定了业务流程之后,我花了大概三天时间把功能模块拆了出来。在这里要提醒一句:不要上来就写代码,先花时间把功能清单列出来,后面会省很多事。我当时是按照角色来划分模块的,这样权限设计的时候也方便。
管理员端包含五个核心部分:新生信息管理(导入、修改、查询、导出)、用户账号管理(重置密码、启用禁用)、院系专业管理(维护学院和专业的层级关系)、宿舍资源管理(楼栋、楼层、房间信息维护)、系统数据看板(报到率统计、宿舍入住率、各院系进度对比)。
院系老师端功能相对收敛:本学院新生列表查看、报到审核(确认学生是否到校)、新生信息编辑(比如联系方式变更)、本学院报到情况统计。
新生端则完全围绕报到流程设计:登录后先看到自己的录取信息,然后按步骤填写个人扩展信息(如家庭成员、接站信息、宗教信仰等非必填项)、查看入学须知、预约报到时间、查看分配的宿舍信息、获取报到流程指引(每一步的状态是待办还是已完成)。
这里有一个非常关键的细节:新生端的每一步操作都会影响后台的状态统计,比如新生只有“确认到校”之后,后台的报到率才会更新;宿舍只有在新生确认入住后才算分配完成。这个状态联动设计是整个系统的核心亮点,也是答辩时值得重点讲的部分。
1.3 技术选型:Java毕业后端技术栈怎么配才稳妥
技术选型这块,我的建议是在“稳妥”和“展示能力”之间取平衡。我选用的是一套非常经典的组合:JDK 8(瞩目点:稳定,兼容性极好)+ Spring Boot 2.3.x + MyBatis-Plus + MySQL 5.7 + Redis + Vue 2 + Element UI。
这个组合有两个明显优势。第一,Spring Boot + MyBatis-Plus是目前Java后端使用率最高的搭配之一,网上资料齐全,遇到报错随便一搜都能找到解决方案;第二,MyBatis-Plus内置的代码生成器可以自动生成实体类、Mapper接口和Service层,能省下大量的重复造轮子时间,让我把精力集中在业务逻辑上。
关于版本踩坑,我在这里多说几句。Spring Boot 2.3.x对应的是JDK 8,不要一上来就装JDK 17、Spring Boot 3.x,因为MyBatis-Plus、PageHelper这些老牌插件对Spring Boot 3的兼容性并不好,而且JDK 9+的模块化机制会让一些反射工具类直接报错。除非你对新版本非常熟悉,否则不要拿毕设做版本升级的实验田。
前端我用了Vue 2 + Element UI,后端只提供RESTful API接口,前后端通过JSON交互。这种前后端分离的架构虽然比传统的JSP方案多了些配置工作,但展示出来的技术水平明显更高,而且Vue的响应式特性在构建数据看板时简直不要太香。
2. 数据库设计与表结构实现
2.1 核心表结构到底要怎么设计
数据库设计是整个系统的地基,地基打不好,后面写代码的时候会处处碰壁。不少同学习惯把所有字段塞进一张大表里,图省事,但实际上迎新系统至少有六个核心实体,必须拆开建表。
这里是我的建表清单(每个表中都加了create_time、update_time这类通用审计字段,代码里统一用MyBatis-Plus的自动填充功能维护):
| 表名 | 用途说明 | 关键字段 |
|---|---|---|
| sys_user | 系统用户账号表,记录登录凭证 | id, username, password, role, status |
| student_info | 新生基础信息表 | id, student_no, name, gender, id_card, phone, major_id, class_id, is_registered |
| major_info | 专业信息表 | id, major_name, dept_id |
| dept_info | 院系信息表 | id, dept_name |
| dormitory_info | 宿舍资源表 | id, building_no, room_no, bed_count, used_count, status |
| student_dorm | 新生宿舍分配关系表 | id, student_id, dorm_id, check_in_time |
| register_appointment | 报到预约表 | id, student_id, appointment_date, time_slot, status |
| sys_log | 操作日志表 | id, user_id, operation, detail, create_time |
这里面有一个特别容易被忽略的设计点:宿舍分配不要直接在student_info表里加一个dorm_id字段,而是要建一个独立的关系表student_dorm。因为一个新生在报到前可能会被预分配一次,到校后如果对宿舍不满意还可能要调换,这个变更历史是需要留痕的。关系表的优势在于可以记录分配时间、操作人、变更原因,后期做追溯非常方便。
专业和院系的层级关系也要拆开,dept_info和major_info通过dept_id关联。我校实际场景中就有“计算机科学与技术”专业同时隶属于“信息工程学院”和“软件学院”的情况,如果不拆表,这种多对多关系根本没法表达。
2.2 学号生成与状态字段的巧妙设计
新生学号怎么生成,是很多第一次做这个项目的人会卡住的地方。学号不是随便编的,一般遵循规则:入学年份(4位) + 院系代码(2位) + 专业序号(2位) + 班级序号(2位) + 个人序号(2位),总共12位。比如202408130101,含义是2024年入学、08号院系、13号专业、01班、01号学生。
我在生成学号的逻辑里用了Redis的INCR命令来保证并发下的序号唯一性。具体做法是:管理员导入新生Excel时,后台解析出院系和专业后,用Redis维护一个自增key,每次生成时从Redis获取当前值再拼上日期前缀。这里要特别注意:不要在每次生成学号时去数据库里SELECT MAX(student_no),因为并发场景下容易拿到相同的最大值,导致主键冲突。
状态字段这块,我给报到流程设计了严格的状态机:0-待报到(默认)、1-已到校(学生点击确认到校或老师代操作)、2-已完成宿舍入住、3-已完成全部报到(所有必办项都通过)。每完成一步,前端页面上的流程指引就亮起对应的步骤灯,后台统计报表同步更新。状态字段的值一定要用int而不是String,因为String的可读性差且容易拼错,int配合常量类就可以做到语义清晰。
2.3 SQL建表脚本与初始化数据的注意事项
建表脚本我没用可视化工具直接点出来的,而是手写SQL保存成init.sql文件,每次项目初始化直接执行脚本即可。这样做的好处是脚本可重复执行,项目交付时连同代码一起交给老师,对方能快速在你的环境里跑起来。
手写建表脚本时有几个点必须注意:一是字符集统一用utf8mb4,因为MySQL 8.0默认是utf8mb4,而MySQL 5.7默认的utf8其实只支持部分字符,万一新生名字里有生僻字就会显示成乱码;二是所有的bigint主键都设置成auto_increment,并且不要用int,因为数据量大了之后int很容易超上限;三是日期字段比如报到时间建议用datetime,不要用timestamp,因为timestamp有2038年的隐患,虽然对毕设来说无所谓,但这个细节可以在文档里写上,说明你考虑到了。
初始化数据里至少要预置一个admin管理员账号(角色为管理员)和几个测试账号(院系老师、学生各一个),这样系统部署登录后第一眼就能看到数据,演示的时候非常顺畅。密码一定要用BCrypt加密后存入数据库,不要明文存储,这不仅是为了安全,答辩时提到密码加密也是一个加分项。
3. 核心功能实现与关键代码解读
3.1 登录鉴权与角色权限控制的两种方案
登录鉴权这块,我花了比较多的时间去权衡。说实话,用Spring Security + JWT是最标准的做法,但配置量比较大,对于不熟悉Spring Security的同学来说,光是把过滤器链配通就能折腾好几天。我当时调研后选择了一个折中方案:使用Spring Boot Interceptor + JWT(或者简单点用Session),不用引入Spring Security依赖。
简单说明一下方案:后端写一个LoginInterceptor实现HandlerInterceptor接口,在preHandle方法里检查请求头里的Token是否有效、是否过期、用户是否存在。有效就放行,无效就返回401状态码。这样做的好处是逻辑透明,完全自己控制,出了问题也能快速定位。
角色控制我用了自定义的@RequireRole注解配合AOP切面实现。给每个接口打上需要的角色标识,比如@RequireRole("ADMIN")就表示只有管理员能访问。AOP切面里先通过反射拿到注解的值,再从当前登录用户的上下文(ThreadLocal里存的LoginUser对象)中取出角色,匹配不通过就抛出异常。整个鉴权链路没有任何重量级框架依赖,代码量在150行以内,非常轻量。
前端配合路由守卫做了一层页面级拦截:Vue Router的beforeEach钩子里判断是否已登录以及当前用户角色是否在允许列表里,不满足就跳到登录页。后端拦截是安全底线,前端拦截只是体验优化,这个双层设计要给老师讲清楚。
3.2 新生名单Excel批量导入的完整实现
迎新系统最核心的功能之一,就是把学校招就处发的Excel新生名单批量导入系统。这个功能实现起来不算难,但涉及的细节非常多,处理不好整个导入过程就会各种报错。我使用了Apache POI来解析Excel文件,在5.0版本之前Excel最多只能有65536行,我直接用POI的XSSFWorkbook来支持.xlsx格式(这个限制在5.0之后不存在了,但用新版本总归稳妥)。
导入的逻辑分为三步:上传文件并保存到服务器临时目录、使用POI逐行解析并做数据校验、将合法的数据批量插入数据库。
数据校验这一步是整段代码的灵魂。新生Excel里的数据不可能每一行都是干干净净的,手机号格式不对、身份证号少了一位、姓名里带空格、学号与库中已有数据重复……这些情况都要在入库前处理掉。我的做法是:解析每一行时先做字段的合法性校验,不合法就把错误信息记录到一个List 里,最后把错误以JSON的形式返回给前端。前端拿到后逐行显示“第7行:手机号格式错误,请检查后重试”之类的提示,方便管理员定位问题。
附上核心解析代码片段,这里用了Stream的方式遍历行数据,比传统的for循环更简洁:
public ImportResult importStudents(MultipartFile file) throws Exception { ImportResult result = new ImportResult(); List<String> errors = new ArrayList<>(); List<StudentInfo> validList = new ArrayList<>(); try (XSSFWorkbook workbook = new XSSFWorkbook(file.getInputStream())) { XSSFSheet sheet = workbook.getSheetAt(0); List<StudentExcelVO> excelData = new ArrayList<>(); // 从下标1开始,跳过表头 for (int i = 1; i <= sheet.getLastRowNum(); i++) { Row row = sheet.getRow(i); if (row == null || isAllCellsEmpty(row)) { continue; } StudentExcelVO vo = new StudentExcelVO(); vo.setRowNum(i + 1); vo.setStudentNo(getCellValue(row.getCell(0))); vo.setName(getCellValue(row.getCell(1))); vo.setGender(getCellValue(row.getCell(2))); vo.setIdCard(getCellValue(row.getCell(3))); vo.setPhone(getCellValue(row.getCell(4))); excelData.add(vo); } // 批量校验 for (StudentExcelVO vo : excelData) { String error = validateStudent(vo); if (StringUtils.hasText(error)) { errors.add("第" + vo.getRowNum() + "行:" + error); continue; } valids.add(convertToEntity(vo)); } if (validList.size() > 0) { studentInfoMapper.insertBatchSomeColumn(validList); } result.setSuccessCount(validList.size()); result.setErrorList(errors); return result; } catch (Exception e) { log.error("导入新生名单失败", e); throw new BusinessException("文件解析失败:" + e.getMessage()); } }这里有一个我被坑过的点:Excel的Cell.getCellType()在不同POI版本里返回值不一样,4.x返回的是int类型,5.x返回的是枚举类型。如果像我一样用POI 5.x写代码,再对照网上的4.x教程,很容易因为类型不匹配导致NPE。解决方式很简单:写一个通用的getCellValue方法,里面判断cellType后分别处理STRING、NUMERIC、FORMULA三种情况,统一转成String返回。
3.3 报到进度跟踪与宿舍分配算法
报到进度跟踪我用了事件驱动的方式:新生每完成一个事项(确认到校、填写信息、预约时间、入住宿舍),后端就发送一个内部事件,系统的ProgressService会重新计算该新生的报到状态。这样做的好处是,以后如果要增加新的报到环节(比如增加一个“领取军训服装”),只需要新增一个对应的事件处理器即可,不用改原有逻辑。
宿舍分配算法这块,很多同学会想得很复杂,比如要搞什么智能推荐、条件约束。实际上在真实校园场景里,宿舍分配就是按“院系集中入住”这个简单规则来做的。我的实现思路是:先从前端拿到新生所在的院系,查询该院系目前可用的宿舍列表(逻辑上先按楼栋排序,再按楼层排序),然后优先分配已使用床位数最少的房间,尽量把同一个班级的新生凑到同一间,没有额外做太花哨的算法。
如果同宿舍楼的空床位不够了怎么办?代码里要做兜底:查询dept_id关联的宿舍楼里是否还有空床,如果没有,则自动分配到临近楼栋,并在宿舍分配的备注字段里写明“跨楼栋分配,原因为XX楼床位已满”。这种兜底逻辑在毕设答辩时一定要主动讲出来,因为老师最喜欢问“如果宿舍满了怎么办”,你提前做了边界处理,这个问题就迎刃而解了。
3.4 数据看板与统计报表的快速实现
管理员首页的数据看板是系统的一个颜值担当,我用了ECharts实现。数据来源是后端提供了四个统计接口:总报到率(已报到/总人数)、各院系报到人数柱状图、各时段预约报到人数折线图、宿舍入住率环形图。
这些统计SQL用MyBatis-Plus的QueryWrapper写起来稍微有点绕,我换了更直接的方式:在Mapper里手写XML查询,用GROUP BY和COUNT直接统计,效率高且逻辑直观。比如各院系报到人数的SQL大概是:
<select id="countRegisterByDept" resultType="map"> SELECT d.dept_name AS name, COUNT(s.id) AS value FROM student_info s INNER JOIN major_info m ON s.major_id = m.id INNER JOIN dept_info d ON m.dept_id = d.id WHERE s.is_registered = 1 GROUP BY d.dept_name </select>前端ECharts的配置非常简单,把后端返回的List<Map<String, Object>>直接给series.data赋值就行。这里要注意的一点是:后端接口的返回结构要和前端图表需要的数据结构保持一致,所以最好定义一个StatVO,包含name和value两个字段,前后端都用这一个结构,免去了在JS里拼数据的麻烦。
在显示数据看板时我还顺手做了一个定时刷新功能,每隔三十秒自动调用一次统计接口,这样就算后台有新数据导入,看板上的数字也会自动变化。这个小细节成本很低,但演示效果极佳,老师看到图表数字自己会跳,就会觉得系统是“活”的。
4. 开发过程中的常见问题与避坑记录
4.1 环境配置与依赖冲突的经典坑
开发环境这块,我强烈建议先把JDK的版本理清楚。很多同学电脑上装了不只一个JDK版本,导致项目运行时的JRE路径和IDE配置不一致,最典型的就是Unrecognized option: --add-opens或Error: Could not create the Java Virtual Machine这类诡异的报错。
另外就是Maven依赖冲突的问题在我的开发过程中出现过好多次。Spring Boot 2.3.x自带的Jackson版本是2.11,如果自己在pom里额外引入了2.13版本的Jackson,可能运行时报错InvalidDefinitionException。解决办法是:引入第三方依赖时,优先用项目原本传递依赖的版本,尽量不要覆盖官方BOM管理好的版本号,除非你真的清楚自己在做什么。
数据库连接这块也有一个隐蔽的坑:MySQL 5.7和8.0的连接驱动地址不一样,5.7是com.mysql.jdbc.Driver,8.0是com.mysql.cj.jdbc.Driver。如果驱动写错,启动时虽然报错,但报错信息是ClassNotFoundException,很容易让人误判成jar包没导入,排查半天找不到原因。我直接在application.yml里把时区也一并配好了:jdbc:mysql://localhost:3306/welcome?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai。
4.2 开发中反复遇到的Api设计与联调问题
前后端分离开发中,最让人头疼的往往是接口联调阶段。我总结了几个让开发过程顺畅的小习惯:第一,后端接口统一返回结构Result<T>,包含code、message、data三个字段,成功返回200,业务异常返回400+错误信息,鉴权失败返回401。前端就用axios拦截器统一处理,代码非常整洁。
第二,接口路径的命名要遵循RESTful规范。比如/api/admin/students表示管理员操作的学生资源,/api/student/info表示当前学生自己的信息。虽然RESTful不是必须的,但规范的命名让你在不同接口切换时不用去查文档,光看URL就能知道这个接口是用来干嘛的。
第三,Redis里的数据要设置过期时间。有些同学习惯把学生的登录Token在Redis里永久保存,觉得反正也不会过期。实际上这样是有安全隐患的,万一Token泄露,攻击者可以永久以学生的身份操作。我统一设置了7天的过期时间,配合拦截器里的续期操作,用户在活跃使用时Token就不会失效,7天不登录则需要重新登录。
4.3 部署测试与演示前要做的最后准备
本地开发模式下一切正常,不代表部署到服务器上也能正常运行。我在部署测试时遇到的最大的一个问题是:服务器上缺少中文字体,导致导出的Excel文件里中文全部变成方块。这个问题的原因是服务器上的JDK绘图库(其实是Java的Font类在渲染中文时)找不到对应字体。解决方式是在服务器上安装fontconfig和中文字体包,或者在导出时使用宋体、微软雅黑等字体名称时走Font.createFont的逻辑加载本地字体。
部署方式我建议直接用Spring Boot的内置Tomcat打成可执行jar包,用nohup java -jar xxx.jar > log.log 2>&1 &在后台运行,不要用外置Tomcat,省去一堆配置。这样不仅部署速度快,而且换服务器时把jar和数据库脚本带走就行,非常方便。
演示前还有一个必须做的准备:准备一套完整的演示数据,包括10名测试新生、3个院系、6个专业、若干宿舍数据。不要用空数据库去演示,不然首页看板全是0,老师看起来观感很差。我自己的演示数据是把家里几个人的身份证号稍微改了改填进去的,姓名、学号、联系方式全是模拟的,现场演示时点开任何功能都有数据可看。
4.4 问题排查速查表
整理一份我踩过的坑的速查表,每一条都是真金白银换来的教训:
| 问题现象 | 可能原因 | 处理方式 |
|---|---|---|
| 后端返回JSON中日期格式为时间戳 | 没配置Jackson的日期格式 | 在application.yml中配置spring.jackson.date-format=yyyy-MM-dd HH:mm:ss并time-zone=GMT+8 |
| 前端调用接口提示跨域 | 前后端端口不一致 | 后端配置CorsFilter或使用@CrossOrigin注解 |
| Excel导入时中文乱码 | 文件流编码不对或POI版本读xlsx不兼容 | 统一用XSSFWorkbook处理.xlsx,Excel文件本身保存为UTF-8格式 |
| 宿舍分配后查询房间列表重复 | 关联查询时未做DISTINCT | 用DISTINCT或GROUP BY处理 |
| Redis连接不上 | Redis服务未启动或密码错误 | 启动Redis服务,检查application.yml配置 |
| MyBatis-Plus自动填充不生效 | 没在实体类上配置@TableField(fill = FieldFill.INSERT) | 在实体类对应字段加注解,并实现MetaObjectHandler |
这个表格里的每一条我都亲自踩过一遍,尤其是日期格式那个问题,前后端调试了快两个小时才定位到是后端序列化格式没配置。
5. 项目扩展方向与答辩建议
5.1 如果想要更高的技术亮点,可以往哪个方向扩
如果时间充裕,想在毕设里再增加一些有区分度的特性,我有几个方向可以推荐。第一个是给系统加上消息推送功能,比如新生确认到校后,自动给院系辅导员的账号推送一条站内通知或短信通知,这里可以接入WebSocket实现页面实时提醒。第二个是引入Excel模板导出的升级版,允许管理员自定义导出哪些字段,而不是写死所有列。第三个是用AOP实现更细粒度的操作审计,记录“谁在什么时间对哪些数据做了改了什么操作”,这个在企业开发中很常见,写到毕业论文里也很有实际意义。
我个人最推荐的是第一个方向。报到高峰当天,院系老师需要在电脑前实时看到新生确认到校的通知,传统的刷新页面方式体验很差,而WebSocket推送能做到服务端主动通知,前端页面弹窗提醒。这个功能一旦实现,系统的交互感和完成度会上一个台阶,答辩时老师看到这个细节也会眼前一亮。
5.2 答辩自述和功能演示的建议节奏
最后聊聊答辩的事。很多同学代码写得不错,但答辩时讲得乱七八糟,最后分数反而没有代码水平不如自己的同学高。我当时的答辩节奏是:先用三分钟讲清楚系统背景和核心业务流程图(其实就是在纸上画了个新生入学报到的流程图),再用两分钟画一下技术架构图(别用花哨的微服务架构,就画标准的Controller-Service-Mapper三层结构),剩下十分钟演示核心功能。
演示的顺序上要有讲究:先演示管理员导入新生Excel,再到新生端登录查看报到状态、确认到校、预约时间,然后切换到院系老师账号进行报到审核,最后回到管理员首页看数据看板的变化。整个演示过程其实就是一条以新生报到为主线的故事线,老师跟着这条线走下来,对系统的理解会非常自然,提问也大多会围绕你演示过的模块展开,不会问你完全没涉及的方向。
关于老师最爱问的问题,我提前准备过这几个:数据库表之间的关联关系为什么要这样设计?如果并发量很大,比如上千人同时登录,系统会有什么瓶颈?微信小程序的想法有没有考虑过?无论能不能答得完美,至少要能说出自己的思考和局限性,做到坦诚且逻辑通顺。
6. 写在最后
做这个Java迎新管理系统的最大体会是:毕设项目不一定要技术多前沿、架构多复杂,真正难的是把一个看似简单的业务场景做扎实。从需求分析到数据库设计,从后台接口到前端页面,再到部署上线和演示答辩,每一个环节都有大量细节需要打磨。我在这个项目上花了两周时间编码,但前面需求分析和数据库设计就花了不少时间,这部分前期工夫后来被证明是最值的——正是因为表结构设计得合理,后面写业务代码时几乎没有返工过。
最后再分享一个经验:就这个迎新管理系统的项目完整性而言,如果再把宿舍分配、专业信息这些模块的代码重构优化一下就可以作为毕业设计模板反复使用。关键是代码里对状态流转、异常捕获、数据校验这些边角问题的处理,这些才是最体现工程素养的地方。
希望这篇经验帖能帮到正在做类似题目的同行。如果你在开发中遇到什么具体问题,也欢迎在评论区留言一起交流,我有时间都会回复。