瑞吉外卖项目,后端源码解析

发现这个项目非常适合作为 SpringBoot 入门案例。它涵盖了企业级应用开发的常见场景,包括 RESTful 接口设计、MyBatis-Plus 实战、事务管理等核心知识点。今天就带大家深入剖析一下瑞吉外卖的源码设计与实现思路。

一、后端整体架构

瑞吉外卖采用经典的三层架构设计,整体结构清晰,职责分明:

bash 复制代码
com.itheima.reggie
├── controller     // 控制器层,处理HTTP请求
├── service        // 业务逻辑层
│   └── impl       // 业务逻辑实现
├── mapper         // 数据访问层
├── entity         // 实体类
├── dto            // 数据传输对象
├── common         // 公共组件
├── config         // web mybatis等配置
├── filter         // 登录过滤器
├── utils         // 常用工具类
└── ReggieApplication.java  // 启动类

这种架构设计符合单一职责原则,每层只关注自己的核心功能:

  • 控制器层:负责接收请求、参数校验、返回响应
  • 服务层:实现核心业务逻辑,处理事务
  • 数据访问层:与数据库交互
  • 实体类:映射数据库表结构
  • DTO:处理跨层数据传输,避免暴露实体类细节

二、后端核心技术点

1. 统一响应结果封装

项目中定义了R类作为统一响应结果封装,这是企业开发中的最佳实践:

bash 复制代码
// 动态数据
public static <T> R<T> success(T object) {
    R<T> r = new R<T>();
    r.data = object;
    r.code = 1;
    return r;
}

这种设计的优势在于:

  • 前后端交互格式统一,便于前端处理
  • 包含状态码,方便错误排查
  • 泛型设计支持各种数据类型的返回

2. MyBatis-Plus 的实战应用

项目大量使用了 MyBatis-Plus 简化数据库操作,以DishController中的分页查询为例:

java 复制代码
@GetMapping("/page")
public R<Page> page(int page, int pageSize, String name){
    // 分页构造器对象
    Page<Dish> pageInfo = new Page<>(page,pageSize);
    Page<DishDto> dishDtoPage = new Page<>();

    // 条件构造器
    LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.like(name != null,Dish::getName,name);
    queryWrapper.orderByDesc(Dish::getUpdateTime);

    // 执行分页查询
    dishService.page(pageInfo,queryWrapper);
    
    // 对象拷贝与处理...
    return R.success(dishDtoPage);
}

MyBatis-Plus 的优势在这里体现得淋漓尽致:

  • 无需编写 XML,通过 LambdaQueryWrapper 构建查询条件
  • 内置分页插件,一行代码实现分页功能
  • 丰富的 CRUD 方法,极大减少重复代码

3. 事务管理

在涉及多表操作的场景中,事务管理至关重要。项目中使用@Transactional注解实现事务控制:

java 复制代码
@Transactional
public void saveWithFlavor(DishDto dishDto) {
    // 新增菜品的基本信息到菜品表dish
    this.save(dishDto);
    Long dishId = dishDto.getId();//获取菜品id
    
    // 处理口味数据
    List<DishFlavor> flavors = dishDto.getFlavors();
    flavors = flavors.stream().map((item) -> {
        item.setDishId(dishId);
        return item;
    }).collect(Collectors.toList());
    
    // 新增菜品口味数据到菜品口味表dish_flavor
    dishFlavorService.saveBatch(flavors);
}

这个方法同时操作了dishdish_flavor两张表,使用@Transactional确保了数据的一致性。

4. DTO 模式的应用

项目中大量使用 DTO(数据传输对象)模式,以DishDto为例:

java 复制代码
@Data
public class DishDto extends Dish {
    // 菜品对应的口味数据
    private List<DishFlavor> flavors = new ArrayList<>();
    private String categoryName;
    private Integer copies;
}

DTO 的主要作用:

  1. 封装前端需要的复杂数据,减少请求次数
  2. 避免直接暴露实体类,提高安全性
  3. 适配前端视图模型,降低前后端耦合

三、核心业务功能

1. 菜品管理模块

