【学习日记2023.5.30】之 管理端订单模块完善_调用百度地图优化用户端提交订单是否超出配送距离

news2024/11/27 21:33:50

文章目录

  • 9. 管理端订单模块完善
    • 9.1 需求分析和涉及
    • 9.2 代码开发
        • Controller层
        • Service层接口
        • Service层实现类
        • Mapper层
    • 9.3 功能测试
    • 9.4 提交代码
    • 9.5 优化用户下单功能,引入距离判断

9. 管理端订单模块完善

  • 订单搜索
  • 各个状态的订单数量统计
  • 查询订单详情
  • 接单
  • 拒单
  • 取消订单
  • 派送订单
  • 完成订单

9.1 需求分析和涉及

接口设计

1)订单搜索
请添加图片描述

2)各个状态的订单数量统计
请添加图片描述

3)查询订单详情
请添加图片描述

4)接单
请添加图片描述

5)拒单
请添加图片描述

6)取消订单
请添加图片描述

7)派送订单
请添加图片描述

8)完成订单
请添加图片描述

9.2 代码开发

Controller层

package com.sky.controller.admin;

import com.sky.dto.OrdersCancelDTO;
import com.sky.dto.OrdersConfirmDTO;
import com.sky.dto.OrdersPageQueryDTO;
import com.sky.dto.OrdersRejectionDTO;
import com.sky.result.PageResult;
import com.sky.result.Result;
import com.sky.service.OrderService;
import com.sky.vo.*;
import com.sky.enumeration.CallType;
import com.sky.vo.OrderStatisticsVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@Slf4j
@RestController
@RequestMapping("/admin/order")
@Api(tags = "商家端订单接口")
public class OrderController {
    @Autowired
    private OrderService orderService;
    
    /**
     * 订单搜索
     * @param ordersPageQueryDTO
     * @return
     */
    @GetMapping("/conditionSearch")
    @ApiOperation("订单搜索")
    public Result<PageResult> historyOrders(OrdersPageQueryDTO ordersPageQueryDTO){
        PageResult pageResult= orderService.historyOrders(ordersPageQueryDTO, CallType.ADMIN);
        log.info("查询到了{}条数据",pageResult.getTotal());
        return Result.success(pageResult);
    }

    /**
     * 订单数量统计
     * @return
     */
    @GetMapping("/statistics")
    @ApiOperation("各个状态的订单数量统计")
    public Result<OrderStatisticsVO> getNumByStatistics(){
        log.info("各个状态的订单数量统计:");
        OrderStatisticsVO orderStatisticsVO = orderService.getNumByStatistics();
        return Result.success(orderStatisticsVO);
    }
    
    /**
     * 查看订单详情
     * @param id
     * @return
     */
    @ApiOperation("查询订单详情")
    @GetMapping("/details/{id}")
    public Result<OrderAndDetailVO> queryDetailById(@PathVariable Long id){
        log.info("订单id为:{}",id);
        OrderAndDetailVO orderAndDetailVO = orderService.getByOrderId(id);
        return Result.success(orderAndDetailVO);
    }

    /**
     * 接单
     * @param ordersConfirmDTO
     * @return
     */
    @ApiOperation("接单")
    @PutMapping("/confirm")
    public Result confirm(@RequestBody OrdersConfirmDTO ordersConfirmDTO){
        log.info("接单数据为:{}",ordersConfirmDTO);
        orderService.confirm(ordersConfirmDTO);
        return Result.success();
    }

    /**
     * 拒绝接单
     * @param ordersRejectionDTO
     * @return
     */
    @PutMapping("/rejection")
    @ApiOperation("拒绝接单")
    public Result<String> rejection(@RequestBody OrdersRejectionDTO ordersRejectionDTO){
        orderService.rejection(ordersRejectionDTO);
        log.info("拒绝接单接口执行");
        return Result.success();
    }

    /**
     * 取消订单
     *
     * @return
     */
    @PutMapping("/cancel")
    @ApiOperation("取消订单")
    public Result cancel(@RequestBody OrdersCancelDTO ordersCancelDTO) {
        orderService.cancel(ordersCancelDTO);
        return Result.success();
    }
    
    /**
     * 派送订单
     * @param id
     * @return
     */
    @PutMapping("/delivery/{id}")
    @ApiOperation("派送订单")
    public Result delivery(@PathVariable long id){
        log.info("派送订单:{}",id);
        orderService.delivery(id);
        return Result.success();
    }

    /**
     * 完成订单
     * @param id
     * @return
     */
    @PutMapping("/complete/{id}")
    @ApiOperation("完成订单")
    public Result complete(@PathVariable long id){
        log.info("完成订单:{}",id);
        orderService.complete(id);
        return Result.success();
    }

}

