SpringBoot新增菜品模块开发(事务管理+批量插入+主键回填)

news2024/11/15 15:39:39

需求分析与设计

一:产品原型

后台系统中可以管理菜品信息,通过 新增功能来添加一个新的菜品,在添加菜品时需要选择当前菜品所属的菜品分类,并且需要上传菜品图片。

新增菜品原型:

当填写完表单信息, 点击"保存"按钮后, 会提交该表单的数据到服务端, 在服务端中需要接受数据, 然后将数据保存至数据库中。

业务规则:

  • 菜品名称必须是唯一的

  • 菜品必须属于某个分类下,不能单独存在

  • 新增菜品时可以根据情况选择菜品的口味

  • 每个菜品必须对应一张图片

二:接口设计

根据上述原型图先**粗粒度**设计接口,共包含3个接口。

- 根据类型查询分类(已完成)
- 文件上传(已完成)
- 新增菜品

接下来明确接口的请求方式、请求路径、传入参数和返回值。

口味非必须,且是object[]数组,可以传多个口味(一个菜品可以对应多种口味)

所以后端使用集合封装

三:数据表设计

新增菜品,其实就是将新增页面录入的菜品信息插入到dish表,如果添加了口味做法,还需要向dish_flavor表插入数据。所以在新增菜品时,涉及到两个表:

表名说明
dish菜品表
dish_flavor菜品口味表

1). 菜品表:dish

字段名数据类型说明备注
idbigint主键自增
namevarchar(32)菜品名称唯一
category_idbigint分类id逻辑外键
pricedecimal(10,2)菜品价格
imagevarchar(255)图片路径
descriptionvarchar(255)菜品描述
statusint售卖状态1起售 0停售
create_timedatetime创建时间
update_timedatetime最后修改时间
create_userbigint创建人id
update_userbigint最后修改人id

2). 菜品口味表:dish_flavor

字段名数据类型说明备注
idbigint主键自增
dish_idbigint菜品id逻辑外键
namevarchar(32)口味名称
valuevarchar(255)口味值

 代码开发

一:设计DTO类

package com.sky.dto;

import com.sky.entity.DishFlavor;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

@Data
public class DishDTO implements Serializable {

    private Long id;
    //菜品名称
    private String name;
    //菜品分类id
    private Long categoryId;
    //菜品价格
    private BigDecimal price;
    //图片
    private String image;
    //描述信息
    private String description;
    //0 停售 1 起售
    private Integer status;
    //口味
    private List<DishFlavor> flavors = new ArrayList<>();
}

细节:

注意口味用List集合封装,因为前端可以传递多种口味数据(对应口味实体类)

口味实体类如下:

/**
 * 菜品口味
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DishFlavor implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;
    //菜品id
    private Long dishId;

    //口味名称
    private String name;

    //口味数据list
    private String value;

}

二:Controller层

package com.sky.controller.admin;

import com.sky.dto.DishDTO;
import com.sky.dto.DishPageQueryDTO;
import com.sky.entity.Dish;
import com.sky.result.PageResult;
import com.sky.result.Result;
import com.sky.service.DishService;
import com.sky.vo.DishVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Set;

/**
 * 菜品管理
 */
@RestController
@RequestMapping("/admin/dish")
@Api(tags = "菜品相关接口")
@Slf4j
public class DishController {

    @Autowired
    private DishService dishService;

    /**
     * 新增菜品
     *
     * @param dishDTO
     * @return
     */
    @PostMapping
    @ApiOperation("新增菜品")
    public Result save(@RequestBody DishDTO dishDTO) {
        log.info("新增菜品:{}", dishDTO);
        dishService.saveWithFlavor(dishDTO);//后绪步骤开发
        return Result.success();
    }
}

细节:

注意接口文档上显示返回Result中data是非必须的,所以Result后可以不加泛型。

三:Service类(事务、forEach循环)

package com.sky.service.impl;


