查询历史订单
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中
流操作
流操作 = 流水线工厂
想象你是一个工厂老板,有一批订单详情(比如汉堡、薯条、可乐的订单)需要变成购物车商品(给顾客结账用)。流操作就像是一条流水线,每个订单在流水线上走一遍,出来就变成了购物车商品。
stream()
- 把一个列表(订单详情)变成 “可以逐个处理的东西”,就像把一堆零件放到传送带上。
map()
- 对流水线上的每个东西做转换(比如把订单→购物车商品)。
x -> {...}
是一个箭头函数,表示 “对每个x
做这些操作”。
- 对流水线上的每个东西做转换(比如把订单→购物车商品)。
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
字段。