ARTICLE DETAIL

资讯详情

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

基于SSM框架的考研报名系统设计与实现——毕业设计实战指南

基于SSM框架的考研报名系统设计与实现——毕业设计实战指南 1. 为什么选考研报名系统做毕设一个被低估的题目每年到了毕设选题季群里总有一批人在纠结管理系统太简单怕过不了算法类太难怕做不完。如果你正在Java方向徘徊我强烈建议你看一眼考研报名系统这个方向——它看起来平平无奇实际上踩中了毕设评分的大部分得分点业务逻辑完整、技术栈经典、有明确的用户角色划分、还能自然融入高并发和事务处理等加分话题。先说你最关心的这个东西到底能做什么简单来说它就是一套面向考生、院校管理员和系统管理员三个角色的全流程报名管理平台。考生端负责注册、登录、填报个人信息、选择报考院校和专业、上传照片和证件、缴纳报名费如果是演示项目可以做成模拟支付、查看审核状态、打印报名信息表。管理端则包括招生计划管理、考生信息审核、报名数据统计、考场编排、公告发布。这套流程几乎复刻了真实考研报名系统的核心环节业务链条长但每一环都不算太难非常适合作为毕业设计的载体。再说它适合谁。如果你目前是Java基础尚可、Spring框架用过但不深入的本科学生这个题目正好卡在舒适区边缘——不会像纯管理系统那样索然无味也不会像秒杀系统那样让你熬夜掉头发。如果你已经工作、想做一个拿得出手的个人项目把这套系统加个在线支付和消息推送放在简历上也是能打的。我做这套系统的过程中最大的感受是考研报名系统最考验人的不是单一技术点而是业务状态管理。整个报名流程从注册到最终确认每一步都有前置条件、都有状态流转、都有异常分支需要处理。把这套流程理顺了你对Web开发的理解会上升一个层次。2. SSM框架选型的真实考量Spring MVC Spring MyBatis组合的取舍2.1 为什么放着Spring Boot不用偏要选SSM这是很多评审老师必问的一道题。2025年的今天新项目基本上都是Spring Boot起步为什么毕设还要用SSM我的回答是不是不能直接用Spring Boot而是SSM更能体现你的底层功底。SSM指的是Spring MVC、Spring、MyBatis三个框架的组合。Spring负责IoC容器和事务管理Spring MVC负责Web层的请求分发和参数绑定MyBatis负责数据持久层。三者各司其职不像Spring Boot那样把一切都自动配置好了。用SSM你至少得亲手配置web.xml、Spring配置文件、MyBatis映射文件这个过程会逼你搞清楚一个请求从浏览器到数据库到底走了哪些路。反过来说如果直接上Spring Boot配置自动搞定你反而少了理解原理的机会。答辩时老师问一句你的starter是怎么把DataSource自动装配进来的很多同学就卡住了。用SSM配置都是你一行行写出来的问任何一行你都能答得上来这就是隐形的护城河。2.2 三件套的分工逻辑从架构上看SSM的分层非常清晰Spring MVC表现层接收HTTP请求调用Service层接口返回JSON或JSP视图。负责参数校验、异常处理、文件上传解析。Spring业务层管理Service层Bean的生命周期通过声明式事务控制业务操作的原子性。像报名提交这种涉及多张表写入的操作必须放在事务里。MyBatis持久层定义Mapper接口和XML映射文件负责SQL的编写和执行。动态SQL用于处理条件查询非常方便后面我会重点讲。我在项目里采用的标准分包结构是com.example.kyc ├── controller // 控制层接收请求 ├── service // 业务接口 实现 ├── dao // MyBatis Mapper接口 ├── entity // 实体类对应数据库表 ├── dto // 数据传输对象承载页面参数 ├── vo // 视图对象输出给前端 ├── common // 公共类常量、异常、工具 ├── config // 配置文件如果有 └── interceptor // 拦截器这个结构在答辩时非常好讲。老师问你的请求是怎么流转的你就能按照 Controller → Service → DAO → Mapper XML → MySQL 的顺序完整说一遍每一层该干什么、为什么不把SQL写在Controller里都能对答如流。2.3 数据库连接池和相关依赖的搭配既然用的是SSM依赖管理就只能用手动方式管理jar包或借助Maven。我建议所有毕设项目都使用Maven理由很简单依赖传递和版本管理能帮你省掉大量ClassNotFoundException的排查时间。我的pom.xml核心依赖大致如下dependencies !-- Spring核心 -- dependency groupIdorg.springframework/groupId artifactIdspring-context/artifactId version5.3.39/version /dependency !-- Spring MVC -- dependency groupIdorg.springframework/groupId artifactIdspring-webmvc/artifactId version5.3.39/version /dependency !-- MyBatis核心 -- dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version3.5.16/version /dependency !-- MyBatis-Spring整合包 -- dependency groupIdorg.mybatis/groupId artifactIdmybatis-spring/artifactId version2.1.2/version /dependency !-- MySQL驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency !-- 数据库连接池 -- dependency groupIdcom.alibaba/groupId artifactIddruid/artifactId version1.2.23/version /dependency !-- 文件上传 -- dependency groupIdcommons-fileupload/groupId artifactIdcommons-fileupload/artifactId version1.5/version /dependency !-- JSON序列化 -- dependency groupIdcom.fasterxml.jackson.core/groupId artifactIdjackson-databind/artifactId version2.17.1/version /dependency /dependencies版本号务必锁死不要写裸版本比如3.5.否则Maven会拉取到不兼容的版本。Druid连接池在这个项目里挺实用它自带的监控页面能看SQL执行情况答辩时打开监控页面展示一下直接加分。3. 数据库设计与核心表结构决定项目上限的关键一步3.1 用户与角色体系怎么建考研报名系统最忌讳的就是把所有用户塞到一张user表里用role字段区分。这么做前期开发快后期扩展想都别想。我采用的做法是用户主表 角色维度扩展表。用户主表只放公共信息字段类型说明idbigint主键自增usernamevarchar(50)登录名唯一passwordvarchar(100)MD5加盐后的密码role_typetinyint1考生 2院校管理员 3系统管理员phonevarchar(20)手机号emailvarchar(100)邮箱statustinyint0禁用 1启用create_timedatetime创建时间然后单独建考生扩展表存报名所需的详细个人信息字段类型说明idbigint主键user_idbigint关联用户主表candidate_novarchar(20)考生编号注册后自动生成real_namevarchar(50)真实姓名id_cardvarchar(18)身份证号gendertinyint性别birthdaydate出生日期ethnicvarchar(20)民族political_statusvarchar(20)政治面貌educationvarchar(50)学历graduation_schoolvarchar(100)毕业院校graduation_yearint毕业年份majorvarchar(50)所学专业photo_urlvarchar(255)证件照地址addressvarchar(255)联系地址postcodevarchar(10)邮编为什么拆成两张表两个原因一是登录只需要username和password查询频繁表越窄查询越快二是考生信息字段多且只在报名环节用拆开后不影响正常登录性能以后想扩展考生专属字段也不会动到主表结构。3.2 报名流程的核心表设计考研报名有明确的时间线填写信息 → 选择报考点 → 上传材料 → 提交审核 → 审核通过 → 缴费 → 确认报名。每一步都涉及到数据落库和状态变更所以核心表必须围绕一次报名这个业务对象来设计。我的核心表包括招生计划表、报名单表、报名明细表、审核记录表。这里重点说报名单表字段类型说明idbigint主键application_novarchar(30)报名单号如 B20251000001user_idbigint考生IDplan_idbigint招生计划ID关联招生计划表school_idbigint报考院校IDmajor_idbigint报考专业IDstatustinyint状态1草稿 2待提交 3待审核 4审核通过 5审核驳回 6已缴费 7已完成submit_timedatetime提交时间verify_timedatetime审核时间verify_remarkvarchar(255)审核意见pay_timedatetime缴费时间pay_order_novarchar(50)支付流水号cancel_reasonvarchar(255)取消原因create_timedatetime创建时间update_timedatetime更新时间状态字段是整个系统的心脏。我的经验是不要让状态随意散落在代码里而是定一个常量类或者枚举管理。比如用枚举public enum ApplicationStatus { DRAFT(1, 草稿), SUBMITTED(2, 待提交), PENDING_REVIEW(3, 待审核), APPROVED(4, 审核通过), REJECTED(5, 审核驳回), PAID(6, 已缴费), COMPLETED(7, 已完成); private final int code; private final String desc; ApplicationStatus(int code, String desc) { this.code code; this.desc desc; } // getter... }所有涉及状态判断的地方都通过枚举比较绝对不要出现散落的魔法数字。这样答辩时你还能顺手引出枚举单例和状态机两个概念都是加分项。招生计划表也不能省。它存储某个学校某个专业在某一年度计划招收多少人、已报名多少人字段类型说明idbigint主键school_idbigint院校IDmajor_idbigint专业IDyearvarchar(10)招生年份quotaint计划招生人数applied_countint当前已有效报名人数exam_subjectvarchar(255)考试科目说明remarkvarchar(500)备注一个经常被忽视的点招生计划表要控制报名上限。当applied_count达到quota时前端应禁止继续报名。这个逻辑在后端检查时要注意并发问题我后面会专门讲。3.3 院校、专业以及省市的关联设计很多同学直接把院校、专业、地区做成一张大表三个字段塞一起。这种设计在考研报名这种多级联动的场景下非常痛苦因为报名时要先选省份再选学校再选院系再选专业每一级都有依赖关系。我的建议是三张表region表省/市/区三级用parent_id做树形结构。school表院校基本信息关联region_id。major表专业基本信息包含专业代码、名称、所属门类。层级关系通过外键关联。MyBatis联表查询时用join或者用嵌套结果映射处理一对多关系。这块做得好不好直接影响报名时级联下拉框的体验也影响答辩时老师对数据库设计能力的判断。我实际建表时还额外加了一张school_major表来做院校和专业的关联因为一个院校开通多个专业、同一个专业在多个院校都有开设多对多关系必须用中间表解耦。4. 报名核心链路的功能实现详解4.1 登录鉴权用拦截器还是Shiro考研报名系统涉及的页面很多但有不少是需要登录才能访问的。最简单的做法是写一个Spring MVC拦截器在preHandle方法里检查session是否存在用户。这个方案对本项目完全够用而且老师能看懂。我的拦截器核心逻辑是这样的public class LoginInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 如果是OPTIONS请求直接放行跨域预检 if (OPTIONS.equals(request.getMethod())) { return true; } HttpSession session request.getSession(); Object loginUser session.getAttribute(Constants.SESSION_USER); if (loginUser null) { // 判断是否ajax请求 String requestedWith request.getHeader(X-Requested-With); if (XMLHttpRequest.equals(requestedWith)) { response.setContentType(application/json;charsetUTF-8); response.getWriter().write(JSON.toJSONString(Result.fail(401, 未登录))); } else { response.sendRedirect(request.getContextPath() /login); } return false; } return true; } }有人会问为什么不用Spring Security或者Shiro。我的想法是SSM项目引入Shiro会把配置复杂度拉高一个档次且在这个项目里核心诉求只是登录拦截 角色权限判断拦截器加注解就能解决。如果你想展示更强的技术能力可以在Service方法上自定义一个RequireRole(ADMIN)注解配合拦截器实现细粒度权限控制这个亮点比生硬地套Shiro更能体现你的设计能力。登录时密码的存储要讲究一点。明文存储万万不可我用的是MD5 固定盐public static String encrypt(String password, String salt) { String str password salt; for (int i 0; i 5; i) { str DigestUtils.md5DigestAsHex(str.getBytes(StandardCharsets.UTF_8)); } return str; }虽然现在更推荐BCrypt但毕设项目里MD5加盐已足以通过安全性的考察点。答辩时如果被追问MD5彩虹表攻击怎么办你就说加了迭代次数和盐值并指出生产环境会换用BCrypt这样回答既有深度又不暴露短板。4.2 报名流程的状态推进逻辑报名不是一个单接口操作而是一系列操作串联起来的结果。我给每个操作都独立设计了Service方法saveDraft(...)保存草稿状态置为DRAFT。submitApplication(...)提交报名前置校验DRAFT或REJECTED状态状态置为PENDING_REVIEW。reviewPass(...)审核通过状态置为APPROVED同时招生计划表的applied_count加1。reviewReject(...)审核驳回记录驳回原因考生可修改后重新提交。payApplication(...)确认缴费状态置为PAID生成订单号。confirmApplication(...)完成报名状态置为COMPLETED。每个方法的第一步都是校验当前状态是否符合预期防止用户跨状态操作。比如已缴费的报名单不能被提交接口再次处理。这种防御性编程在答辩时就是亮点体现你对业务边界有清晰的思考。submitApplication的伪代码大概是Transactional(rollbackFor Exception.class) public boolean submitApplication(Long applicationId, Long userId) { Application application applicationMapper.selectById(applicationId); if (application null) { throw new BusinessException(报名单不存在); } if (!userId.equals(application.getUserId())) { throw new BusinessException(无权操作他人报名单); } // 只有草稿或驳回状态才能提交 if (application.getStatus() ! ApplicationStatus.DRAFT.getCode() application.getStatus() ! ApplicationStatus.REJECTED.getCode()) { throw new BusinessException(当前状态不允许提交); } // 校验招生计划是否已满 Plan plan planMapper.selectById(application.getPlanId()); if (plan.getAppliedCount() plan.getQuota()) { throw new BusinessException(该专业招生名额已满); } application.setStatus(ApplicationStatus.PENDING_REVIEW.getCode()); application.setSubmitTime(new Date()); applicationMapper.updateStatus(application); return true; }这段代码体现了三个关键点事务、状态校验、业务规则校验。缺一不可。很多同学只写状态更新不做事前校验结果就是别人能通过猜测接口把任意报名单状态改成审核通过这是严重的安全漏洞。4.3 文件上传与校验照片和证件的处理细节考研报名必然要上传证件照、身份证扫描件、学历证书等。用SSM的CommonsMultipartResolver处理上传并不复杂真正容易出问题的是文件类型校验和大小限制。我建议在Spring配置里显式声明上传解析器bean idmultipartResolver classorg.springframework.web.multipart.commons.CommonsMultipartResolver !-- 最大上传大小这里设为5MB -- property namemaxUploadSize value5242880/ !-- 单个文件最大大小 -- property namemaxUploadSizePerFile value2097152/ !-- 默认编码 -- property namedefaultEncoding valueUTF-8/ /bean服务层接收MultipartFile之后除了检查为空还要做三件事校验文件扩展名白名单、校验文件MIME类型、把文件写到磁盘或OSS并保存URL。扩展名校验要防绕过比如只允许.jpg/.png/.pdf不允许.jsp/.php。private static final SetString ALLOWED_EXTENSIONS new HashSet(Arrays.asList(jpg, jpeg, png, pdf)); public String uploadFile(MultipartFile file) { if (file null || file.isEmpty()) { throw new BusinessException(文件不能为空); } String originalFilename file.getOriginalFilename(); String ext originalFilename.substring(originalFilename.lastIndexOf(.) 1).toLowerCase(); if (!ALLOWED_EXTENSIONS.contains(ext)) { throw new BusinessException(不支持的文件类型: ext); } // 文件大小二次校验 if (file.getSize() 2 * 1024 * 1024) { throw new BusinessException(文件大小不能超过2MB); } // 生成唯一文件名防止重名覆盖 String fileName UUID.randomUUID().toString().replace(-, ) . ext; // 按日期分目录存储 String datePath new SimpleDateFormat(yyyyMMdd).format(new Date()); String dirPath uploadDir File.separator datePath; File dir new File(dirPath); if (!dir.exists()) { dir.mkdirs(); } file.transferTo(new File(dirPath File.separator fileName)); return /upload/ datePath / fileName; }这里有个非常经典的坑file.transferTo()在跨服务器部署时可能因为相对路径问题在Tomcat的临时目录写入文件最好用绝对路径。我在项目里把上传根目录做成了配置项部署时单独指定不要依赖程序的当前工作目录。4.4 动态SQL搞定多条件筛选管理端必然有列表筛选功能按状态查、按专业查、按考生姓名模糊查、按时间区间查。如果每个条件都写一个Mapper方法代码会膨胀得很厉害。MyBatis的动态SQL正好解决这个问题。select idselectApplicationPage resultTypecom.example.kyc.vo.ApplicationVO SELECT a.*, s.school_name, m.major_name FROM application a LEFT JOIN school s ON a.school_id s.id LEFT JOIN major m ON a.major_id m.id where if teststatus ! null and status ! 0 AND a.status #{status} /if if testschoolId ! null AND a.school_id #{schoolId} /if if testkeyword ! null and keyword ! AND (u.username LIKE CONCAT(%, #{keyword}, %) OR a.application_no LIKE CONCAT(%, #{keyword}, %)) /if if teststartTime ! null AND a.create_time gt; #{startTime} /if if testendTime ! null AND a.create_time lt; #{endTime} /if /where ORDER BY a.create_time DESC LIMIT #{offset}, #{pageSize} /selectwhere标签会自动处理最前面的AND不会因为第一个条件为false而留下游离的AND。这个细节会让SQL拼接Bug减少一大半。LIMIT分页在数据量不大的情况下完全够用不需要引入PageHelper插件如果你想把项目做得更精细引入PageHelper也可以但要注意PageHelper和MyBatis版本兼容性。5. 踩坑实录我在开发中遇到的5个典型问题5.1 MyBatis#{}和${}混用的悲剧我第一次做条件排序时图省事把排序字段直接用了${}拼接ORDER BY ${sortField} ${sortOrder}结果前端传入sortFieldid;DROP TABLE user这类恶意参数时整个SQL直接变成灾难。虽然项目只做课程设计但这个习惯必须改。我的修正方案是排序字段在前端枚举白名单里做校验后端只接收id、create_time、status这几个合法值其他一律拒绝。凡是SQL中出现的表名、字段名这种不能预编译的变量都必须走白名单校验。5.2 声明式事务失效同一个类内部方法调用我在开发审核功能时遇到过这样的问题审核通过需要更新报名单状态 更新招生计划已报名人数 写入审核记录三个操作必须在一个事务里。我一开始在reviewApproved方法上加Transactional然后在方法内直接调用了本类的updatePlanCount方法结果发现其中一个操作失败前面的操作并没有回滚。原因是Spring的声明式事务基于AOP代理而同一个类内部的方法调用不会经过代理对象导致事务注解失效。解决办法有两个一是把事务边界尽量设计在Controller调用的Service方法上二是如果有内部事务需要就拆分到不同Service类中互相调用。我采用的是前者——三个数据操作全部写在同一个public方法内通过注入其他Service或者用TransactionTemplate包裹。答辩时如果老师问到这个你可以直接讲清楚AOP代理的生效条件就这一个知识点就能展示你对Spring底层原理的理解。5.3 招生名额并发的超报问题这是整个系统里最有技术含量的问题。当多个考生同时报名同一个已经只剩下最后一个名额的专业时普通逻辑是检查appliedCount quota。执行update语句将appliedCount加1。但在并发场景下A和B同时通过了第一步检查都会执行第二步最终导致超报。我的解决方式是把校验和更新合并成一条原子SQLUPDATE plan SET applied_count applied_count 1 WHERE id #{planId} AND applied_count quota然后判断update返回值等于1表示名额抢占成功等于0表示名额已满。这个思路本质上是用数据库行锁来保证并发安全比编程层面的synchronized可靠得多。我在项目说明文档里专门写了这段设计的分析答辩时讲出来老师的印象分会明显不一样。Transactional(rollbackFor Exception.class) public void reviewApproved(Long applicationId, Long planId) { // 1. 更新报名单状态 applicationMapper.updateStatus(applicationId, ApplicationStatus.APPROVED.getCode()); // 2. 原子化更新名额 int affectedRows planMapper.incrementAppliedCount(planId); if (affectedRows 0) { throw new BusinessException(该专业招生名额已满无法通过审核); } // 3. 写入审核记录 auditMapper.insert(new AuditRecord(applicationId, 审核通过, new Date())); }5.4 JSP页面EL表达式取不到值我用JSP做前端页面时踩过一个很蠢的坑明明在Controller里往ModelAndView塞了对象页面上却取不到值。排查了半天发现是web.xml中Servlet版本声明的问题——Servlet 2.4以下默认EL表达式是关闭的需要在JSP头部加% page isELIgnoredfalse %。还有就是JSTL的依赖没有引入完整导致c:forEach标签不生效。这两个问题在百度一搜一大把但自己踩过一次才记得牢。5.5 跨域问题前后端分离模式下的CORS处理如果你的毕设选择Vue作为前端、SSM作为后端前后端分离部署就必须处理跨域。最简单的方式是在Spring MVC中配置全局CORSConfiguration public class WebConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*) .allowCredentials(true) .maxAge(3600); } }注意allowCredentials(true)时allowedOrigins不能是*必须用allowedOriginPatterns。这是很多教程没讲透的地方我也是踩了坑之后才确认的。6. 部署与答辩准备让项目真正完整起来6.1 环境部署的关键步骤毕设演示前没有部署好的系统技术做得再好也白搭。我整理了一套从零到一的部署清单照着走基本不会翻车安装JDK 1.8配置JAVA_HOME和PATH环境变量。建议用1.8因为SSM框架在JDK 8下最稳定不会有模块化带来的兼容问题。安装MySQL 5.7或8.0创建数据库并导入初始SQL脚本。注意MySQL 8.0的密码认证方式是caching_sha2_passwordJDBC连接需要多带一个useSSLfalseserverTimezoneAsia/Shanghai参数。安装Maven 3.6.3配置阿里云镜像否则依赖下载速度感人。安装Tomcat 9.0在IDE中配置好运行环境。用Maven打包mvn clean package生成war包放入Tomcat的webapps目录启动即可。这里要特别提醒一点数据库初始化脚本一定要提前准备好。我见过太多同学到了演示前一天才去手工建表结果字段对不上前端页面报错。应该在开发期就用Navicat或MySQL Workbench把建表语句导成SQL文件部署时直接source导入干净又可靠。6.2 答辩时的功能展示路径答辩时不要按菜单逐个点击那会让老师觉得项目很平庸。我的建议是带着一个故事线去演示让每一步操作都有前因后果先以管理员身份登录展示招生计划的创建和发布。切换到考生身份注册账号填写报名信息模拟一次完整报名流程。切回管理员审核刚提交的报名单展示通过或驳回操作。考生端查看审核结果进行模拟缴费完成报名。最后展示系统管理端的统计报表或列表查询说明系统支持条件筛选。演示过程中刻意展示几个细节比如被驳回的报名单考生修改后重新提交、招生名额已满时前端提示不可报名、未登录访问受保护页面会跳转到登录页。这些边界情况恰恰是普通同学不会专门处理的展示出来效果极好。我还建议提前准备一份200字左右的项目重点总结内容包含技术栈、核心功能、数据库设计概况、一个亮点难点比如并发名额控制。答辩开场简短说明老师马上就能抓住你的技术主线后面的追问也会围绕你熟悉的领域展开。6.3 论文写作的对应结构如果学校要求提交毕业设计论文章节结构可以这样组织第一章 绪论背景、意义、国内外研究现状、主要工作。第二章 相关技术介绍Java、SSM框架、MySQL、前端技术。第三章 需求分析功能性需求、非功能性需求、用例图。第四章 系统设计总体架构、功能模块设计、数据库设计。第五章 系统实现每个模块的界面截图 核心代码 实现说明。第六章 系统测试功能测试用例表、性能测试简述。论文和代码是相辅相成的数据库设计的ER图务必用工具画好PowerDesigner或者draw.io都可以。测试部分至少列出10个以上的功能测试用例覆盖正常流程和异常流程比如提交空表单是否提示、重复用户名注册是否拦截、名额满后报名是否失败等。7. 写在最后的经验之谈做完这个项目我自己最大的体会是毕设项目不是技术的堆砌而是业务闭环的完整呈现。很多同学一头扎进框架新特性的研究里反而忽略了最基础的设计一个报名单的状态流转是否清晰、一个用户角色有没有权限漏洞、一个名额并发控制是否安全。这些才是真正体现工程能力的地方。我个人推荐的时间分配是这样的需求分析和表结构设计花3天框架搭建和环境配置花2天核心业务功能开发花7到10天测试和Bug修复花3天论文和答辩PPT花4天。整个过程控制在三周左右节奏合适也不会因为战线太长而疲劳。最后给你一个实操建议无论代码写得怎么样一定要把项目跑起来录制一段完整的操作演示视频。一方面答辩时设备出问题可以直接放视频救场另一方面录制过程会逼迫你把系统所有流程走一遍很多隐藏Bug就是在这个过程中暴露出来的。我那句画重点的话就是先把流程走通再谈优化。如果你准备做这个题目或者正在卡在某个环节希望这篇梳理能帮你少走几步弯路。有具体问题欢迎在评论区交流我会根据实际经验回复。别觉得自己的问题简单开发里没有愚蠢的问题只有没掉进去过的坑而已。
返回列表