苍穹外卖学习笔记——第三天

菜品管理

公共字段自动填充

问题分析

  • 业务表中存在公共字段:
字段名 含义 数据类型
create_time 创建时间 datetime
create_user 创建人id bigint
update_time 修改时间 datetime
update_user 修改人id bigint
  • 这些公共字段会在多处被执行相同的操作,导致代码冗余、不便于后期维护。

实现思路

  1. 自定义注解 AutoFill,用于标识需要进行公共字段自动填充的方法。
  2. 自定义切面类 AutoFillAspect,统一拦截加入了 AutoFill 注解的方法,通过反射为公共字段赋值。
  3. 在 Mapper 的方法上加入 AutoFill 注解。
  • 技术点:枚举、注解、AOP、反射。

代码开发

自定义注解AutoFill

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
    //数据库操作类型:UPDATE INSERT
    OperationType value();
}

自定义切面AutoFillAspect

@Aspect
@Component
@Slf4j
public class AutoFillAspect {

    /**
     * 切入点
     */
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void autoFillPointcut() {}

    /**
     * 前置通知,在通知中进行公共字段的赋值
     */
    @Before("autoFillPointcut()")
    public void autoFill(JoinPoint joinPoint) {
        //待完善
    }
}

完善自定义切面AutoFillAspect的autoFill方法

@Before("autoFillPointcut()")
public void autoFill(JoinPoint joinPoint) {
    log.info("开始进行公共字段的自动填充...");

    //获取到当前被拦截的方法上的数据库操作类型
    MethodSignature signature = (MethodSignature) joinPoint.getSignature(); //方法签名对象
    AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class); //获得方法签名上的注解对象
    OperationType operationType = autoFill.value(); //获得数据库操作类型

    //获取到当前被拦截的方法的参数——实体对象
    Object[] args = joinPoint.getArgs(); //约定:实体对象始终在形参列表的第一个位置
    if (args == null || args.length == 0) {
        return;
    }

    Object entity = args[0];

    //准备赋值的数据
    LocalDateTime now = LocalDateTime.now();
    Long currentId = BaseContext.getCurrentId();

    //根据当前不同的操作类型,为对应的属性通过反射来赋值
    if (operationType == OperationType.INSERT) {
        //为四个公共字段赋值
        try {
            Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
            Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
            Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
            Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

            //通过反射为对象赋值
            setCreateTime.invoke(entity, now);
            setCreateUser.invoke(entity, currentId);
            setUpdateTime.invoke(entity, now);
            setUpdateUser.invoke(entity, currentId);
        } catch (Exception e) {
            e.printStackTrace();
        }

    } else if (operationType == OperationType.UPDATE) {
        //为两个公共字段赋值
        try {
            Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
            Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

            //通过反射为对象赋值
            setUpdateTime.invoke(entity, now);
            setUpdateUser.invoke(entity, currentId);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

在Mapper接口的方法上加入AutoFill注解

//EmployeeMapper.java

@Insert("insert into employee (name, username, password, phone, sex, id_number, status, create_time, " + 
        "update_time, create_user, update_user) VALUES (#{name}, #{username}, #{password}, #{phone}, " + 
        "#{sex}, #{idNumber}, #{status}, #{createTime}, #{updateTime}, #{createUser}, #{updateUser})")
@AutoFill(OperationType.INSERT)
void insert(Employee employee);

@AutoFill(OperationType.UPDATE)
void update(Employee employee);

//CategoryMapper.java
@Insert("insert into category(type, name, sort, status, create_time, update_time, create_user, " + 
        "update_user) VALUES (#{type}, #{name}, #{sort}, #{status}, #{createTime}, #{updateTime}, " + 
        "#{createUser}, #{updateUser})")
@AutoFill(OperationType.INSERT)
void insert(Category category);

@AutoFill(OperationType.UPDATE)
void update(Category category);

将业务层为公共字段赋值的代码注释掉

功能测试

  • 通过观察控制台输出的SQL来确定公共字段填充是否完成。

新增菜品

需求分析和设计

产品原型

新增菜品产品原型

业务规则

  • 菜品名称必须是唯一的。
  • 菜品必须属于某个分类下,不能单独存在。
  • 新增菜品时可以根据情况选择菜品的口味
  • 每个菜品必须对应一张图片。

接口设计

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

数据库设计

dish菜品表
字段名 数据类型 说明 备注
id bigint 主键 自增
name varchar(32) 菜品名称 唯一
category_id bigint 分类id 逻辑外键
price decimal(10,2) 菜品价格
image varchar(255) 图片路径
description varchar(255) 菜品描述
status int 售卖状态 1起售 0停售
create_time datetime 创建时间
update_time datetime 最后修改时间
create_user bigint 创建人id
update_user bigint 最后修改人id
dish_flavor口味表
字段名 数据类型 说明 备注
id bigint 主键 自增
dish_id bigint 菜品id 逻辑外键
name varchar(32) 口味名称
value varchar(255) 口味值

代码开发

文件上传接口

在application-dev.yml配置阿里云相关信息
sky:
  alioss:
    endpoint: oss-cn-beijing.aliyuncs.com
    access-key-id: LTAI5tPeFLzsPPT8gG3LPW64
    access-key-secret: U6k1brOZ8gaOIXv3nXbulGTUzy6Pd7
    bucket-name: sky-itcast
在application.yml引用application-dev.yml里的配置信息
sky:
  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}
自定义配置类OssConfiguration为阿里云工具类AliOssUtil注入配置信息
@Configuration
@Slf4j
public class OssConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public AliOssUtil aliOssUtil(AliOssProperties aliOssProperties) {
        log.info("开始创建阿里云上传工具类对象:{}", aliOssProperties);
        return new AliOssUtil(aliOssProperties.getEndpoint(),
                aliOssProperties.getAccessKeyId(),
                aliOssProperties.getAccessKeySecret(),
                aliOssProperties.getBucketName());
    }
}
自定义CommonController类并实现upload方法
@RestController
@RequestMapping("/admin/commom")
@Slf4j
@Api(tags = "通用接口")
public class CommonController {

