首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >苍穹外卖菜品管理:新增功能实战解析

苍穹外卖菜品管理:新增功能实战解析

作者头像
北极的代码
发布2026-04-22 18:19:51
发布2026-04-22 18:19:51
650
举报
前言:上一章节我们对项目的公共字段进行整体的赋值,利用反射和AOP的原理,这一阶段我们将进行新增菜品的操作,具体操作原理以及难点的业务逻辑分析。

新增菜品的接口分析:

首先,我们要分析业务需求,菜品名称,价格,分类,描述,图片,以及库存数量,口味选项,以及上架状态。 然后,我们分析功能需求,

  • 保存菜品基本信息
  • 上传菜品图片
  • 保存菜品与分类的关联关系
  • 返回新增菜品的ID
  • 数据校验(防止重复、非法数据)
2.1 HTTP方法选择

操作

方法

说明

新增

POST

向服务器提交数据

查询

GET

获取数据

修改

PUT/PATCH

更新数据

删除

DELETE

删除数据

结论:新增菜品 → POST

2.2 URL设计
代码语言:javascript
复制
// RESTful 风格 POST /api/dishes // 新增菜品 POST /api/category/{id}/dishes // 向指定分类添加菜品 // 实际选择 POST /api/admin/dishes // 后台管理接口
2.3 请求参数设计

JSON提交
代码语言:javascript
复制
// 定义请求对象
@Data
public class DishAddRequest {
    @NotBlank(message = "菜品名称不能为空")
    private String name;
    
    @NotNull(message = "价格不能为空")
    @DecimalMin(value = "0.01", message = "价格必须大于0")
    private BigDecimal price;
    
    @NotNull(message = "分类不能为空")
    private Long categoryId;
    
    private String description;
    
    private List<String> imageUrls;  // 图片URL列表
    
    @NotNull(message = "库存不能为空")
    @Min(value = 0, message = "库存不能小于0")
    private Integer stock;
    
    private Boolean status = true;  // 默认上架
    