Service层接口

/**
 * 历史订单查询 or 管理端订单搜索(已完成)
 * @param ordersPageQueryDTO
 * @return
 */
PageResult historyOrders(OrdersPageQueryDTO ordersPageQueryDTO,CallType callType);

/**
 * 订单数量统计
 * @return
 */
OrderStatisticsVO getNumByStatistics();

/**
 * 查询订单详情
 * @param orderId
 * @return
 */
OrderAndDetailVO getByOrderId(Long orderId);

/**
 * 接单
 * @param ordersConfirmDTO
 */
void confirm(OrdersConfirmDTO ordersConfirmDTO);


/**
 * 拒单
 * @param ordersRejectionDTO
 */
void rejection(OrdersRejectionDTO ordersRejectionDTO);

/**
 * 用户取消订单
 * @param id
 */
void userCancelById(Long id);

/**
 * 派送订单
 * @param id
 */
void delivery(long id);

/**
 * 完成订单
 * @param id
 */
void complete(long id);

Service层实现类

/**
 * 历史订单查询 or 管理端订单搜索(已完成)
 *
 * @param ordersPageQueryDTO
 * @return
 */
@Override
public PageResult historyOrders(OrdersPageQueryDTO ordersPageQueryDTO,CallType callType) {
    //开启分页插件
    PageHelper.startPage(ordersPageQueryDTO.getPage(), ordersPageQueryDTO.getPageSize());

    //如果是用户端就加入userid查询
    if (callType==CallType.USER){
        ordersPageQueryDTO.setUserId(BaseContext.getCurrentId());
    }

    //查询出所有订单数据
    Page<Orders> page = orderMapper.getByOrders(ordersPageQueryDTO);
    //判断是否查询到数据
    if (page == null) {
        throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
    }

    //遍历每个订单,取出其中每个明细表并封装为OrderAndDetailVO
    List<OrderAndDetailVO> orderAndDetailVOS = new ArrayList<>();
    for (Orders order : page) {
        Long id = order.getId();
        //获取订单中对应的多条明细数据
       List<OrderDetail> orderDetails = orderDetailMapper.getByOrderId(id);
       //临时创建一个orderAndDetailVO用于封装订单和明细数据
       OrderAndDetailVO orderAndDetailVO=new OrderAndDetailVO();
       BeanUtils.copyProperties(order,orderAndDetailVO);

       orderAndDetailVO.setOrderDetailList(orderDetails);
       //封装完成的orderAndDetailVO再添加到集合中
       orderAndDetailVOS.add(orderAndDetailVO);
    }
    PageResult pageResult=new PageResult();
    pageResult.setTotal(page.getTotal());
    pageResult.setRecords(orderAndDetailVOS);

    return pageResult;
}

/**
 * 订单数量统计
 * @return
 */
@Override
public OrderStatisticsVO getNumByStatistics() {
    OrderStatisticsVO orderStatisticsVO = new OrderStatisticsVO();
    orderStatisticsVO.setToBeConfirmed(orderMapper.getNumByStatistics(Orders.TO_BE_CONFIRMED));
    orderStatisticsVO.setConfirmed(orderMapper.getNumByStatistics(Orders.CONFIRMED));
    orderStatisticsVO.setDeliveryInProgress(orderMapper.getNumByStatistics(Orders.DELIVERY_IN_PROGRESS));
    return orderStatisticsVO;
}

/**
 * 查询订单详情(已完成,与用户端查询订单同一个接口)
 * @param orderId
 * @return
 */
@Override
public OrderAndDetailVO getByOrderId(Long orderId) {
    Orders order  = orderMapper.getByOrdersId(orderId);
    List<OrderDetail> list = orderDetailMapper.getByOrderId(order.getId());
    OrderAndDetailVO orderAndDetailVO = new OrderAndDetailVO();
    //将order信息存入订单及订单详情里
    BeanUtils.copyProperties(order,orderAndDetailVO);
    orderAndDetailVO.setOrderDetailList(list);
    return orderAndDetailVO;
}

/**
 * 管理端接单
 * @param ordersConfirmDTO
 */
@Override
public void confirm(OrdersConfirmDTO ordersConfirmDTO) {
    //判断订单是否支付完成
    if (isPay(ordersConfirmDTO.getId(),OrderStatusType.CONFIRMED))
        orderMapper.update(Orders.builder().id(ordersConfirmDTO.getId()).status(ordersConfirmDTO.getStatus()==null?Orders.CONFIRMED:ordersConfirmDTO.getStatus()).build());
}

