[Added most functions of St. Regis takeout]

Most functions of St. Regis takeaway are added

On and off sale of dishes

After clicking the corresponding function in the browser console, you can see that the request sent by the front end is: http://localhost:9999/dish/status/1?ids=1413342036832100354, and the request method is POST.
Insert image description here
After receiving the front-end parameters, complete the controller layer code and add the following interface code to 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("售卖状态设置异常");
}

Dishes are on sale in batches and are off sale in batches

Modify the above method of selling the sales status of a single dish;

/**
 * 对菜品批量或者是单个 进行停售或者是起售
 * @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("售卖状态修改成功");
}

Note: The code in the controller layer cannot directly write business. It is recommended to extract it to the service layer, and the controller can just call the service method. The following batch deletion function is extracted, and the controller does not write business code;

Batch deletion of dishes

Request from the front end:
Insert image description here
In the DishFlavor entity class, add the @TableLogic annotation to the private Integer isDeleted; field to indicate that the deletion is a logical deletion, provided by mybatis-plus of;
Insert image description here

Add interface in DishController:

/**
 * 套餐批量删除和单个删除
 * @return
 */
@DeleteMapping
public 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("菜品删除成功");
}

Add related methods in DishServicez:

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

Implement this method in the implementation class:

/**
 *套餐批量删除和单个删除
 * @param ids
 */
@Override
@Transactional
public 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("删除菜品中有正在售卖菜品,无法全部删除");
        }
    }
 
}

Functional test: single deletion, batch deletion, batch deletion has sales enabled...

Test success!

Insert image description here

Optimization of dish deletion logic

The deletion function of the dishes written above is a bit simple. Let’s improve the relevant logic below;

Related service injections are not listed here. Which service is used in the code, you just autowire;

The code below may be a bit redundant, so I won’t extract it here;

    /**
     * 菜品批量删除和单个删除
     * 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("菜品删除成功");
    }

Start and stop sales of package management

Request from the front end:
Insert image description here

According to the functions implemented by the previous dish module, we can know that we only need to write a batch processing method to start and stop selling single or batch packages;

Controller layer code in SetmealController:

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

Add the following method to SetmealService:

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

Implementation of this method

/**
 * 根据套餐id修改售卖状态
 * @param status
 * @param ids
 */
@Override
public 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);
        }
    }
}

Functional test successful:
Insert image description here

Modifications to package management

It is divided into two steps: data display and submission of modified data to the database.

The front-end clicks on the package modification, and the request sent by the front-end:

The request method is: get, and the parameters carried are: stemealId

Insert image description here
Then we found that there was no data in the pop-up editing window: and a 404 was reported, which means that reported an error when the data was echoed, no specific echo interface was found to handle this request;

Insert image description here
Add the following code to SetmealController:

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

SetmealService add the following code:

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

Implementation of this method:

/**
 * 回显套餐数据:根据套餐id查询套餐
 * @return
 */
@Override
public 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;
}

Test: Data echoed successfully:
Insert image description here
But when we click to add a dish, we will find that only the price of the dish is displayed on the right and the corresponding name of the dish is not displayed:

The dishes in the selected dishes do not display the corresponding dish names;
Insert image description here
Modify the front-end code: change dishName in line 335 of backend/combo/add.html to name ;
Insert image description here
Because the item here represents a dish object, the dish entity class uses name as the dish name;
Insert image description here
Display of the modified operation:
Insert image description here
After modifying the package, click Save. We found that the front end issued a put request:
Insert image description here
The parameters carried are:
Insert image description here
According to the data passed by the front end and the required return value, we can know the return value of the controller layer method and what parameters are used to receive the data passed to us by the front end; note that the dishes in this set meal must also be saved and modified: setealDish needs to be saved to the seteal_dish table; < /span>

Controller layer code:

@PutMapping
public 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("套餐修改成功");
}

View and display customer orders based on conditions in the background

Click on the order details, and the front-end will send the following request: the data carried is for paging query;
Insert image description here
It is mainly used to generate mybatis-plus dynamic sql statements:

