2-6 新增菜品
02 05-新增菜品_需求分析和设计





03 06-新增菜品_代码开发_1
文件上传接口开发:

在这一部分我们主要在于对阿里云oss的代码开发和实现
1.配置阿里云oss:
XML
alioss:
endpoint: oss-cn-beijing-internal.aliyuncs.com
access-key-id:
access-key-secret:
bucket-name:
填你自己的。
2.创建公共接口管理类CommonController:
java
Slf4j
@RestController
@ApiOperation("通用接口")
@RequestMapping("/admin/common")
public class CommonController {
/**
* 文件上传接口
* @param file
* @return
*/
@ApiOperation("文件上传接口")
@PostMapping("/upload")
public Result<String> upload(MultipartFile file){
//接受文件的参数需要和请求参数保持一致。所以这里采用file
return null;
}
}
3.熟悉我们已经有的阿里云工具类:
java
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();
}
}
可以看到除了基础的阿里云oss的配置代码之后我们还自己创建了一个stringbuilder对象用于存放一个经过字符串拼接的url。这个url就是用于我们前端来回显我们上传内容的。
4.创建一个配置类用于生成aliOssUtil对象:
java
package com.sky.config;
import com.sky.properties.AliOssProperties;
import com.sky.utils.AliOssUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class AliOssConfiguaration {
// 配置类,用来创建aliyunossUtil对象
@Bean
public AliOssUtil aliOssUtil(AliOssProperties aliOssProperties) {
log.info("开始创建阿里云文件上传工具类对象:{}", aliOssProperties);
return new AliOssUtil(aliOssProperties.getEndpoint(),
aliOssProperties.getAccessKeyId(),
aliOssProperties.getAccessKeySecret(),
aliOssProperties.getBucketName());
}
}
注意这个@Bean注解
04 07-新增菜品_代码开发_2
在这里我们主要实现文件上传的具体代码。
java
package com.sky.controller.admin;
import com.sky.result.Result;
import com.sky.utils.AliOssUtil;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.Pointcut;
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;
@Slf4j
@RestController
@ApiOperation("通用接口")
@RequestMapping("/admin/common")
public class CommonController {
@Autowired
private AliOssUtil aliOssUtil;
/**
* 文件上传接口
* @param file
* @return
*/
@ApiOperation("文件上传接口")
@PostMapping("/upload")
public Result<String> upload(MultipartFile file){
//接受文件的参数需要和请求参数保持一致。所以这里采用file
log.info("文件上传:{}",file);
try {
// 获取文件原始名称
String originalFilename = file.getOriginalFilename();
// 截取文件类型
String type = originalFilename.substring(originalFilename.lastIndexOf("."));
//使用UUid生成文件名
String objectName = UUID.randomUUID().toString() + type;
// 调用工具类进行文件上传,获取文件上传路径
String filePath=aliOssUtil.upload(file.getBytes(),objectName);
return Result.success(filePath);
} catch (IOException e) {
log.error("文件上传失败:{}",e);
}
return null;
}
}
通过前后端联调我们发现可以实现数据的上传