/**
 * 判断是否支付
 * @param id
 * @param orderStatusType
 * @return
 */
private boolean isPay(Long id, OrderStatusType orderStatusType){
    switch (orderStatusType){
        case TO_BE_CONFIRMED://待接单
        case CONFIRMED://接单
            //判断订单是否支付完成
            Orders orders = orderMapper.getByOrdersId(id);
            if (orders.getPayStatus() != Orders.PAID){
                throw new OrderBusinessException(MessageConstant.ORDER_PAYSTATUS_ERROR);
            }
    }
    return true;
}

/**
 * 拒绝接单
 * @param ordersRejectionDTO
 */
@Override
public void rejection(OrdersRejectionDTO ordersRejectionDTO) {
//根据订单id查询到订单状态
    Orders orders = orderMapper.getByOrdersId(ordersRejectionDTO.getId());

    if (orders.getStatus()==Orders.TO_BE_CONFIRMED){

        //如果已经支付,需要先退款
        Integer payStatus = orders.getPayStatus();
        if (payStatus==1){
            //调用微信支付退款接口
            try {
                weChatPayUtil.refund(
                        orders.getNumber(), //商户订单号
                        orders.getNumber(), //商户退款单号
                        new BigDecimal(0.01),//退款金额,单位 元
                        new BigDecimal(0.01));//原订单金额
            } catch (Exception e) {
                e.printStackTrace();
                throw new OrderBusinessException(MessageConstant.ORDER_REFUND_ERROR);
            }
        }

        Orders build = Orders.builder()
                .id(ordersRejectionDTO.getId())
                .status(Orders.CANCELLED)
                .payStatus(Orders.REFUND)//支付状态修改为 退款
                .rejectionReason(ordersRejectionDTO.getRejectionReason())
                .build();
        orderMapper.update(build);
    }
}


/**
 * 取消订单(已完成,与用户端取消订单同一个接口)
 * @param ordersCancelDTO
 */
@Override
public void cancel(OrdersCancelDTO ordersCancelDTO) throws Exception {

    //根据id查询订单
    Orders orders = orderMapper.getByOrdersId(ordersCancelDTO.getId());
    //如果已经支付,需要先退款
        Integer payStatus = orders.getPayStatus();
        if (payStatus==1){
            //调用微信支付退款接口
            try {
                weChatPayUtil.refund(
                        orders.getNumber(), //商户订单号
                        orders.getNumber(), //商户退款单号
                        new BigDecimal(0.01),//退款金额,单位 元
                        new BigDecimal(0.01));//原订单金额
            } catch (Exception e) {
                e.printStackTrace();
                throw new OrderBusinessException(MessageConstant.ORDER_REFUND_ERROR);
            }
            //支付状态修改为 退款
            orders.setPayStatus(Orders.REFUND);
        }
    //修改订单状态:
    //取消时间
    orders.setCancelTime(LocalDateTime.now());
    //前端传入的取消原因
    orders.setCancelReason(ordersCancelDTO.getCancelReason());
    //修改订单状态至取消
    orders.setStatus(Orders.CANCELLED);
    //更新订单数据
    orderMapper.update(orders);
}

/**
 * 派送订单
 * @param id
 */
@Override
public void delivery(long id) {
    if(orderMapper.getorders(id).getStatus() == Orders.CONFIRMED){
        orderMapper.update(Orders.builder().status(Orders.DELIVERY_IN_PROGRESS).id(id).build());
    }else{
        throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
    }
}

/**
 * 完成订单
 * @param id
 */
@Override
public void complete(long id) {
    if(orderMapper.getorders(id).getStatus() == Orders.DELIVERY_IN_PROGRESS){
        orderMapper.update(Orders.builder().status(Orders.DELIVERY_IN_PROGRESS).id(id).build());
    }else{
        throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
    }
}

Mapper层

OrderMapper.java

/**
 * 根据条件查询一个/多个订单(已完成)
 * @param ordersPageQueryDTO
 * @return
 */
Page<Orders> getByOrders(OrdersPageQueryDTO ordersPageQueryDTO);

/**
 * 订单数量统计
 * @param status
 * @return
 */
@Select("select count(*) from orders where status =#{status}")
Integer getNumByStatistics(Integer status);

/**
 * 根据id查询一个订单数据
 */
@Select("select * from orders where id=#{id}")
Orders getByOrdersId(Long id);

/**
 * 修改订单信息(已完成)
 * @param orders
 */
void update(Orders orders);

OrderDetailMapper.java

/**
 * 根据id查询订单数据(已完成)
 * @param id
 * @return
 */
@Select("select * from order_detail where order_id=#{id}")
List<OrderDetail> getByOrderId(Long id);

