毕业设计常见痛点:为什么“写代码”只占 20% 时间
信息管理与信息系统专业的毕设,往往被戏称为“需求管理大赏”。我带的 8 个组里,有 6 组在答辩前两周还在改字段名。把高频痛点拆一拆,大致如下:
- 需求像橡皮泥——教务老师一句“顺便把成绩预测也做进去”,原型图就得重画。
- 技术选型拍脑袋——Spring Boot 还是 Django?拍脑袋的结果就是中期发现“不会部署”。
- 前后端联调马拉松——接口文档写在微信里,字段大小写不一致,调一次通一次。
- 重复代码写到吐——每个模块都要分页、都要导入导出,复制粘贴一时爽,维护火葬场。
- 测试靠手点——没有单元测试,答辩现场一输入中文符号直接 500,老师眉头一皱。
这些体力活,正是 AI 辅助开发最能发挥价值的“低垂果实”。
主流 AI 编程助手横评:谁更适合毕设“短平快”
目前学生最容易拿到的三把“瑞士军刀”:
| 维度 | GitHub Copilot | 通义灵码 | Amazon CodeWhisperer |
|---|---|---|---|
| 中文注释理解 | 一般 | 优秀 | 一般 |
| 单文件补全 | 强 | 强 | 中等 |
| 跨文件上下文 | 强 | 中等 | 弱 |
| 安全扫描 | 无 | 内置(Java/Python) | 内置 |
| 价格 | 学生包免费 | 免费 | 免费 |
| 离线场景 | 不可 | 可本地模型 | 不可 |
结论:
- 纯英文项目、深度算法模块优先 Copilot;
- 中文需求、教务类 MIS 优先通义灵码;
- 若未来打算部署到 AWS,CodeWhisperer 可顺手埋好 SDK 调用。
典型毕设场景:RBAC 教务管理系统
系统边界划到最小可跑通:
- 角色:学生、教师、教务员
- 功能:登录、选课、成绩录入、数据看板(ECharts 展示不及格率)
- 技术栈:Spring Boot 3 + MyBatis-Plus + Vue3 + MySQL 8
把 AI 当“结对菜鸟”,让它先写,我们再 Code Review,效率最高。
用 AI 生成核心模块:从提示词到可运行代码
1. 用户认证(Spring Security + JWT)
提示词(通义灵码):
“用 Spring Security 写一个 RBAC 登录接口,角色分学生、教师、教务员,返回 JWT,要包含全局异常处理。”
AI 返回的UserDetailsService实现大致可用,但暗藏三处坑:
- 密码明文比对——提醒改成 BCrypt;
- 角色硬编码——建议用枚举;
- 未捕获
UsernameNotFoundException——会被默认 500 暴露用户名不存在。
Clean Code 示例(片段):
@Service public class RbacUserDetailsService implements UserDetailsService { @Autowired private UserMapper userMapper; @Override public UserDetails loadUserByUsername(String username)enetUsernameNotFoundException { return userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getUsername, username)) .map(u -> org.springframework.security.core.userdetails.User .withUsername(u.getUsername()) .password(u.getPassword()) // 已 BCrypt 加密 .authorities(mapToGrantedAuthorities(u.getRoles())) .build()) .orElseThrow(() -> new UsernameNotFoundException("用户不存在")); } private Collection<GrantedAuthority> mapToGrantedAuthorities(List<Role> roles) { return roles.stream() .map(r -> new SimpleGrantedAuthority("ROLE_" + r.getCode())) .toList(); } }要点:
- Optional 链式处理空值,杜绝 if-null;
- 角色前缀统一
ROLE_,与 Spring Security 默认对齐; - 异常信息模糊化,防止用户名枚举。
2. 数据看板(Vue3 + ECharts)
提示词:
“用 Vue3 组合式 API 写一个组件,调用 /api/dashboard/fail-rate,返回不及格率折线图,要有 loading 状态。”
AI 生成骨架后,我们补两处防御式编程:
- 输入校验:后端返回空数组时,ECharts 会抛
setOption异常;加v-if="dataset.length"保护; - 异常处理:封装
useFetch,统一捕获 4xx/5xx,Toast 提示“数据飞走了”。
AI 代码的安全隐患与性能陷阱
硬编码密钥
场景:AI 顺手把 JWT 密钥写成String SECRET = "123456";
解决:抽到application.yml,配合 Jasypt 加密。SQL 注入
场景:MyBatis XML 里${}拼接 like 语句。
解决:一律改#{},like 用concat('%',#{name},'%')。N+1 查询
场景:遍历学生列表,逐条 select 成绩。AI 喜欢写 for-loop。
解决:用 MyBatis-PlusselectBatch或@EntityGraph。事务失效
场景:AI 把@Transactional加到 private 方法。
解决:Spring AOP 仅对 public 代理,记得自检。
生产环境避坑指南
版本控制策略
- main 分支只放可跑通代码,feature 分支用 AI 快速试错;
- commit 信息加
ai-gen标签,方便回滚。
人工审查 Checklist(打印出来贴实验室墙)
- 是否含硬编码?
- 是否捕获异常并日志脱敏?
- 是否写单元测试?分支覆盖 >60% 即可。
- 是否依赖最新漏洞版本?
mvn dependency-check跑一遍。
灰度发布
校园网就是最好 Canary,先给室友账号,观察一晚 Grafana 曲线,CPU 飙高就回滚。
动手环节:重构一段 AI 代码
把下面这段“AI 原味”代码保存为OldService.java,用 30 分钟完成:
- 将
if-else级联改成策略模式; - 补全输入校验(成绩 0-100);
- 加单元测试,Mock 数据库。
public String evaluate(int score){ if(score>=90) return "优秀"; else if(score>=80) return "良好"; else if(score>=70) return "中等"; else if(score>=60) return "及格"; else return "不及格"; }完成后跑mvn test,如果测试绿条且 JaCoCo 报告分支覆盖 100%,恭喜你,已具备把 AI 当“初级外包”的底气。
写在最后
AI 辅助开发不是“一键毕业”,而是把最枯燥的 50% 体力活外包给算法,再把省下的时间用来写测试、修漏洞、陪女朋友。下次需求再变,别急着吐槽产品狗,先让 AI 帮你把脚手架搭好,你只需专注真正的业务价值——以及,记得把踩过的坑写成博客,学弟学妹会替你点赞。