欢迎光临
我们一直在努力

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

 🔥个人主页:北极的代码(欢迎来访) 🎬作者简介:java后端学习者 ❄️个人专栏:苍穹外卖日记,SSM框架深入,JavaWeb ✨命运的结局尽可永在,不屈的挑战却不可须臾或缺!

前言:上一章节我们对项目的公共字段进行整体的赋值,利用反射和AOP的原理,这一阶段我们将进行新增菜品的操作,具体操作原理以及难点的业务逻辑分析。

新增菜品的接口分析:

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

然后,我们分析功能需求,

  • 保存菜品基本信息

  • 上传菜品图片

  • 保存菜品与分类的关联关系

  • 返回新增菜品的ID

  • 数据校验(防止重复、非法数据)

2.1 HTTP方法选择

操作方法说明
新增 POST 向服务器提交数据
查询 GET 获取数据
修改 PUT/PATCH 更新数据
删除 DELETE 删除数据

结论:新增菜品 → POST

2.2 URL设计

// RESTful 风格 POST /api/dishes // 新增菜品 POST /api/category/{id}/dishes // 向指定分类添加菜品 // 实际选择 POST /api/admin/dishes // 后台管理接口

2.3 请求参数设计

JSON提交

// 定义请求对象
@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; // 口味选项
// 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的目的是接收前端传过来的图片,从而为接下来的操作准备。不仅仅是菜品的,套餐服务需要上传图片时也能使用。

@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 代码通过对象获取配置,改配置不用改代码,类型安全,有代码提示

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

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(创建对象)

/**
* 配置类,用于创建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. 放进容器 → 以后谁要就给谁,所以可以注入。

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

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

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); }

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

赞(0)
未经允许不得转载:171主机测评 » 苍穹外卖菜品管理:新增功能实战解析
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址