套餐:一组菜品的集合

点击之后就会弹出下面的界面:

上面是后台的管理操作,下面是处理完成后在用户端展示的界面效果:

目录
1.3新增套餐---代码开发---准备工作&梳理交互过程 71
1.5新增套餐---代码开发---服务端接收页面提交的数据 73
5.3短信发送---代码开发---参照官方文档封装短信发送工具类 83
6.3手机验证码登陆---代码开发---梳理交互过程&修改LoginCheckFliter 85






1.3.1中的交互过程包含六次交互请求,前两次的请求交互在CategoryController中进行。

选用其中的List集合中的数据信息。

这两种类都在List中进行。

实现的是下面的效果内容:
本部分代码实现的效果:

本部分使用的代码如下所示:
- /**
- * 根据条件查询对应的菜品数据
- * @param dish
- * @return
- */
- @GetMapping("/list")
- public R
> list(Dish dish){//这个部分传递的参数,可以是Long categoryid,
- // 但是可以将其进行扩展使用,使用Dish类中的参数,它包含了很多的参数信息,包含categoryid
- //构造查询条件
- LambdaQueryWrapper
queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(dish.getCategoryId() != null , Dish::getCategoryId,dish.getCategoryId());
- //该部分是设置一个判断语句,确定id传递过来,并不是空的指针
- //添加排序条件
- queryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);
- //使用了两个判断条件,一个是根据sort进行升序排序,如果sort排序一致,再根据更新时间进行降序判断
- //添加条件,查询状态为1(起售状态)的菜品
- queryWrapper.eq(Dish::getStatus,1);
- List
list = dishService.list(queryWrapper);//使用该方法,获取得到了一个集合 -
- return R.success(list);
- }
下面部分代码开发实现的内容:

使用的是CommonController层的图片上传和下载的功能。


下面本部分实现的是下面的效果:

将客户端的数据信息发布反馈到后端当中:
反馈到后端的内容数据信息:

本部分代码:
- /**
- * 新增套餐
- * @param setmealDto
- * @return
- */
- @PostMapping
- public R
save(@RequestBody SetmealDto setmealDto){ - log.info("套餐信息: {}",setmealDto);
- return null;
- }
套餐表中插入数据、套餐和菜品对应的关系表里面进行插入数据处理。这两个表都需要进行处理。
对两张表的操作。
在SetmealService接口中进行处理。
本部分的代码如下所示:底层对两个表之间处理。
步骤一:对SetmealService接口进行修改

代码:
- /**
- * 新增套餐
- * @param setmealDto
- * @return
- */
- @PostMapping
- public R
save(@RequestBody SetmealDto setmealDto){ - log.info("套餐信息: {}",setmealDto);
- return R.success("新增套餐成功");
- }
步骤二:在SetmealServiceImpl驱动类中进行修改。
- /**
- * 新增套餐,同时需要保存套餐和菜品的关联关系
- * @param setmealDto
- */
- @Transactional
- public void saveWithDish(SetmealDto setmealDto) {
- //保存套餐的基本信息,操作setmeal,执行insert操作
- this.save(setmealDto);
- List
setmealDishes = setmealDto.getSetmealDishes(); - setmealDishes.stream().map((item) -> {
- item.setSetmealId(setmealDto.getId());
- return item;
- }).collect(Collectors.toList());
-
- //保存套餐和菜品的关联信息,操作setmeal_dish,执行insert操作
- setmealDishService.saveBatch(setmealDishes);
-
- }


一共能涉及到2次请求信息
注:
1、中的name参数获取
2、图片进行展示


目前下面的代码能够实现主要的内容,但是在套餐分类的这一类当中是不进行显示的。是由于pageInfo中继承的泛型是Setmeal。

但是Setmeal中不包含套餐分类的功能,只是返回的是套餐分类的id。
本部分解决套餐分类中分类的类别显示问题:
问题描述如下:

本部分代码:
- /**
- * 套餐分页查询
- * @param page
- * @param pageSize
- * @param name
- * @return
- */
- @GetMapping("/page")
- public R
page(int page,int pageSize,String name){//输入的是三部分的参数信息 -
- //分页构造器对象的创建
- Page
pageInfo = new Page<>(page,pageSize);//分页构造器对象 - Page
dtoPage = new Page<>();//使用SetmealDto中的内容对象,进行使用操作处理, - // 由于SetmealDto继承Setmeal,并且还包含那个套餐分类的名称,所以使用该类
-
- LambdaQueryWrapper
queryWrapper = new LambdaQueryWrapper<>(); - //添加查询条件,根据name进行like模糊查询
- queryWrapper.like(name != null,Setmeal::getName,name);//括号内是进行条件的查询的判断,判断内容不为空,
- // 并且进行name模糊查询
- //添加排序条件,根据更新时间降序排序
- queryWrapper.orderByDesc(Setmeal::getUpdateTime);
-
- setmealService.page(pageInfo,queryWrapper);
- //对象拷贝
- BeanUtils.copyProperties(pageInfo,dtoPage,"records");//是将pageInfo中的数据拷贝到dtoPage中
- //并且忽略pageInfo中的records的保存数据的信息记录。由于pageInfo中的泛型为Setmeal,
- //我们新创建的是dtoPage的泛型为SetmealDto,所以需要进行先排除
- List
records = pageInfo.getRecords();//获取pageInfo中的records,对后面的这个records进行处理解决 -
- List
list = records.stream().map((item) ->{ - SetmealDto setmealDto = new SetmealDto();
- //对象拷贝,因为创建的集合SetmealDto中是空的,所以需要将原来item的数据内容拷贝到新的SetmealDto中。
- BeanUtils.copyProperties(item,setmealDto);
- //分类id
- Long categoryId = item.getCategoryId();
- //根据分类id查询分类对象
- Category category = categoryService.getById(categoryId);
- if(category != null){
- //分类名称,获取套餐分类名称
- String categoryName = category.getName();
- setmealDto.setCategoryName(categoryName);//将查询到的categoryName添加到setmealDto中
- //因为创建的setmealDto是个新的集合,所以使用set进行添加到集合中
- }
- return setmealDto;
- }).collect(Collectors.toList());
-
- dtoPage.setRecords(list);
- return R.success(dtoPage);
- }

