AI为何必须拒绝某些请求:安全合规的技术实现
2026/9/30 12:48:37
摘要:许多计算机专业学生在完成Java毕业设计时,常因缺乏工程经验陷入技术选型混乱、架构耦合严重或部署流程复杂等困境。本文面向零实战经验的新手,系统梳理从需求分析、技术栈选择(Spring Boot + MyBatis + MySQL)到CI/CD部署的全流程,提供可运行的模块化代码模板,并重点解析常见陷阱如事务失效、N+1查询、权限绕过等。读者将获得一套结构清晰、安全合规且易于扩展的毕业设计参考实现,显著降低开发成本与答辩风险。
在实验室里,很多同学的代码第一次跑通就长舒一口气,结果答辩时被老师三连问:
常见误区总结如下:
一句话:能跑只是起点,能维护、能扩展、能回滚,才配得上“工程”二字。
| 方案 | 学习成本 | 生态完整度 | 运维友好度 | 毕设适配度 |
|---|---|---|---|---|
| 传统 SSM(Spring+SpringMVC+MyBatis) | 高,需配大量 XML | 中 | 低,配置散落 | 中 |
| Spring Boot + MyBatis | 低,注解+自动配置 | 高 | 高,单 jar 直接跑 | 极高 |
| Node.js + Express | 低,但需掌握 JS 异步 | 中 | 高 | 低(非 Java 技术栈) |
| Python Django | 低,自带后台管理 | 高 | 高 | 低(非 Java 技术栈) |
结论:
下面以“校园二手书交易平台”为例,展示用户、商品、订单三大模块的最小可运行骨架。代码均按 Clean Code 要求:
tree -L 2 -d com.secondbook ├── user │ ├── UserController │ ├── UserService │ ├── UserMapper │ └── model │ ├── UserEntity │ └── UserDTO ├── book │ ├── BookController │ └── … ├── order │ └── … ├── common │ ├── GlobalExceptionAdvice │ └── PageResp └── SecondbookApplicationAuthorization: Bearer <token>UserHolder.save(userId)(ThreadLocal 封装),Service 层随时UserHolder.get()拿到当前用户,避免层层传参。关键代码:
@Component public class LoginInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String token = request.getHeader("Authorization"); if (token == null || !token.startsWith("Bearer ")) throw new BizException("缺失令牌"); String userId = JwtUtil.verify(token.substring(7)); UserHolder.save(Long.valueOf(userId)); // ThreadLocal return true; } }BaseMapper<T>即可。PageResp<T>,前端无感知。@RestController @RequestMapping("/book") public class BookController { @Resource private BookService bookService; @GetMapping public PageResp<BookDTO> list(@RequestParam(defaultValue = "1") int current, @RequestParam(defaultValue = "10") int size) { return bookService.pageBooks(current, size); } }@Transactional只加在 Service写操作公有方法,且同类内调用无效(Spring AOP 代理限制)。@Service public class OrderService { @Transactional(rollbackFor = Exception.class) // 显式声明回滚 public Long createOrder(CreateOrderDTO dto){ // 1. 扣减库存 boolean ok = bookMapper.decreaseStock(dto.getBookId(), dto.getQuantity()); if (!ok) throw new BizException("库存不足"); // 2. 创建订单 OrderEntity order = OrderEntity.builder() .userId(UserHolder.get()) .bookId(dto.getBookId()) .quantity(dto.getQuantity()) .build(); orderMapper.insert(order); return order.getId(); } }R<T>,含code、msg、data三字段。@Getter @AllArgsConstructor public enum ResultCode { SUCCESS(0, "成功"), PARAM_ERROR(1001, "参数错误"), UNAUTHORIZED(2001, "未登录"), SYSTEM_ERROR(5001, "系统繁忙"); private final int code; private final String msg; }#{}占位符已防,禁止${}拼接。clientId字段,数据库建唯一索引(user_id, client_id),重复提交直接返回原订单号。left join一次把关联字段带出,关闭延迟加载,否则循环取列表会爆炸。server.port=8080,服务器若被占用,启动即挂。application-prod.yml改成 8081 并加server.servlet.context-path=/secondbook,Nginx 反代时不会冲突。logging.file.path=/var/log/secondbook提前建好目录并赋权,否则 Spring Boot 默认写/tmp,重启系统日志被清空。maximum-pool-size=5足够,再大反而 OOM。spring.jackson.time-zone=GMT+8,否则订单时间差 8 小时,答辩现场翻车。mvn package+scp到云主机重启服务,全程 3 分钟,老师看你当场发版,印象分 +20。下图是“校园二手书平台”最小骨架,每个箭头都能一句话讲清作用,答辩 PPT 直接贴。
毕业设计不是“最后一门课”,而是第一次真正对自己代码全生命周期负责。把本文模板跑通后,不妨问自己三个问题:
能回答清楚,你就拥有了工程能力——这比任何新技术都保值。祝你答辩顺利,把“坑”留给文章,把亮点留给自己。