新增套餐
数据库设计

service
java
/**
* 套餐业务实现
*/
@Service
@Slf4j
public class SetmealServiceImpl implements SetmealService {
@Autowired
private SetmealMapper setmealMapper;
@Autowired
private SetmealDishMapper setmealDishMapper;
@Autowired
private DishMapper dishMapper;
/**
* 新增套餐,同时需要保存套餐和菜品的关联关系
* @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);
}
}
先保存套餐并得到套餐Id,套餐Id是在插入时因为useGeneratedKeys="true" keyProperty="id"由mybatis自动赋值的,得到id后赋值给套餐中的每个菜品,然后将菜品列表通过
(#{sd.setmealId},#{sd.dishId},#{sd.name},#{sd.price},#{sd.copies})
保存到setmeal_dish表中
套餐分页查询
controller
java
@GetMapping("/page")
@ApiOperation("分页查询")
public Result<PageResult> page( SetmealPageQueryDTO setmealPageQueryDTO) {
PageResult pageResult = setmealService.pageQuery(setmealPageQueryDTO);
return Result.success(pageResult);
}
注意这里不能用@RequestBody,@RequestBody只能解析请求体中的数据,而GET请求参数通过查询字符串传递,而在不写明的情况下默认使用@RequestParam,符合get请求的条件
删除套餐
java
@DeleteMapping
@ApiOperation("删除")
public Result delete(@RequestParam List<Long> ids)
{
setmealService.deleteBatch(ids);
return Result.success();
}
这里不写@RequestParam不会默认生效,原因:
对于简单类型(如Long,String,Integer)默认按@RequestParam处理,即从请求参数(?id=1)中提取值,可省略
但如果是复杂类型(List,自定义对象)
默认按对象属性绑定处理,Spring 会认为 ids
是一个复杂类型的属性 (而非请求参数),但由于没有对应的 "父对象",会导致 参数绑定失败 (报 MissingServletRequestParameterException
或无法解析 List)。
当显式添加 @RequestParam
时:解析器会从请求参数中提取 所有同名的 ids
值 (如 ?ids=1&ids=2
),并自动封装为 List<Long>
(前提是参数能转换为 Long
类型)。
修改套餐
service
java
@Override
public SetmealVO getByIdWithDish(Long id) {
Setmeal setmeal = setmealMapper.getById(id);
List<SetmealDish> setmealDishes = setmealDishMapper.getBySetmealId(id);
SetmealVO setmealVO = new SetmealVO();
BeanUtils.copyProperties(setmeal,setmealVO);
setmealVO.setSetmealDishes(setmealDishes);
return setmealVO;
}
这里的setmealVO.setSetmealDishes(setmealDishes);
不能写成BeanUtils.copyProperties(setmealDishes,setmealVO);
原因在于 BeanUtils.copyProperties
的工作机制是 "复制同名属性" ,而 setmealDishes
作为 集合对象 ,无法通过 BeanUtils.copyProperties(setmealDishes, setmealVO)
完成赋值。,具体来说BeanUtils.copyProperties的作用时遍历源对象的所有属性(通过getter方法),找到目标对象中同名的属性(通过setter方法),而setmealDishes是一个List类型的集合,而非一个"包含setmealDishes"属性的对象
java
@Transactional
@Override
public void update(SetmealDTO setmealDTO) {
Setmeal setmeal = new Setmeal();
BeanUtils.copyProperties(setmealDTO, setmeal);
setmealMapper.update(setmeal);
Long setmealId = setmealDTO.getId();
setmealDishMapper.deleteBySetmealId(setmealId);
List<SetmealDish> setmealDishes = setmealDTO.getSetmealDishes();
setmealDishes.forEach(setmealDish ->
{
setmealDish.setSetmealId(setmealId);
});
setmealDishMapper.insertBatch(setmealDishes);
}
这里先删除特定套餐与菜品的关联关系,再根据菜品列表重新建立关联功能,比如原来的套餐关联了菜品A、B,就可以先删除与A、B的关联,再插入与C、D的关联
mapper
答案中没有的XML的update写法
xml
<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>
</set>
where id=#{id}</update>
启售停售套餐
service
java
@PostMapping("/status/{status}")
@ApiOperation("套餐启售停售")
public Result startOrStop(@PathVariable Integer status,Long id)
{
setmealService.startOrStop(status,id);
return Result.success();
}
这里区分一下,POST请求参数可以通过三种方式传递
查询参数 ?id=xxx
表单数据 通过表单提交Content-Type: application/x-www-form-urlencoded
id=101&name=套餐A
请求体Content-Type: application/json <br>
{"id": 101, "name": "套餐A"}`
@RequestBody从请求体中读取数据并将其反序列化成Java对象
补一个Dishservice的启售停售方法
java
@Override
public void startOrStop(Integer status, Long id) {
Dish dish = dishMapper.getById(id);
dish.setStatus(status);
dishMapper.update(dish);
}
mapper
sql
@Select("select a.* from dish a left join setmeal_dish b on a.id=b.dish_id where b.setmeal_id=#{setmealId}")
List<Dish> getBySetmealId(Long id);
从 dish
表(别名为 a
)和 setmeal_dish
表(别名为 b
)进行左连接操作。左连接的条件是 a.id = b.dish_id
。查询的结果是满足 b.setmeal_id
等于传入参数 #{setmealId}
的 dish
表的所有列(即 a.*
)。
总结
1.对于@RequestParam的两种情况:
对于简单类型(如Long,String,Integer)默认按@RequestParam处理,即从请求参数(?id=1)中提取值,可省略
但如果是复杂类型(List,自定义对象)
默认按对象属性绑定处理,Spring 会认为 ids
是一个复杂类型的属性 (而非请求参数),但由于没有对应的 "父对象",会导致 参数绑定失败 (报 MissingServletRequestParameterException
或无法解析 List)。
当显式添加 @RequestParam
时:解析器会从请求参数中提取 所有同名的 ids
值 (如 ?ids=1&ids=2
),并自动封装为 List<Long>
(前提是参数能转换为 Long
类型)。
2.BeanUtils.copyProperties的工作机制:
"复制同名属性"**,而 setmealDishes
作为 集合对象 ,无法通过 BeanUtils.copyProperties(setmealDishes, setmealVO)
完成赋值。,具体来说BeanUtils.copyProperties的作用时遍历源对象的所有属性(通过getter方法),找到目标对象中同名的属性(通过setter方法),而setmealDishes是一个List类型的集合,而非一个"包含setmealDishes"属性的对象
3.@RequestBody从POST的请求体中读取数据并将其反序列化成Java对象,而不是表单数据