新增套餐:
需求分析:
套餐就是菜品的集合。
后台系统中可以管理套餐信息,通过新增套餐功能来添加一个新的套餐,在添加套餐时需要选择当前套餐所属的套餐分类和包含的菜品,并且需要上传套餐对应的图片,在移动端会按照套餐分类来展示对应的套餐。
数据模型:
新增套餐,其实就是将新增页面录入的套餐信息插入到setmeal表,还需要向setmeal_dish表插入套餐和菜品关联数据。所以在新增套餐时,涉及到两个表:
setmeal套餐表
setmeal_dish 套餐菜品关系表
准备工作:
需要用到的类和接口基本结构
1、实体类SetmealDish(Setmeal实体前面课程中已经导入过了)
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;/*** 套餐菜品关系*/@Datapublic class SetmealDish implements Serializable {private static final long serialVersionUID = 1L;private Long id;//套餐idprivate Long setmealId;//菜品idprivate 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;}
2、DTO SetmealDto数据传输对象
import com.itzq.reggie.entity.Setmeal;import com.itzq.reggie.entity.SetmealDish;import lombok.Data;import java.util.List;@Datapublic class SetmealDto extends Setmeal {private List<SetmealDish> setmealDishes;private String categoryName;}
3、Mapper接口SetmealDishMapper
import com.baomidou.mybatisplus.core.mapper.BaseMapper;import com.itzq.reggie.entity.SetmealDish;import org.apache.ibatis.annotations.Mapper;@Mapperpublic interface SetmealDishMapper extends BaseMapper<SetmealDish> {}
4、业务层接口SetmealDishService
import com.baomidou.mybatisplus.extension.service.IService;import com.itzq.reggie.entity.SetmealDish;public interface SetmealDishService extends IService<SetmealDish> {}
5、业务层实现类SetmealDishservicelmpl
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;import com.itzq.reggie.entity.SetmealDish;import com.itzq.reggie.mapper.SetmealDishMapper;import com.itzq.reggie.service.SetmealDishService;import org.springframework.stereotype.Service;@Servicepublic class SetmealDishServiceImpl extends ServiceImpl<SetmealDishMapper,SetmealDish> implements SetmealDishService {}
6、控制层SetmealController
import com.itzq.reggie.service.SetmealDishService;import com.itzq.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;@RestController@RequestMapping("/setmeal")@Slf4jpublic class SetmealController {@Autowiredprivate SetmealService setmealService;@Autowiredprivate SetmealDishService setmealDishService;}
交互流程:
1、页面(backend/page/combo/add.html)发送ajax请求,请求服务端获取套餐分类数据并展示到下拉框中
2、页面发送ajax请求,请求服务端,获取菜品分类数据并展示到添加菜品窗口中
3、页面发送ajax请求,请求服务端,根据菜品分类查询对应的菜品数据并展示到添加菜品窗口中
4、页面发送请求进行图片上传,请求服务端将图片保存到服务器
5、页面发送请求进行图片下载,将上传的图片进行回显
6、点击保存按钮,发送ajax请求,将套餐相关数据以json形式提交到服务端
开发新增套餐功能,其实就是在服务端编写代码去处理前端页面发送的这6次请求即可
代码开发:
在DishController类中,添加list方法
注意:需要添加额外的查询条件,只查询status为1的数据,表示该菜品为起售状态,才能被加入套餐中,供用户选择
/*** 根据条件来查询对应的菜品数据* @param dish* @return*/@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);}
刷新界面,查询数据成功,并回显到前端页面
服务端接收页面提交的数据:
添加套餐页面,输入数据,点击保存,插卡前端页面发送的请求:
根据前端传过来的数据我们可以在后端确定我们需要在后端使用什么来接受前端的参数:
在SetmealController类中添加save方法。编写controller:上面的dishList,我们数据库并不需要这个数据,所以接收数据的实体类没有dishList这个属性也没有关系,前端传过来的数据都是自动映射到接收数据的实体类的属性上的,没有对应起来就不会映射。
/*** 新增套餐* @param setmealDto* @return*/@PostMappingpublic R<String> save(@RequestBody SetmealDto setmealDto){log.info("套餐信息:{}",setmealDto);setmealService.saveWithDish(setmealDto);return R.success("新增套餐成功");}
SetmealService中添加自定义的方法:
/*** 新增套餐,同时需要保存套餐和菜品的关联关系* @param setmealDto*/public void saveWithDish(SetmealDto setmealDto);
SetmealServiceImpl实现类:
@Autowiredprivate SetmealDishService setmealDishService;/*** 新增套餐,同时需要保存套餐和菜品的关联关系* @param setmealDto*/@Transactionalpublic void saveWithDish(SetmealDto setmealDto) {//保存套餐基本信息,操作setmeal表,执行insert操作this.save(setmealDto);List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes();setmealDishes.stream().map((item) -> {item.setSetmealId(setmealDto.getId());return item;}).collect(Collectors.toList());//保存套餐和菜品的关联信息操作setmeal_dish,执行insert操作setmealDishService.saveBatch(setmealDishes);}
套餐分页查询:
需求分析:
系统中的套餐数据很多的时候,如果在一个页面中全部展示出来会显得比较乱,不便于查看,所以一般的系统中都会以分页的方式来展示列表数据。
交互流程:
1、页面(backend/page/combo/list.html)发送ajax请求,将分页查询参数(page、pageSize、name)提交到服务端,获取分页数据。
2、页面发送请求,请求服务端进行图片下载,用于页面图片展示。
开发套餐信息分页查询功能,其实就是在服务端编写代码去处理前端页面发送的这2次请求即可。
代码开发:
在SetmealController类中添加page方法(与前面菜品信息分页查询方法类似)
/*** 套餐分页查询* @param page* @param pageSize* @param name* @return*/@GetMapping("/page")public R<Page> page(int page, int pageSize, String name){//分页构造器对象Page<Setmeal> pageInfo = new Page<>(page,pageSize);Page<SetmealDto> dtoPage = new Page<>();LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();//添加查询条件,根据name进行like模糊查询queryWrapper.like(name != null,Setmeal::getName,name);//添加排序条件,根据更新时间降序排列queryWrapper.orderByDesc(Setmeal::getUpdateTime);setmealService.page(pageInfo,queryWrapper);//对象拷贝BeanUtils.copyProperties(pageInfo,dtoPage,"records");List<Setmeal> records = pageInfo.getRecords();List<SetmealDto> list = records.stream().map((item) -> {SetmealDto setmealDto = new SetmealDto();//对象拷贝BeanUtils.copyProperties(item,setmealDto);Long categoryId = item.getCategoryId();//根据分类id来查询分类对象Category category = categoryService.getById(categoryId);if(category != null){//分类名称String categoryName = category.getName();setmealDto.setCategoryName(categoryName);}return setmealDto;}).collect(Collectors.toList());dtoPage.setRecords(list);return R.success(dtoPage);}
删除、起售以及停售套餐:
需求分析:
在套餐管理列表页面点击删除按钮,可以删除对应的套餐信息。也可以通过复选框选择多个套餐,点击批量删除按钮一次删除多个套餐。注意,对于状态为售卖中的套餐不能删除,需要先停售,然后才能删除。
代码开发:
开发删除套餐功能,其实就是在服务端编写代码去处理前端页面发送的这2次请求即可。
观察删除单个套餐和批量删除套餐的请求信息可以发现,两种请求的地址和请求方式都是相同的,不同的则是传递的id个数,所以在服务端可以提供一个方法来统一处理。
(批量)停售、起售套餐:
/*** 根据id(批量)停售/启售套餐信息* @param status* @param ids* @return*/@PostMapping("/status/{status}")public R<String> updateMulStatus(@PathVariable Integer status, Long[] ids){List<Long> list = Arrays.asList(ids);//构造条件构造器LambdaUpdateWrapper<Setmeal> updateWrapper = new LambdaUpdateWrapper<>();//添加过滤条件updateWrapper.set(Setmeal::getStatus,status).in(Setmeal::getId,list);setmealService.update(updateWrapper);return R.success("套餐信息修改成功");}
删除套餐:
1、在SetmealService中添加自定义的方法:
/*** 删除套餐,同时删除套餐和菜品的关联关系* @param ids*/public void removeWithDish(List<Long> ids);
2、在SetmealServiceImpl中实现该方法:
/*** 删除套餐,同时删除套餐和菜品的关联关系* @param ids*/@Transactionalpublic void removeWithDish(List<Long> ids) {//select count(*) from setmeal where id in (1,2,3) and statue = 1//查询套餐状态,确定是否可以删除LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.in(Setmeal::getId,ids);queryWrapper.eq(Setmeal::getStatus,1);int count = this.count(queryWrapper);if(count >0){ //在售卖中,不能删除//如果不能删除,抛出一个业务异常throw new CustomException("套餐正在售卖中,不能删除");}//如果可以删除,先删除套餐表中的数据---setmealthis.removeByIds(ids);//delete from setmeal_dish where setmeal_id in (1,2,3)LambdaQueryWrapper<SetmealDish> lambdaQueryWrapper = new LambdaQueryWrapper<>();lambdaQueryWrapper.in(SetmealDish::getSetmealId,ids);//再删除关系表中的数据---setmeal_dishsetmealDishService.remove(lambdaQueryWrapper);}
3、在SetmealController中添加delete方法:
/*** 删除套餐* @param ids* @return*/@DeleteMappingpublic R<String> delete(@RequestParam List<Long> ids){log.info("ids:{}",ids);setmealService.removeWithDish(ids);return R.success("套餐数据删除成功");}
【瑞吉外卖】学习笔记-day5:(一)套餐管理开发——新增套餐 套餐分页查询 删除/起售/停售套餐
如果觉得《【瑞吉外卖】学习笔记-day5:(一)套餐管理开发——新增套餐 套餐分页查询 删除/起》对你有帮助,请点赞、收藏,并留下你的观点哦!