二刷 苍穹外卖day09

发布于:2025-07-01 ⋅ 阅读:(25) ⋅ 点赞:(0)

查询历史订单

service

public PageResult pageQuery4User(int pageNum, int pageSize, Integer status) {
        // 设置分页
        PageHelper.startPage(pageNum, pageSize);

        OrdersPageQueryDTO ordersPageQueryDTO = new OrdersPageQueryDTO();
        ordersPageQueryDTO.setUserId(BaseContext.getCurrentId());
        ordersPageQueryDTO.setStatus(status);

        // 分页条件查询
        Page<Orders> page = orderMapper.pageQuery(ordersPageQueryDTO);

        List<OrderVO> list = new ArrayList();

        // 查询出订单明细,并封装入OrderVO进行响应
        if (page != null && page.getTotal() > 0) {
            for (Orders orders : page) {
                Long orderId = orders.getId();// 订单id

                // 查询订单明细
                List<OrderDetail> orderDetails = orderDetailMapper.getByOrderId(orderId);

                OrderVO orderVO = new OrderVO();
                BeanUtils.copyProperties(orders, orderVO);
                orderVO.setOrderDetailList(orderDetails);

                list.add(orderVO);
            }
        }
        return new PageResult(page.getTotal(), list);
    }

先创建了一个OrdersPageQueryDTO对象,用于封装查询条件

通过BaseContent.getCurrentId()获取当前用户id
在设置好状态后
用条件查询功能查询符合要求的订单数据,返回一个Page对象

创建OrderVO类型的list列表用于存储封装后的订单数据

将page对象中的每一个订单Orders,查询订单id,并通过订单id查询订单明细,通过BeanUtils工具将Orders对象的属性复制到orderVO中,并将查询到的订单明细列表也赋值到orderVO中

取消订单

 public void userCancelById(Long id) throws Exception {
        // 根据id查询订单
        Orders ordersDB = orderMapper.getById(id);

        // 校验订单是否存在
        if (ordersDB == null) {
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }

        //订单状态 1待付款 2待接单 3已接单 4派送中 5已完成 6已取消
        if (ordersDB.getStatus() > 2) {
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }

        Orders orders = new Orders();
        orders.setId(ordersDB.getId());

        // 更新订单状态、取消原因、取消时间
        orders.setStatus(Orders.CANCELLED);
        orders.setCancelReason("用户取消");
        orders.setCancelTime(LocalDateTime.now());
        orderMapper.update(orders);
    }

先检查订单是否存在,再检查订单状态是否能够取消(这里省略了退款情况,因为没做支付功能)
然后创建一个orders对象,将部分信息修改,这里是Update,只会修改有的,而没提到的菜品信息等仍然会保留

再来一单

service

    /**

     * 再来一单

     *

     * @param id

     */

    public void repetition(Long id) {

        // 查询当前用户id

        Long userId = BaseContext.getCurrentId();// 根据订单id查询当前订单详情

        List<OrderDetail> orderDetailList = orderDetailMapper.getByOrderId(id);// 将订单详情对象转换为购物车对象

        List<ShoppingCart> shoppingCartList = orderDetailList.stream().map(x -> {

            ShoppingCart shoppingCart = new ShoppingCart();// 将原订单详情里面的菜品信息重新复制到购物车对象中

            BeanUtils.copyProperties(x, shoppingCart, "id");

            shoppingCart.setUserId(userId);

            shoppingCart.setCreateTime(LocalDateTime.now());return shoppingCart;

        }).collect(Collectors.toList());// 将购物车对象批量添加到数据库

        shoppingCartMapper.insertBatch(shoppingCartList);

    }

使用Stream(流)操作,对orderDetailList中的每个元素进行映射操作,map会对OrderDetailList中的每个元素执行括号内的逻辑,再将其转换为ShoppingCart类型的对象
最后通过collect(Collectors.toList())将转换后的对象收集到一个List类型的shoppingCartList中

流操作

流操作 = 流水线工厂

想象你是一个工厂老板,有一批订单详情(比如汉堡、薯条、可乐的订单)需要变成购物车商品(给顾客结账用)。流操作就像是一条流水线,每个订单在流水线上走一遍,出来就变成了购物车商品。

  1. stream()

    • 把一个列表(订单详情)变成 “可以逐个处理的东西”,就像把一堆零件放到传送带上。
  2. map()

    • 对流水线上的每个东西做转换(比如把订单→购物车商品)。x -> {...} 是一个箭头函数,表示 “对每个 x 做这些操作”。
  3. collect(Collectors.toList())

    • 流水线的终点,把处理好的东西重新收集回一个列表。

订单搜索

    /**
     * 订单搜索
     *
     * @param ordersPageQueryDTO
     * @return
     */
    public PageResult conditionSearch(OrdersPageQueryDTO ordersPageQueryDTO) {
        PageHelper.startPage(ordersPageQueryDTO.getPage(), ordersPageQueryDTO.getPageSize());

        Page<Orders> page = orderMapper.pageQuery(ordersPageQueryDTO);

        // 部分订单状态,需要额外返回订单菜品信息,将Orders转化为OrderVO
        List<OrderVO> orderVOList = getOrderVOList(page);

        return new PageResult(page.getTotal(), orderVOList);
    }

    private List<OrderVO> getOrderVOList(Page<Orders> page) {
        // 需要返回订单菜品信息,自定义OrderVO响应结果
        List<OrderVO> orderVOList = new ArrayList<>();

        List<Orders> ordersList = page.getResult();
        if (!CollectionUtils.isEmpty(ordersList)) {
            for (Orders orders : ordersList) {
                // 将共同字段复制到OrderVO
                OrderVO orderVO = new OrderVO();
                BeanUtils.copyProperties(orders, orderVO);
                String orderDishes = getOrderDishesStr(orders);

                // 将订单菜品信息封装到orderVO中,并添加到orderVOList
                orderVO.setOrderDishes(orderDishes);
                orderVOList.add(orderVO);
            }
        }
        return orderVOList;
    }

    /**
     * 根据订单id获取菜品信息字符串
     *
     * @param orders
     * @return
     */
    private String getOrderDishesStr(Orders orders) {
        // 查询订单菜品详情信息(订单中的菜品和数量)
        List<OrderDetail> orderDetailList = orderDetailMapper.getByOrderId(orders.getId());

        // 将每一条订单菜品信息拼接为字符串(格式:宫保鸡丁*3;)
        List<String> orderDishList = orderDetailList.stream().map(x -> {
            String orderDish = x.getName() + "*" + x.getNumber() + ";";
            return orderDish;
        }).collect(Collectors.toList());

        // 将该订单对应的所有菜品信息拼接在一起
        return String.join("", orderDishList);
    }

