苍穹外卖03(公共字段自动填充,多表的新增,多表分页查询,多表删除,多表修改)

目录

一、公共字段自动填充

1.出现的问题

2. 实现思路

3. 代码开发

二、新增菜品

1 需求分析与设计

1 产品原型

2 接口设计

3 表设计

2 代码开发

1 文件上传实现

2 新增菜品实现

三、菜品分页查询

1 需求分析和设计

1 产品原型

2 接口设计

2 代码开发

四、删除菜品

1 需求分析和设计

1 产品原型

2 接口设计

3 注意事项

2 代码开发

五、修改菜品

1 需求分析和设计

1 产品原型

2 接口设计

2 代码开发

1 根据id查询菜品实现

2 修改菜品实现


一、公共字段自动填充

1.出现的问题

在上一章节我们已经完成了后台系统的员工管理功能菜品分类功能的开发,在新增员工或者新增菜品分类时需要设置创建时间、创建人、修改时间、修改人等字段,在编辑员工或者编辑菜品分类时需要设置修改时间、修改人等字段。这些字段属于公共字段,也就是也就是在我们的系统中很多表中都会有这些字段,如下:

新增员工方法:

编辑员工方法:

我们使用AOP切面编程,实现功能增强,来完成公共字段自动填充功能。

2. 实现思路

在实现公共字段自动填充,也就是在插入或者更新的时候为指定字段赋予指定的值,使用它的好处就是可以统一对这些字段进行处理,避免了重复代码。在上述的问题分析中,我们提到有四个公共字段,需要在新增/更新中进行赋值操作, 具体情况如下:

实现步骤:

1). 自定义注解 AutoFill,用于标识需要进行公共字段自动填充的方法

2). 自定义切面类 AutoFillAspect,统一拦截加入了 AutoFill 注解的方法,通过反射为公共字段赋值

3). 在 Mapper 的方法上加入 AutoFill 注解

若要实现上述步骤,需掌握以下知识(之前课程内容都学过)

技术点:枚举、注解、AOP、反射

3. 代码开发

//**自定义注解 AutoFill**              
//进入到sky-server模块,创建com.sky.annotation包

package com.sky.annotation;

import com.sky.enumeration.OperationType;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定义注解,用于标识某个方法需要进行功能字段自动填充处理
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
    //数据库操作类型:UPDATE INSERT
    OperationType value();
}


-------------------------
//其中OperationType已在sky-common模块中定义package com.sky.enumeration;

/**
 * 数据库操作类型,枚举
 */
public enum OperationType {

    /**
     * 更新操作
     */
    UPDATE,

    /**
     * 插入操作
     */
    INSERT
}



-------------------------
// Mapper里方法加注解
//在新增和修改的mapper上加

@AutoFill(OperationType.INSERT)
    @Options(useGeneratedKeys = true, keyProperty = "id")
    @Insert("INSERT INTO dish (name, category_id, price, image, description, status, create_time, update_time, create_user, update_user) " +
            "VALUES (#{name}, #{categoryId}, #{price}, #{image}, #{description}, #{status}, #{createTime}, #{updateTime}, #{createUser}, #{updateUser})")
    void insert(Dish dish);


@AutoFill(OperationType.UPDATE)
    void updateById(Dish dish);



------------------------
//### 自定义切面AutoFillAspect
//在sky-server模块,创建com.sky.aspect包。

package com.sky.aspect;

import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * @author liuyp
 * @since 2023/09/01
 */
@Slf4j
@Aspect
@Component
public class AutofillAspect {