菜品管理涉及菜品基本信息和口味信息的维护,这是一个典型的一对多关系处理场景。

DishServiceImpl中,saveWithFlavor方法实现了菜品和口味的同时保存:

  1. 先保存菜品基本信息
  2. 获取生成的菜品 ID
  3. 给所有口味设置菜品 ID
  4. 批量保存口味信息

这种实现方式既高效又保证了数据的完整性。

2. 套餐管理模块

套餐管理与菜品管理类似,但更复杂一些,因为套餐包含多个菜品。

SetmealController中,save方法接收SetmealDto对象,通过setmealService.saveWithDish方法实现套餐和套餐菜品关系的保存:

java 复制代码
@PostMapping
public R<String> save(@RequestBody SetmealDto setmealDto){
    log.info("套餐信息:{}",setmealDto);
    setmealService.saveWithDish(setmealDto);
    return R.success("新增套餐成功");
}

这种设计遵循了 "聚合根" 设计模式,将套餐作为聚合根,负责管理套餐包含的菜品关系。

3. 购物车与订单模块

购物车和订单是电商系统的核心功能,瑞吉外卖的实现也很有参考价值。

购物车添加功能:

java 复制代码
@PostMapping("/add")
public R<ShoppingCart> add(@RequestBody ShoppingCart shoppingCart){
    // 设置用户ID,确保数据隔离
    Long currentId = BaseContext.getCurrentId();
    shoppingCart.setUserId(currentId);
    
    // 查询是否已存在
    LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(ShoppingCart::getUserId,currentId);
    
    // 根据是菜品还是套餐设置查询条件
    if(dishId != null){
        queryWrapper.eq(ShoppingCart::getDishId,dishId);
    }else{
        queryWrapper.eq(ShoppingCart::getSetmealId,shoppingCart.getSetmealId());
    }
    
    ShoppingCart cartServiceOne = shoppingCartService.getOne(queryWrapper);
    
    // 存在则数量+1,不存在则新增
    if(cartServiceOne != null){
        cartServiceOne.setNumber(cartServiceOne.getNumber() + 1);
        shoppingCartService.updateById(cartServiceOne);
    }else{
        shoppingCart.setNumber(1);
        shoppingCart.setCreateTime(LocalDateTime.now());
        shoppingCartService.save(shoppingCart);
        cartServiceOne = shoppingCart;
    }
    
    return R.success(cartServiceOne);
}

订单提交功能则更为复杂,涉及多表操作和事务控制:

  1. 查询购物车数据
  2. 计算总金额
  3. 保存订单信息
  4. 保存订单明细
  5. 清空购物车

四、总结

瑞吉外卖项目作为 SpringBoot 实战案例非常合适,它涵盖了:

  • RESTful API 设计
  • 分层架构实践
  • ORM 框架应用
  • 事务管理
  • 复杂业务逻辑实现

对于初学者来说,通过这个项目可以快速掌握企业级 Java 开发的核心技能。建议学习时不要只看代码,更要理解其中的设计思想和最佳实践,这样才能真正提升自己的开发水平。

相关推荐
Wokoo78 分钟前
开发者AI大模型学习与接入指南
java·人工智能·学习·架构
南山乐只15 分钟前
【Spring AI 开发指南】ChatClient 基础、原理与实战案例
人工智能·后端·spring ai
电摇小人41 分钟前
我的“C++之旅”(博客之星主题作文)
java·开发语言
资生算法程序员_畅想家_剑魔42 分钟前
Java常见技术分享-23-多线程安全-总结
java·开发语言
萧曵 丶1 小时前
ArrayList 和 HashMap 自动扩容机制详解
java·开发语言·面试
㳺三才人子1 小时前
初探 Spring Framework OncePerRequestFilter
spring boot·spring·junit
这是程序猿1 小时前
基于java的ssm框架学生作业管理系统
java·开发语言·spring boot·spring·学生作业管理系统
千百元1 小时前
限制网段访问服务器端口63790
java·网络·mybatis
宋情写1 小时前
JavaAI03-数据来源
java
钦拆大仁1 小时前
JDK17新特性
java