conditionSearch是对外暴露的订单搜索接口,负责分页查询并返回订单列表
调用getOrderVOList将Orders对象转换为OrderVO对象,其中包含更多展示字段
在gerOrderVOList方法中通过调用page.getResult就能拿到List
先判断是否为空,然后将所有值都复制到OrderVO中,再调用getOrderDishesStr方法将所有菜品信息拼接成特定格式的字符串

而getOrderDishesStr方法使用了Stream流,将所有菜品详情都转换成了字符串的格式,最后通过Stream.join拼接

检验收货地址是否超出配送范围

/**
     * 检查客户的收货地址是否超出配送范围
     * @param address
     */
    private void checkOutOfRange(String address) {
        Map map = new HashMap();
        map.put("address",shopAddress);
        map.put("output","json");
        map.put("ak",ak);

        //获取店铺的经纬度坐标
        String shopCoordinate = HttpClientUtil.doGet("https://api.map.baidu.com/geocoding/v3", map);

        JSONObject jsonObject = JSON.parseObject(shopCoordinate);
        if(!jsonObject.getString("status").equals("0")){
            throw new OrderBusinessException("店铺地址解析失败");
        }

        //数据解析
        JSONObject location = jsonObject.getJSONObject("result").getJSONObject("location");
        String lat = location.getString("lat");
        String lng = location.getString("lng");
        //店铺经纬度坐标
        String shopLngLat = lat + "," + lng;

        map.put("address",address);
        //获取用户收货地址的经纬度坐标
        String userCoordinate = HttpClientUtil.doGet("https://api.map.baidu.com/geocoding/v3", map);

        jsonObject = JSON.parseObject(userCoordinate);
        if(!jsonObject.getString("status").equals("0")){
            throw new OrderBusinessException("收货地址解析失败");
        }

        //数据解析
        location = jsonObject.getJSONObject("result").getJSONObject("location");
        lat = location.getString("lat");
        lng = location.getString("lng");
        //用户收货地址经纬度坐标
        String userLngLat = lat + "," + lng;

        map.put("origin",shopLngLat);
        map.put("destination",userLngLat);
        map.put("steps_info","0");

        //路线规划
        String json = HttpClientUtil.doGet("https://api.map.baidu.com/directionlite/v1/driving", map);

        jsonObject = JSON.parseObject(json);
        if(!jsonObject.getString("status").equals("0")){
            throw new OrderBusinessException("配送路线规划失败");
        }

        //数据解析
        JSONObject result = jsonObject.getJSONObject("result");
        JSONArray jsonArray = (JSONArray) result.get("routes");
        Integer distance = (Integer) ((JSONObject) jsonArray.get(0)).get("distance");

        if(distance > 5000){
            //配送距离超过5000米
            throw new OrderBusinessException("超出配送范围");
        }
    }

先通过调用百度地图api获取店铺的经纬度坐标
然后解析json数据得到店铺的经纬度坐标
然后同理获取用户的经纬度坐标
然后解析json数据得到用户收货地址的经纬度坐标
解析json数据后得到店铺的经纬度坐标
然后把两地的经纬度坐标放到map中让百度地图进行路径规划
把规划好后的距离解析查看距离是否大于5000米,大于回复超出配送范围

记得修改submitOrder方法,在其中调用这个函数

总结

1.为什么在订单查询中使用PageResult和OrderVO对象

PageResult用于封装分页查询结果(包括总记录数和当前页数据),便于前端展示分页信息
OrderVO是专为前端展示设计的对象,在Orders实体的基础上扩展了额外字段,避免返回数据,提升接口性能。

2.Stream流在订单处理中主要是什么应用场景

对象转换:将OrderDetail转换为ShoppingCart对象
数据拼接:将订单菜品信息拼接成字符串

3.取消订单时为什么要校验订单状态?

订单状态决定了业务流程的合法性:
仅当状态为代付款和代接单才能被允许取消,比较已配送或已完成的订单被误操作.

4.”再来一单“功能如何实现从订单到购物车的转换?

通过Stream.map()遍历整个订单详情,将每个OrderDetail转换为ShoppingCart对象
利用BeanUtils.copyProperties复制基础属性
最终通过collect(Collectors.toList())收集为购物车列表,批量存入数据库
5.## 配送范围校验中,百度地图 API 的核心调用流程是什么?
地址解析:将店铺和用户地址转换为经纬度坐标。
路线规划:调用 driving 接口计算两地驾车距离。
距离判断:若距离超过 5000 米,抛出 “超出配送范围” 异常。
关键是确保 API 请求参数正确,并正确解析 JSON 响应中的 distance 字段。


网站公告

今日签到

点亮在社区的每一天
去签到