二刷苍穹外卖 day04

新增套餐

数据库设计

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对象,而不是表单数据

相关推荐
Naiva8 分钟前
【小技巧】Python + PyCharm 小智AI配置MCP接入点使用说明(内测)( PyInstaller打包成 .exe 可执行文件)
开发语言·python·pycharm
云动雨颤12 分钟前
Java并发性能优化|读写锁与互斥锁解析
java
梦子要转行17 分钟前
matlab/Simulink-全套50个汽车性能建模与仿真源码模型9
开发语言·matlab·汽车
ldj202025 分钟前
Centos 安装Jenkins
java·linux
hqxstudying32 分钟前
Intellij IDEA中Maven的使用
java·maven·intellij-idea
SimonKing35 分钟前
拯救大文件上传:一文彻底彻底搞懂秒传、断点续传以及分片上传
java·后端·架构
深栈解码35 分钟前
JUC并发编程 内存布局和对象头
java·后端
北方有星辰zz1 小时前
数据结构:栈
java·开发语言·数据结构
Seven971 小时前
一个static关键字引发的线上故障:深度剖析静态变量与配置热更新的陷阱
java
山野万里__1 小时前
C++与Java内存共享技术:跨平台与跨语言实现指南
android·java·c++·笔记