    @Before("execution(* com.sky.mapper.*.*(..)) && @annotation(autoFill)")
    public void autoFill(JoinPoint joinPoint, AutoFill autoFill){
        log.info("开始自动填充公共字段值");

        //获取Mapper方法的参数:entity对象
        Object[] args = joinPoint.getArgs();
        if (args == null || args.length == 0) {
            return;
        }
        Object entity = args[0];

        //准备要赋的值
        LocalDateTime now = LocalDateTime.now();
        Long currentUser = BaseContext.getCurrentId();

        //判断操作的类型
        Class<?> clazz = entity.getClass();
        if (autoFill.value() == OperationType.INSERT) {
            try {
                //是新增操作:获取setCreateTime、setUpdateTime、setCreateUser、setUpdateUser四个方法
                Method setCreateTimeMethod = clazz.getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                Method setUpdateTimeMethod = clazz.getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setCreatorMethod = clazz.getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                Method setUpdatorMethod = clazz.getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

                //使用反射调用entity的对应方法,给属性赋值
                setCreateTimeMethod.invoke(entity, now);
                setUpdateTimeMethod.invoke(entity, now);
                setCreatorMethod.invoke(entity, currentUser);
                setUpdatorMethod.invoke(entity, currentUser);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }else{
            try {
                //是修改操作:获取setUpdateTime、setUpdateUser两个方法
                Method setUpdateTimeMethod = clazz.getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdatorMethod = clazz.getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
                //使用反射调用entity的对应方法,给属性赋值
                setUpdateTimeMethod.invoke(entity, now);
                setUpdatorMethod.invoke(entity, currentUser);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

二、新增菜品

1 需求分析与设计

1 产品原型

2 接口设计

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

接口设计:

  • 根据类型查询分类(已完成)

  • 文件上传

  • 新增菜品

接下来细粒度分析每个接口,明确每个接口的请求方式、请求路径、传入参数和返回值。

1. 根据类型查询分类

2. 文件上传

3. 新增菜品

3 表设计

2 代码开发

1 文件上传实现

//(1) 配置OSS参数
//在sky-server模块application-dev.yml

sky:
  alioss:
    endpoint: oss-cn-beijing.aliyuncs.com
    accessKeyId: LTAI5tG3TbA9HLs22KEtimyB
    accessKeySecret: 4avUxhaO5KCTl5pqpta3AdU98mT9um
    bucketName: itheima-liuyp


-----------------------------
// 2) 读取配置参数(已完成)
//在sky-common模块中,已定义

package com.sky.properties;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "sky.alioss")
@Data
public class AliOssProperties {

    private String endpoint;
    private String accessKeyId;
    private String accessKeySecret;
    private String bucketName;

}


------------------------
// 3) 将OSS工具对象放到容器里
//在sky-server模块

package com.sky.config;

import com.sky.properties.AliOssProperties;
import com.sky.utils.AliOssUtil;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author liuyp
 * @since 2023/09/01
 */
@Configuration
public class OssConfig {

    @Bean
    @ConditionalOnMissingBean
    public AliOssUtil ossUtil(AliOssProperties properties){
        return new AliOssUtil(
                properties.getEndpoint(),
                properties.getAccessKeyId(),
                properties.getAccessKeySecret(),
                properties.getBucketName()
        );
    }
}


------------------------
//其中,AliOssUtil.java已在sky-common模块中定义

package com.sky.utils;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.io.ByteArrayInputStream;

@Data
@AllArgsConstructor
@Slf4j
public class AliOssUtil {

    private String endpoint;
    private String accessKeyId;
    private String accessKeySecret;
    private String bucketName;

    /**
     * 文件上传
     *
     * @param bytes
     * @param objectName
     * @return
     */
    public String upload(byte[] bytes, String objectName) {

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        try {
            // 创建PutObject请求。
            ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes));
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }

        //文件访问路径规则 https://BucketName.Endpoint/ObjectName
        StringBuilder stringBuilder = new StringBuilder("https://");
        stringBuilder
                .append(bucketName)
                .append(".")
                .append(endpoint)
                .append("/")
                .append(objectName);

        log.info("文件上传到:{}", stringBuilder.toString());

        return stringBuilder.toString();
    }
}



-------------------------
//4) CommonController

package com.sky.controller.admin;

import com.sky.constant.MessageConstant;
import com.sky.result.Result;
import com.sky.utils.AliOssUtil;
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.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.UUID;

/**
 * 通用接口
 */
@RestController
@RequestMapping("/admin/common")
@Api(tags = "通用接口")
@Slf4j
public class CommonController {

    @Autowired
    private AliOssUtil aliOssUtil;

    /**
     * 文件上传
     * @param file
     * @return
     */
    @PostMapping("/upload")
    @ApiOperation("文件上传")
    public Result<String> upload(MultipartFile file){
        log.info("文件上传:{}",file);

        try {
            //原始文件名
            String originalFilename = file.getOriginalFilename();
            //截取原始文件名的后缀   dfdfdf.png
            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.error("文件上传失败:{}", e);
        }

        return Result.error(MessageConstant.UPLOAD_FAILED);
    }
}



    

2 新增菜品实现

//1)准备DTO类(已完成)
//在sky-pojo模块中

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


-----------------------------
// 2) DishController
进入到sky-server模块

package com.sky.controller.admin;

import com.sky.dto.DishDTO;
import com.sky.result.Result;
import com.sky.service.DishService;
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.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


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

    @PostMapping
    @ApiOperation("新增菜品")
    public Result addDish(@RequestBody DishDTO dto){
        return dishService.addDish(dto);
    }
}


------------------------
//3) DishService

package com.sky.service;

import com.sky.dto.DishDTO;
import com.sky.result.Result;

public interface DishService {
    /**
     * 新增菜品
     * @param dto
     * @return
     */
    Result addDish(DishDTO dto);
}



--------------------------
//4) DishServiceImpl

package com.sky.service.impl;

import com.sky.dto.DishDTO;
import com.sky.entity.Dish;
import com.sky.entity.DishFlavor;
import com.sky.mapper.DishFlavorMapper;
import com.sky.mapper.DishMapper;
import com.sky.result.Result;
import com.sky.service.DishService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;


@Service
public class DishServiceImpl implements DishService {
    @Autowired
    private DishMapper dishMapper;
    @Autowired
    private DishFlavorMapper dishFlavorMapper;