OrderMapper.xml

<!--根据条件查询一个/多个订单-->
<select id="getByOrders" resultType="com.sky.entity.Orders">
    select * from orders
   <where>
      <if test="status != null">
         and status=#{status}
      </if>
      <if test="number != null">
         and number like concat('%',#{number},'%')
      </if>
      <if test="phone != null">
         and phone like concat('%',#{phone},'%')
      </if>
      <if test="beginTime != null and endTime !=null">
         and order_time between #{beginTime} and #{endTime}
      </if>
   </where>
      order by order_time desc
</select>
<!--根据条件更新订单-->
<update id="update">
	update orders
	<set>
		<if test="cancelReason != null and cancelReason!='' ">
			cancel_reason=#{cancelReason},
		</if>
		<if test="rejectionReason != null and rejectionReason!='' ">
			rejection_reason=#{rejectionReason},
		</if>
		<if test="cancelTime != null">
			cancel_time=#{cancelTime},
		</if>
		<if test="payStatus != null">
			pay_status=#{payStatus},
		</if>
		<if test="payMethod != null">
			pay_method=#{payMethod},
		</if>
		<if test="checkoutTime != null">
			checkout_time=#{checkoutTime},
		</if>
		<if test="status != null">
			status = #{status},
		</if>
		<if test="deliveryTime != null">
			delivery_time = #{deliveryTime}
		</if>
	</set>
	where id = #{id}
</update>

9.3 功能测试

前后端联调

订单搜索
请添加图片描述
请添加图片描述
请添加图片描述

各个状态的订单数量统计
请添加图片描述

查询订单详情
请添加图片描述

接单
请添加图片描述
请添加图片描述

拒单
请添加图片描述

取消订单
请添加图片描述
请添加图片描述

派送订单
请添加图片描述
请添加图片描述

完成订单
请添加图片描述
请添加图片描述

9.4 提交代码

commit—>describe—>push

9.5 优化用户下单功能,引入距离判断

优化用户下单功能,加入校验逻辑,如果用户的收货地址距离商家门店超出配送范围(配送范围为5公里内),则下单失败。

提示:

​ 1. 基于百度地图开放平台实现(https://lbsyun.baidu.com/)

​ 2. 注册账号—>创建应用获取AK(服务端应用)—>调用接口

  1. 相关接口

    https://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-geocoding

    https://lbsyun.baidu.com/index.php?title=webapi/directionlite-v1

  2. 商家门店地址可以配置在配置文件中,例如:

    sky:
      shop:
        address: 北京市海淀区上地十街10号
    

application-dev.yml

sky:
  baiduopenmap:
    ak: AewmQZZPsxQhcwGZe5mYUOwKt4iy4Yxj
    ret-coordtype: gcj02ll #gcj02ll(国测局坐标)、bd09mc(百度墨卡托坐标)
    output: json #json或xml
    geocoding-url: https://api.map.baidu.com/geocoding/v3/ #地理编码请求地址
    path-planning-url: https://api.map.baidu.com/directionlite/v1/driving #轻量级路线规划请求地址
    delivery-area: 5000 #配送范围(米)
    business-address: 重庆市沙坪坝区西永大道二期xxxxxx #商家地址

application.yml

sky:
  baiduopenmap:
    ak: ${sky.baiduopenmap.ak}
    ret-coordtype: ${sky.baiduopenmap.ret-coordtype}
    output: ${sky.baiduopenmap.output}
    geocoding-url: ${sky.baiduopenmap.geocoding-url}
    path-planning-url: ${sky.baiduopenmap.path-planning-url}
    delivery-area: ${sky.baiduopenmap.delivery-area}
    business-address: ${sky.baiduopenmap.business-address}

创建BaiduOpenMapProperties类,使用ConfigurationProperties注解注入配置文件中对应的值到数据中

package com.sky.properties;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * @Auther: Yishooo
 * @Date: 2023-5-28 - 05 - 28 - 21:56
 * @Description:
 */
@Component
@ConfigurationProperties(prefix = "sky.baiduopenmap")
@Data
public class BaiduOpenMapProperties {
    private String ak; //申请注册的key,自v2开始参数修改为“ak”
    private String retCoordtype; //返回国测局经纬度坐标或百度米制坐标
    private String output; //输出格式为json或者xml
    private String geocodingUrl; //地理编码请求地址
    private String pathPlanningUrl;//轻量级路线规划请求地址
    private Integer deliveryArea;//配送范围(米),行车路径
    private String businessAddress;//商家地址
}

创建BaiduOpenMapUtils类,完善获取坐标和判断距离两个方法(注意:百度开放地图接口调用距离地址经纬度的值为反的,传入值为【纬度,经度】)

package com.sky.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @Auther: Yishooo
 * @Date: 2023-5-28 - 05 - 28 - 22:10
 * @Description:
 */
@Data
@AllArgsConstructor
@Slf4j
public class BaiduOpenMapUtils {

    private String ak; //申请注册的key,自v2开始参数修改为“ak”
    private String retCoordtype; //返回国测局经纬度坐标或百度米制坐标
    private String output; //输出格式为json或者xml
    private String geocodingUrl; //地理编码请求地址
    private String pathPlanningUrl;//轻量级路线规划请求地址
    private Integer deliveryArea;//配送范围(米),行车路径
    private String businessAddress;//商家地址

    public boolean IsOutOfRange(String origin) {
        //载入商家坐标
        String destination = getLocation(businessAddress);
        Integer distance = null;
        Map<String,String> map = new HashMap<>();
        map.put("origin",origin);
        map.put("destination",destination);
        map.put("ak",ak);
        String body = HttpClientUtil.doGet(pathPlanningUrl,map);
        log.info("返回路径地址:{}",body);
        JSONObject jsonObject = JSON.parseObject(body);
        Map<String, Object> mapResult = new HashMap<>();
        //查询 返回状态 status 并存入集合
        getKeyMap(jsonObject, "status", mapResult);
        if (Integer.valueOf(mapResult.get("status").toString()) == 0) {
            getKeyMap(jsonObject, "distance", mapResult);
            distance = Integer.parseInt(mapResult.get("distance").toString());
            log.info("商家距离客户:{}米",distance);
        }
        if (distance <= deliveryArea){//小于默认配送返回,则返回false,标识没有超出范围
            return false;
        }
        return true;
    }

    /**
     * 获取经纬度坐标
     * @param address
     * @return  字符串:lat,lng
     * @throws Exception
     */
    public String getLocation(String address) {
        String location = null;
        //封装地址传参路径 map 集合
        Map<String,String> map = new HashMap<>();
        map.put("address",address);
        map.put("output",output);
        map.put("ak",ak);
        map.put("ret_coordtype",retCoordtype);
        //发送请求得到响应返回的json串
        String body = HttpClientUtil.doGet(geocodingUrl, map);
        //将json串转换为json对象
        JSONObject jsonObject = JSON.parseObject(body);
        //定义Map集合保存要返回查询的键值对
        Map<String, Object> mapResult = new HashMap<>();
        //查询 返回状态 status 并存入集合
        getKeyMap(jsonObject, "status", mapResult);
        //如果状态返回为 0(成功) 继续执行后续取值操作
        if (Integer.parseInt(mapResult.get("status").toString()) == 0) {
            getKeyMap(jsonObject, "lng", mapResult);
            getKeyMap(jsonObject, "lat", mapResult);
            //经度
            double lng = ((BigDecimal) mapResult.get("lng")).setScale(6, RoundingMode.HALF_UP).doubleValue();
            //纬度
            double lat = ((BigDecimal) mapResult.get("lat")).setScale(6, RoundingMode.HALF_UP).doubleValue();
            location = lat + "," + lng;
        }
        return location;
    }

    /**
     * 查询json对象类中指定key的值存入传入的map集合,只适用于查询第一次键值,包含多层key相同的只取第一次查到的值
     * @param object json对象
     * @param keyword 要查询关键字
     * @param jsonMap 保存查询的数据
     */
    public void getKeyMap(Object object, String keyword, Map<String, Object> jsonMap){
        //判断传入对象是否属于JSONObject对象
        if (object instanceof JSONObject){
            JSONObject jsonObject = (JSONObject) object;
            //将对象进行遍历迭代,先迭代第一层键值对,符合则存入跳出循环,否则递归遍历直到结束
            Iterator<Map.Entry<String, Object>> iterator = jsonObject.entrySet().iterator();
            while (iterator.hasNext()){
                Map.Entry<String, Object> entry = iterator.next();
                String key = entry.getKey();
                Object value = entry.getValue();
                if (keyword.equals(key)){
                    //存在key为指定key的,判断值为json数组,只取第一个值
                    if (value instanceof JSONArray){
                        JSONArray valueArr = (JSONArray) value;
                        value = valueArr.get(0);
                    }
                    //将查找到的值存入指定map中
                    jsonMap.put(key, value);
                    break;
                }else {
                    //没有采用递归进行第二次键值对查找
                    getKeyMap(value, keyword, jsonMap);
                }
            }
            //是否属于JSONArray对象
        } else if (object instanceof JSONArray){
            JSONArray jsonArray = (JSONArray) object;
            Iterator<Object> iterator = jsonArray.iterator();
            while (iterator.hasNext()){
                Object value = iterator.next();
                getKeyMap(value, keyword, jsonMap);
            }
        }
    }

}

HTTPClientUtil工具类

package com.sky.utils;

import com.alibaba.fastjson.JSONObject;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Http工具类
 */
public class HttpClientUtil {

    static final  int TIMEOUT_MSEC = 5 * 1000;

    /**
     * 发送GET方式请求
     * @param url
     * @param paramMap
     * @return
     */
    public static String doGet(String url,Map<String,String> paramMap){
        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();

        String result = "";
        CloseableHttpResponse response = null;

        try{
            URIBuilder builder = new URIBuilder(url);
            if(paramMap != null){
                for (String key : paramMap.keySet()) {
                    builder.addParameter(key,paramMap.get(key));
                }
            }
            URI uri = builder.build();

            //创建GET请求
            HttpGet httpGet = new HttpGet(uri);

            //发送请求
            response = httpClient.execute(httpGet);

            //判断响应状态
            if(response.getStatusLine().getStatusCode() == 200){
                result = EntityUtils.toString(response.getEntity(),"UTF-8");
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                response.close();
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return result;
    }

    /**
     * 发送POST方式请求
     * @param url
     * @param paramMap
     * @return
     * @throws IOException
     */
    public static String doPost(String url, Map<String, String> paramMap) throws IOException {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";

        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);

            // 创建参数列表
            if (paramMap != null) {
                List<NameValuePair> paramList = new ArrayList();
                for (Map.Entry<String, String> param : paramMap.entrySet()) {
                    paramList.add(new BasicNameValuePair(param.getKey(), param.getValue()));
                }
                // 模拟表单
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
                httpPost.setEntity(entity);
            }

            httpPost.setConfig(builderRequestConfig());

            // 执行http请求
            response = httpClient.execute(httpPost);

            resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
        } catch (Exception e) {
            throw e;
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return resultString;
    }

    /**
     * 发送POST方式请求
     * @param url
     * @param paramMap
     * @return
     * @throws IOException
     */
    public static String doPost4Json(String url, Map<String, String> paramMap) throws IOException {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";

        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);

            if (paramMap != null) {
                //构造json格式数据
                JSONObject jsonObject = new JSONObject();
                for (Map.Entry<String, String> param : paramMap.entrySet()) {
                    jsonObject.put(param.getKey(),param.getValue());
                }
                StringEntity entity = new StringEntity(jsonObject.toString(),"utf-8");
                //设置请求编码
                entity.setContentEncoding("utf-8");
                //设置数据类型
                entity.setContentType("application/json");
                httpPost.setEntity(entity);
            }

            httpPost.setConfig(builderRequestConfig());

            // 执行http请求
            response = httpClient.execute(httpPost);

            resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
        } catch (Exception e) {
            throw e;
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return resultString;
    }
    private static RequestConfig builderRequestConfig() {
        return RequestConfig.custom()
                .setConnectTimeout(TIMEOUT_MSEC)
                .setConnectionRequestTimeout(TIMEOUT_MSEC)
                .setSocketTimeout(TIMEOUT_MSEC).build();
    }

}

创建OpenMapConfiguration配置类,初始化百度开放地图工具类。

package com.sky.config;

import com.sky.properties.BaiduOpenMapProperties;
import com.sky.utils.BaiduOpenMapUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Auther: Yishooo
 * @Date: 2023-5-28 - 05 - 28 - 23:49
 * @Description:
 */
@Slf4j
@Configuration
public class OpenMapConfiguration {

    /**
     * 通过spring管理对象
     * @param baiduOpenMapProperties
     * @return
     */
    @Bean
    @ConditionalOnMissingBean//没有才创建,保证工具类唯一
    public BaiduOpenMapUtils baiduOpenMapUtils(BaiduOpenMapProperties baiduOpenMapProperties){
        log.info("开始创建百度开放地图工具类……");
        return new BaiduOpenMapUtils(baiduOpenMapProperties.getAk()
                ,baiduOpenMapProperties.getRetCoordtype()
                ,baiduOpenMapProperties.getOutput()
                ,baiduOpenMapProperties.getGeocodingUrl()
                ,baiduOpenMapProperties.getPathPlanningUrl()
                ,baiduOpenMapProperties.getDeliveryArea()
                ,baiduOpenMapProperties.getBusinessAddress());
    }
}

优化OrderServiceImpl类中的提交订单部分

/**
 * 用户下单
 * @param ordersSubmitDTO
 * @return
 */
@Override
@Transactional
public OrderSubmitVO submitOrder(OrdersSubmitDTO ordersSubmitDTO) {
    //1.检验提交数据是否异常,增强程序的健壮性
    //1.1 用户地址簿是否为空
    //...代码省略....
    //1.2 用户购物车数据是否为空
    //...代码省略....
    //1.3 校验地址是否超出配送范围
    String userAddress =
            currentAddress.getProvinceName()+currentAddress.getCityName()+currentAddress.getDistrictName()+currentAddress.getDetail();
    String userLocation = null;
    //获取用户地址的经纬度
    userLocation = baiduOpenMapUtils.getLocation(userAddress);
    if (baiduOpenMapUtils.IsOutOfRange(userLocation)){
        throw new OrderBusinessException(MessageConstant.ORDER_OUTOFRANGE_ERROR);
    }

    //...代码省略....
}

前后端联调
请添加图片描述
后台日志如下所示:
请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/590632.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

古诗生成-pytorch

本文为RNN做古诗生成的一个小demo&#xff0c;只要是为了完成课上的作业&#xff08;由于训练比较慢&#xff0c;所以周期仅设置为3&#xff0c;大一点性能可能会更好&#xff09;&#xff0c;如有需要可以在这基础之上进行加工&#xff0c;数据集没办法上传&#xff0c;如有需…

FreeRTOS_从底层学习实时操作系统

目录 1. 裸机系统和多任务系统 2. 任务的定任务切换的实现 2.1 什么是任务&#xff1f; 2.2 调度器 2.3 临界段 3. 空闲任务和阻塞延迟 4. 时间片 1. 裸机系统和多任务系统 裸机系统&#xff1a; 裸机系统分为轮询系统和前后台系统&#xff1b;&#xff08;51单片机就属…

八大排序:直接插入排序、希尔排序、选择排序、堆排序、冒泡排序、快速排序、归并排序、计数排序

文章目录 排序概念常见的排序算法常见排序算法的实现直接插入排序希尔排序选择排序堆排序冒泡排序快速排序递归实现Hoare版本挖坑法前后指针法 非递归实现Hoare版本挖坑法前后指针法 快速排序俩个优化 归并排序递归实现非递归实现外排序 计数排序 常见排序算法的性能分析 排序概…

【已完美解决】scons问题求助:如何设置编译输出目录搞清楚后,有些编译输出的obj文件却在源码目录,而不是设置的输出目录。

【已完美解决】scons问题求助&#xff1a;如何设置编译输出目录搞清楚后&#xff0c;有些编译输出的obj文件却在源码目录&#xff0c;而不是设置的输出目录。 文章目录 1 前置背景2 我的疑问3 一手点拨4 问题解决 1 前置背景 最近在基于目前已有的rt-thread构建框架&#xff0…

【Spring源码解读一】IoC容器之AnnotationConfigApplicationContext

根据AnnotationConfigApplicationContext类去阅读其将Bean对象交给IoC容器管理的过程。以下这三个代码块是将配置类注册进IoC容器的例子。下面是关于这个类的继承与实现的类图关系树。 public class Test {public static void main(String[] args) {// 配置类注册进IoC容器App…

解决Ubuntu16中安装opencv后找不到vtk库的问题

最近一个项目中要用到OpenCV的VTK库&#xff0c;但引入头文件#include <opencv2/viz.hpp>时却说找不到这个库&#xff0c;网上搜了下说在编译opencv源码的时候&#xff0c;需要加上编译VTK库的选项&#xff0c;于是重新下载、编译、安装了源码&#xff0c;在cmake时加上了…

最流行的AI绘图工具Midjourney,你不得不知道的使用技巧

​关注文章下方公众号&#xff0c;可免费获取AIGC最新学习资料 本文字数&#xff1a;1500&#xff0c;阅读时长大约&#xff1a;10分钟 Midjourney成为了最受欢迎的生成式AI工具之一。它的使用很简单。输入一些文本&#xff0c;Midjourney背后的大脑&#xff08;或计算机&#…

Linux 权限

目录 一、 从问题开始 问题一: 什么叫shell? 问题二: 为什么不能直接使用kernel呢? 问题三: shell 与bash 有什么不同吗? 二、 Linux权限 0x01 Linux用户 0x02 切换用户命令 0x03 sudo命令 0x04 权限的相关概念 0x05 chmod 0x06 chown 0x07 chgrp 0x08 文件权…

重磅!软著申请不需要邮寄纸质材料啦,附软著申请流程。

重磅&#xff01;软著申请不需要邮寄纸质材料啦&#xff0c;附软著申请流程。 最新消息申请流程一&#xff0c;准备申请材料二&#xff0c;申请人填写申请表三&#xff0c;提交申请材料四&#xff0c;补正五&#xff0c;审查六&#xff0c;发布公告七&#xff0c;接受异议八&am…

力扣---二叉树OJ题(多种题型二叉树)

文章目录 前言&#x1f31f;一、剑指 Offer 55 - I. 二叉树的深度&#x1f30f;1.1 链接&#xff1a;&#x1f30f;1.2 代码一&#xff1a;&#x1f30f;1.3 代码二&#xff1a;&#x1f30f;1.4 流程图&#xff1a; &#x1f31f;二、100. 相同的树&#x1f30f;2.1 链接&…

超强实用!利用xfsdump和xfsrestore打造无懈可击的数据备份与恢复策略

前言 上次我们分析了EXT文件系统的恢复方式&#xff0c;借助于extundelete工具仅可以恢复EXT类型的文件&#xff0c;但无法恢复CentOS 7系统&#xff0c;因为centos7默认采用xfs类型的文件。 xfs文件系统恢复工具有以下几种&#xff1a; xfsprogs&#xff1a;xfs文件系统扩展…

HTB MonitorsTwo

MonitorsTwo HTB MonitorsTwo 老规矩信息收集了&#xff1a; NMAP信息收集 ┌──(kali㉿kali)-[~/桌面] └─$ sudo nmap --min-rate 1000 10.10.11.211 Starting Nmap 7.93 ( https://nmap.org ) at 2023-05-19 09:18 CST Nmap scan report for 10.10.11.211 Host is up…

Python入门(十六)函数(四)

函数&#xff08;四&#xff09; 1.传递列表1.1 在函数中修改列表 2.传递任意数量的实参2.1 结合使用位置实参和任意数量实参2.2 使用任意数量的关键字实参 作者&#xff1a;Xiou 1.传递列表 我们经常会发现&#xff0c;向函数传递列表很有用&#xff0c;其中包含的可能是名字…

设计模式-模板方法模式

模板方法模式 问题背景解决方案&#xff1a;模板方法模式基本介绍解决问题代码示例运行结果 钩子方法注意事项和细节 问题背景 豆浆的制作&#xff1a; 1&#xff09;制作豆浆的流程&#xff1a;选材—>添加配料—>浸泡—>放到豆浆机打碎 2&#xff09;通过添加不同…

高可用性和双机热备浅析

在用户眼里&#xff0c;业务需要永远正常对外提供服务&#xff0c;这就要求应用系统的高可用&#xff08;High availability&#xff0c;即 HA&#xff09;。高可用主要是针对架构而言&#xff0c;第一步一般会采用分层的思想将一个庞大的应用系统拆分成应用层、中间件、数据存…

SpringBoot+MyBatis-plus实现CRUD (踩坑总结!!!)

一、创建项目&#xff0c;引入相应的依赖 (项目源码在文末) &#xff08;不要选Module !!!!&#xff09; <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.2</version&g…

linux常见的二十多个指令

目录 一、指令的概念 二、28个常见的指令 ⭐2.1 ls指令 ⭐2.2 pwd指令 ⭐2.3 cd指令 ⭐2.4tree指令 ⭐2.5 mkdir指令 ⭐2.6 touch指令 ⭐2.7 rmdir指令 ⭐2.8 rm指令 ⭐2.9 clear指令 ⭐2.10 man指令 ⭐2.11 cp指令 ⭐2.12 mv指令 ⭐2.13 cat指令&#xff08;适…

正规文法、正规表达式、有限自动机及其之间的转换(笔记)

The Equivalent Transforming among RG, RE and FA 正规文法 A Grammar G is a quadruple (四元组):G (VN, VT, S, P ) Where, VN is a finite set of nonterminals.VT is a finite set of terminals.S is the start symbol, S ∈ \in ∈ VN.P is a finite set of product…

.Net 使用OpenAI开源语音识别模型Whisper

.Net 使用OpenAI开源语音识别模型 Whisper 前言 Open AI在2022年9月21日开源了号称其英文语音辨识能力已达到人类水准的 Whisper 神经网络&#xff0c;且它亦支持其它98种语言的自动语音辨识。 Whisper系统所提供的自动语音辨识&#xff08;Automatic Speech Recognition&…

python基础知识(四):input语句、if语句和pass语句

目录 1. input语句2. 强制转换3. if语句4. pass语句 1. input语句 input语句是程序获取从键盘输入的内容&#xff0c;会把输入的内容自动转换成字符串。 使用方法: 变量名 input(“提示语”) 例如 language input("你最爱什么语言?") print(language)这两行代码…