需求:
1、点击删除按钮删除商品
2、批量删除商品的实现
3、停售按键的正常使用,售卖的套餐不能被删除,停售后才能够被删除

注:
1、请求方式和请求地址是相同的
2、区别在于两者的传递的id的个数不一样
步骤一:在SetmealController层中进行书写删除的主代码
- /**
- * 删除套餐
- * @param ids
- * @return
- */
- @DeleteMapping
- public R
delete(@RequestParam List ids) { - log.info("ids:{}",ids);
- // setmealService.removeWithDish(ids);
- return R.success("套餐删除成功");
- }
步骤二:在SetmealSerice接口中创建新的方法
public void removeWithDish(List list) ;
步骤三:添加服务驱动类
- /**
- * 删除套餐,同时需要删除套餐和菜品的关联数据
- * @param ids
- */
- @Override
- public void removeWithDish(List
ids) { - //select count(*) from setmeal where id in (1,2,3) and status =1
- //查询套餐状态,确定是否可用删除
- LambdaQueryWrapper
queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.in(Setmeal::getId,ids);//是查询判断的第一部分条件是在(1,2,3)中进行查询进行表达
- queryWrapper.eq(Setmeal::getStatus,1);//判断条件等值查询判断,判断该商品的状态,1:在售;2:停售
-
- int count = this.count(queryWrapper);//ServiceImpl实现的框架下的一个count,封装生成
- if(count > 0 ){//异常提示报错,>0表示状态为1,处于售卖的状态。
- //如果不能被删除,抛出一个业务异常
- throw new CustomException("套餐正在售卖中,不能删除");
- }
- //如果可以删除,先删除套餐表中的数据---setmeal 这个是套餐(批量删除)
-
- this.removeByIds(ids);
-
- //删除关系表中的数据---setmeal_dish(关联数据)
- //创建一个新的处理方式,mysql中的编程处理的代码 delete from setmeal_dish where setmeal_id in (1,2,3...)
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - lambdaQueryWrapper.in(SetmealDish::getSetmealId,ids);//该部分表示mysql的代码编写
- //删除关系表中的数据---setmeal_dish
- setmealDishService.remove(lambdaQueryWrapper);
-
- }
步骤四:在主方法中进行调用使用该方法
- /**
- * 删除套餐
- * @param ids
- * @return
- */
- @DeleteMapping
- public R
delete(@RequestParam List ids) { - log.info("ids:{}",ids);
- setmealService.removeWithDish(ids);
- return R.success("套餐删除成功");
- }












修改部分一:

修改部分二:

本部分代码如下:

代码:
- @Slf4j
- @RestController
- @RequestMapping("/user")
- public class UserController {
- @Autowired
- private UserService userService;
-
- public R
sendMsg(@RequestBody User user, HttpSession session){ -
- //获取手机号
- String phone = user.getPhone();
-
- if (StringUtils.isNotEmpty(phone)){//首先进行条件判断
- //生成4位随机的验证码,通过ailiyun提供的功能类
- String code = ValidateCodeUtils.generateValidateCode(4).toString();
- log.info("code={}",code);
-
- //调用阿里云提供的短信服务API完成发送短信
- // SMSUtils.sendMessage("瑞吉外卖","",phone,code);
-
- //需要将生成的验证码保存到Session
- session.setAttribute(phone,code);
-
- return R.success("手机验证码短信发送成功");
-
- }
- return R.error("短信发送失败");
- }
-
- }
使得前端能够进行登陆
本部分代码:
- /**
- * 移动端用户登陆
- * @param map
- * @param session
- * @return
- */
- @PostMapping("/login")
- public R
login(@RequestBody Map map, HttpSession session){//使用Map类 -
- log.info(map.toString());
- //获取手机号
- String phone = map.get("phone").toString();
- //获取验证码
- String code = map.get("code").toString();
- //从Session中获取保存的验证码
- Object codeInSession = session.getAttribute(phone);
- //进行验证码的比对(页面提交的验证码和Session中保存的验证码比对)
- if(codeInSession != null && codeInSession.equals(code)){
- //如果能够对比成功,说明登陆成功
-
- LambdaQueryWrapper
queryWrapper =new LambdaQueryWrapper<>(); - queryWrapper.eq(User::getPhone,phone);
-
- User user = userService.getOne(queryWrapper);
- if(user == null){
- //判断当前手机号对应的用户是否位新用户,如果是新用户就自动完成注册
- user = new User();
- user.setPhone(phone);
- user.setStatus(1);
- userService.save(user);
-
- }
- return R.success(user);
- }
- return R.error("登陆失败");
- }
效果:实现在移动端进行登陆

注:如果登陆时出现登陆不上的情况,可以尝试清理下浏览器的缓存,在进行登陆。