    @Override
    @Transactional
    public Result addDish(DishDTO dto) {
        //保存菜品
        Dish dish = new Dish();
        BeanUtils.copyProperties(dto, dish);
        dishMapper.insert(dish);

        //保存菜品与品味的关系
        List<DishFlavor> flavors = dto.getFlavors();
        if (!CollectionUtils.isEmpty(flavors)) {
            flavors.forEach(dishFlavor -> dishFlavor.setDishId(dish.getId()));
            dishFlavorMapper.batchInsert(flavors);
        }
        return Result.success();
    }
}


---------------------
// 5) DishMapper
DishMapper.java中添加

@AutoFill(OperationType.INSERT)
@Options(   = true, keyProperty = "id")
@Insert("INSERT INTO dish (name, category_id, price, image, description, status, create_time, update_time, create_user, update_user) " +
        "VALUES (#{name}, #{categoryId}, #{price}, #{image}, #{description}, #{status}, #{createTime}, #{updateTime}, #{createUser}, #{updateUser})")
void insert(Dish dish);


----------------------
//6) DishFlavorMapper

package com.sky.mapper;

import com.sky.entity.DishFlavor;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface DishFlavorMapper {
    void batchInsert(List<DishFlavor> flavors);
}



-----------------------
//7) DishFlavorMapper.xml
//在/resources/mapper中创建DishFlavorMapper.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="batchInsert">
        INSERT INTO dish_flavor (dish_id, name, value) VALUES
        <foreach collection="flavors" item="f" separator=",">
            (#{f.dishId}, #{f.name}, #{f.value})
        </foreach>
    </insert>
</mapper>


三、菜品分页查询

1 需求分析和设计

1 产品原型

业务规则:

  • 根据页码展示菜品信息

  • 每页展示10条数据

  • 分页查询时可以根据需要输入菜品名称、菜品分类、菜品状态进行查询

2 接口设计

2 代码开发

// 1 设计DTO类
//根据菜品分页查询接口定义设计对应的DTO:**
//在sky-pojo模块中,已定义

package com.sky.dto;

import lombok.Data;

import java.io.Serializable;

@Data
public class DishPageQueryDTO implements Serializable {

    private int page;

    private int pageSize;

    private String name;

    //分类id
    private Integer categoryId;

    //状态 0表示禁用 1表示启用
    private Integer status;

}


-------------------
//2 设计VO类
//根据菜品分页查询接口定义设计对应的VO:
//在sky-pojo模块中,已定义

package com.sky.vo;

import com.sky.entity.DishFlavor;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DishVO 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 LocalDateTime updateTime;
    //分类名称
    private String categoryName;
    //菜品关联的口味
    private List<DishFlavor> flavors = new ArrayList<>();
}


---------------------
//3 DishController
//根据接口定义创建DishController的page分页查询方法:

@GetMapping("/page")
@ApiOperation("分页查询菜品")
public Result queryDishesByPage(DishPageQueryDTO dto){
    return dishService.queryDishesByPage(dto);
}


--------------------
// 4 DishService
//在 DishService 中扩展分页查询方法:

    /**
     * 分页查询菜品
     * @param dto
     * @return
     */
    Result queryDishesByPage(DishPageQueryDTO dto);


-----------------
//5 DishServiceImpl
//在 DishServiceImpl 中实现分页查询方法

@Override
public Result queryDishesByPage(DishPageQueryDTO dto) {
    //开启分页
    PageHelper.startPage(dto.getPage(), dto.getPageSize());
    //查询列表
    Page<DishVO> page = dishMapper.selectByPage(dto);
    //封装结果
    PageResult result = new PageResult(page
                                       .getTotal(), page.getResult());
    return Result.success(result);
}


------------------
//6 DishMapper
//在 DishMapper 接口中声明 pageQuery 方法:

Page<DishVO> selectByPage(DishPageQueryDTO dto);


-------------------
//7 DishMapper.xml
//在 resources/mapper/DishMapper.xml 中编写SQL

<?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">
    <select id="selectByPage" resultType="com.sky.vo.DishVO">
        select d.*, c.name as categoryName from dish d left join category c on d.category_id = c.id
        <where>
            <if test="name!=null and name.length()>0">
                and d.name like concat('%', #{name}, '%')
            </if>
            <if test="categoryId!=null">
                and d.category_id = #{categoryId}
            </if>
            <if test="status!=null">
                and d.status = #{status}
            </if>
        </where>
        order by create_time desc
    </select>
</mapper>




    

四、删除菜品

1 需求分析和设计

1 产品原型

业务规则:

  • 可以一次删除一个菜品,也可以批量删除菜品

  • 起售中的菜品不能删除

  • 被套餐关联的菜品不能删除

  • 删除菜品后,关联的口味数据也需要删除掉

2 接口设计

3 注意事项

  • 如果有菜品状态是“起售”状态,也不允许删除

  • 若删除的菜品数据关联着某个套餐,此时,删除失败(setmeal_dish表为菜品和套餐关联的中间表。)

  • 在dish表中删除菜品基本数据时,同时,也要把关联在dish_flavor表中的数据一块删除。

2 代码开发

//DishController

@DeleteMapping
@ApiOperation("删除菜品")
public Result deleteDishesByIds(@RequestParam("ids") List<Long> ids){
    return dishService.deleteDishesByIds(ids);
}


-----------------
//DishService

    /**
     * 删除菜品
     * @param ids
     * @return
     */
Result deleteDishesByIds(List<Long> ids);


---------------
//DishServiceImpl

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

@Override
@Transactional
public Result deleteDishesByIds(List<Long> ids) {
   //1. 如果ids对应的菜品里,有未停售的菜品,则不能删除
    int enableDishCount = dishMapper.selectEnableDishCountByIds(ids);
    if (enableDishCount > 0) {
        throw new DeletionNotAllowedException(MessageConstant.DISH_ON_SALE);
    }
    //2. 如果ids对应的菜品里,有关联的套餐,则简单处理,直接不予删除
    int setmealCount = setmealDishMapper.selectSetmealCountByDishIds(ids);
    if (setmealCount > 0) {
        throw new DeletionNotAllowedException(MessageConstant.DISH_BE_RELATED_BY_SETMEAL);
    }

    //删除菜品
    dishMapper.batchDeleteByIds(ids);
    //删除菜品对应的口味
    dishFlavorMapper.batchDeleteByDishIds(ids);

    return Result.success();
}


-----------------
//DishMapper
//在DishMapper中声明getById方法,并配置SQL

/**
 * 查询ids对应的菜品中,启售中状态的菜品数量
 */
int selectEnableDishCountByIds(List<Long> ids);

/**
 * 根据ids集合,批量删除对应的菜品
 */
void batchDeleteByIds(List<Long> ids);


-----------------
//DishMapper.xml

<select id="selectEnableDishCountByIds" resultType="int">
    select count(*) from dish
    <where>
        <foreach collection="ids" item="id" separator="," open="and id in (" close=")">
            #{id}
        </foreach>
        and status = 1
    </where>
</select>

<delete id="batchDeleteByIds">
    delete from dish where id in
    <foreach collection="ids" item="id" separator="," open="(" close=")">
        #{id}
    </foreach>
</delete>


-----------------
//SetmealDishMapper

package com.sky.mapper;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;

@Mapper
public interface SetmealDishMapper {
    /**
     * 根据菜品id集合,查询关联的套餐数量
     */
    int selectSetmealCountByDishIds(List<Long> ids);
}


-----------------
//SetmealDishMapper.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.SetmealDishMapper">
    <select id="selectSetmealCountByDishIds" resultType="int">
        select count(*) from setmeal_dish where id in
        <foreach collection="ids" item="dishId" separator="," open="(" close=")">
            #{dishId}
        </foreach>
    </select>
</mapper>

五、修改菜品

1 需求分析和设计

1 产品原型

2 接口设计

1). 根据id查询菜品

2). 修改菜品

