Java Web项目—餐饮管理系统Day05-菜品管理

文章目录

      • 1. 表结构与菜品展示页面
      • 2. 菜品的分类选择
      • 3. 图片的上传与下载
      • 4. 新增菜品
      • 5. 分页展示菜品
      • 6. 修改菜品
        • 6-1. 菜品信息回显
        • 6-1. 菜品信息更新

开始进行 Dish 菜品管理相关的开发. 该表包含一个图片字段, 需要上传图片以及图片回显的业务.
另外, 每个菜品可能包含多个口味选择, 例如 甜度, 辣度 等等. 因此需要单独一张表格存储: dish_flavor
表格的一行保存: dish_id, 对应的口味(其中一种)名称, 对应的口味(其中一种)可选列表 等等.

1. 表结构与菜品展示页面

id
name
category_id
price
code
image
description
status
sort
create_time
update_time
create_user
update_user
is_deleted

在这里插入图片描述

id
dish_id
name
value
create_time
update_time
create_user
update_user
is_deleted

在这里插入图片描述

2. 菜品的分类选择

在界面上, 需要展示菜品分类的下拉列表, 因此需要一个依据分类类型查询所有分类的业务函数, 它位于CategoryController

@GetMapping("list")
public R<List<Category>> getAllCat(Integer type){
    log.info("查询键值: {}", type);
    LambdaQueryWrapper<Category> wrapper = new LambdaQueryWrapper<>();
    wrapper.eq(Category::getType, type);
    List<Category> res = service.list(wrapper);
    return R.success(res);
}

3. 图片的上传与下载

采用的是用户上传, 服务器下载保存的形式
上传图片, POST请求: /common/upload/, 使用 MultipartFile 类接收, 随后就是将文件流转存.
注意首先要生成一个新的文件名, 其次规定图片的临时存储地址, 随后进行转存:

my-config:
  basic-cache-dir: D:/cache/reggie/

通过 value 注解进行注入:

@RestController
@RequestMapping("common")
@Slf4j
public class UpDownLoadController {
    @Value("${my-config.basic-cache-dir}")
    private String cacheRoot;

    @PostMapping("upload")
    public R<String> upload(MultipartFile file){
        log.info("接收到文件 {}, 大小 {}", file.getName(), file.getSize());
        File rootDir = new File(cacheRoot);
        if (!rootDir.exists())
            rootDir.mkdirs()
        String orgName = file.getOriginalFilename();
        String suffix = orgName.substring(orgName.lastIndexOf('.'));
        String newFileName = UUID.randomUUID() + suffix;
        try {
            file.transferTo(Paths.get(cacheRoot + newFileName));
        } catch (IOException e) {
            throw new BusinessException(e.getMessage());
        }
        return R.success(cacheRoot + newFileName);
    }
}

下载, 是指浏览器发送请求后服务器需要将指定的文件资源写入到响应中的过程.
注意这是一个 Get 请求, 同时这里采用每写入1024字节就刷新一次的方式而不是一次性写入, 注意传输完毕后关闭流:

@GetMapping("download")
public R<String> download(String name, HttpServletResponse response){
    log.info("发送文件(用于客户端浏览器下载或展示): {}", name);
    try{
        FileInputStream inputStream = new FileInputStream(name);
        ServletOutputStream outputStream = response.getOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        while (true){
            len = inputStream.read(buffer);
            if (len == -1)
                break;
            outputStream.write(buffer);
            outputStream.flush();
        }
        inputStream.close();
        outputStream.close();
        return R.success("下载成功");
    } catch (IOException e) {
        throw new BusinessException(e.getMessage());
    }
}

此时, 在新增菜品的页面就可以正常上传和展示图片了.

4. 新增菜品

新增菜品的页面要素基本齐全, 接下来就是接收传入参数, 并把数据插入到对应表格.

@PostMapping
public R<String> insert(@RequestBody DishDto dishDto){
    log.info("接收到菜品信息: {}", dishDto);
    service.addWithFlavor(dishDto);
    return R.success("添加成功");
}

注意此时前端传入的数据并非恰好对应某一个实体类, 例如:

  1. 菜品的口味, 这些数据要存到 dish_flavor 表
  2. 菜品的分类, 传入的是分类名称, 但 Dish 实体类存储的是分类的 id.
    为了接收这些数据, 需要创建一个 DTO 类(Data Transfer Object), 即 DishDto:
package com.rain.reggie.dto;

