黑马-瑞吉外卖 day4 菜品管理

本文介绍了瑞吉外卖系统的菜品管理功能,包括文件上传下载、新增菜品、菜品信息分页查询、修改菜品状态及删除菜品等操作。在新增菜品中,涉及到查询菜品分类并保存菜品及其相关口味信息。在修改菜品时,提供了根据ID查询菜品信息和更新菜品及口味的流程。整个系统利用Spring Boot、MyBatis等技术实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1. 文件上传下载

1.1 上传upload

1.2 下载download

2. 新增菜品

2.1 查询菜品分类

2.2 保存菜品及其相关信息

3. 菜品信息分页查询

4. 修改菜品

4.1 根据id查询菜品信息

4.2 修改菜品以及口味信息

5. 修改菜品售卖状态(可批量)

6. 删除菜品(可批量)


1. 文件上传下载

1.1 上传upload

简述:将本地文件上传至服务器的过程,以便后续用户浏览或者下载。

前端

  • 必须采用post方式提交数据
  • 必须采用multipart格式上传文件
  • 使用input的file控件上传

eg:

后端

服务器接收客户端页面上传的文件通常要使用Apache的两个组件:

  • commons-fileupload
  • commons-io

Spring在spring-web包中对其进行了封装,极大简化了服务端代码,只需在Controller的方法中声明一个MultipartFile类型的参数即可接收上传的文件。

1. 在CommonController.java中定义方法实现

    //转存路径参数声明
    @Value("${greenTea.path}")
    private String basePath;

    /**
     * 文件上传
     * @param file
     * @return
     */
    @PostMapping("/upload")
    public R<String> upload(MultipartFile file){

        //获取原始文件名
        String originalFilename = file.getOriginalFilename();
        //截取文件名后缀
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));

        //使用UUID重新生成文件名,防止文件名称重复造成文件覆盖
        String fileName = UUID.randomUUID() + suffix;

        //判断目录是否存在,如果不存在则创建目录
        File dir = new File(basePath);
        if(!dir.exists()){
            dir.mkdirs();
        }

        //file是一个临时文件,需要转存到指定位置,否则请求结束后会自动删除
        try {
            file.transferTo(new File(basePath+fileName));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return R.success(fileName);
    }

2. 配置文件application.yml中设置文件转存路径参数值:

greenTea:
  path: D:\img\

1.2 下载download

简述:将文件从服务器传输到本地计算机或浏览器的过程。

     /**
     * 文件下载
     * @param name
     * @param response
     * @throws IOException
     */
    @GetMapping("/download")
    public void download(String name, HttpServletResponse response) throws IOException {

        //通过输入流读取文件内容到服务器
        FileInputStream fileInputStream = new FileInputStream(basePath+name);
        //通过输出流将文件写出到浏览器,在浏览器上展示图片
        ServletOutputStream outputStream = response.getOutputStream();

        //设置响应给页面的文件类型
        response.setContentType("image/jpeg");

        int len = 0;
        byte[] bytes = new byte[1024];
        while((len = fileInputStream.read(bytes))!=-1){
            outputStream.write(bytes,0,len);
            outputStream.flush();
        }
        //关闭资源
        outputStream.close();
        fileInputStream.close();

    }

2. 新增菜品

简述:管理员可以添加新的菜品,具体如下图:

 该页面需要发送两个请求:

2.1 查询菜品分类

具体请求信息:

代码如下:

     /**
     * 查询菜品或套餐分类
     * @param category
     * @return
     */
    @GetMapping("/list")
    // 请求路径:category/list?type=1 传过来的参数可以使用(String type)接收,也可以使用(Category category)将type封装为该对象的一个属性,建议使用后者,因为通用性更好
    public R<List<Category>> list(Category category){

        //构造查询条件
        LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
        //添加查询条件
        queryWrapper.eq(Category::getType,category.getType());
        //添加排序条件:先按照sort升序排列,如果sort相同再按照更新时间降序排列
        queryWrapper.orderByAsc(Category::getSort).orderByDesc(Category::getUpdateTime);
        List<Category> categories = categoryService.list(queryWrapper);
        return R.success(categories);
    }

 结果展示:

2.2 保存菜品及其相关信息

1. 创建dishDto实体类,用于封装增加菜品页面提交的数据;

注:DTO,全称Data Transfer Object ,数据传输对象,一般用于展示层与服务层之间的数据传输。

@Data
public class DishDto extends Dish {

    private List<DishFlavor> flavors = new ArrayList<>();

    private String categoryName;

    private Integer copies;
}

2. 保存菜品信息到数据库,并且保存相应的口味信息。

注:涉及多张表操作,需要进行事务控制,在启动类上添加开启事务的注解@EnableTransactionManagement,同时在实现业务逻辑的方法上添加@Transactional 注解。

@EnableTransactionManagement //开启事务注解的支持
public class GreenTeaApplication {
    public static void main(String[] args) {
        SpringApplication.run(GreenTeaApplication.class,args);
        log.info("项目启动成功...");
    }
}

方法一:for增强

    /**
     * 保存新增的菜品信息和相应的口味信息
     * @param dishDto
     * @return
     */
    @Transactional //因为操作多张表,需要进行事务控制,保证操作的原子性
    @PostMapping
    public R<String> save(@RequestBody DishDto dishDto){
        //保存菜品信息
        dishService.save(dishDto);
        //获取菜品id
        Long dishId = dishDto.getId();
        //取出菜品口味信息
        List<DishFlavor> flavors = dishDto.getFlavors();
        //为每条菜品口味信息赋上菜品id并保存进数据库
        for (DishFlavor dishFlavor : flavors) {
            dishFlavor.setDishId(dishId);
            dishFlavorService.save(dishFlavor);
        }
        return R.success("新增菜品成功");
    }