    @Autowired
    private AliOssUtil aliOssUtil;

    @PostMapping("/upload")
    @ApiOperation("文件上传")
    public Result<String> upload(MultipartFile file) {
        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 (Exception e) {
            log.error("文件上传失败:{}", e);
        }

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

新增菜品接口

根据新增菜品接口设计对应的DTO
@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<>();

}
自定义DishController类并创建save方法
@RestController
@RequestMapping("/admin/dish")
@Api(tags = "菜品相关接口")
@Slf4j
public class DishController {

    @Autowired
    private DishService dishService;

    /**
     * 新增菜品
     *
     * @param dishDTO
     * @return
     */
    @PostMapping
    public Result save(@RequestBody DishDTO dishDTO) {
        log.info("新增菜品:{}", dishDTO);
        dishService.saveWithFlavor(dishDTO);
        return Result.success();
    }
}
自定义DishService接口并声明saveWithFlavor方法
public interface DishService {

    /**
     * 新增菜品和对应的口味数据
     *
     * @param dishDTO
     */
    void saveWithFlavor(DishDTO dishDTO);
}
自定义DishServiceImpl实现类并实现saveWithFlavor方法
@Service
public class DishServiceImpl implements DishService {

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

    /**
     * 新增菜品和对应的口味数据
     *
     * @param dishDTO
     */
    @Override
    @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.isEmpty()) {
            flavors = flavors.stream().filter(dishFlavor -> !Objects.equals(dishFlavor.getName(), "")).collect(Collectors.toList());
            flavors.forEach(dishFlavor -> dishFlavor.setDishId(dishId));
            //向口味表插入n条数据
            dishFlavorMapper.insertBatch(flavors);
        }
    }
}
在DishMapper中声明insert方法
@AutoFill(value = OperationType.INSERT)
void insert(Dish dish);
自定义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">

    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        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})
    </insert>
</mapper>
自定义DishFlavorMapper接口并声明insertBatch方法
@Mapper
public interface DishFlavorMapper {

    /**
     * 批量插入口味数据
     *
     * @param flavors
     */
    void insertBatch(List<DishFlavor> flavors);
}
自定义DishFlavorMapper.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.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>

功能测试

  • 可以通过接口文档进行测试,最后完成前后端联调测试即可。

菜品分页查询

需求分析和设计

产品原型

菜品分页查询产品原型