    private List<DishFlavor> flavors;  // 口味选项
代码语言:javascript
复制
// Controller
@PostMapping("/dishes")
public Result<Long> addDish(@RequestBody @Valid DishAddRequest request) {
    Long dishId = dishService.addDish(request);
    return Result.success(dishId);
}

适用:纯数据提交,图片可先上传返回URL

2.4 返回结果设计

也就是定义一个Result类

总结:

维度

检查项

是否完成

功能

是否满足业务需求

参数

参数是否完整、合理

校验

是否有参数校验和业务校验

安全

是否有权限控制

幂等

重复提交是否有防护

返回

返回格式是否统一

文档

是否有API文档

测试

是否有单元测试

具体实现:

文件上传接口的开发: 前端通过浏览器进行图片上传,之后把图片传到后端,后端不是把图片上传到后端服务器,而是将图片上传到阿里云对象存储服务OSS,推荐使用阿里云OSS,核心是为了让专业的工具做专业的事:你的后端专注于业务逻辑,而图片的存储、分发、处理这些复杂且通用的工作,交给阿里云这样专业的云服务商来处理,最终实现更高效、更稳定、更省钱

根据文件上传的接口,我们先创建一个CommonController

设计这个controller的目的是接收前端传过来的图片,从而为接下来的操作准备。不仅仅是菜品的,套餐服务需要上传图片时也能使用。

代码语言:javascript
复制
@RestController
@RequestMapping("/admin/common")
@Slf4j
@Api(tags = "通用接口")
public class CommonController {
    /**
     * 文件上传
     * @param file
     * @return
     */
    @PostMapping("/upload")
    @ApiOperation("文件上传")
    public Result<String> upload(MultipartFile file){//注意,这里面的参数必须要和前端传过来的一样file,不然就接收不到前端的图片了,String是返回图片的路径,用于用户查看照片,可以直接调用这个路径
        log.info("文件上传:{}",file);
        //把文件上传到阿里云服务

我们需要在配置文件中配置阿里云OSS:

需要注意的是,我们在项目中还创建了一个AliOssProperties类,这个类加上了注解@ConfigrationProperties,这种类是读取配置文件的配置项,然后把这些封装成java对象。

  • Java 代码通过对象获取配置,改配置不用改代码,类型安全,有代码提示

这样就把配置信息业务代码分离开,实现了更好的代码组织和维护性。

代码语言:javascript
复制
alioss:
  endpoint: ${sky.alioss.endpoint}
  access-key-id: ${sky.alioss. access-key-id}
  access-key-secret: ${sky.alioss.access-key-secret}
  bucket-name: ${sky.alioss.bucket-name}

初始化AliOssUtil(创建对象)

代码语言:javascript
复制
/**
 * 配置类,用于创建AliUtil对象
 */
@Configuration
@Slf4j
public class OssConfiguration {
    @Bean
    @ConditionalOnBean
    public AliOssUtil aliOssUtil(AliOssProperties aliOssProperties){
        log.info("开始创建阿里云工作类对象,{}",aliOssProperties);
     return    new AliOssUtil(aliOssProperties.getEndpoint(),
             aliOssProperties.getAccessKeyId(),
             aliOssProperties.getAccessKeySecret(),
             aliOssProperties.getBucketName());
客户端对象对比Util

对比项

客户端对象 (OSSClient)

Util类对象 (AliOssUtil)

谁写的

阿里云官方

你自己

数量

通常只有一个(单例)

通常只有一个(单例)

复杂度

高(几十个方法)

低(只有几个你需要的方法)

依赖

内部包含客户端对象

配置

每次用都要配置

初始化时配置一次

异常处理

抛出原始异常

统一处理成业务异常

复用性

低(每个地方都要写重复代码)

高(一个方法到处用)

测试难度

难(依赖真实网络)

易(可mock客户端)

客户端对象是阿里云提供的"真工人",Util类对象是你雇来管理工人的"包工头"——包工头让工人干活更规范、更方便,你只需要跟包工头打交道就行。

对象

角色

比喻

OSSClient

执行者

洗碗工

AliOssUtil

封装者

洗碗机

你的Service

使用者

餐厅老板

注解辨析

代码概念

现实比喻

@Configuration

"我是总店长"的胸牌

@Bean

"我负责采购这些设备"的采购清单

AliOssUtil

奶茶机

OssProperties

设备说明书(配置参数)

application.yml

总部发的统一采购标准

@Autowired

各门店领用设备

注解

作用

比喻

@Configuration

标记类是配置类

挂上"总店"招牌

@Bean

标记方法是创建Bean的方法

写出"采购清单"

角色

比喻

是否需要@Configuration

OssConfiguration

配置类

总店长(负责采购)

需要 @Configuration

AliOssUtil

工具类

奶茶机(干活的)

不需要

OssProperties

属性类

设备说明书

不需要

@Configuration是挂牌子,@Bean是写采购清单——挂了总店的牌子(@Configuration)还不够,必须写明要采购什么设备(@Bean),仓库(Spring容器)才知道要准备什么!

关于在阿里云oss中的设置(补充)

我们只需要设置一个用于存储文件的Bucket

关于用量的问题,由于我们是用于个人的测试为主,因此我们不需要设置成公共的,设置成私人即可。

补充cotroller层中的方法:

由于我们已经创建了AliOssUtil的对象,所以直接其中注入,因为是被Spring管理的

// Spring启动时: // 1. 看到@Configuration → 哦,这是配置类 // 2. 看到@Bean → 哦,这个方法返回的对象要管理 // 3. 执行方法 → 创建AliOssUtil对象 // 4. 放进容器 → 以后谁要就给谁,所以可以注入。

代码语言:javascript
复制
┌─────────────────┐
│  OssProperties  │ ← 读取配置
└────────┬────────┘
         ↓
┌─────────────────┐
│OssConfiguration │ ← 配置类,创建Bean
└────────┬────────┘
         ↓
┌─────────────────┐
│   AliOssUtil    │ ← 工具类,真正干活
└────────┬────────┘
         ↓
┌─────────────────┐
│ 业务Service     │ ← 使用工具类
└─────────────────┘
代码语言:javascript
复制

然后在controller中调用工具类中的上传文件的方法,里面有两个参数,一个是byte数组,另一个是文件名,用UUID生成的,避免文件名重复产生错误。

代码语言:javascript
复制
log.info("文件上传:{}",file); //把文件上传到阿里云服务 try { //原始文件名 String originalFilename = file.getOriginalFilename(); //截取原始文件名的后缀 String extension = originalFilename.substring(originalFilename.lastIndexOf(".")); //构造新文件名名称 String objectName= UUID.randomUUID().toString()+extension; //文件的地址/网址 String filePath = aliOssUtil.upload(file.getBytes(), objectName); return Result.success(filePath); } catch (IOException e) { log.info("文件上传失败,{}",e); }

结语:感谢看到最后的大家,如果对你有帮助,请点赞,关注,收藏,你的鼓励就是我最大的动力!!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2026-04-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 新增菜品的接口分析:
    • 2.1 HTTP方法选择
    • 2.2 URL设计
    • 2.3 请求参数设计
    • 2.4 返回结果设计
  • 总结:
  • 具体实现:
    • 根据文件上传的接口,我们先创建一个CommonController
    • 我们需要在配置文件中配置阿里云OSS:
    • 初始化AliOssUtil(创建对象)
      • 客户端对象对比Util
      • 注解辨析
    • 关于在阿里云oss中的设置(补充)
    • 补充cotroller层中的方法:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档