news 2026/4/18 5:14:26

基于SpringBoot的Java毕设入门实战:从零搭建高内聚低耦合的后端架构

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于SpringBoot的Java毕设入门实战:从零搭建高内聚低耦合的后端架构


背景痛点:为什么你的毕设总是一团麻

做毕设最怕“跑起来就行”。很多同学把代码全写在 Controller 里,一个方法里既查库又算折扣还顺手发邮件,结果:

  • 需求一改,牵一发动全身,调试靠“打桩+重启”;
  • Service 层复制粘贴,同名变量满天飞,自己三天后都看不懂;
  • 事务注解乱贴,付款失败订单却生成,老师一问就“偶发”;
  • 部署到服务器,日志一屏红,敏感信息直接 console 打印,现场翻车。

归根结底:缺一套“能讲清楚、能改得动、能跑得稳”的骨架。下面这套 SpringBoot 3.x 模板,是我当年答辩 90→95 分的翻盘笔记,今天拆给你。

技术选型:为什么不是 JPA、不是 Spring Security 全家桶

  1. SpringBoot 3.x:内置虚拟线程、原生编译支持,答辩提到“新技术”能加分。
  2. MyBatis-Plus:
    • 比 JPA 好写复杂 SQL,毕设里多表统计、模糊分页是常态;
    • 内置代码生成器,两分钟撸完 Entity→Mapper→Service→Controller,肉眼可见节约时间。
  3. H2(本地)+ MySQL(生产):
    • H2 文件模式,git push 即走,队友拉下来直接跑,0 搭建成本;
    • 切到 MySQL 只需改一条 jdbc-url,答辩演示“秒级切换”很帅。
  4. Lombok:消灭 60% Get/Set/Builder,代码行数立降,老师一眼看过去“清爽”。
  5. 不选 Spring Security:
    • 对新手太重,过滤器链讲半小时都说不清;
    • JWT 自己写 80 行就够,答辩能讲清“签发→验签→续期”三步,反而体现掌握。

核心实现:一张图先看清包结构

com.example.demo ├── controller // 仅处理 http,一行业务逻辑都不写 ├── service // 事务边界,一个 public 方法一个事务 ├── mapper // MyBatis-Plus,纯 CRUD ├── domain // 仅含 POJO/实体,不依赖任何框架 ├── common │ ├── config // 全局配置(MyBatis、Redis、JWT) │ ├── exception // 统一异常+返回封装 │ └── utils // 雪花算法、JwtUtil、BCrypt DemoApplication.java

1. 分层约定

  • Controller 只做三件事:参数校验、调用 Service、返回 VO。
  • Service 绝不出现 HttpServletRequest,保证以后可无缝迁移到 Dubbo。
  • Mapper 层禁止手写 SQL 拼接,全部用 MyBatis-Plus 条件构造器,防注入。

2. RESTful 路由规范

GET /api/users 列表 POST /api/users 新增 GET /api/users/{id} 详情 PUT /api/users/{id} 全量更新 PATCH /api/users/{id}/status 局部更新 DELETE /api/users/{id} 删除

统一返回体:

@Getter @AllArgsConstructor public class R<T> { private int code; private String msg; private T data; public static <T> R<T> ok(T data){ return new R<>(200,"success",data); } public static R<Void> fail(String msg){ return new R<>(500,msg,null); } }

3. 全局异常拦截

@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(BizException.class) public R<Void> handleBiz(BizException e){ return R.fail(e.getMessage()); } @ExceptionHandler(Exception.class) public R<Void> handleAll(Exception e){ log.error("系统异常", e); return R.fail("服务器开小差~"); } }

业务里想抛就抛,Controller 里看不见 try-catch,清爽。

4. JWT 基础认证(最简版)

工具类:

public class JwtUtil { private static final String KEY = "demo2025"; private static final long EXPIRE = 864_000_00; // 1d public static String create(Long userId){ return Jwts.builder() .setSubject(userId.toString()) .setExpiration(new Date(System.currentTimeMillis()+EXPIRE)) .signWith(SignatureAlgorithm.HS256, KEY) .compact(); } public static Long parse(String jwt){ try{ String sub = Jwts.parser().setSigningKey(KEY) .parseClaimsJws(jwt).getBody().getSubject(); return Long.valueOf(sub); }catch(JwtException e){ return null; } } }

拦截器:

@Component public class JwtInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest rq, HttpServletResponse rp, Object h) throws Exception { String token = rq.getHeader("Authorization"); if(token==null不设Bearer) throw new BizException("缺少令牌"); Long uid = JwtUtil.parse(token.replace("Bearer ","")); if(uid==null) throw new BizException("令牌无效"); rq.setAttribute("uid",uid); // 下游直接取 return true; } }

注册拦截器放过登录接口即可,答辩时老师问“怎么保证安全”——答:签名密钥存服务器,过期可续期,敏感接口全拦截。

完整代码示例:User 模块 CRUD

下面代码全部可跑,注释已写好,直接粘。

1. 实体 & 枚举

@Data @TableName("t_user") public class User { @TableId(type = IdType.ASSIGN_ID) // 雪花算法 private Long id; private String username; private String password; // 已加密 private Integer status; // 0=禁用 1=启用 private LocalDateTime createTime; }

2. Mapper

public interface UserMapper extends BaseMapper<User> { // 连表统计自己写,简单 CRUD 直接用 IService }

3. Service 接口 & 实现

public interface IUserService extends IService<User> { Long createUser(UserDTO dto); void disable(Long id); } @Service @RequiredArgsConstructor public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements IUserService { @Override @Transactional(rollbackFor = Exception.class) public Long createUser(UserDTO dto){ // 1. 重复名校验 long c = lambdaQuery().eq(User::getUsername,dto.getUsername()).count(); if(c>0) throw new BizException("用户名已存在"); // 2. 加密 User u = new User(); u.setUsername(dto.getUsername()); u.setPassword(BCrypt.hashpw(dto.getPassword(), BCrypt.gensalt())); u.setStatus(1); u.setCreateTime(LocalDateTime.now()); // 3. 落库 save(u); return u.getId(); } @Override @Transactional public void disable(Long id){ lambdaUpdate().set(User::getStatus,0).eq(User::getId,id).update(); } }

4. Controller

@RestController @RequestMapping("/api/users") @RequiredArgsConstructor public class UserController { private final IUserService userService; @PostMapping public R<Long> create(@Valid @RequestBody UserDTO dto){ return R.ok(userService.createUser(dto)); } @GetMapping("/{id}") public R<UserVO> get(@PathVariable Long id){ User u = userService.getById(id); if(u==null) throw new BizException("用户不存在"); UserVO vo = new UserVO(); BeanUtils.copyProperties(u,vo); return R.ok(vo); } @PatchMapping("/{id}/status") public R<Void> disable(@PathVariable Long id){ userService.disable(id); return R.ok(null); } }

DTO/VO 用 MapStruct 转,篇幅略。至此,User 模块写完,Service 层一个 public 方法一个事务,回滚点清晰。

性能与安全:把“能跑”升级成“敢上线”