业务规则

  • 根据页码展示菜品信息。
  • 每页展示10条数据。
  • 分页查询时可以根据需要输入菜品名称、菜品分类、菜品状态进行查询。

接口设计

菜品分页查询接口设计

代码开发

根据菜品分页查询接口定义设计对应的DTO

@Data
public class DishPageQueryDTO implements Serializable {

    private int page;

    private int pageSize;

    private String name;

    //分类id
    private Integer categoryId;

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

}

根据菜品分页查询接口定义设计对应的VO

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

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

@GetMapping("/page")
public Result<PageResult> page(DishPageQueryDTO dishPageQueryDTO) {
    log.info("菜品分页查询:{}", dishPageQueryDTO);
    PageResult pageResult = dishService.pageQuery(dishPageQueryDTO);
    return Result.success(pageResult);
}

在 DishService 中扩展分页查询方法

PageResult pageQuery(DishPageQueryDTO dishPageQueryDTO);

在 DishServiceImpl 中实现分页查询方法

@Override
public PageResult pageQuery(DishPageQueryDTO dishPageQueryDTO) {
    PageHelper.startPage(dishPageQueryDTO.getPage(), dishPageQueryDTO.getPageSize());
    Page<DishVO> page = dishMapper.pageQuery(dishPageQueryDTO);
    return new PageResult(page.getTotal(), page.getResult());
}

在 DishMapper 接口中声明 pageQuery 方法

Page<DishVO> pageQuery(DishPageQueryDTO dishPageQueryDTO);

在 DishMapper.xml 中编写SQL

<select id="pageQuery" resultType="com.sky.vo.DishVO">
    select d.*, c.name category_name from dish d left join category c on d.category_id = c.id
    <where>
        <if test="name != null">and d.name = #{name}</if>
        <if test="name != null">and d.category_id = #{categoryId}</if>
        <if test="name != null">and d.status = #{status}</if>
    </where>
    order by d.create_time desc
</select>

功能测试

  • 可以通过接口文档进行测试,最后完成前后端联调测试即可。

删除菜品

需求分析和设计

产品原型

删除菜品产品原型

业务规则

  • 可以一次删除一个菜品,也可以批量删除菜品。
  • 启售中的菜品不能删除。
  • 被套餐关联的菜品不能删除。
  • 删除菜品后,关联的口味数据也需要删除掉。

接口设计

删除菜品接口设计

数据库设计

删除菜品数据库设计

代码开发

根据删除菜品的接口定义在DishController中创建方法

@DeleteMapping
@ApiOperation("批量删除菜品")
public Result delete(@RequestParam List<Long> ids) {
    log.info("批量删除菜品:{}", ids);
    dishService.deleteBatch(ids);
    return Result.success();
}

在DishService接口中声明deleteBatch方法

void deleteBatch(List<Long> ids);

在DishServiceImpl中实现deleteBatch方法

    @Override
    @Transactional
    public void deleteBatch(List<Long> ids) {
        for (Long id : ids) {
            Dish dish = dishMapper.getById(id);
            if (dish.getStatus().equals(StatusConstant.ENABLE)) {
                throw new DeletionNotAllowedException(MessageConstant.DISH_ON_SALE);
            }
        }

        List<Long> setmealIds = setmealDishMapper.getSetmealIdsByDishIds(ids);
        if (setmealIds != null && !setmealIds.isEmpty()) {
            throw new DeletionNotAllowedException(MessageConstant.DISH_BE_RELATED_BY_SETMEAL);
        }

        for (Long id : ids) {
            dishMapper.deleteById(id);
            dishFlavorMapper.deleteByDishId(id);
        }
    }

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

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

创建SetmealDishMapper,声明getSetmealIdsByDishIds方法,并在xml文件中编写SQL

//SetmealDishMapper.java
package com.sky.mapper;

import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface SetmealDishMapper {

    /**
     * 根据菜品id查询对应的套餐id
     *
     * @param dishIds
     * @return
     */
    List<Long> getSetmealIdsByDishIds(List<Long> dishIds);
}
<!--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="getSetmealIdsByDishIds" resultType="java.lang.Long">
        select setmeal_id from setmeal_dish where dish_id in
        <foreach collection="dishIds" item="dishId" open="(" separator="," close=")">
            #{dishId}
        </foreach>
    </select>
</mapper>

在DishMapper中声明deleteById方法并配置SQL