方法二:stream流

3. 菜品信息分页查询

使用mybatis-plus封装的分页工具,除了需要菜品表里的信息外,还需要查询分类表中的分类信息。

    /**
     * 菜品信息分页查询
     * @param page
     * @param pageSize
     * @param name
     * @return
     */
    @GetMapping("/page")
    public R<Page> page(int page, int pageSize, String name){

        //检验前端是否正常发送请求且是否被控制器正常接收
        //log.info("page:{},pageSize:{},name:{}",page,pageSize,name);

        //构建分页信息对象,传入参数:页数和每页条数
        Page<Dish> pageInfo = new Page<>(page,pageSize);
        Page<DishDto> dishDtoPage = new Page<>();

        //构造条件构造器
        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
        //添加查询条件,如果搜索框里输入了查询条件,就使用模糊查询
        queryWrapper.like(name!=null,Dish::getName,name);
        //添加排序条件
        queryWrapper.orderByDesc(Dish::getUpdateTime);
        //进行查询,传入分页信息对象和条件构造器
        dishService.page(pageInfo,queryWrapper);

        //对象拷贝,将dish的分页信息复制到dishDto,但不复制其中的records属性(records中保存了查询的菜品信息)
        BeanUtils.copyProperties(pageInfo,dishDtoPage,"records");
        //获取dish分页对象records属性中保存的菜品信息
        List<Dish> dishRecords = pageInfo.getRecords();
        //创建一个list集合用来保存dishDto的信息
        List<DishDto> dtoRecords = new ArrayList<>();

        //遍历dishRecords,将dish的全部信息拷贝给dishDto对象
        //根据菜品表的分类id查询分类名,然后赋给dishDto中的categoryName属性
        //将拼凑好的每一个dishDto类型数据全部加入集合中
        for (Dish dish : dishRecords) {
            DishDto dishDto = new DishDto();
            BeanUtils.copyProperties(dish,dishDto); 
            String categoryName = categoryService.getById(dish.getCategoryId()).getName(); //获取分类名
            dishDto.setCategoryName(categoryName); //将分类名赋值给dishDto
            dtoRecords.add(dishDto); //将dishDto添加到集合中
        }
        //将dtoRecords存入dishDtoPage对象中
        dishDtoPage.setRecords(dtoRecords); 

        //最后返回分页信息对象,包含了前端所需的信息
        return R.success(dishDtoPage);
    }

4. 修改菜品

修改菜品信息需要发送两个请求:

4.1 根据id查询菜品信息

回显要修改的那个菜品的相关信息包括菜品口味信息,此处复用了增加菜品的页面。

    /**
     * 根据id查询菜品信息
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public R<DishDto> getById(@PathVariable Long id){
        Dish dish = dishService.getById(id); //查出菜品信息
        //查询菜品口味信息
        LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DishFlavor::getDishId,id);
        List<DishFlavor> dishFlavors = dishFlavorService.list(queryWrapper);

        //设置要展示的菜品信息包括口味信息
        DishDto dishDto = new DishDto();
        BeanUtils.copyProperties(dish,dishDto); //将dish属性值复制给dishDto
        dishDto.setFlavors(dishFlavors);

        return R.success(dishDto);
    }

 4.2 修改菜品以及口味信息

    /**
     * 修改菜品
     * @param dishDto
     * @return
     */
    @Transactional
    @PutMapping
    public R<String> update(@RequestBody DishDto dishDto){

        //保存菜品信息
        dishService.updateById(dishDto);
        //获取菜品id
        Long dishId = dishDto.getId();
        //删除原来的口味数据
        LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DishFlavor::getDishId,dishId);
        dishFlavorService.remove(queryWrapper);
        //取出新的菜品口味信息
        List<DishFlavor> flavors = dishDto.getFlavors();
        //为每条菜品口味信息赋上菜品id并保存进数据库
        for (DishFlavor dishFlavor : flavors) {
            dishFlavor.setDishId(dishId);
            dishFlavorService.save(dishFlavor);
        }
        return R.success("修改成功");
    }

5. 修改菜品售卖状态(可批量)

可以批量修改,也可以只修改一个。

法一:stream流

    /**
     * 修改餐品状态
     * @param status
     * @param ids
     * @return
     */
    @PostMapping("/status/{status}")
    public R<String> updateStatus(@PathVariable Integer status, Long[] ids){

        //方法一:使用stream流和lambda表达式
        List<Dish> list = Arrays.stream(ids).map((item)->{
            Dish dish = dishService.getById(item);
            dish.setStatus(status);
            return dish;
        }).collect(Collectors.toList());

        dishService.updateBatchById(list);

        return R.success("修改成功");
    }

法二:for增强

    @PostMapping("/status/{status}")
    public R<String> updateStatus(@PathVariable Integer status, Long[] ids){

        for (Long id : ids) {
            Dish dish = dishService.getById(id);
            dish.setStatus(status);
            dishService.updateById(dish);
        }

        return R.success("修改成功");
    }

        

6. 删除菜品(可批量)

    /**
     * 删除菜品
     * @param ids
     */
    @Transactional
    @DeleteMapping
    public R<String> delete(Long[] ids){
        for (Long id : ids) {
            //删除菜品
            dishService.removeById(id);
            //删除菜品口味
           LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();
           queryWrapper.eq(DishFlavor::getDishId,id);
           dishFlavorService.remove(queryWrapper);
        }
        return R.success("删除成功");
    }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值