05 08-新增菜品_代码开发_3
完成了菜品上传的具体业务代码:
1,创建DishController:
java
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;
@RequestMapping("/dish")
@RestController
@Api(tags = "菜品管理接口")
@Slf4j
public class DishController {
@Autowired
private DishService dishService;
/**
* 新增菜品
* @param dishDTO
* @return
*/
@ApiOperation("新增菜品")
@PostMapping
public Result save(@RequestBody DishDTO dishDTO) {
log.info("新增菜品:{}", dishDTO);
dishService.saveWithFlavor(dishDTO);
return Result.success();
}
}
创建接口和接口实现类:
java
@Service
@Slf4j
public class DishServiceImpl implements DishService {
@Autowired
private DishMapper dishMapper;
@Autowired
private DishFlavorMapper dishFlavorMapper;
/**
* 新增菜品和口味
* @param dishDTO
* @return
*/
@Override
@Transactional
public void saveWithFlavor(DishDTO dishDTO) {
log.info("新增菜品:{}", dishDTO);
//向菜品表插入数据
//属性拷贝:
Dish dish = new Dish();
BeanUtils.copyProperties(dishDTO, dish);
dishMapper.insert(dish);
//获取插入后的菜品id
Long dishId = dish.getId();
//向口味表插入数据
List<DishFlavor> flavors = dishDTO.getFlavors();
if (flavors != null && flavors.size() > 0) {
//遍历
/* for (DishFlavor flavor : flavors) {
flavor.setDishId(dishId);
}*/
flavors.forEach(flavor -> flavor.setDishId(dishId));
//向表中插入n条数据
dishFlavorMapper.insertBatch(flavors);
}
}
}
根据接口文档我们发现,这里的方法需要对两个表进行修改操作,需要同时修改菜品表和口味表。于是我们需要在实现方法前添加@Transactional注解来保证二者同步进行。
3,创建对应的Mapper层并提供Sql方法:
java
<?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>
<?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="flavor" separator=",">
(#{flavor.dishId}, #{flavor.name}, #{flavor.value})
</foreach>
</insert>
</mapper>
由于我们添加口味的方法需要菜品的id,我们会在新增菜品的mapper.xml中添加这一段:
java
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
表明需要返回值且返回内容是id。
然后再实现类中就可以获取到对应的dishId了:
java
//获取插入后的菜品id
Long dishId = dish.getId();
最后使用foreach的形式遍历,将dishId存进去:
java
//遍历
/* for (DishFlavor flavor : flavors) {
flavor.setDishId(dishId);
}*/
flavors.forEach(flavor -> flavor.setDishId(dishId));
这样就可以将dishId获取并存入dishFlavor表中了。
06 09-新增菜品_功能测试
测试范本如下:

结果如下:


新增菜品业务完成!
作业:完成菜品管理模块中的 **菜品起售停售** 功能
1. 根据产品原型进行需求分析,分析出业务规则
大概一个业务规则口述下来就是:
点击起售按钮,修改数据库dish表中的status,0是停售,1是起售
起售按钮点击后完成业务会变成停售按钮(不知道这点业务是前端还是后端完成的,是后端的话可能会需要一个返回值来帮助前端完成改变)
2. 设计 菜品起售停售 功能的接口

由图片可知是一个post请求

会有一个路径参数status,一个id,不需要返回值
3. 根据接口设计进行代码实现
java
/**
* 控制起售停售
* @param status
* @param id
* @return
*/
@ApiOperation("控制起售停售")
@PostMapping("/status/{status}")
public Result<String> startOrStop(@PathVariable("status") Integer status, Long id) {
log.info("控制起售停售:{},{}", status, id);
dishService.startOrStop(status, id);
return Result.success();
}
/**
* 控制起售停售
* @param status
* @param id
* @return
*/
@Override
public void startOrStop(Integer status, Long id) {
log.info("控制起售停售:{},{}", status, id);
//有现成的id判断,直接用update方法修改得了说是
Dish dish = Dish.builder()
.status(status)
.id(id)
.build();
dishMapper.update(dish);
}
写这个作业的时间节点是写完2.7之后了。索性直接调用修改方法,一样可以实现这个需求。毕竟是动态sql且id喂嘴里了。
然后发现自己傻波一了,想东西又没想全。
如果是商品停售的操作,那么商品所关联的套餐也需要停售!
于是灰溜溜的修改实现类代码:
java
@Override
public void startOrStop(Integer status, Long id) {
log.info("控制起售停售:{},{}", status, id);
//有现成的id判断,直接用update方法修改得了说是
Dish dish = Dish.builder()
.status(status)
.id(id)
.build();
dishMapper.update(dish);
if (status == StatusConstant.DISABLE) {
// 如果是停售操作,还需要将包含当前菜品的套餐也停售
List<Long> dishIds = new ArrayList<>();
dishIds.add(id);
// select setmeal_id from setmeal_dish where dish_id in (?,?,?)
List<Long> setmealIds = setmealDishMapper.getSetmealIdsByDishIds(dishIds);
if (setmealIds != null && setmealIds.size() > 0) {
for (Long setmealId : setmealIds) {
Setmeal setmeal = Setmeal.builder()
.id(setmealId)
.status(StatusConstant.DISABLE)
.build();
setmealMapper.update(setmeal);
}
}
}
}
代码逻辑是:先正常修改菜品,后续做一个判断,如果是停售操作:
先用一个dishId来存储id,并且用这个idshid获取到对应的套餐id。
然后判断:如果获取到的id不为空且大于0,说明有套餐关联。
这时候选择遍历获取id,依次用一个setmeal来存储数据,然后作为形参交给setalMapper的修改方法去修改套餐。之所以用集合的方式来存储是因为存在一个商品关联多个套餐的情况。
update方法就是常规的动态sql,不贴代码了。
2-7 菜品分页查询&删除菜品&修改菜品
01 10-菜品分页查询_需求分析和设计



你会发现返回数据当中存在一个CategoryName和其他返回数据并不在一个表
02 11-菜品分页查询_代码开发和功能测试
1.需要使用dishPageQueryDTO来接收数据,用DishVO来返回数据
代码开发如下:
java
/**
* 菜品分页查询
* @param dishPageQueryDTO
* @return
*/
@ApiOperation("菜品分页查询")
@GetMapping("/page")
public Result<Object> page(DishPageQueryDTO dishPageQueryDTO) {
log.info("菜品分页查询:{}", dishPageQueryDTO);
PageResult pageResult =dishService.pageQuery(dishPageQueryDTO);
return Result.success(pageResult);
}
/**
* 菜品分页查询
* @param dishPageQueryDTO
* @return
*/
@Override
public PageResult pageQuery(DishPageQueryDTO dishPageQueryDTO) {
log.info("菜品分页查询:{}", dishPageQueryDTO);
//1.获取分页参数和总数
PageHelper.startPage(dishPageQueryDTO.getPage(), dishPageQueryDTO.getPageSize());
//2,根据条件查询
Page<DishVO> page= dishMapper.pageQuery(dishPageQueryDTO);
//3.对返回对象进行处理
Long total = page.getTotal();
List<DishVO> records = page.getResult();
return new PageResult(total, records);
}
<select id="pageQuery" resultType="com.sky.vo.DishVO">
SLECT 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 != ''">
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 d.update_time DESC
</select>
和以往的分页查询没什么大区别。值得注意一下的就是这里的sql语法实现了一个左外连接的多表查询。
SLECT d.*, c.name as categoryName from dish d LEFT JOIN category c ON d.category_id = c.id
理解这一句的别名,和逻辑就好了。
03 12-删除菜品_需求分析和设计

具体要操作三个表:

04 13-删除菜品_代码实现
Controller:
java
/**
* 批量删除菜品
* @param ids
* @return
*/
@ApiOperation("批量删除菜品")
@DeleteMapping
public Result delete(@RequestParam List<Long> ids) {
log.info("批量删除菜品:{}", ids);
dishService.deleteBatch(ids);
return Result.success();
}
impl:
java
/**
* 批量删除菜品
* @param ids
* @return
*/
@Transactional
@Override
public void deleteBatch(List<Long> ids) {
//1,判断当前菜品是否在售
for (Long id : ids) {
Dish dish = dishMapper.getByIds(id);
if (dish.getStatus() == StatusConstant.ENABLE) {
throw new DeletionNotAllowedException(MessageConstant.DISH_ON_SALE);
}
}
//2,判断是否被套餐关联,关联的菜品不能删除,没有关联的可以删除
List<Long> setmealIds = setmealDishMapper.getSetmealDishIdByDishId(ids);
if (setmealIds != null && setmealIds.size() > 0) {
throw new DeletionNotAllowedException(MessageConstant.DISH_BE_RELATED_BY_SETMEAL);
}
//3.可以删除了
for (Long id : ids) {
//3,删除菜品表中的数据
dishMapper.deleteById(id);
//4,删除口味表中的数据
dishFlavorMapper.deleteByDishId(id);
}
}
关联到的Sql语法:
XML
<--查询有无关联套餐-->
<select id="getSetmealDishIdByDishId" resultType="java.lang.Long">
select * from setmeal_dish where dish_id in
<foreach collection="ids" item="dishId" separator="," open="(" close=")">
#{dishId}
</foreach>
</select>
/**
* 根据id查询菜品
* @param id
* @return
*/
@Select("select * from dish where id = #{id}")
Dish getByIds(Long id);
/**
* 根据id删除菜品
* @param id
*/
@Delete("delete from dish where id = #{id}")
void deleteById(Long id);
/**
* 根据菜品id删除对应的口味数据
* @param id
*/
@Delete("delete from dish_flavor where dish_id = #{id}")
void deleteByDishId(Long id);
关键点其实不多,主要是三个表的查询外加条件判断会比较复杂,需要熟练度的支撑。
多表查询,@Transactional注解别忘了。
此外需要注意foreach的格式:
collection="ids" 这里的内容要和mapper层方法的形参相同
item="dishId" 这里的内容要和下方foreach#{}内的内容相同
where后调用in 的时候注意一定要有括号:open="(" close=")"
05 14-删除菜品_功能测试

创建了几个,自己删了下,没啥毛病。
06 15-修改菜品_需求分析和设计

需要回显的东西还是比较多比较复杂的


存在flavors数组。可能有多个口味。

07 16-修改菜品_代码开发_1
根据id查询菜品接口代码实现如下:
java
/**
* 根据id查询菜品
* @param id
* @return
*/
@ApiOperation("根据id查询菜品")
@GetMapping("/{id}")
public Result<DishVO> getById(@PathVariable Long id) {
log.info("根据id查询菜品:{}", id);
DishVO dishVO = dishService.getByIdWithFlavor(id);
return Result.success(dishVO);
}
/**
* 根据id查询菜品
* @param id
* @return
*/
@Override
public DishVO getByIdWithFlavor(Long id) {
log.info("根据id查询菜品:{}", 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;
}
只贴出了核心业务部分。我发现自己编写实现类的时候操作不太规范,**我直接new了一个dishVO对象去存储dishMapper.getById(id);的值。这并不合规。**但是代码逻辑没问题。
以后需要刻意性质的用实体类来调用mapper层方法获取返回值,想要标准化以VO的形式返回给前端就做数据拷贝
08 17-修改菜品_代码开发_2
修改菜品代码实现如下:
java
/**
* 修改菜品
* @param dishDTO
* @return
*/
@ApiOperation("修改菜品")
@PutMapping
public Result update(@RequestBody DishDTO dishDTO) {
log.info("修改菜品:{}", dishDTO);
dishService.update(dishDTO);
return Result.success();
}
/**
* 修改菜品
* @param dishDTO
* @return
*/
@Override
public void update(DishDTO dishDTO) {
log.info("修改菜品:{}", dishDTO);
Dish dish = new Dish();
BeanUtils.copyProperties(dishDTO, dish);
//修改菜品表数据
dishMapper.update(dish);
//修改口味表数据:先删除,再插入
log.info("修改口味表数据:先删除,再插入");
dishFlavorMapper.deleteByDishId(dishDTO.getId());
//插入新数据
List<DishFlavor> flavors = dishDTO.getFlavors();
if (flavors != null && flavors.size() > 0) {
flavors.forEach(flavor -> flavor.setDishId(dishDTO.getId()));
dishFlavorMapper.insertBatch(flavors);
}
log.info("修改菜品成功");
}
这个业务里面比较有意思的有两点:
1,获取到的dishDTO里包含了flavors口味集合。所以一方面为了规范,一方面为了查询,我们创建了一个dish对象拷贝DTO中的内容后,来对dish数据库表进行修改操作。
2,由于口味传过来的是一个集合,直接修改会比较复杂。我们这里采用先删除口味信息,再新增口味信息的方式来实现对口味更改的操作。
09 18-修改菜品_功能测试
测试成功没毛病

作业:完成套餐管理模块所有业务功能
包括:
- 新增套餐 ok-套餐分页查询 ok -删除套餐 ok - 修改套餐 - 起售停售套餐
要求:
-
根据产品原型进行需求分析,分析出业务规则
-
设计接口
-
梳理表之间的关系(分类表、菜品表、套餐表、口味表、套餐菜品关系表)
-
根据接口设计进行代码实现
-
分别通过swagger接口文档和前后端联调进行功能测试
分析:
-
套餐名称唯一
-
套餐必须属于某个分类
-
套餐必须包含菜品
-
名称、分类、价格、图片为必填项
-
添加菜品窗口需要根据分类类型来展示菜品
-
新增的套餐默认为停售状态
接口设计:
-
根据类型查询分类(已完成)
-
根据分类id查询菜品 搞定
-
图片上传(已完成)
-
新增套餐 搞定
套餐分页查询代码实现:
java
/**
* 套餐分页查询
* @param
* @return
*/
@ApiOperation("套餐分页查询")
@GetMapping("/page")
public Result<Object> page(SetmealPageQueryDTO setmealPageQueryDTO) {
log.info("菜品分页查询:{}", setmealPageQueryDTO);
PageResult pageResult =setmealService.pageQuery(setmealPageQueryDTO);
return Result.success(pageResult);
}
/**
* 套餐分页查询
* @param setmealPageQueryDTO
* @return
*/
@Override
public PageResult pageQuery(SetmealPageQueryDTO setmealPageQueryDTO) {
log.info("套餐分页查询:{}", setmealPageQueryDTO);
//1.获取分页参数和总数
PageHelper.startPage(setmealPageQueryDTO.getPage(), setmealPageQueryDTO.getPageSize());
//2,根据条件查询
Page<SetmealVO> page= setmealMapper.pageQuery(setmealPageQueryDTO);
//3.对返回对象进行处理
Long total = page.getTotal();
List<SetmealVO> records = page.getResult();
return new PageResult(total, records);
}
<select id="pageQuery" resultType="com.sky.vo.SetmealVO">
SELECT s.*, c.name as categoryName from setmeal s LEFT JOIN category c ON s.category_id = c.id
<where>
<if test="name != null and name != ''">
and s.name like concat('%',#{name},'%')
</if>
<if test="categoryId != null">
and s.category_id = #{categoryId}
</if>
<if test="status !=null">
and s.status = #{status}
</if>
</where>
order by s.update_time desc
</select>
新增套餐代码实现:
java
/**
* 新增套餐
* @param setmealDTO
* @return
*/
@PostMapping
@ApiOperation("新增套餐")
public Result save(@RequestBody SetmealDTO setmealDTO) {
setmealService.saveWithDish(setmealDTO);
return Result.success();
}
/**
* 新增套餐,同时需要保存套餐和菜品的关联关系
* @param setmealDTO
*/
@Transactional
public void saveWithDish(SetmealDTO setmealDTO) {
Setmeal setmeal = new Setmeal();
BeanUtils.copyProperties(setmealDTO, setmeal);
//向套餐表插入数据
setmealMapper.insert(setmeal);
//获取生成的套餐id
Long setmealId = setmeal.getId();
List<SetmealDish> setmealDishes = setmealDTO.getSetmealDishes();
setmealDishes.forEach(setmealDish -> {
setmealDish.setSetmealId(setmealId);
});
//保存套餐和菜品的关联关系
setmealDishMapper.insertBatch(setmealDishes);
}
删除套餐代码实现:
java
/**
* 批量删除套餐
* @param ids
* @return
*/
@ApiOperation("批量删除套餐")
@DeleteMapping
public Result delete(@RequestParam List<Long> ids) {
log.info("批量删除套餐,ids:{}", ids);
setmealService.deleteBatch(ids);
return Result.success();
}
/**
* 批量删除套餐
*
* @param ids
* @return
*/
@Override
public void deleteBatch(List<Long> ids) {
//1,判断当前套餐是否在售
for (Long id : ids) {
Setmeal setmeal = setmealMapper.getByIds(id);
if (setmeal.getStatus() == StatusConstant.ENABLE) {
throw new DeletionNotAllowedException(MessageConstant.SETMEAL_ON_SALE);
}
}
//3.可以删除了
for (Long id : ids) {
//3,删除套餐表中的数据
setmealMapper.deleteById(id);
}
}
/**
* 批量删除套餐
* @param id
*/
@Delete("delete from setmeal where id = #{id}")
void deleteById(Long id);
修改套餐代码实现:
java
/**
* 根据id查询套餐,应对回显
* @param id
* @return
*/
@ApiOperation("根据id查询套餐")
@GetMapping("/{id}")
public Result<SetmealVO> getById(@PathVariable Long id) {
log.info("根据id查询套餐:{}", id);
SetmealVO setmealVO = setmealService.getByIdWithDish(id);
return Result.success(setmealVO);
}
/**
* 修改套餐
* @param setmealDTO
* @return
*/
@ApiOperation("修改套餐")
@PutMapping
public Result update(@RequestBody SetmealDTO setmealDTO) {
log.info("修改套餐:{}", setmealDTO);
setmealService.update(setmealDTO);
return Result.success();
}
/**
* 修改套餐
* @param setmealDTO
* @return
*/
@Override
public void update(SetmealDTO setmealDTO) {
Setmeal setmeal = new Setmeal();
BeanUtils.copyProperties(setmealDTO, setmeal);
//修改套餐表数据
setmealMapper.update(setmeal);
}
/**
* 根据id查询套餐
* @param id
* @return
*/
@Override
public SetmealVO getByIdWithDish(Long id) {
log.info("根据id查询套餐:{}", id);
Setmeal setmeal = setmealMapper.getByIds(id);
SetmealVO setmealVO = new SetmealVO();
BeanUtils.copyProperties(setmeal, setmealVO);
return setmealVO;
}
/**
* 根据分类id查询套餐的数量
* @param id
* @return
*/
@Select("select count(id) from setmeal where category_id = #{categoryId}")
Integer countByCategoryId(Long id);
/**
* 修改套餐
* @param setmeal
*/
@AutoFill(OperationType.UPDATE)
void update(Setmeal setmeal);
<update id="update">
update setmeal
<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="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>
套餐起售停售:
java
/**
* 套餐起售、停售
* @param status
* @param id
* @return
*/
@Override
public void startOrStop(Integer status, Long id) {
//public static final String SETMEAL_ENABLE_FAILED = "套餐内包含未启售菜品,无法启售";
//如果当前套餐中如果包含未起售的菜品,则无法起售套餐
//1.根据套餐id查询套餐中菜品的数据,并装在一个集合中
List<Dish> dish =setmealDishMapper.getDishIdBySetmealId(id);
//创建集合
List<Long> dishIds = new ArrayList<>();
//遍历集合,将菜品id添加到集合中
for (Dish dish1 : dish) {
dishIds.add(dish1.getId());
}
//2.根据菜品id查询菜品信息,判断菜品是否在售,如果存在停售菜品,则抛出异常,无法起售套餐
for (Long dishId : dishIds) {
Dish dish1 = dishMapper.getByIds(dishId);
if (dish1.getStatus() == StatusConstant.DISABLE) {
throw new DeletionNotAllowedException(MessageConstant.SETMEAL_ENABLE_FAILED);
}
}
//3.如果套餐中菜品都起售,则允许起售套餐
Setmeal setmeal = new Setmeal();
setmeal.setId(id);
setmeal.setStatus(status);
setmealMapper.update(setmeal);
}