@Delete("delete from dish where id = #{id}")
void deleteById(Long id);

在DishFlavorMapper中声明deleteByDishId方法并配置SQL

@Delete("delete from dish_flavor where dish_id = #{dishId}")
void deleteByDishId(Long dishId);

代码优化:根据菜品id集合批量删除菜品数据及其关联的口味数据

//DishServiceImpl.java
@Override
@Transactional
public void deleteBatch(List<Long> ids) {
    for (Long id : ids) {
        Dish dish = dishMapper.getById(id);
        if (dish.getStatus().equals(StatusConstant.ENABLE)) {
            throw new DeletionNotAllowedException(MessageConstant.DISH_ON_SALE);
        }
    }

    List<Long> setmealIds = setmealDishMapper.getSetmealIdsByDishIds(ids);
    if (setmealIds != null && !setmealIds.isEmpty()) {
        throw new DeletionNotAllowedException(MessageConstant.DISH_BE_RELATED_BY_SETMEAL);
    }

    dishMapper.deleteByIds(ids);
    dishFlavorMapper.deleteByDishIds(ids);
}

//DishMapper.java
void deleteByIds(List<Long> ids);

//DishFlavorMapper.java
void deleteByDishIds(List<Long> dishIds);
<!--DishMapper.xml-->
<delete id="deleteByIds">
    delete from dish where id in
    <foreach collection="ids" item="id" open="(" separator="," close=")">
        #{id}
    </foreach>
</delete>

<!--DishFlavorMapper.xml-->
<delete id="deleteByDishIds">
    delete from dish_flavor where dish_id in
    <foreach collection="dishIds" item="dishId" open="(" separator="," close=")">
        #{dishId}
    </foreach>
</delete>

功能测试

  • 可以通过接口文档进行测试,最后完成前后端联调测试即可。

修改菜品

需求分析和设计

产品原型

修改菜品产品原型

接口设计

根据id查询菜品
根据id查询菜品接口设计
根据类型查询分类(已实现)
文件上传(已实现)
修改菜品
修改菜品接口设计

代码开发

根据id查询菜品接口开发

根据根据id查询菜品的接口定义在DishController中创建方法
@GetMapping("/{id}")
@ApiOperation("根据id查询菜品")
public Result<DishVO> getById(@PathVariable Long id) {
    log.info("根据id查询菜品:{}", id);
    DishVO dishVO = dishService.getByIdWithFlavor(id);
    return Result.success(dishVO);
}
在DishService接口中声明getByIdWithFlavor方法
DishVO getByIdWithFlavor(Long id);
在DishServiceImpl中实现getByIdWithFlavor方法
@Override
@Transactional
public DishVO getByIdWithFlavor(Long id) {
    Dish dish = dishMapper.getById(id);
    List<DishFlavor> flavors = dishFlavorMapper.getByDishId(id);

    DishVO dishVO = new DishVO();
    BeanUtils.copyProperties(dish, dishVO);
    dishVO.setFlavors(flavors);

    return dishVO;
}
在DishFlavorMapper中声明getByDishId方法,并配置SQL
@Select("select * from dish_flavor where dish_id = #{dishId}")
List<DishFlavor> getByDishId(Long dishId);

修改菜品接口开发

根据修改菜品的接口定义在DishController中创建方法
@PutMapping
@ApiOperation("修改菜品")
public Result update(@RequestBody DishDTO dishDTO) {
    log.info("修改菜品:{}", dishDTO);
    dishService.updateWithFlavor(dishDTO);
    return Result.success();
}
在DishService接口中声明updateWithFlavor方法
void updateWithFlavor(DishDTO dishDTO);
在DishServiceImpl中实现updateWithFlavor方法
@Override
@Transactional
public void updateWithFlavor(DishDTO dishDTO) {
    Dish dish = new Dish();
    BeanUtils.copyProperties(dishDTO, dish);
    dishMapper.update(dish);

    //先删除原来的口味数据
    dishFlavorMapper.deleteByDishId(dishDTO.getId());

    //再插入新的口味数据
    Long dishId = dish.getId();

    List<DishFlavor> flavors = dishDTO.getFlavors();
    if (flavors != null && !flavors.isEmpty()) {
        flavors = flavors.stream().filter(dishFlavor -> !dishFlavor.getName().isEmpty()).collect(Collectors.toList());
        flavors.forEach(dishFlavor -> dishFlavor.setDishId(dishId));
        //向口味表插入n条数据
        dishFlavorMapper.insertBatch(flavors);
    }
}
在DishMapper中声明update方法
@AutoFill(OperationType.UPDATE)
void update(Dish dish);
在DishMapper.xml中声明update方法并配置SQL
<update id="update">
    update dish
    <set>
        <if test="name != null">name = #{name},</if>
        <if test="categoryId != null">category_id = #{categoryId},</if>
        <if test="price != null">price = #{price},</if>
        <if test="image != null">image = #{image},</if>
        <if test="description != null">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>