@Service
@Slf4j
public class DishServiceImpl implements DishService {

    @Autowired
    private DishMapper dishMapper;
    @Autowired
    private DishFlavorMapper dishFlavorMapper;

    /**
     * 新增菜品和对应的口味
     *
     * @param dishDTO
     */
    @Transactional
    public void saveWithFlavor(DishDTO dishDTO) {

        Dish dish = new Dish();
        BeanUtils.copyProperties(dishDTO, dish);

        //向菜品表插入1条数据
        dishMapper.insert(dish);//后绪步骤实现

        //获取insert语句生成的主键值
        Long dishId = dish.getId();

        List<DishFlavor> flavors = dishDTO.getFlavors();
        if (flavors != null && flavors.size() > 0) {
            flavors.forEach(dishFlavor -> {
                dishFlavor.setDishId(dishId);
            });
            //向口味表插入n条数据
            dishFlavorMapper.insertBatch(flavors);//后绪步骤实现
        }
    }

}

细节:

  • Service层别忘记要把DTO转换为实体对象
    • 利用BeanUtils提供的copyProperties方法可以快速转换
  • 因为新增菜品需要操作两张数据表(菜品表和口味表),所以需要原子操作,于是定义事务
    • @Transactional注解
  • 又因为口味表需要菜品表的主键(菜品id),而菜品id是数据库负责维护的自增主键,所以需要mybatis配合进行主键回填
    • Long dishId = dish.getId();成功的前提是mapper层set了id
  • 因为口味是非必须的请求数据,所以首先需要判断集合是否为空
    • 之后需要为口味对象赋值菜品id
    • 最后批量的插入口味表
  • forEach方法的使用
    • 集合.forEach(元素名->{元素所进行的操作})

四:Mapper层(主键回填、批量删除)

dishMapper:

	/**
     * 插入菜品数据
     *
     * @param dish
     */
    @AutoFill(value = OperationType.INSERT)
    void insert(Dish dish);