  1. SQL 注入:MyBatis-Plus 条件构造器内部预编译,只要不用wrapper.apply("xxx="+var)就安全。
  2. 密码加密:BCrypt 加盐,明文在任何日志里不可见。
  3. 接口幂等:
    • 新增带“username 唯一”约束,重复重试会抛业务异常,天然幂等;
    • 更新用乐观锁@Version,更新行数=0 抛“数据已变更”提示。
  4. 关键日志脱敏:
log.info("用户注册: username={}", username.replaceAll("(?<=\\w{2})\\w","*"));
  1. 慢 SQL 监控:MyBatis-Plus 自带PerformanceInterceptor,超 500ms 自动打印,答辩展示“性能保障”。

生产环境避坑 6 条

  1. Controller 直接调 Mapper → 事务失效,Service 层必须包一层。
  2. 配置分离:
    application.yml只放默认,真实密码放在application-prod.yml,服务器上用环境变量覆盖,git 不留痕。
  3. 禁止用System.out→ 用 Slf4j + Logback,文件按天滚动,日志目录外挂硬盘,防止打爆磁盘。
  4. 跨域放生产:
    spring.web.cors.allowed-origins=https://www.xxx.com,不要写*
  5. 文件上传别放工程目录,单独建/data/upload,重启容器不丢。
  6. 服务器时间不同步会导致 JWT 验签失败,装 ntpdate 定时同步。

结语:把模板变成你自己的“高分作品”

上面这套骨架,我帮三位学弟套过外卖、二手书、实验室预约三个完全不同业务的毕设,平均答辩分数 92。它最大的价值不是代码行数,而是“能讲清”——每层职责、每个异常、每条日志都能回答老师“为什么”。

下一步,把 demo 拉下来,删掉 User,换上你的业务:课程?宠物?民宿?重构过程中你会遇到“一对多分页”“多角色鉴权”“分布式文件”等真实问题,再把解决过程写进论文,那就是货真价实的“工作量”。

祝你编码愉快,答辩时也能自信地说:
“我的系统支持水平扩展,下一版加微服务只需换注解,老师您要看哪个模块?”


版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 1:42:10

Docker Compose+低代码平台实战:5个被90%团队忽略的配置陷阱及修复清单

第一章&#xff1a;Docker Compose与低代码平台融合的底层逻辑 Docker Compose 与低代码平台的融合并非简单的工具叠加&#xff0c;而是基于“可编程基础设施”与“可视化抽象层”之间的双向解耦与语义对齐。其底层逻辑根植于声明式配置、服务契约标准化和运行时环境一致性三大…

作者头像 李华
网站建设 2026/3/13 9:46:49

基于Coze构建企业级内部智能客服:从架构设计到生产环境部署

基于Coze构建企业级内部智能客服&#xff1a;从架构设计到生产环境部署 一、背景痛点&#xff1a;传统工单系统“慢”在哪 去年我们内部做过一次统计&#xff1a; 平均工单响应时间 2.3 h多轮追问的二次响应率只有 38 %运维同学每月要花 2 人日专门“调规则”——正则一改&am…

作者头像 李华
网站建设 2026/4/8 19:36:49

如何设计高效的ChatGPT提示词:课题与实验设计的最佳实践

背景痛点&#xff1a;为什么你的提示词总让 ChatGPT 跑题&#xff1f; 在课题或实验设计阶段&#xff0c;很多开发者把 ChatGPT 当成“万能搜索引擎”——甩一句“帮我设计一个实验”就坐等惊喜。结果往往得到&#xff1a; 研究目标漂移&#xff1a;模型默认走“大众科普”路…

作者头像 李华
网站建设 2026/4/18 0:18:17

信息学奥赛实战解析:图像相似度算法实现与优化

1. 图像相似度算法基础入门 第一次接触图像相似度计算时&#xff0c;我也被这个看似高大上的概念吓到了。但实际动手后发现&#xff0c;它的核心思想简单得令人惊讶——就像玩"找不同"游戏一样&#xff0c;只不过这次是让计算机来帮我们数数。 图像相似度计算本质上…

作者头像 李华