功能测试

  • 可以通过接口文档进行测试,最后完成前后端联调测试即可。

菜品启售停售

需求分析和设计

产品原型

菜品启售停售产品原型

业务规则

  • 菜品停售,则包含菜品的套餐同时停售。

接口设计

菜品启售停售接口设计

代码开发

根据菜品启售停售的接口定义在DishController中创建方法

@PostMapping("/status/{status}")
@ApiOperation("菜品启售停售")
public Result startOrStop(@PathVariable Integer status, Long id) {
    log.info("菜品启售停售:{},{}", status, id);
    dishService.startOrStop(status, id);
    return Result.success();
}

在DishService接口中声明startOrStop方法

void startOrStop(Integer status, Long id);

在DishServiceImpl中实现startOrStop方法

@Override
@Transactional
public void startOrStop(Integer status, Long id) {
    Dish dish = Dish.builder()
            .status(status)
            .id(id)
            .build();
    dishMapper.update(dish);

    if (status.equals(StatusConstant.DISABLE)) {
        List<Long> dishIds = new ArrayList<>();
        dishIds.add(id);

        List<Long> setmealIds = setmealDishMapper.getSetmealIdsByDishIds(dishIds);
        if (setmealIds != null && !setmealIds.isEmpty()) {
            for (Long setmealId : setmealIds) {
                Setmeal setmeal = Setmeal.builder()
                        .status(StatusConstant.DISABLE)
                        .id(setmealId)
                        .build();
                setmealMapper.update(setmeal);
            }
        }
    }
}

在SetmealMapper中声明update方法

@AutoFill(OperationType.UPDATE)
void update(Setmeal setmeal);

创建SetmealMapper.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.SetmealMapper">

    <update id="update">
        update setmeal
        <set>
            <if test="categoryId != null">category_id = #{categoryId},</if>
            <if test="name != null">name = #{name},</if>
            <if test="price != null">price = #{price},</if>
            <if test="status != null">status = #{status},</if>
            <if test="description != null">description = #{description},</if>
            <if test="image != null">image = #{image},</if>
            <if test="updateTime != null">update_time = #{updateTime},</if>
            <if test="updateUser != null">update_user = #{updateUser},</if>
        </set>
        where id = #{id}
    </update>
</mapper>

代码优化:根据套餐id集合批量修改套餐数据

//DishServiceImpl.java
@Override
@Transactional
public void startOrStop(Integer status, Long id) {
    Dish dish = Dish.builder()
        .status(status)
        .id(id)
        .build();
    dishMapper.update(dish);

    if (status.equals(StatusConstant.DISABLE)) {
        List<Long> dishIds = new ArrayList<>();
        dishIds.add(id);

        List<Long> setmealIds = setmealDishMapper.getSetmealIdsByDishIds(dishIds);
        if (setmealIds != null && !setmealIds.isEmpty()) {
            setmealMapper.startOrStopBatch(setmealIds, StatusConstant.DISABLE);
        }
    }
}

//setmealMapper.java
@AutoFill(OperationType.UPDATE)
void startOrStopBatch(List<Long> setmealIds, Integer startOrStop);
//SetmealMapper.xml
<update id="startOrStopBatch">
    update setmeal set status = #{startOrStop} where id in
    <foreach collection="setmealIds" item="setmealId" open="(" separator="," close=")">
        #{setmealId}
    </foreach>
</update>

功能测试

  • 可以通过接口文档进行测试,最后完成前后端联调测试即可。
posted @ 2024-04-10 20:04  zgg1h  阅读(553)  评论(0编辑  收藏  举报