对应的xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.DishMapper">

    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        insert into dish (name, category_id, price, image, description, create_time, update_time, create_user, update_user,status)
        VALUES (#{name},#{categoryId},#{price},#{image},#{description},#{createTime},#{updateTime},#{createUser},#{updateUser},#{status})
    </insert>
</mapper>

细节:

这行定义了主键回填:<insert id="insert" useGeneratedKeys="true" keyProperty="id">,会将id的值返回到参数列表的Dish对象dish的id属性中

dishFlavorMapper:

package com.sky.mapper;

import com.sky.entity.DishFlavor;
import java.util.List;

@Mapper
public interface DishFlavorMapper {
    /**
     * 批量插入口味数据
     * @param flavors
     */
    void insertBatch(List<DishFlavor> flavors);

}

对应的XML:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.DishFlavorMapper">
    <insert id="insertBatch">
        insert into dish_flavor (dish_id, name, value) VALUES
        <foreach collection="flavors" item="df" separator=",">
            (#{df.dishId},#{df.name},#{df.value})
        </foreach>
    </insert>
</mapper>

细节:

批量插入

        <foreach collection="参数列表中传递过来的集合名" item="元素名称(自定义)" separator="(下列元素的属性之间分割的分隔符)">
            (#{df.dishId},#{df.name},#{df.value})
        </foreach>

形成的效果

(  ,   ,   ,)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【御控物联】物联网平台设备接入-JSON数据格式转化(场景案例四)

文章目录 一、背景二、解决方案三、在线转换工具四、技术资料 一、背景 物联网平台是一种实现设备接入、设备监控、设备管理、数据存储、消息多源转发和数据分析等能力的一体化平台。南向支持连接海量异构&#xff08;协议多样&#xff09;设备&#xff0c;实现设备数据云端存…

绝地求生:杜卡迪来了,这些摩托车技巧不学一下吗?

摩托车在远古版本和现在完全不一样&#xff0c;虽然容易翻车造就了一批玩家“摩托杀手”的外号&#xff0c;但是速度可比今天快多了。 后来在蓝洞的削弱了其加速度&#xff0c;虽然资料上写着最高时速155km/h&#xff0c;但是平时游戏中一般只能拉到110~120km/h。这里写一点摩托…

Java GUI制作双人对打游戏(上)

文章目录 前言什么是Java GUI一、打开IDEA 新建一个Maven项目(后续可以打包、引入相关依赖也很容易)二、引入依赖三.绘制UI界面四.绘制JPanel面板总结 前言 什么是Java GUI Java UI&#xff0c;即Java用户界面&#xff0c;是指使用Java编程语言创建的图形用户界面&#xff08…

第一节:什么是操作系统

什么是操作系统 一、一台计算机的组成部分1、计算机能干啥2、谈谈计算机硬件 二、什么是操作系统三、学习操作系统的层次 一、一台计算机的组成部分 如下图所示&#xff1a; 这就是就是构成一台计算机的组成部分 1、计算机能干啥 ∙ \bullet ∙计算机是我们专业吃饭的家伙&a…

《springcloud alibaba》 六 微服务链路跟踪skywalking

目录 准备调整配置接入多个微服务网关项目调整order-seata项目stock-seata项目测试 接入网关微服务 skywalking持续化到mysql自定义链路跟踪pom .xmlorderControllerOrderServiceOrderDaoOrderTblMapper.xml测试 性能剖析日志tid打印pom.xmllogback-spring.xml日志收集启动项目…

2024年MathorCup数学应用挑战赛C题思路分析(妈妈杯)

2024年第十四届MathorCup数学应用挑战赛C题解析 文章目录 题目概览第一问&#xff1a;货量预测第二问&#xff1a;运输线路变化的预测第三问&#xff1a;单目标优化第四问&#xff1a;排班计划的优化 MATLAB代码框架货量预测人员排班 2024年的MathorCup数学应用挑战赛再次为我…

硬盘分区无法访问,数据恢复与防范全攻略

当我们尝试打开某个硬盘分区时&#xff0c;有时会遇到分区无法访问的困扰。这不仅让我们无法读取分区内的文件&#xff0c;还可能导致重要数据的丢失。面对这种情况&#xff0c;我们该如何应对呢&#xff1f;本文将详细解析硬盘分区无法访问的原因&#xff0c;并给出两种有效的…

加速度JUSDO | 电子元器件商城行业调研及运营方案

一、行业背景与竞品分析 随着电子元器件行业的快速发展&#xff0c;线上元器件商城已成为行业交易的重要渠道。目前市场上存在多个知名的元器件商城&#xff0c;如立创、云汉芯城、贸泽商城等&#xff0c;它们都提供了丰富的元器件产品和便捷的线上交易服务。 立创商城&#x…

构建第一个ArkTS应用之stateStyles:多态样式

Styles和Extend仅仅应用于静态页面的样式复用&#xff0c;stateStyles可以依据组件的内部状态的不同&#xff0c;快速设置不同样式。这就是我们本章要介绍的内容stateStyles&#xff08;又称为&#xff1a;多态样式&#xff09;。 概述 stateStyles是属性方法&#xff0c;可以…

Web前端 Javascript笔记1

为什么学习 JavaScript? JavaScript 是 web 开发人员必须学习的 3 门语言中的一门&#xff1a; HTML 定义了网页的内容CSS 描述了网页的布局JavaScript 控制了网页的行为 JavaScript 是可插入 HTML 页面的编程代码。 JavaScript 插入 HTML 页面后&#xff0c;可由所有的现代浏…

Qt实现XYModem协议(一)

1 概述 Kermit文件运输协议提供了一条从大型计算机下载文件到微机的途径。它已被用于进行公用数据传输。 其特性如下: Kermit文件运输协议是一个半双工的通信协议。它支持7位ASCII字符。数据以可多达96字节长度的可变长度的分组形式传输。对每个被传送分组需要一个确认。Kerm…

【剪映专业版】05常见视频专业术语

视频课程&#xff1a;B站有知公开课【剪映电脑版教程】 视频格式与编码 剪映支持导出MP4、MOV格式 视频分辨率与像素 常见分辨率&#xff1a;1080P 1080P&#xff1a;日常剪辑可用&#xff0c;日常拍摄时选择该分辨率 4K&#xff1a;比如演唱会大屏 剪映支持导出&#xff…

Ubuntu安装VMVare Workstation pro 17.5.1

由于需要装Kali&#xff0c;我电脑是Ubuntu单系统&#xff0c;所以只能使用linux版本的虚拟机&#xff0c;通过这种方式来安装虚拟机和Kali镜像。 参考CSDN博客资料&#xff1a;https://blog.csdn.net/xiaochong0302/article/details/127420124 github代码资料&#xff1a;vm…

less+rem+媒体查询布局(主流)

rem适配布局 一.rem基础二.媒体查询1.概念2.语法&#xff08;1&#xff09;.mediatype查询类型&#xff08;2&#xff09;.关键字&#xff08;3&#xff09;.媒体特性&#xff08;4&#xff09;.应用 3.媒体查询rem实现元素动态大小变化4.引入资源&#xff08;针对不同媒体查询…

学习MQ异步

1.MQ异步调用的优势 事件驱动模式&#xff1a; 优势&#xff1a; 总结&#xff1a; 2.初识MQ 核心概念以及结构&#xff1a; 常见的消息模型&#xff1a; 基本消息队列模型&#xff1a; 生产者代码&#xff1a; Testpublic void testSendMessage() throws IOException, Timeo…

图片尺寸在线修改怎么改?修改图片方法详解

图片尺寸在线修改怎么改&#xff1f;在数字化时代&#xff0c;图片尺寸的调整与修改已成为我们日常生活和工作中不可或缺的一部分。无论是为了满足特定平台的上传要求&#xff0c;还是为了提升图片的视觉效果&#xff0c;对图片尺寸进行在线修改都显得尤为重要。本文将详细介绍…

推荐系统学习记录——数据稀疏性衡量

在推荐系统中&#xff0c;数据稀疏性通常通过计算用户-物品交互矩阵的稀疏度来衡量。用户-物品交互矩阵是一个二维矩阵&#xff0c;其中行表示用户&#xff0c;列表示物品&#xff0c;矩阵中的每个元素表示用户对物品的交互情况&#xff08;如评分、点击、购买等&#xff09;&a…

专访云仓酒庄《综合品酒师》培训带领酒水行业专业与形象新篇章

在春意盎然的季节里&#xff0c;云仓酒庄成功举办了首届《综合品酒师》培训&#xff0c;吸引了业界的广泛关注。本次培训不仅为酒水行业注入了新的活力&#xff0c;更在提升行业专业性和形象方面迈出了坚实的步伐。我们有幸采访到了云仓酒庄的负责人&#xff0c;就此次培训的背…

使用DNSTOP进行DNS流量分析

一、前言 dnstop 是一个用于监听和解析 DNS 流量的实用工具。它可以帮助您监视网络中的 DNS 查询&#xff0c;并提供有关域名、IP 地址、查询类型等信息的实时统计。 当我们在分析DNS 服务器日志时&#xff0c;想去了解哪些用户在使用DNS 服务器&#xff0c;同时也希望对DNS …

完美提升Stable Diffusion生成质量和效率!UniFL:统一反馈学习框架(字节中山)

文章链接&#xff1a;https://arxiv.org/pdf/2404.05595 git链接&#xff1a;https://uni-fl.github.io/ 扩散模型已经彻底改变了图像生成领域&#xff0c;导致高质量模型和多样化的下游应用不断涌现。然而&#xff0c;尽管取得了重大进展&#xff0c;当前竞争性解决方案仍然存…