Here I just write the functions directly in the controller layer and layer them according to my own needs;

    /**
     * 后台查询订单明细
     * @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);
    }

The test results are as follows:
Insert image description here
But if you want this username to display the username, then there is Two ways:

Method 1: Add the user name to the registered user table; (Actually, this user did not fill in the username option when registering, so the query here is all null, so the front end cannot display the user)

Method 2: (recommended)

Because we can't always go to the database to modify the specific value, here we use the consignee of the user's order to display it, which is also available in the database. However, the consignee in the database can be null, so we add this to the backend code for the order. When using attributes, you need to determine whether they are null! Then just modify the front-end code:

Just change the userName in line 72 to consignee;
Insert image description here
The test results are as follows:

Reduce the number of dishes or packages in the shopping cart on the mobile phone (there is a slight problem with the front-end display)

Front-end request: http://localhost:8080/shoppingCart/sub

Request method: post

The carrying parameter may be dish_id or setmealId, so we need the entity class shoppingCart to receive it;
Insert image description here
The bug encountered: the number of dishes and packages in the shopping cart may be different Reduce to a negative number! ! ! Therefore, judgment and front-end processing are required here;

And I don’t know why. . . . The above quantity is already 0, but the following addition and subtraction can still be changed, resulting in the data in the database being negative. . . The front-end problem,,, is temporarily solved with a simple method. . . Set this field in the database to an unsigned field, so when the number of num is less than 0, an error will be reported (500 interface exception), but the small shopping cart in the lower left corner will still display the dish as 0
Insert image description here
Add the following interface method in ShoppingCartController to receive requests:

    /**
     * 客户端的套餐或者是菜品数量减少设置
     * 没必要设置返回值
     * @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("操作异常");
    }

Solve the bug in the front-end display: modify the above code (this is based on the ideas provided by other experts)

   /**
     * 客户端的套餐或者是菜品数量减少设置
     * 没必要设置返回值
     * @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("操作异常");
    }

Users view their orders

Add the following method in 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);
}

In fact, it’s not perfect yet! ! ! Continue to improve the code below;

Through the order.html page, we can find that the front end also needs the following data; so we need to pass it to the back end. . .
Insert image description here
Analyze the front-end code: This item is obtained from order.orderDetails, but there is no orderDetails attribute in the orders entity class, and the order in the database There is no such field in the table, so here I use dto to encapsulate the data to the front end, which requires the use of paging query of the dto object,,,,, and what’s outrageous is that the front end passes data of the size of a paging page. ,,,,so we can only start by getting the user id from the local thread,and query the data all the way. . . . .

Create the OrdersDto entity class:

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
 */
@Data
public class OrderDto extends Orders  {
    
    
 
    private List<OrderDetail> orderDetails;
}

It is not recommended that you write your business in the controller. I write it here for convenience. Never do this in the actual development of the enterprise! ! ! Don’t follow suit!

    //抽离的一个方法,通过订单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);
    }

Code test:
Insert image description here

One more function on the mobile side

Since there is no backend order confirmation function written here, the test is completed by modifying the order status through the database!
Insert image description here
After refreshing the user page, you will find that the order has been completed

Insert image description here
You can see this piece of front-end code in order.html:
Insert image description here
Then click on the user page to place another order, and you will find that the front-end uses a post request, and the request address is order/again:

Insert image description here
Write the back-end interface: It is not recommended to write the business code in the controller, otherwise it will be very troublesome when you want to reuse it in the future! ! !

    //客户端点击再来一单
    /**
     * 前端点击再来一单是直接跳转到购物车的,所以为了避免数据有问题,再跳转之前我们需要把购物车的数据给清除
     * ①通过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和serviceImpl中建立对应方法,建议抽取到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("操作成功");
    }

After clicking Place Another Order, the same product appears in the shopping cart:
Insert image description here

Click on the set meal picture on the mobile terminal to view the specific dishes of the set meal

Click on the picture of the mobile package and find that a get request will be sent to the backend:
Insert image description here
Implementation code:

 
        /**
     * 移动端点击套餐图片查看套餐具体内容
     * 这里返回的是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);
    }

function test:
Insert image description here

Delete address

Click to delete the address on the front end: and then send a deletion request to the backend
Insert image description here
The function implementation code is as follows:

     /**
     * 根据地址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("删除地址成功");
    }

The function is implemented. After clicking delete, the address is deleted successfully.

Change address

Click the modification symbol and find that the echo information has been written;
Click to save the address and find an error request
Insert image description here
The parameters carried are as follows:
Insert image description here

Write related interfaces:

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

Testing the save address function was successful!

Modifications to backend order delivery

Click the delivery button in the background order details: the front end will send the following request: it is data in json format;
Insert image description here
Interface code:

    @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("订单状态修改成功");
 
    }

The functional test is as follows:

Insert image description here

Insert image description here

Mobile login and exit function

The error request is as follows:
Insert image description here
The interface code is as follows:

    /**
     * 退出功能
     * ①在controller中创建对应的处理方法来接受前端的请求,请求方式为post;
     * ②清理session中的用户id
     * ③返回结果(前端页面会进行跳转到登录页面)
     * @return
     */
    @PostMapping("/loginout")
    public R<String> logout(HttpServletRequest request){
    
    
        //清理session中的用户id
        request.getSession().removeAttribute("user");
        return R.success("退出成功");
    }

Test success! ! !

Guess you like

Origin blog.csdn.net/qq_62124267/article/details/133975449