@Data
public class DishDto extends Dish{
    private List<DishFlavor> flavors;
    private String categoryName;
    private Integer copies;
}

需要在 service 层编写 addWithFlavor 方法, 显然, 应当先执行插入操作保存 Dish 信息. 此时, 该条记录(Dish)在插入后会自动获得一个 id(a), 取出 flavors 字段, 遍历该列表, 设置其中的 dish_id 为a.

 @Override
public void addWithFlavor(DishDto dishDto) {
    this.save(dishDto);
    Long dishId = dishDto.getId();
    List<DishFlavor> flavors = dishDto.getFlavors();
    flavors = flavors.stream().map(
            (item)->{
                item.setDishId(dishId);
                return item;
            }
    ).collect(Collectors.toList());
    flavorService.saveBatch(flavors);
}

5. 分页展示菜品

同样需要处理多表格查询的问题, 前端发来请求:
http://localhost:8080/dish/page?page=1&pageSize=10&name=aaa
这里是指, 假如仅仅是查询 Dish 表格, 得到的信息无法为前端页面提供足够的信息, 例如菜品的分类名称, 这需要查询分类表.
同时需要借助于 DishDto 类, 尽管此时已经不需要口味相关的信息.

基本步骤是:

  1. 新建 Dish 的 Page 和 Wrapper, 调用 dishService 查询得到 dishPage.
  2. 新建 DishDto 的 Page 对象 info, 将 dishPage 的属性值复制到 info 中, 忽略 records 的值.
  3. 初始化一个空的 DishDto 列表 dl, 遍历 dishPage 的 records, 对于每一个 r:
    1. 取得 category_id, 调用 categoryService 获取到对应 Category 对象, 取得 categoryName.
    2. 新建 DishDto 对象 d, 将 r 的属性值复制给 d, 将 d 的 categoryName 字段设置为刚才查询到的值.
    3. 将 d 加入到 dl.
  4. 将 info 的 records 属性设置为 dl.
  5. 将 info 包装到 R 返回.
@GetMapping("page")
public R<Page> page(int page, int pageSize, String name){
    LambdaQueryWrapper<Dish> wrapper = new LambdaQueryWrapper<>();
    Page<Dish> info = new Page<>(page, pageSize);
    wrapper.like(name!=null, Dish::getName, name);
    wrapper.orderByDesc(Dish::getUpdateTime);
    service.page(info);

    Page<DishDto> dtoPage = new Page<>();
    BeanUtils.copyProperties(info, dtoPage, "records");
    List<Dish> dishes = info.getRecords();
    List<DishDto> records = new ArrayList<>();
    for (Dish d: dishes){
        Long cat_id = d.getCategoryId();
        Category category = categoryService.getById(cat_id);
        DishDto rec = new DishDto();
        BeanUtils.copyProperties(d, rec);
        rec.setCategoryName(category.getName());
        records.add(rec);
    }
    dtoPage.setRecords(records);
    return R.success(dtoPage);
}

6. 修改菜品

在于两个点, 一是菜品信息回显, 需要一个依据菜品id查询到菜品基本信息以及菜品口味的信息.

二是具体修改, 需要修改菜品的基本信息以及口味信息, 由于菜品口味信息可删除或者可添加, 尽管也是修改了数据表, 但实际上并非针对某一条或者某一批数据条目中某些字段的修改, 可以认为是由删除操作和插入操作结合而来.

6-1. 菜品信息回显

请求参数 dish_id 位于请求路径中:

// DishController
@GetMapping("{dishId}")
public R<DishDto> getDishById(@PathVariable Long dishId){
    log.info("获取菜品信息(包括口味){}", dishId);
    DishDto dishDto = service.getDishWithFlavor(dishId);
    return R.success(dishDto);
}

DishService 中编写 getDishWithFlavor 方法:

public DishDto getDishWithFlavor(Long dishId){
    Dish dish = this.getById(dishId);
    DishDto dishDto = new DishDto();
    BeanUtils.copyProperties(dish, dishDto);

    LambdaQueryWrapper<DishFlavor> wrapper = new LambdaQueryWrapper<>();
    wrapper.eq(DishFlavor::getDishId, dishId);
    List<DishFlavor> flavors = flavorService.list(wrapper);
    dishDto.setFlavors(flavors);
    
    return dishDto;
}
6-1. 菜品信息更新

此时请求为 PUT 请求, 参数包装在 json 数据中:

@PutMapping
public R<String> update(@RequestBody DishDto dishDto){
    log.info("更新菜品: {}", dishDto);
    service.updateWithFlavor(dishDto);
    return R.success("更新成功");
}

DishService 中编写 updateWithFlavor 方法:

@PutMapping
public void updateWithFlavor(DishDto dishDto){
    this.updateById(dishDto);
    LambdaQueryWrapper<DishFlavor> wrapper = new LambdaQueryWrapper<>();
    wrapper.eq(DishFlavor::getDishId, dishId);
    flavorService.remove(wrapper);
    Long dishId = dishDto.getId();
    List<DishFlavor> flavors = dishDto.getFlavors();
    flavors = flavors.stream().map(
        (item)->{
            item.setDishId(dishId);
            return item;
        }
    ).collect(Collectors.toList());
    flavorService.saveBatch(flavors);
}

这里仍需对 flavors 的 dishId 进行设置, 这是由于部分口味可能是删除了的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/461544.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot(异常处理)

SpringBoot&#xff08;异常处理&#xff09; 1.基本介绍 2.debug异常处理机制 1.找到 DefaultErrorViewResolver 2.下断点 3.debug启动&#xff0c;浏览器输出一个不存在的页面 4.第一次查找 error/404 1.查看目前要找的视图名 2.准备去查找资源 3.准备从四个默认存放静态资…

测试环境搭建整套大数据系统(十一:docker部署superset,无密码登录嵌入html,http改为https)

一&#xff1a;安装docker 参考文档 https://blog.csdn.net/weixin_43446246/article/details/136554243 二&#xff1a;安装superset 下载镜像。 拉取镜像&#xff08;docker pull amancevice/superset&#xff09; 查看镜像是否下载完成&#xff08;docker images&#xf…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:RichText)

富文本组件&#xff0c;解析并显示HTML格式文本。 说明&#xff1a; 该组件从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。该组件无法根据内容自适应设置宽高属性&#xff0c;需要开发者设置显示布局。 子组件 不包含子组…

广度优先算法(一篇文章讲透)

目录 引言 一、算法概述 二、算法步骤 1 初始化 2 循环处理 三、算法应用 1 图的最短路径问题 2 网络爬虫 3 社交网络分析 4 游戏路径搜索 事例 四、算法特点与性能 五、性能优化 1 剪枝策略&#xff1a; 2 使用高效的数据结构&#xff1a; 3 并行化处理&#…

Machine Vision Technology:Lecture6 Blob detection斑点检测

Machine Vision Technology&#xff1a;Lecture6 Blob detection斑点检测 Blob detectionAchieving scale covarianceRecall&#xff1a;Edge detectionScale selectionBlob detection in 2DCharacteristic scale特征尺度Scale-space blob detectorEfficient implementation&am…

webconfig-boot项目说明

1、前言 最近利用空余时间写了一个项目webconfig-boot 。该项目主要配置了web项目常用的一些配置&#xff0c;如统一参数校验、统一异常捕获、统一日期的处理、常用过滤器、常用注解等。引入依赖接口完成常规的web配置。 这里也是总结了笔者在项目开发中遇到的一些常用的配置…

C语言葵花宝典之——文件操作

前言&#xff1a; 在之前的学习中&#xff0c;我们所写的C语言程序总是在运行结束之后&#xff0c;就会自动销毁&#xff0c;那如果我们想将一个结果进行长期存储应该如何操作呢&#xff1f;这时候就需要我们用文件来操作。 目录 1、什么是文件&#xff1f; 1.1 程序文件 1.2…

2024年AI辅助研发:科技创新的引擎

CSND - 个人主页&#xff1a;17_Kevin-CSDN博客 收录专栏&#xff1a;《人工智能》 技术进展 进入2024年&#xff0c;人工智能&#xff08;AI&#xff09;在科技界和工业界的焦点地位更加巩固&#xff0c;其在辅助研发领域的技术进步尤为显著。深度学习技术的突飞猛进使得数据分…

Window API 使用的一些注意事项

文章目录 1、LPCWSTR类型2、LPCTSTR类型3、LPCSTR类型4、LPCTSTR和LPCWSTR区别5、LPCTSTR和LPCSTR、LPCWSTR三者区别6、_T(" ")7、DWORD类型转换为std::wstring类型8、char类型转换为LPCSTR类型9、获取当前时间戳(毫秒)10、std::wstring和LPCSTR区别11、std::wstring…

