套餐管理业务开发
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
1. 新增套餐 5-2
1.1 需求分析 5-2
1.2 数据模型 5-2
新增套餐,其实就是将新增页面录入的套餐信息插入到setmeal表,还需要向setmeal dish表插入套餐和菜品关联数据。
所以在新增套餐时,涉及到两个表:
● setmeal 套餐表
● setmeal _dish 套餐菜品关系表
1.3 代码开发 5-3
1.3.1 代码开发-准备工作 5-3
在开发业务功能前,先将需要用到的类和接口基本结构创建好:
●实体类SetmealDish (直接从课程资料中导入即可,Setmeal实体前面课程中已经导入过了)
●DTO SetmealDto (直接从课程资料中导入即可)
●Mapper接 口SetmealDishMapper
●业务层接口SetmealDishService
●业务层实现类SetmealDishServicelmpl
●控制层SetmealController
套餐菜品关系实体类SetmealDish
package com.itheima.reggie.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 套餐菜品关系 5-3
*/
@Data
public class SetmealDish implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
//套餐id
private Long setmealId;
//菜品id
private Long dishId;
//菜品名称 (冗余字段)
private String name;
//菜品原价
private BigDecimal price;
//份数
private Integer copies;
//排序
private Integer sort;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
//是否删除
private Integer isDeleted;
}
数据传输对象DTO SetmealDto
package com.itheima.reggie.dto;
import com.itheima.reggie.entity.Setmeal;
import com.itheima.reggie.entity.SetmealDish;
import lombok.Data;
import java.util.List;
//数据传输对象DTO 5-3
@Data
public class SetmealDto extends Setmeal {
private List<SetmealDish> setmealDishes;
private String categoryName;
}
套餐管理持久层接口SetmealDishMapper
package com.itheima.reggie.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.reggie.entity.SetmealDish;
import org.apache.ibatis.annotations.Mapper;
//套餐管理持久层接口 5-3
@Mapper
public interface SetmealDishMapper extends BaseMapper<SetmealDish> {
}
套餐管理业务层接口SetmealDishService
package com.itheima.reggie.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.itheima.reggie.entity.SetmealDish;
//套餐管理业务层接口 5-3
public interface SetmealDishService extends IService<SetmealDish> {
}
套餐管理业务层接口实现类SetmealDishServiceImpl
package com.itheima.reggie.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.reggie.entity.SetmealDish;
import com.itheima.reggie.mapper.SetmealDishMapper;
import com.itheima.reggie.service.SetmealDishService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
//套餐管理业务层接口实现类 5-3
@Service
@Slf4j
public class SetmealDishServiceImpl extends ServiceImpl<SetmealDishMapper,SetmealDish> implements SetmealDishService {
}
套餐管理控制层SetmealController
package com.itheima.reggie.controller;
import com.itheima.reggie.service.SetmealDishService;
import com.itheima.reggie.service.SetmealService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
//套餐管理控制层 5-3
@RestController
@RequestMapping("/setmeal")
@Slf4j
public class SetmealController {
@Autowired
private SetmealService setmealService;
@Autowired
private SetmealDishService setmealDishService;
}
1.3.2 业务开发
在开发代码之前,需要梳理一下 新增套餐时前端页面和服务端的交互过程:
1、页面(backend/ page/ combo/add.html)发送ajax请求, 请求服务端获取套餐分类数据并展示到下拉框中
2、页面发送ajax请求,请求服务端获取菜品分类数据并展示到添加菜品窗口中
3、页面发送ajax请求,请求服务端,根据菜品分类查询对应的菜品数据并展示到添加菜品窗口中
4、页面发送请求进行图片上传,请求服务端将图片保存到服务器
5、页面发送请求进行图片下载,将上传的图片进行回显
6、点击保存按钮,发送ajax请求,将套餐相关数据以json形式提交到服务端
开发新增套餐功能,其实就是在服务端编写代码去处理前端页面发送的这6次请求即可。
根据菜品分类的id查询菜品 5-4
菜品管理DishController
//根据菜品分类的id查询菜品 5-4
@GetMapping("/list")
public R<List<Dish>> list(Dish dish){
//构造查询条件对象
LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(dish.getCategoryId()!=null,Dish::getCategoryId,dish.getCategoryId());
//添加条件,查询状态为1的也就是起售的菜品
queryWrapper.eq(Dish::getStatus,1);
//添加排序条件
queryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);
List<Dish> list = dishService.list(queryWrapper);
return R.success(list);
}
新增套餐业务开发 5-5 5-6
注意setmealId没有赋值所以代码中我们需要手动赋值
套餐管理业务层接口SetmealService
/**
* 新增套餐,同时需要保存套餐和菜品的关联关系 5-6
* @param setmealDto
*/
public void saveWithDish(SetmealDto setmealDto);
套餐管理业务层接口实现类SetmealServiceImpl
@Autowired
private SetmealDishService setmealDishService;
//新增套餐,同时需要保存套餐和菜品的关联关系 5-6
@Override
@Transactional //事务
public void saveWithDish(SetmealDto setmealDto) {
//保存套餐的基本信息,操作setmeal,执行insert操作
this.save(setmealDto);
//保存套餐和菜品的关联信息,操作setmeal_dish,执行insert操作
List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes();
//因为通过debug看到套餐id setmealId没有赋值,所以我们需要手动添加
setmealDishes = setmealDishes.stream().map((item)->{
item.setSetmealId(setmealDto.getId());
return item;
}).collect(Collectors.toList());
setmealDishService.saveBatch(setmealDishes);
}
套餐管理控制层SetmealController
//新增套餐 5-5 5-6
@PostMapping
public R<String> save(@RequestBody SetmealDto setmealDto){
log.info("套餐信息 {}",setmealDto);
setmealService.saveWithDish(setmealDto);
return R.success("新增套餐成功");
}
测试成功
2. 套餐信息的分页查询 5-8
2.1 需求分析 5-8
2.2 代码开发-梳理交互过程 5-8
在开发代码之前,需要梳理一下套餐分页查询时前端页面和服务端的交互过程:
1、页面(backend/page/combo/list.html)发送ajax请求, 将分页查询参数(page、pageSize、
name)提交到服务端,获取分页数据
2、页面发送请求,请求服务端进行图片下载,用于页面图片展示
开发套餐信息分页查询功能,其实就是在服务端编写代码去处理前端页面发送的这2次请求即可。
2.3 代码开发 5-9
依然存在和菜品分页查询一样的问题,解决方法也是一样的
套餐管理控制层SetmealController
//方便我们做套餐分页查询时使用 5-9
@Autowired
private CategoryService categoryService;
套餐管理控制层SetmealController
//套餐信息分页查询 5-9
@GetMapping("/page")
public R<Page> page(int page,int pageSize,String name){
//分页构造器
Page<Setmeal> pageInfo = new Page<>();
Page<SetmealDto> setmealDtoPage = new Page<>();
//添加查询条件
LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
//添加查询条件 根据名字进行like模糊查询
queryWrapper.like(name!=null,Setmeal::getName,name);
//添加排序条件,根据更新时间降序排列
queryWrapper.orderByDesc(Setmeal::getUpdateTime);
//执行分页查询
//这条语句会将我们查询到的数据进行封装 全部封装进Page的对象pageInfo
setmealService.page(pageInfo,queryWrapper);
//此时这个情况和菜品的分页查询一样的原因,我们这里套餐分类的名字显示不出来因为
// 我们传的是id,而前端需要的是name 解决办法和菜品的分页查询一样
//拷贝pageInfo给setmealDtoPage,但是不拷贝records,因为pageInfo对应的泛型是Setmeal
//而我们需要的是SetmealDto
//这个拷贝也只是拷贝page对象的普通属性不包括records属性集合
BeanUtils.copyProperties(pageInfo,setmealDtoPage,"records");
List<Setmeal> records = pageInfo.getRecords();
List<SetmealDto> list = records.stream().map((item)->{
//这个setmealDto是我们新new出来的,里面的属性都是空的,需要我们给赋值
SetmealDto setmealDto = new SetmealDto();
//将Setmeal的普通属性拷贝给setmealDto
BeanUtils.copyProperties(item,setmealDto);
//得到套餐分类id
Long categoryId = item.getCategoryId();
//根据套餐分类id查询出分类对象
Category category = categoryService.getById(categoryId);
if(category!=null){
//得到套餐分类的名称
String categoryName = category.getName();
//将分类名赋值给setmealDto对象
setmealDto.setCategoryName(categoryName);
}
return setmealDto;
}).collect(Collectors.toList());//将这些setmealDto对象收集起来封装成集合
//经过上面一番操作我们就得到了带有 套餐分类名称 的 泛型为setmealDto 的集合
setmealDtoPage.setRecords(list);//给setmealDtoPage的records赋值
return R.success(setmealDtoPage);
}
3. 删除套餐 5-10
3.1 业务需求 5-10
3.2 代码开发-梳理交互过程 5-10
3.3 代码开发 5-11
删除单个套餐
删除多个套餐
套餐管理业务层接口SetmealService
/**
* 删除套餐,同时需要删除套餐和菜品的关联数据 5-11
* @param ids
*/
public void removeWithDish(List<Long> ids);
套餐管理业务层接口实现类SetmealServiceImpl
/**
* 删除套餐,同时需要删除套餐和菜品的关联数据 5-11
* @param ids
*/
@Transactional
public void removeWithDish(List<Long> ids) {
//查询套餐状态,确定是否可用删除
LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper();
//select count(*) from setmeal where id in (1,2,3) and status = 1
queryWrapper.in(Setmeal::getId,ids);
queryWrapper.eq(Setmeal::getStatus,1);
//这里的思想是根据id和status查询,如果查询出来的数据大于0,就证明处于售卖状态,否则为停售状态
int count = this.count(queryWrapper);
if(count > 0){
//如果不能删除,抛出一个业务异常
throw new CustomException("套餐正在售卖中,不能删除");
}
//如果可以删除,先删除套餐表中的数据---setmeal
this.removeByIds(ids);
LambdaQueryWrapper<SetmealDish> lambdaQueryWrapper = new LambdaQueryWrapper<>();
//delete from setmeal_dish where setmeal_id in (1,2,3)
lambdaQueryWrapper.in(SetmealDish::getSetmealId,ids);
//删除关系表中的数据----setmeal_dish
setmealDishService.remove(lambdaQueryWrapper);
}
套餐管理控制层SetmealController
/**
* 删除套餐
* @param ids
* @return
*/
@DeleteMapping
public R<String> delete(@RequestParam List<Long> ids){
log.info("ids:{}",ids);
setmealService.removeWithDish(ids);
return R.success("套餐数据删除成功");
}
测试
4. 拓展,修改套餐 自己实现 代码在reggie_take_out5_1中
分两步实现
4.1 首先是将数据回显
这个和菜品修改原理一模一样
套餐管理业务层接口SetmealService
//根据套餐id来查询菜品信息和口味信息 自己实现
public SetmealDto getByIdWithDish(Long id);
套餐管理业务层接口实现类SetmealServiceImpl
//根据套餐id查询套餐数据和对应的菜品 回显数据 自己实现
@Override
public SetmealDto getByIdWithDish(Long id) {
//因为没有SetmealDto这张表,所以我们分两张表查询,一个是Setmeal表一个是SetmealDish表
//首先查询Setmeal表,查到套餐的基本数据不包括套餐对应的菜品
Setmeal setmeal = this.getById(id);
//new一个SetmealDto出来因为我们最终要返回的是SetmealDto因为它里面包括了套餐
// 的基本数据还有对应的菜品
//我们刚new出来的SetmealDto是空的,所以需要将查询到的数据设置进去
SetmealDto setmealDto = new SetmealDto();
BeanUtils.copyProperties(setmeal,setmealDto);
//接着查询套餐菜品关系表,查出对应的菜品
//因为我们的参数id数套餐的id不是套餐菜品关系表的id,所以自己构造查询条件
LambdaQueryWrapper<SetmealDish> queryWrapper = new LambdaQueryWrapper<>();
//使用套餐表id查询套餐菜品关系表
queryWrapper.eq(SetmealDish::getSetmealId,id);
List<SetmealDish> list = setmealDishService.list(queryWrapper);//查出来肯定是集合
//将查出来的对应菜品放进setmealDto
setmealDto.setSetmealDishes(list);
return setmealDto;
}
SetmealController
//修改套餐 之回显数据 自己实现的
//根据套餐id来查询套餐信息和菜品信息
@GetMapping("/{id}")
public R<SetmealDto> get(@PathVariable Long id){
//调用我们自己实现的方法,因为修改套餐涉及两张表
SetmealDto setmealDto = setmealService.getByIdWithDish(id);
return R.success(setmealDto);
}
4.2 保存修改
这个也是和修改菜品原理一样
套餐管理业务层接口SetmealService
//更新套餐信息 同时更新菜品信息 自己实现
public void updateWithDish(SetmealDto setmealDto);
套餐管理业务层接口实现类SetmealServiceImpl
//更新套餐信息同时更新对应菜品 自己实现
@Override
@Transactional
public void updateWithDish(SetmealDto setmealDto) {
//还是一样分两张表来做
//首先更新套餐表
this.updateById(setmealDto);
//更新套餐菜品关系表
//这里我们直接根据套餐id删除原来的菜品,在添加即可
LambdaQueryWrapper<SetmealDish> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(SetmealDish::getSetmealId,setmealDto.getId());
setmealDishService.remove(queryWrapper);
//往餐菜品关系表添加新数据
List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes();
//这里和添加一样的问题 继续为餐菜品关系表添加套餐id
setmealDishes = setmealDishes.stream().map((item)->{
item.setSetmealId(setmealDto.getId());
return item;
}).collect(Collectors.toList());
setmealDishService.saveBatch(setmealDishes);
}
SetmealController
//更新套餐信息 自己实现
@PutMapping
public R<String> update(@RequestBody SetmealDto setmealDto){
//调用我们自己实现的方法,因为修改套餐涉及两张表
setmealService.updateWithDish(setmealDto);
return R.success("套餐修改成功");
}
5. 拓展 停售起售状态修改 自己实现 代码在reggie_take_out5_1
停售
起售
批量停售
批量起售
由上图可以这四种功能的请求路径都是一样的,且均使用了restful风格
套餐管理业务层接口SetmealService
//批量停售起售 自己实现
public void stop(int status,List<Long> ids);
套餐管理业务层接口实现类SetmealServiceImpl
@Autowired
private SetmealService setmealService;
//批量停售起售 自己实现
@Override
public void stop(int status,List<Long> ids) {
LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.in(Setmeal::getId,ids);//先构造id(可能一个也可能多个,因为我们单独停售起售和批量写一起了)
//在构造售卖状态
Setmeal setmeal = new Setmeal();
setmeal.setStatus(status);
setmealService.update(setmeal,queryWrapper);
}
SetmealController
//套餐的起售停售 批量停售 批量起售 自己实现
@PostMapping("/status/{status}")
public R<String> update(@PathVariable int status,@RequestParam List<Long> ids){
//调用我们的方法
setmealService.stop(status,ids);
return R.success("套餐售卖修改成功");
}
测试成功
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |