位置: IT常识 - 正文

瑞吉外卖项目剩余功能补充(瑞吉接送)

编辑:rootadmin
瑞吉外卖项目剩余功能补充

目录

菜品启售和停售

菜品批量启售和批量停售

菜品的批量删除

菜品删除逻辑优化

套餐管理的启售,停售

套餐管理的修改

后台按条件查看和展示客户订单

手机端减少购物车中的菜品或者套餐数量(前端展示有一点小问题)

用户查看自己订单

移动端的再来一单功能

移动端点击套餐图片查看套餐具体菜品

删除地址

修改地址

后台订单状态的修改

移动端登陆退出功能


推荐整理分享瑞吉外卖项目剩余功能补充(瑞吉接送),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:瑞吉早餐价格,瑞吉餐饮,瑞吉接送,瑞吉接送,瑞吉超市,瑞吉接送,瑞吉餐饮,瑞吉接送,内容如对您有帮助,希望把文章链接给更多的朋友!

这个是自己基于学习B站 黑马瑞吉外卖项目,补充一些视频里面没有定义的功能或者是需要自己实现的功能;仅供学习参考,本人可能代码不太规范,但是功能自己测试是没有问题的;

黑马程序员Java项目实战《瑞吉外卖》,轻松掌握springboot + mybatis plus开发核心技术的真java实战项目_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV13a411q753?spm_id_from=333.337.search-card.all.click

菜品启售和停售

前端发过来的请求(使用的是post方式):http://localhost:8080/dish/status/1?ids=1516568538387079169

后端接受的请求:

@PostMapping("/status/{status}")public R<String> status(@PathVariable("status") Integer status,Long ids){ log.info("status:{}",status); log.info("ids:{}",ids); return null;}

先看看后端能不能接收到前端传过来的数据:

 发现可以接收到前端参数后,开始补全controller层代码:在DishController中添加下面的接口代码;

/** * 对菜品进行停售或者是起售 * @return */@PostMapping("/status/{status}")public R<String> status(@PathVariable("status") Integer status,Long ids){ log.info("status:{}",status); log.info("ids:{}",ids); Dish dish = dishService.getById(ids); if (dish != null){ dish.setStatus(status); dishService.updateById(dish); return R.success("开始启售"); } return R.error("售卖状态设置异常");}菜品批量启售和批量停售

把上面对单个菜品的售卖状态的方法进行修改;

/** * 对菜品批量或者是单个 进行停售或者是起售 * @return */@PostMapping("/status/{status}")//这个参数这里一定记得加注解才能获取到参数,否则这里非常容易出问题public R<String> status(@PathVariable("status") Integer status,@RequestParam List<Long> ids){ //log.info("status:{}",status); //log.info("ids:{}",ids); LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper(); queryWrapper.in(ids !=null,Dish::getId,ids); //根据数据进行批量查询 List<Dish> list = dishService.list(queryWrapper); for (Dish dish : list) { if (dish != null){ dish.setStatus(status); dishService.updateById(dish); } } return R.success("售卖状态修改成功");}

注意:controller层的代码是不可以直接写业务的,建议把它抽离到service层,controller调用一下service的方法就行;下面的批量删除功能是抽离的,controller没有写业务代码;

菜品的批量删除

前端发来的请求:

在DishController中添加接口:

在DishFlavor实体类中,在private Integer isDeleted;字段上加上@TableLogic注解,表示删除是逻辑删除,由mybatis-plus提供的;

/** * 套餐批量删除和单个删除 * @return */@DeleteMappingpublic R<String> delete(@RequestParam("ids") List<Long> ids){ //删除菜品 这里的删除是逻辑删除 dishService.deleteByIds(ids); //删除菜品对应的口味 也是逻辑删除 LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.in(DishFlavor::getDishId,ids); dishFlavorService.remove(queryWrapper); return R.success("菜品删除成功");}

 DishServicez中添加相关的方法:

//根据传过来的id批量或者是单个的删除菜品void deleteByIds(List<Long> ids);

在实现类实现该方法:

/** *套餐批量删除和单个删除 * @param ids */@Override@Transactionalpublic void deleteByIds(List<Long> ids) { //构造条件查询器 LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>(); //先查询该菜品是否在售卖,如果是则抛出业务异常 queryWrapper.in(ids!=null,Dish::getId,ids); List<Dish> list = this.list(queryWrapper); for (Dish dish : list) { Integer status = dish.getStatus(); //如果不是在售卖,则可以删除 if (status == 0){ this.removeById(dish.getId()); }else { //此时应该回滚,因为可能前面的删除了,但是后面的是正在售卖 throw new CustomException("删除菜品中有正在售卖菜品,无法全部删除"); } }}

功能测试:单个删除,批量删除,批量删除中有启售的...

测试成功!

菜品删除逻辑优化

上面写的菜品的删除功能有点小简单,下面完善一下相关的逻辑;

相关的service的注入,这里就不列举出来了,代码中使用了哪个service,你就autowire就行;

下面的代码可能会有点冗余,这里我就不进行抽离了;

/** * 菜品批量删除和单个删除 * 1.判断要删除的菜品在不在售卖的套餐中,如果在那不能删除 * 2.要先判断要删除的菜品是否在售卖,如果在售卖也不能删除 * @return */ //遇到一个小问题,添加菜品后,然后再添加套餐,但是套餐可选择添加的菜品选项是没有刚刚添加的菜品的? //原因:redis存储的数据没有过期,不知道为什么redis没有重新刷新缓存 // (与DishController中的@GetMapping("/list")中的缓存设置有关,目前不知道咋配置刷新缓存。。。。。 // 解决方案,把redis中的数据手动的重新加载一遍,或者是等待缓存过期后再添加相关的套餐,或者改造成使用spring catch @DeleteMapping public R<String> delete(@RequestParam("ids") List<Long> ids){ //根据菜品id在stemeal_dish表中查出哪些套餐包含该菜品 LambdaQueryWrapper<SetmealDish> setmealDishLambdaQueryWrapper = new LambdaQueryWrapper<>(); setmealDishLambdaQueryWrapper.in(SetmealDish::getDishId,ids); List<SetmealDish> SetmealDishList = setmealDishService.list(setmealDishLambdaQueryWrapper); //如果菜品没有关联套餐,直接删除就行 其实下面这个逻辑可以抽离出来,这里我就不抽离了 if (SetmealDishList.size() == 0){ //这个deleteByIds中已经做了菜品起售不能删除的判断力 dishService.deleteByIds(ids); LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.in(DishFlavor::getDishId,ids); dishFlavorService.remove(queryWrapper); return R.success("菜品删除成功"); } //如果菜品有关联套餐,并且该套餐正在售卖,那么不能删除 //得到与删除菜品关联的套餐id ArrayList<Long> Setmeal_idList = new ArrayList<>(); for (SetmealDish setmealDish : SetmealDishList) { Long setmealId = setmealDish.getSetmealId(); Setmeal_idList.add(setmealId); } //查询出与删除菜品相关联的套餐 LambdaQueryWrapper<Setmeal> setmealLambdaQueryWrapper = new LambdaQueryWrapper<>(); setmealLambdaQueryWrapper.in(Setmeal::getId,Setmeal_idList); List<Setmeal> setmealList = setmealService.list(setmealLambdaQueryWrapper); //对拿到的所有套餐进行遍历,然后拿到套餐的售卖状态,如果有套餐正在售卖那么删除失败 for (Setmeal setmeal : setmealList) { Integer status = setmeal.getStatus(); if (status == 1){ return R.error("删除的菜品中有关联在售套餐,删除失败!"); } } //要删除的菜品关联的套餐没有在售,可以删除 //这下面的代码并不一定会执行,因为如果前面的for循环中出现status == 1,那么下面的代码就不会再执行 dishService.deleteByIds(ids); LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.in(DishFlavor::getDishId,ids); dishFlavorService.remove(queryWrapper); return R.success("菜品删除成功"); }套餐管理的启售,停售

前端发来的请求:

 根据前面菜品模块自己实现的功能,我们可以知道,我们只需要写一个批量处理的方法就可以完成单个或者是批量套餐的启售,停售;

SetmealController中的controller层代码:

/** * 对菜品批量或者是单个 进行停售或者是起售 * @return */@PostMapping("/status/{status}")//这个参数这里一定记得加注解才能获取到参数,否则这里非常容易出问题public R<String> status(@PathVariable("status") Integer status,@RequestParam List<Long> ids){ setmealService.updateSetmealStatusById(status,ids); return R.success("售卖状态修改成功");}

SetmealService中添加下面方法:

/** * 根据套餐id修改售卖状态 * @param status * @param ids */void updateSetmealStatusById(Integer status,List<Long> ids);

该方法的实现:

/** * 根据套餐id修改售卖状态 * @param status * @param ids */@Overridepublic void updateSetmealStatusById(Integer status, List<Long> ids) { LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper(); queryWrapper.in(ids !=null,Setmeal::getId,ids); List<Setmeal> list = this.list(queryWrapper); for (Setmeal setmeal : list) { if (setmeal != null){ setmeal.setStatus(status); this.updateById(setmeal); } }}

记得功能测试,我自己测试的时候是没有问题的;

套餐管理的修改

分为两步:数据回显示,和提交修改数据到数据库

前端点击套餐修改,前端发过来的请求:

请求方式是:get

携带的参数是:stemealId

 然后我们发现在弹出编辑窗口是没有数据的:并且报了一个404,那就是说是**在数据回显的时候报错了**,没有找到具体的回显接口来处理这个请求;

SetmealController 中添加下面的代码:

/** * 回显套餐数据:根据套餐id查询套餐 * @return */@GetMapping("/{id}")public R<SetmealDto> getData(@PathVariable Long id){ SetmealDto setmealDto = setmealService.getDate(id); return R.success(setmealDto);}

 SetmealService添加下面的代码:

/** * 回显套餐数据:根据套餐id查询套餐 * @return */SetmealDto getDate(Long id);

该方法的实现:

/** * 回显套餐数据:根据套餐id查询套餐 * @return */@Overridepublic SetmealDto getDate(Long id) { Setmeal setmeal = this.getById(id); SetmealDto setmealDto = new SetmealDto(); LambdaQueryWrapper<SetmealDish> queryWrapper = new LambdaQueryWrapper(); //在关联表中查询,setmealdish queryWrapper.eq(id!=null,SetmealDish::getSetmealId,id); if (setmeal != null){ BeanUtils.copyProperties(setmeal,setmealDto); List<SetmealDish> list = setmealDishService.list(queryWrapper); setmealDto.setSetmealDishes(list); return setmealDto; } return null;}

测试:数据回显成功:

但是这样我们再点击添加菜品会发现,右边只展示菜品的价格并没有展示菜品对应的名称:

已选菜品中的菜品并没有展示对应的菜品名;

 修改后的运行情况展示:(个人感觉这个菜品搜索框没啥用。。。。反正我是搜索不出来。。)

 修改具体的前端代码:把backend/combo/add.html中的335行修改为下面的代码;

 因为这里的item是代表dish对象,dish实体类是使用name作为菜品名称的;

修改完成后,点击保存,我们发现前端发出一个put请求:

 携带的参数为:

 根据前端传过来的数据和需要的返回值,我们就可以知道controller层方法的返回值和用什么参数来接收前端传给我们的数据;注意这个套餐里面的菜品也要保存修改:需要把setealDish保存到seteal_dish表中;

 点击修改后的保存,后端会接收到下面的数据:发现setmealId == null,所以这里需要自己单独填充;

controller层代码:

为了不把问题复杂化,我是先把相关的setmealDish内容移除然后再重新添加,这样就可以不用考虑dish重复的问题和哪些修改哪些没修改;

@PutMappingpublic R<String> edit(@RequestBody SetmealDto setmealDto){ if (setmealDto==null){ return R.error("请求异常"); } if (setmealDto.getSetmealDishes()==null){ return R.error("套餐没有菜品,请添加套餐"); } List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes(); Long setmealId = setmealDto.getId(); LambdaQueryWrapper<SetmealDish> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(SetmealDish::getSetmealId,setmealId); setmealDishService.remove(queryWrapper); //为setmeal_dish表填充相关的属性 for (SetmealDish setmealDish : setmealDishes) { setmealDish.setSetmealId(setmealId); } //批量把setmealDish保存到setmeal_dish表 setmealDishService.saveBatch(setmealDishes); setmealService.updateById(setmealDto); return R.success("套餐修改成功");}后台按条件查看和展示客户订单

点击订单明细,前端会发下面的请求:携带的数据是分页使查询用的;

 先写个controller看能不能接收到前端传过来的参数:发现只要参数和前端传过来的参数名对应就可以拿到参数的

主要使用到mybatis-plus动态sql语句的生成:

这里我就直接把功能直接写在controller层了,看自己需求分层;(本人这里偷个懒)

/** * 后台查询订单明细 * @param page * @param pageSize * @param number * @param beginTime * @param endTime * @return */ @GetMapping("/page") public R<Page> page(int page, int pageSize, String number,String beginTime,String endTime){ //分页构造器对象 Page<Orders> pageInfo = new Page<>(page,pageSize); //构造条件查询对象 LambdaQueryWrapper<Orders> queryWrapper = new LambdaQueryWrapper<>(); //添加查询条件 动态sql 字符串使用StringUtils.isNotEmpty这个方法来判断 //这里使用了范围查询的动态SQL,这里是重点!!! queryWrapper.like(number!=null,Orders::getNumber,number) .gt(StringUtils.isNotEmpty(beginTime),Orders::getOrderTime,beginTime) .lt(StringUtils.isNotEmpty(endTime),Orders::getOrderTime,endTime); orderService.page(pageInfo,queryWrapper); return R.success(pageInfo); }

 测试:

但是如果你想要这个username显示用户名的话,那么有两种办法:

瑞吉外卖项目剩余功能补充(瑞吉接送)

方法1:就是在注册的user表中添加用户名;(实际上这个用户在注册的时候是没有填写username这个选项的,所以这里查询出来全是null,所以前端就展示不出来用户)

方法二:(推荐使用)

因为我们不可能老是自己去数据库修改具体的值,所以这里我们使用用户下单的consignee来显示,数据库中也有,但是数据库中的consignee是可以为null的,所以在后台代码中帮订单添加该属性的时候要判断是否null!然后就是去修改前端代码就行:

 把72行的userName改成consignee就行;

测试效果:

手机端减少购物车中的菜品或者套餐数量(前端展示有一点小问题)

前端请求: http://localhost:8080/shoppingCart/sub

请求方式:post

携带参数可能是dish_id 也可能是 setmealId,所以我们需要实体类shoppingCart来接收;

遇到的bug: 就是购物车里面的菜品和套餐的数量可能会减少至负数!!!所以这里要判断和需要前端处理;

而且不知道为什么。。。。上面的数量已经为0了,但是下面的加减还是可以变话的就导致了数据库中的数据可以为负数。。。前端的问题,,,暂时使用一个简单的做法解决。。。把数据库的该字段设置为无符号字段,所以当num数小于0的时候就会报错(500接口异常),但是左下角的小购物车还是会显示菜品为0

 在ShoppingCartController中添加下面的接口方法来接收请求:

/** * 客户端的套餐或者是菜品数量减少设置 * 没必要设置返回值 * @param shoppingCart */ @PostMapping("/sub") @Transactional public R<ShoppingCart> sub(@RequestBody ShoppingCart shoppingCart){ Long dishId = shoppingCart.getDishId(); LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>(); //代表数量减少的是菜品数量 if (dishId != null){ //通过dishId查出购物车对象 queryWrapper.eq(ShoppingCart::getDishId,dishId); ShoppingCart cart1 = shoppingCartService.getOne(queryWrapper); cart1.setNumber(cart1.getNumber()-1); //对数据进行更新操作 shoppingCartService.updateById(cart1); return R.success(cart1); } Long setmealId = shoppingCart.getSetmealId(); if (setmealId != null){ //代表是套餐数量减少 queryWrapper.eq(ShoppingCart::getSetmealId,setmealId); ShoppingCart cart2 = shoppingCartService.getOne(queryWrapper); cart2.setNumber(cart2.getNumber()-1); //对数据进行更新操作 shoppingCartService.updateById(cart2); return R.success(cart2); } return R.error("操作异常"); }

解决前端展示的bug:对上面的代码进行修改(这是评论区一个老哥提供的思路)

/** * 客户端的套餐或者是菜品数量减少设置 * 没必要设置返回值 * @param shoppingCart */ @PostMapping("/sub") @Transactional public R<ShoppingCart> sub(@RequestBody ShoppingCart shoppingCart){ Long dishId = shoppingCart.getDishId(); LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>(); //代表数量减少的是菜品数量 if (dishId != null){ //通过dishId查出购物车对象 queryWrapper.eq(ShoppingCart::getDishId,dishId); //这里必须要加两个条件,否则会出现用户互相修改对方与自己购物车中相同套餐或者是菜品的数量 queryWrapper.eq(ShoppingCart::getUserId,BaseContext.getCurrentId()); ShoppingCart cart1 = shoppingCartService.getOne(queryWrapper); cart1.setNumber(cart1.getNumber()-1); Integer LatestNumber = cart1.getNumber(); if (LatestNumber > 0){ //对数据进行更新操作 shoppingCartService.updateById(cart1); }else if(LatestNumber == 0){ //如果购物车的菜品数量减为0,那么就把菜品从购物车删除 shoppingCartService.removeById(cart1.getId()); }else if (LatestNumber < 0){ return R.error("操作异常"); } return R.success(cart1); } Long setmealId = shoppingCart.getSetmealId(); if (setmealId != null){ //代表是套餐数量减少 queryWrapper.eq(ShoppingCart::getSetmealId,setmealId).eq(ShoppingCart::getUserId,BaseContext.getCurrentId()); ShoppingCart cart2 = shoppingCartService.getOne(queryWrapper); cart2.setNumber(cart2.getNumber()-1); Integer LatestNumber = cart2.getNumber(); if (LatestNumber > 0){ //对数据进行更新操作 shoppingCartService.updateById(cart2); }else if(LatestNumber == 0){ //如果购物车的套餐数量减为0,那么就把套餐从购物车删除 shoppingCartService.removeById(cart2.getId()); }else if (LatestNumber < 0){ return R.error("操作异常"); } return R.success(cart2); } //如果两个大if判断都进不去 return R.error("操作异常"); }用户查看自己订单

在OrderController中添加下面的方法;

/** * 用户订单分页查询 * @param page * @param pageSize * @return */@GetMapping("/userPage")public R<Page> page(int page, int pageSize){ //分页构造器对象 Page<Orders> pageInfo = new Page<>(page,pageSize); //构造条件查询对象 LambdaQueryWrapper<Orders> queryWrapper = new LambdaQueryWrapper<>(); //添加排序条件,根据更新时间降序排列 queryWrapper.orderByDesc(Orders::getOrderTime); orderService.page(pageInfo,queryWrapper); return R.success(pageInfo);}

其实这里还没有完善!!!下面继续完善代码;

通过order.html这个页面我们可以发现:前端还需要下面这些数据;所以我们后端要传给它。。。

 分析前端代码: 这个item是从order.orderDetails里面 获取到的,但是orders实体类里面并没有orderDetails这个属性,而且数据库中这个order表里面也没有这个字段,所以这里我使用的是dto来封装数据给前端,这就需要使用到dto对象的分页查询了,,,,,而且离谱的是前端就是传了一个分页页面大小的数据,,,,所以我们只能从本地线程中获取用户id开始,,一路查询数据。。。。。

创建OrdersDto实体类:

package com.itheima.reggie.dto;import com.baomidou.mybatisplus.core.metadata.IPage;import com.itheima.reggie.entity.OrderDetail;import com.itheima.reggie.entity.Orders;import lombok.Data;import java.util.List;/** * @author LJM * @create 2022/5/3 */@Datapublic class OrderDto extends Orders { private List<OrderDetail> orderDetails;}

代码:这里面的代码我踩了很多坑才写出来的,看到这里的小伙伴,希望给个赞,码字不易^_^谢谢

不建议大家把业务写在controller,我是为了方便才写这里的,在企业的实际开发中千万不要这么干!!!请勿效仿!

//抽离的一个方法,通过订单id查询订单明细,得到一个订单明细的集合 //这里抽离出来是为了避免在stream中遍历的时候直接使用构造条件来查询导致eq叠加,从而导致后面查询的数据都是null public List<OrderDetail> getOrderDetailListByOrderId(Long orderId){ LambdaQueryWrapper<OrderDetail> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(OrderDetail::getOrderId, orderId); List<OrderDetail> orderDetailList = orderDetailService.list(queryWrapper); return orderDetailList; } /** * 用户端展示自己的订单分页查询 * @param page * @param pageSize * @return * 遇到的坑:原来分页对象中的records集合存储的对象是分页泛型中的对象,里面有分页泛型对象的数据 * 开始的时候我以为前端只传过来了分页数据,其他所有的数据都要从本地线程存储的用户id开始查询, * 结果就出现了一个用户id查询到 n个订单对象,然后又使用 n个订单对象又去查询 m 个订单明细对象, * 结果就出现了评论区老哥出现的bug(嵌套显示数据....) * 正确方法:直接从分页对象中获取订单id就行,问题大大简化了...... */ @GetMapping("/userPage") public R<Page> page(int page, int pageSize){ //分页构造器对象 Page<Orders> pageInfo = new Page<>(page,pageSize); Page<OrderDto> pageDto = new Page<>(page,pageSize); //构造条件查询对象 LambdaQueryWrapper<Orders> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(Orders::getUserId,BaseContext.getCurrentId()); //这里是直接把当前用户分页的全部结果查询出来,要添加用户id作为查询条件,否则会出现用户可以查询到其他用户的订单情况 //添加排序条件,根据更新时间降序排列 queryWrapper.orderByDesc(Orders::getOrderTime); orderService.page(pageInfo,queryWrapper); //通过OrderId查询对应的OrderDetail LambdaQueryWrapper<OrderDetail> queryWrapper2 = new LambdaQueryWrapper<>(); //对OrderDto进行需要的属性赋值 List<Orders> records = pageInfo.getRecords(); List<OrderDto> orderDtoList = records.stream().map((item) ->{ OrderDto orderDto = new OrderDto(); //此时的orderDto对象里面orderDetails属性还是空 下面准备为它赋值 Long orderId = item.getId();//获取订单id List<OrderDetail> orderDetailList = this.getOrderDetailListByOrderId(orderId); BeanUtils.copyProperties(item,orderDto); //对orderDto进行OrderDetails属性的赋值 orderDto.setOrderDetails(orderDetailList); return orderDto; }).collect(Collectors.toList()); //使用dto的分页有点难度.....需要重点掌握 BeanUtils.copyProperties(pageInfo,pageDto,"records"); pageDto.setRecords(orderDtoList); return R.success(pageDto); }

代码测试:

 点击去支付,然后点击去查看订单:

收工!

移动端的再来一单功能

由于这里没有写后台的确认订单功能,所以这里通过数据库修改订单状态来完成测试!

 先把数据库中的订单表中的status改一些为4:这样在前端才能点击这个再来一单的按钮:

 在order.html中可以看见这样一段前端代码:

<div class="btn" v-if="order.status === 4"> //状态是4才会让你点击下面这个再来一单 <div class="btnAgain" @click="addOrderAgain(order)">再来一单 </div></div>

然后找到addOrderAgain这个方法:前端使用post请求,请求地址order/again:

 写后端接口:不建议把业务代码写在controller,不然以后想复用的时候就会很麻烦的!!!

//客户端点击再来一单 /** * 前端点击再来一单是直接跳转到购物车的,所以为了避免数据有问题,再跳转之前我们需要把购物车的数据给清除 * ①通过orderId获取订单明细 * ②把订单明细的数据的数据塞到购物车表中,不过在此之前要先把购物车表中的数据给清除(清除的是当前登录用户的购物车表中的数据), * 不然就会导致再来一单的数据有问题; * (这样可能会影响用户体验,但是对于外卖来说,用户体验的影响不是很大,电商项目就不能这么干了) */ @PostMapping("/again") public R<String> againSubmit(@RequestBody Map<String,String> map){ String ids = map.get("id"); long id = Long.parseLong(ids); LambdaQueryWrapper<OrderDetail> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(OrderDetail::getOrderId,id); //获取该订单对应的所有的订单明细表 List<OrderDetail> orderDetailList = orderDetailService.list(queryWrapper); //通过用户id把原来的购物车给清空,这里的clean方法是视频中讲过的,建议抽取到service中,那么这里就可以直接调用了 shoppingCartService.clean(); //获取用户id Long userId = BaseContext.getCurrentId(); List<ShoppingCart> shoppingCartList = orderDetailList.stream().map((item) -> { //把从order表中和order_details表中获取到的数据赋值给这个购物车对象 ShoppingCart shoppingCart = new ShoppingCart(); shoppingCart.setUserId(userId); shoppingCart.setImage(item.getImage()); Long dishId = item.getDishId(); Long setmealId = item.getSetmealId(); if (dishId != null) { //如果是菜品那就添加菜品的查询条件 shoppingCart.setDishId(dishId); } else { //添加到购物车的是套餐 shoppingCart.setSetmealId(setmealId); } shoppingCart.setName(item.getName()); shoppingCart.setDishFlavor(item.getDishFlavor()); shoppingCart.setNumber(item.getNumber()); shoppingCart.setAmount(item.getAmount()); shoppingCart.setCreateTime(LocalDateTime.now()); return shoppingCart; }).collect(Collectors.toList()); //把携带数据的购物车批量插入购物车表 这个批量保存的方法要使用熟练!!! shoppingCartService.saveBatch(shoppingCartList); return R.success("操作成功"); }

测试:

点击再来一单:

并且购物车表中也有数据:

移动端点击套餐图片查看套餐具体菜品

点击移动端套餐的图片,发现会向后端发送一个get请求,浏览器具体请求的图片我就不放了,我在前端页面找到了对应的axios请求:

 至于前端展示需要的具体数据,我在前端页面没有找到。。。。。。然后就不想找了,但是找到了下面的代码;

 然后我就试了三次,一次是返回R<List<SetmealDish>> ,一次是R<List<Dish>>,还有一次是创建了一个SetmealDishDto,用R<List<DishDto>>,但是这个用dto怎么把dish的图片有序的设置进去我是真的处理不了>_<,  最后还是选择返回R<List<Dish>>,,,,,不知道返回这个数据对不对哈,如果评论区有老哥有更好的写法,可以在评论区分享一下;  这个事情告诉我们和前端对接好是多么的重要!!! 

下面的写法是修正后的写法,是评论区一位老哥指点后写出的;我开始返回的确实是<List<Dish>>,不过下面的代码是纠正后的代码;

代码:

/** * 移动端点击套餐图片查看套餐具体内容 * 这里返回的是dto 对象,因为前端需要copies这个属性 * 前端主要要展示的信息是:套餐中菜品的基本信息,图片,菜品描述,以及菜品的份数 * @param SetmealId * @return */ //这里前端是使用路径来传值的,要注意,不然你前端的请求都接收不到,就有点尴尬哈 @GetMapping("/dish/{id}") public R<List<DishDto>> dish(@PathVariable("id") Long SetmealId){ LambdaQueryWrapper<SetmealDish> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(SetmealDish::getSetmealId,SetmealId); //获取套餐里面的所有菜品 这个就是SetmealDish表里面的数据 List<SetmealDish> list = setmealDishService.list(queryWrapper); List<DishDto> dishDtos = list.stream().map((setmealDish) -> { DishDto dishDto = new DishDto(); //其实这个BeanUtils的拷贝是浅拷贝,这里要注意一下 BeanUtils.copyProperties(setmealDish, dishDto); //这里是为了把套餐中的菜品的基本信息填充到dto中,比如菜品描述,菜品图片等菜品的基本信息 Long dishId = setmealDish.getDishId(); Dish dish = dishService.getById(dishId); BeanUtils.copyProperties(dish, dishDto); return dishDto; }).collect(Collectors.toList()); return R.success(dishDtos); }

测试展示: 之前我自己第一次写的这个代码的展示效果是没有这个菜品的具体份数的,因为当时我返回给前端的数据是:<List<Dish>>;

删除地址

前端点击删除地址:然后发送删除请求到后端

 

 在后端使用controller接收:

/** * 根据地址id删除用户地址 * @param id * @return */ @DeleteMapping public R<String> delete(@RequestParam("ids") Long id){ if (id == null){ return R.error("请求异常"); } LambdaQueryWrapper<AddressBook> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(AddressBook::getId,id).eq(AddressBook::getUserId,BaseContext.getCurrentId()); addressBookService.remove(queryWrapper); //addressBookService.removeById(id); 感觉直接使用这个removeById不太严谨..... return R.success("删除地址成功"); }修改地址

点击修改符号,发现回显信息已经写好了;

 回显信息的接口之前已经写好了:点击编辑,前端会发送下面的请求;

 在该方法打一个debug,看回显信息是不是该接口:然后发现确实是该接口;

编写修改接口:修改完成后点击保存地址,前端会发下面的请求:

 编写相关的接口:

/** * 修改收货地址 * @param addressBook * @return */ @PutMapping public R<String> update(@RequestBody AddressBook addressBook){ if (addressBook == null){ return R.error("请求异常"); } addressBookService.updateById(addressBook); return R.success("修改成功"); }后台订单状态的修改

在后台订单明细中点击派送按钮:前端会发送下面的请求来:是json格式的数据;

请求地址:http://localhost:8080/order

后台接收:

@PutMapping public R<String> orderStatusChange(@RequestBody Map<String,String> map){ String id = map.get("id"); Long orderId = Long.parseLong(id); Integer status = Integer.parseInt(map.get("status")); if(orderId == null || status==null){ return R.error("传入信息不合法"); } Orders orders = orderService.getById(orderId); orders.setStatus(status); orderService.updateById(orders); return R.success("订单状态修改成功"); }

测试:自己测试就行;

移动端登陆退出功能 /** * 退出功能 * ①在controller中创建对应的处理方法来接受前端的请求,请求方式为post; * ②清理session中的用户id * ③返回结果(前端页面会进行跳转到登录页面) * @return */ @PostMapping("/loginout") public R<String> logout(HttpServletRequest request){ //清理session中的用户id request.getSession().removeAttribute("user"); return R.success("退出成功"); }
本文链接地址:https://www.jiuchutong.com/zhishi/299531.html 转载请保留说明!

上一篇:Springboot怎么实现restfult风格Api接口(springboot -d)

下一篇:主动学习(Active Learning,AL)的理解以及代码流程讲解

  • 苹果防丢失定位功能怎么用(苹果防丢失定位设置)

    苹果防丢失定位功能怎么用(苹果防丢失定位设置)

  • 网易云音乐链接怎么复制(网易云音乐链接下载)

    网易云音乐链接怎么复制(网易云音乐链接下载)

  • 淘宝互动消息如何查看(淘宝互动消息别人能看到吗)

    淘宝互动消息如何查看(淘宝互动消息别人能看到吗)

  • 荣耀v20怎样隐藏应用(荣耀v20怎样隐藏图标)

    荣耀v20怎样隐藏应用(荣耀v20怎样隐藏图标)

  • 硬盘内存一般多大(硬盘内存多少够用)

    硬盘内存一般多大(硬盘内存多少够用)

  • 抖音违反社区规则多久恢复(抖音违反社区规定私信功能关闭)

    抖音违反社区规则多久恢复(抖音违反社区规定私信功能关闭)

  • soul怎么才算已读(soul怎么判断对方把你删除)

    soul怎么才算已读(soul怎么判断对方把你删除)

  • 快充跟尾插有关系吗(手机快充尾插多少价格合适)

    快充跟尾插有关系吗(手机快充尾插多少价格合适)

  • 抖音怎么解绑公会(抖音怎么解绑公司账号)

    抖音怎么解绑公会(抖音怎么解绑公司账号)

  • 热点频段2.4和5.0哪个快(热点频段2.4和5.0哪个网速好)

    热点频段2.4和5.0哪个快(热点频段2.4和5.0哪个网速好)

  • mde5是什么型号(mde7是什么型号)

    mde5是什么型号(mde7是什么型号)

  • 打开开始菜单的组合键(界面返回键在哪里)

    打开开始菜单的组合键(界面返回键在哪里)

  • ipad2怎么拆开(ipad2拆解图ipad2拆机教程全图)

    ipad2怎么拆开(ipad2拆解图ipad2拆机教程全图)

  • 微信明明没有消息却一直显示有一条(微信明明没有消息但却有时间)

    微信明明没有消息却一直显示有一条(微信明明没有消息但却有时间)

  • 华为maral00是什么型号(华为maral00是什么型号多少钱)

    华为maral00是什么型号(华为maral00是什么型号多少钱)

  • 手机qq怎么设置密码锁(手机qq怎么设置在线状态)

    手机qq怎么设置密码锁(手机qq怎么设置在线状态)

  • 苹果手机录屏没有声音(苹果手机录屏没有声音可以补救吗)

    苹果手机录屏没有声音(苹果手机录屏没有声音可以补救吗)

  • oppor11通话设置在哪里找(oppor11的通话设置在哪里设置)

    oppor11通话设置在哪里找(oppor11的通话设置在哪里设置)

  • 华为体脂秤怎么解除绑定(华为体脂秤怎么调整公斤和斤)

    华为体脂秤怎么解除绑定(华为体脂秤怎么调整公斤和斤)

  • 华为tlo1h是什么型号

    华为tlo1h是什么型号

  • opporenoz是啥处理器(opo reno z什么处理器)

    opporenoz是啥处理器(opo reno z什么处理器)

  • 小米9有无线充电吗(小米9有无线充电功能吗怎么用)

    小米9有无线充电吗(小米9有无线充电功能吗怎么用)

  • 布莱顿码头,阿德莱德布莱顿 (© Darryl Leach/Alamy)(布莱顿小镇介绍)

    布莱顿码头,阿德莱德布莱顿 (© Darryl Leach/Alamy)(布莱顿小镇介绍)

  • vim-cmd命令  控制虚拟机状态(vim操作命令)

    vim-cmd命令 控制虚拟机状态(vim操作命令)

  • 税务师补报名时间可以交费吗
  • 印花税需要每月缴纳吗
  • 外币报表折算差额是一种未实现的汇兑损益
  • 企业注销库存怎么做账
  • 发票的规格和型号有哪些
  • 分红免征企业所得税
  • 金蝶多核算项目怎么做
  • 服务,不动产和无形资产扣除项目本期实际扣除金额
  • 将固定资产转给母公司属于债务重组吗
  • 发生哪些情形的应判定为重大电力安全隐患
  • 铸造厂的销售废料有哪些
  • 工业企业制造费用具体怎么摊
  • 以现金形式发放的福利怎么入账
  • 增值税专用发票可以开电子发票吗
  • 销售货款会计分录怎么做
  • 软件开发公司怎么找客户
  • 小规模纳税人的认定标准是什么
  • 增值税税负率高于预警值
  • 再生资源税率多少合理
  • 企业所得税视同销售的捐赠扣除
  • 哪些行业可以加计抵扣进项税
  • 房屋贷款基准利率表 历年查询
  • 计提工资是计提当月的还是上个月的
  • 个人代收工程款分录
  • 单位收到项目前的钱
  • win11windows键没反应
  • 非正常损失的进项税额如何计算
  • 清卡处于非征期是什么意思
  • “linux系统”
  • php字符串定义
  • 公网访问内网主机
  • 增值税防伪税控系统
  • 审核过程中发现的问题应由被审核部门实施纠正
  • php自定义函数的语法格式
  • 怎么用html做一个收藏夹
  • 微信红包 python
  • idea如何导入sql文件
  • 研发支出资本化支出属于什么科目
  • 投资他人公司
  • 货物入库会计分录怎么做
  • 营销策划费会计分录
  • 织梦cms为什么不维护了
  • 补发去年工资会被扣税吗
  • 内帐税金会计分录
  • 普通的增值税
  • 税控盘怎么看是否清盘
  • 买手机手续费怎么算的
  • sql去除重复项
  • 单位卖车怎么做账
  • 个人新冠肺炎确诊,要和单位领导说吗
  • 营业外收入应如何核算
  • 应付账款收不回发票该如何调整
  • 工会经费与工会福利的区别
  • 税率与征收率是怎么回事
  • 工会活动购买的产品
  • 认缴款和投资款区别
  • 季度现金流量表本期数和上期数
  • 年数总和法净残值怎么算
  • win7系统无法安装软件
  • win8操作
  • rhel7.5重置密码
  • 安装win7系统需要注意什么
  • hke是什么意思
  • cpu资源占用率计算原理
  • win7系统鼠标指针异常
  • win10用户账户guest
  • linux系统怎么更改语言
  • opengl es3.0metal
  • three.js gui
  • 如何理解闭包,闭包的优缺点
  • 使用的英文
  • Android5.1 SystemUI 启动流程
  • 安卓手机管家在哪里打开
  • android应用层是什么
  • ruby format
  • Sublime Text 3常用插件及安装方法
  • 四川国税局局长是谁
  • 浙江省电税务局电话
  • 国家税务总局云平台网址
  • 一般纳税人资格是什么意思
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设