漫途桥梁结构安全监测方案,护航桥梁安全!

桥梁作为城市生命线的重要组成部分&#xff0c;承载着城市交通、物流输送、应急救援等重要职能。然而&#xff0c;随着我国社会经济的飞速发展&#xff0c;桥梁所承载的交通流量逐年增长&#xff0c;其安全性所面临的挑战亦日益严峻。例如恶劣的外部环境、沉重的荷载以及长期使…

南大通用数据库-Gbase-8a-学习-43-SQL长时间处于Writing to net状态排查

目录 一、问题截图 二、排查思路 1、Gbase8a SQL有几种状态 2、问题导致原因猜想 3、观察服务端&#xff08;集群端&#xff09;网络情况 4、观察客户端网络情况 5、排查客户端程序处理数据慢 5.1、send &#xff08;1&#xff09;声明 &#xff08;2&#xff09;作用…

springboot“期待相遇”图书借阅系统的设计与实现

摘 要 伴随着我国社会的发展&#xff0c;人民生活质量日益提高。于是对系统进行规范而严格是十分有必要的&#xff0c;所以许许多多的信息管理系统应运而生。此时单靠人力应对这些事务就显得有些力不从心了。所以本论文将设计一套“期待相遇”图书借阅系统&#xff0c;帮助商家…

TS的el-tree数据处理方式,递归

private async initData() {let res await GetAllOranizationInfo()console.log(res数据, res)//获取递归方法return回来的数据this.treeData this.organData(res, null)console.log(tree数据, this.treeData)} private organData(allData: any[], topparentId: string): Tr…

智慧交通:构建智慧城市的重要一环

随着信息技术的飞速发展&#xff0c;智慧城市已成为现代城市发展的重要方向。作为智慧城市的重要组成部分&#xff0c;智慧交通以其高效、便捷、环保的特性&#xff0c;成为推动城市现代化进程的关键力量。本文将从智慧交通的概念、发展现状、面临挑战以及未来趋势等方面&#…

蓝桥杯单片机快速开发笔记——独立键盘

一、原理分析 二、思维导图 三、示例框架 #include "reg52.h" sbit S7 P3^0; sbit S6 P3^1; sbit S5 P3^2; sbit S4 P3^3; void ScanKeys(){if(S7 0){Delay(500);if(S7 0){while(S7 0);}}if(S6 0){Delay(500);if(S6 0){while(S6 0)…

GaN HEMTs在电力电子应用中的交叉耦合与基板电容分析与建模

来源&#xff1a;Analysis and Modeling of Cross-Coupling and Substrate Capacitances in GaN HEMTs for Power-Electronic Applications&#xff08; TED 17年&#xff09; 摘要 本文提出了一种考虑了基板电容与场板之间交叉耦合效应的场板AlGaN/GaN高电子迁移率晶体管(HE…

TOP-K问题

TOP-K问题&#xff1a;即求数据结合中前K个最大的元素或者最小的元素&#xff0c;一情况下数据量都比较大。 比如&#xff1a;专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等。 对于Top-K问题&#xff0c;能想到的最简单直接的方式就是排序&#xff0c;但是&#x…

Python-sklearn-diabetes项目实战

目录 1 下载数据集和预处理 1.1 加载/下载数据集 1.2 数据可视化 1.3 数据清洗 1.4 特征工程 1.5 构建特征集和标签集 1.6 拆分训练集和测试集 2 训练模型 2.1 选择算法和确定模型 2.2 训练拟合模型 3 评估并优化模型性能 本文以糖尿病数据集diabetes为基础进行线性…

掌握高级设计原则:Java中的过滤器模式解析与实战演练,构建灵活且可扩展的系统架构

过滤器模式是一种结构型设计模式&#xff0c;它允许开发者使用不同的标准来过滤一组对象&#xff0c;并通过逻辑运算以解耦的方式将它们联系起来。 过滤器模式的核心在于提供了一个处理对象的机制&#xff0c;这个机制可以根据一个或多个标准来决定哪些对象应该被接受、哪些应…

数据指标体系方法—OSM模型

了解 OSM 模型 OSM 模型&#xff0c;全称为 Object-Strategy-Measure 模型。 O 代表业务目标&#xff0c;不仅仅是指公司战略级别的目标&#xff0c;也包含了产品中某个功能的目的&#xff0c;某场活动的目标等。S 代表业务策略&#xff0c;这里指的是要实现 O 需要采用的策略…