2 代码开发

修改功能先要根据id返回数据,然后才能改数据

1 根据id查询菜品实现

//1 根据id查询菜品实现
//1) DishController

@GetMapping("/{id}")
@ApiOperation("根据id查询菜品")
public Result queryDishById(@PathVariable("id") Long id) {
    return dishService.queryDishById(id);
}


-----------------
2) DishService

    /**
     * 根据id查询菜品
     * @param id
     * @return
     */
Result queryDishById(Long id);


-----------------
3) DishServiceImpl

@Override
public Result queryDishById(Long id) {
    //根据id查询菜品信息
    Dish dish = dishMapper.selectById(id);
    //根据菜品id查询口味列表
    List<DishFlavor> dishFlavors = dishFlavorMapper.selectByDishId(id);
    //封装结果
    DishVO vo = new DishVO();
    BeanUtils.copyProperties(dish, vo);
    vo.setFlavors(dishFlavors);
    return Result.success(vo);
}

-----------------
4) DishMapper

@Select("select * from dish where id=#{id}")
Dish selectById(Long id);

-----------------
5) DishFlavorMapper

/**
 * 根据菜品id,查询品味列表
 */
@Select("select * from dish_flavor where dish_id = #{dishId}")
List<DishFlavor> selectByDishId(Long dishId);


2 修改菜品实现

//1) DishController
//根据修改菜品的接口定义在DishController中创建方法:

@PutMapping
@ApiOperation("修改菜品")
public Result updateDishById(@RequestBody DishDTO dto){
    return dishService.updateDishById(dto);
}


--------------
//2) DishService
//在DishService接口中声明updateWithFlavor方法:

    /**
     * 根据id修改菜品
     * @param dto
     * @return
     */
Result updateDishById(DishDTO dto);


--------------
//3) DishServiceImpl
//在DishServiceImpl中实现updateWithFlavor方法:

@Override
public Result updateDishById(DishDTO dto) {
    //1. 修改菜品信息
    Dish dish = new Dish();
    BeanUtils.copyProperties(dto, dish);
    dishMapper.updateById(dish);

    //2. 删除菜品对应的原口味列表
    dishFlavorMapper.batchDeleteByDishIds(Collections.singletonList(dto.getId()));

    //3. 重新添加菜品的口味列表
    List<DishFlavor> flavors = dto.getFlavors();
    if (!CollectionUtils.isEmpty(flavors)) {
        flavors.forEach(dishFlavor -> dishFlavor.setDishId(dto.getId()));
        dishFlavorMapper.batchInsert(flavors);
    }
    return Result.success();
}


--------------
//4) DishMapper

@AutoFill(OperationType.UPDATE)
void updateById(Dish dish);

--------------
//5) DishMapper.xml

<update id="updateById">
    UPDATE dish
    <set>
        <if test="name!=null and name.length()>0">name = #{name},</if>
        <if test="categoryId!=null">category_id = #{categoryId},</if>
        <if test="price!=null">price = #{price},</if>
        <if test="image!=null and image.length()>0">image = #{image},</if>
        <if test="description!=null and description.length()>0">description = #{description},</if>
        <if test="status!=null">status = #{status},</if>
        <if test="updateTime!=null">update_time = #{updateTime},</if>
        <if test="updateUser!=null">update_user = #{updateUser}</if>
    </set>
    WHERE id = #{id}
</update>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值