曾富康
2026-06-17 916d0f9012590ff4b4eb7ce838f5d69d305fe539
显示乘客地址定位信息
2个文件已添加
5个文件已修改
394 ■■■■■ 已修改文件
ManagementYKDTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/controller/DistanceDisplayController.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MessagePushTravel/src/main/java/com/sinata/push/util/applets/NettyWebSocketController.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MessagePushTravel/src/main/java/com/sinata/push/util/echo/Method.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
MessagePushTravel/src/main/java/com/sinata/push/util/echo/NettyServerController.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
UserYKDTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/api/PassengerLocationController.java 221 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
UserYKDTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/PushUtil.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
UserYKDTravel/guns-admin/src/main/resources/application-dev.yml 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ManagementYKDTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/controller/DistanceDisplayController.java
New file
@@ -0,0 +1,39 @@
package com.stylefeng.guns.modular.system.controller;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.stylefeng.guns.modular.system.model.TSysDistanceDisplay;
import com.stylefeng.guns.modular.system.service.ITSysDistanceDisplayService;
import com.stylefeng.guns.modular.system.util.ResultUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**
 * 距离展示配置内部接口
 */
@RestController
@RequestMapping("/base/distanceDisplay")
public class DistanceDisplayController {
    @Autowired
    private ITSysDistanceDisplayService tSysDistanceDisplayService;
    /**
     * 查询企业乘客定位推送距离阈值,供用户端实时定位过滤使用
     */
    @ResponseBody
    @RequestMapping(value = "/passengerLocationDistance", method = RequestMethod.POST)
    public ResultUtil passengerLocationDistance(Integer companyId) {
        if (companyId == null || companyId == 0) {
            return ResultUtil.paranErr();
        }
        TSysDistanceDisplay distanceDisplay = tSysDistanceDisplayService.selectOne(
                new EntityWrapper<TSysDistanceDisplay>().eq("companyId", companyId));
        if (distanceDisplay == null || distanceDisplay.getPassengerLocationDistance() == null) {
            return ResultUtil.success();
        }
        return ResultUtil.success(distanceDisplay.getPassengerLocationDistance());
    }
}
MessagePushTravel/src/main/java/com/sinata/push/util/applets/NettyWebSocketController.java
@@ -2,6 +2,11 @@
import com.alibaba.fastjson.JSONObject;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.sinata.push.config.QYTConfig;
import com.sinata.push.util.RedisUtil;
import com.sinata.push.util.SinataUtil;
import com.sinata.push.util.SpringUtil;
@@ -13,8 +18,11 @@
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import org.springframework.http.MediaType;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
@@ -23,6 +31,8 @@
    public static Hashtable<String, Hashtable<ChannelHandlerContext, String>> map = new Hashtable<String, Hashtable<ChannelHandlerContext, String>>();
    private RedisUtil redisUtil = SpringUtil.getObject(RedisUtil.class);
    private QYTConfig qytConfig = SpringUtil.getObject(QYTConfig.class);
    public static Hashtable<String, String> table;
@@ -112,6 +122,10 @@
            }
            // 乘客上传位置,转发到用户端服务做订单校验和司机推送
            if (method.equals(Method.passengerLocation)) {
                forwardPassengerLocation(ctx, jsonCon);
            }
        } catch (Exception e) {
            if (isdebug) {
                NettyWebSocketController.sendMsgToClient(ctx, "__error__" + msg.toString());
@@ -121,6 +135,42 @@
    }
    /**
     * 转发乘客实时定位到用户服务,由用户服务校验订单后推送给司机端
     */
    private void forwardPassengerLocation(ChannelHandlerContext ctx, JSONObject jsonCon) {
        Integer userId = jsonCon.getInteger("userId");
        Integer orderId = jsonCon.getInteger("orderId");
        Integer orderType = jsonCon.getInteger("orderType");
        Double lon = jsonCon.getDouble("lon");
        Double lat = jsonCon.getDouble("lat");
        String timestamp = jsonCon.getString("timestamp");
        // 基础参数不合法时直接返回错误,不再调用后端业务接口
        if (userId == null || orderId == null || orderType == null || lon == null || lat == null || lon == 0 || lat == 0) {
            sendMsgToClient(ctx, "__error__" + jsonCon.toJSONString());
            return;
        }
        Map<String, Object> params = new HashMap<>();
        params.put("userId", String.valueOf(userId));
        params.put("orderId", String.valueOf(orderId));
        params.put("orderType", String.valueOf(orderType));
        params.put("lon", String.valueOf(lon));
        params.put("lat", String.valueOf(lat));
        params.put("timestamp", timestamp);
        HttpRequest post = HttpUtil.createPost(qytConfig.getChuxingUrl() + "/user-server/base/passenger/location/push");
        post.contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE);
        post.form(params);
        HttpResponse execute = post.execute();
        if (200 != execute.getStatus()) {
            System.err.println("调用user-server推送乘客定位出错");
            return;
        }
        JSONObject jsonObject = JSON.parseObject(execute.body(), JSONObject.class);
        if (jsonObject.getIntValue("code") != 200) {
            System.err.println("调用user-server推送乘客定位出错:" + jsonObject.getString("msg"));
        }
    }
    /**
     * 向客户端发送消息
     *
     * @param ctx
MessagePushTravel/src/main/java/com/sinata/push/util/echo/Method.java
@@ -21,6 +21,9 @@
    /** 司机上传位置 */
    public static final String location = "LOCATION";
    /** 乘客上传位置 */
    public static final String passengerLocation = "PASSENGER_LOCATION";
    
}
MessagePushTravel/src/main/java/com/sinata/push/util/echo/NettyServerController.java
@@ -171,6 +171,10 @@
                    sendMsgToClient(ctx, jsonMsg.toJSONString());
                }
            }
            //乘客上传位置,转发到用户端服务做订单校验和司机推送
            if(method.equals(Method.passengerLocation)){
                forwardPassengerLocation(ctx, jsonCon);
            }
            //司机上传位置
            if(method.equals(Method.location)){
                Integer driverId = jsonCon.getInteger("driverId");
@@ -265,6 +269,42 @@
    }
    /**
     * 转发乘客实时定位到用户服务,由用户服务校验订单后推送给司机端
     */
    private void forwardPassengerLocation(ChannelHandlerContext ctx, JSONObject jsonCon) {
        Integer userId = jsonCon.getInteger("userId");
        Integer orderId = jsonCon.getInteger("orderId");
        Integer orderType = jsonCon.getInteger("orderType");
        Double lon = jsonCon.getDouble("lon");
        Double lat = jsonCon.getDouble("lat");
        String timestamp = jsonCon.getString("timestamp");
        // 基础参数不合法时直接返回错误,不再调用后端业务接口
        if (userId == null || orderId == null || orderType == null || lon == null || lat == null || lon == 0 || lat == 0) {
            this.sendMsgToClient(ctx, "__error__" + jsonCon.toJSONString());
            return;
        }
        Map<String, Object> params = new HashMap<>();
        params.put("userId", String.valueOf(userId));
        params.put("orderId", String.valueOf(orderId));
        params.put("orderType", String.valueOf(orderType));
        params.put("lon", String.valueOf(lon));
        params.put("lat", String.valueOf(lat));
        params.put("timestamp", timestamp);
        HttpRequest post = HttpUtil.createPost(qytConfig.getChuxingUrl() + "/user-server/base/passenger/location/push");
        post.contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE);
        post.form(params);
        HttpResponse execute = post.execute();
        if (200 != execute.getStatus()) {
            System.err.println("调用user-server推送乘客定位出错");
            return;
        }
        JSONObject jsonObject = JSON.parseObject(execute.body(), JSONObject.class);
        if (jsonObject.getIntValue("code") != 200) {
            System.err.println("调用user-server推送乘客定位出错:" + jsonObject.getString("msg"));
        }
    }
    /**
     * 向客户端发送消息
     * 
     * @param ctx
UserYKDTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/api/PassengerLocationController.java
New file
@@ -0,0 +1,221 @@
package com.stylefeng.guns.modular.api;
import com.alibaba.fastjson.JSONObject;
import com.stylefeng.guns.core.util.ToolUtil;
import com.stylefeng.guns.modular.crossCity.model.OrderCrossCity;
import com.stylefeng.guns.modular.crossCity.server.IOrderCrossCityService;
import com.stylefeng.guns.modular.smallLogistics.model.OrderLogistics;
import com.stylefeng.guns.modular.smallLogistics.server.IOrderLogisticsService;
import com.stylefeng.guns.modular.specialTrain.model.OrderPrivateCar;
import com.stylefeng.guns.modular.specialTrain.server.IOrderPrivateCarService;
import com.stylefeng.guns.modular.system.util.GeodesyUtil;
import com.stylefeng.guns.modular.system.util.PushUtil;
import com.stylefeng.guns.modular.system.util.ResultUtil;
import com.stylefeng.guns.modular.taxi.model.OrderTaxi;
import com.stylefeng.guns.modular.taxi.service.IOrderTaxiService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@RestController
@RequestMapping("/base/passenger/location")
public class PassengerLocationController {
    @Autowired
    private IOrderPrivateCarService orderPrivateCarService;
    @Autowired
    private IOrderTaxiService orderTaxiService;
    @Autowired
    private IOrderCrossCityService orderCrossCityService;
    @Autowired
    private IOrderLogisticsService orderLogisticsService;
    @Autowired
    private PushUtil pushUtil;
    @Autowired
    private GeodesyUtil geodesyUtil;
    @Autowired
    private RestTemplate restTemplate;
    @Value("${qyt.management_uri:http://127.0.0.1:8010}")
    private String managementUri;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @ResponseBody
    @PostMapping("/push")
    public ResultUtil push(Integer userId, Integer orderId, Integer orderType, String lon, String lat, String timestamp) {
        try {
            // 校验乘客定位上报的必填参数
            if (ToolUtil.isEmpty(userId) || ToolUtil.isEmpty(orderId) || ToolUtil.isEmpty(orderType)
                    || ToolUtil.isEmpty(lon) || ToolUtil.isEmpty(lat)) {
                return ResultUtil.paranErr();
            }
            Double lonValue;
            Double latValue;
            try {
                lonValue = Double.valueOf(lon);
                latValue = Double.valueOf(lat);
            } catch (NumberFormatException e) {
                return ResultUtil.paranErr();
            }
            if (lonValue == 0 || latValue == 0) {
                return ResultUtil.paranErr();
            }
            if (ToolUtil.isEmpty(timestamp)) {
                timestamp = String.valueOf(System.currentTimeMillis());
            }
            if (!isSupportedOrderType(orderType)) {
                return ResultUtil.error("订单类型暂不支持");
            }
            // 根据订单类型查询对应订单,并校验乘客、司机和订单状态
            OrderData orderData = queryOrder(orderId, orderType);
            if (orderData == null) {
                return ResultUtil.error("订单不存在");
            }
            if (!userId.equals(orderData.userId)) {
                return ResultUtil.error("用户与订单不匹配");
            }
            if (ToolUtil.isEmpty(orderData.driverId) || orderData.driverId == 0) {
                return ResultUtil.error("订单暂无司机");
            }
            if (!Integer.valueOf(3).equals(orderData.state)) {
                return ResultUtil.error("订单状态不是待到达预约地点");
            }
            if (!validLonLat(orderData.startLon, orderData.startLat)) {
                return ResultUtil.error("订单上车点经纬度异常");
            }
            if (exceedPassengerLocationDistance(orderData, lonValue, latValue)) {
                return ResultUtil.success("乘客距离上车点超过配置范围,未推送司机", new JSONObject());
            }
            // 只缓存乘客最新位置,不记录历史轨迹
            JSONObject location = new JSONObject();
            location.put("orderId", orderId);
            location.put("orderType", orderType);
            location.put("userId", userId);
            location.put("driverId", orderData.driverId);
            location.put("lon", lon);
            location.put("lat", lat);
            location.put("timestamp", timestamp);
            redisTemplate.opsForValue().set("dache:PASSENGER_LOCATION:" + orderType + ":" + orderId,
                    location.toJSONString(), 30, TimeUnit.SECONDS);
            // 缓存成功后实时推送给订单司机
            return pushUtil.pushPassengerLocationToDriver(orderData.driverId, userId, orderId, orderType, lon, lat, timestamp);
        } catch (Exception e) {
            e.printStackTrace();
            return ResultUtil.runErr();
        }
    }
    private boolean isSupportedOrderType(Integer orderType) {
        return orderType == 1 || orderType == 2 || orderType == 3 || orderType == 4 || orderType == 5;
    }
    /**
     * 判断乘客当前位置是否超过企业配置的上车点距离阈值
     */
    private boolean exceedPassengerLocationDistance(OrderData orderData, Double lon, Double lat) {
        BigDecimal passengerLocationDistance = queryPassengerLocationDistance(orderData.companyId);
        if (passengerLocationDistance == null) {
            return false;
        }
        Map<String, Double> distance = geodesyUtil.getDistance(lon + "," + lat, orderData.startLon + "," + orderData.startLat);
        Double distanceMeter = distance == null ? null : distance.get("WGS84");
        if (distanceMeter == null) {
            return false;
        }
        BigDecimal distanceKm = BigDecimal.valueOf(distanceMeter).divide(BigDecimal.valueOf(1000));
        return distanceKm.compareTo(passengerLocationDistance) > 0;
    }
    /**
     * 远程查询企业乘客定位推送距离阈值,查询失败时不影响主流程
     */
    private BigDecimal queryPassengerLocationDistance(Integer companyId) {
        if (ToolUtil.isEmpty(companyId) || companyId == 0) {
            return null;
        }
        try {
            String result = restTemplate.postForObject(managementUri + "/base/distanceDisplay/passengerLocationDistance?companyId=" + companyId,
                    null, String.class);
            JSONObject jsonObject = JSONObject.parseObject(result);
            if (jsonObject == null || jsonObject.getIntValue("code") != 200 || jsonObject.get("data") == null) {
                return null;
            }
            return jsonObject.getBigDecimal("data");
        } catch (Exception e) {
            System.err.println("查询乘客定位推送距离阈值失败:" + e.getMessage());
            return null;
        }
    }
    /**
     * 校验经纬度是否有效
     */
    private boolean validLonLat(Double lon, Double lat) {
        return lon != null && lat != null && lon != 0 && lat != 0;
    }
    /**
     * 根据订单类型查询对应订单的乘客、司机和状态
     */
    private OrderData queryOrder(Integer orderId, Integer orderType) {
        switch (orderType) {
            case 1:
                OrderPrivateCar orderPrivateCar = orderPrivateCarService.selectById(orderId);
                return orderPrivateCar == null ? null : new OrderData(orderPrivateCar.getUserId(), orderPrivateCar.getDriverId(),
                        orderPrivateCar.getState(), orderPrivateCar.getCompanyId(), orderPrivateCar.getStartLon(), orderPrivateCar.getStartLat());
            case 2:
                OrderTaxi orderTaxi = orderTaxiService.selectById(orderId);
                return orderTaxi == null ? null : new OrderData(orderTaxi.getUserId(), orderTaxi.getDriverId(),
                        orderTaxi.getState(), orderTaxi.getCompanyId(), orderTaxi.getStartLon(), orderTaxi.getStartLat());
            case 3:
                OrderCrossCity orderCrossCity = orderCrossCityService.selectById(orderId);
                return orderCrossCity == null ? null : new OrderData(orderCrossCity.getUserId(), orderCrossCity.getDriverId(),
                        orderCrossCity.getState(), orderCrossCity.getCompanyId(), orderCrossCity.getStartLon(), orderCrossCity.getStartLat());
            case 4:
            case 5:
                OrderLogistics orderLogistics = orderLogisticsService.selectById(orderId);
                return orderLogistics == null ? null : new OrderData(orderLogistics.getUserId(), orderLogistics.getDriverId(),
                        orderLogistics.getState(), orderLogistics.getCompanyId(), orderLogistics.getStartLon(), orderLogistics.getStartLat());
            default:
                return null;
        }
    }
    private static class OrderData {
        private final Integer userId;
        private final Integer driverId;
        private final Integer state;
        private final Integer companyId;
        private final Double startLon;
        private final Double startLat;
        private OrderData(Integer userId, Integer driverId, Integer state, Integer companyId, Double startLon, Double startLat) {
            this.userId = userId;
            this.driverId = driverId;
            this.state = state;
            this.companyId = companyId;
            this.startLon = startLon;
            this.startLat = startLat;
        }
    }
}
UserYKDTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/PushUtil.java
@@ -138,6 +138,43 @@
    }
    
    /**
     * 推送乘客位置给司机端
     */
    public ResultUtil pushPassengerLocationToDriver(Integer driverId, Integer userId, Integer orderId, Integer orderType,
                                                    String lon, String lat, String timestamp) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", 200);
        jsonObject.put("msg", "SUCCESS");
        jsonObject.put("method", "PASSENGER_LOCATION");
        Map<String, Object> map = new HashMap<>();
        map.put("orderId", orderId);
        map.put("orderType", orderType);
        map.put("userId", userId);
        map.put("lon", lon);
        map.put("lat", lat);
        map.put("timestamp", timestamp);
        jsonObject.put("data", map);
        HttpRequest post = HttpUtil.createPost(socket_uri + "/netty/sendMsgToClient");
        post.header("Content-Type", MediaType.APPLICATION_FORM_URLENCODED_VALUE);
        Map<String, Object> params = new HashMap<>();
        params.put("msg", jsonObject.toJSONString());
        params.put("id", driverId);
        params.put("type", 2);
        params.put("bussinessType", "dache");
        post.form(params);
        HttpResponse execute = post.execute();
        if (200 != execute.getStatus()) {
            return ResultUtil.error("司机端定位推送失败");
        }
        JSONObject jsonObject1 = JSON.parseObject(execute.body(), JSONObject.class);
        if (jsonObject1.getIntValue("code") != 200) {
            return ResultUtil.error(jsonObject1.getString("msg"));
        }
        return ResultUtil.success();
    }
    /**
     * 推送司机位置给乘客端
     */
    public void pushDriverPosition(Integer orderId, Integer orderType) {
UserYKDTravel/guns-admin/src/main/resources/application-dev.yml
@@ -99,6 +99,8 @@
qyt:
  socket_uri: http://127.0.0.1:6000
  # 管理端地址,用于远程查询乘客定位推送距离阈值
  management_uri: http://127.0.0.1:8010
---
@@ -129,4 +131,4 @@
# pdf生成位置
trip:
  sheet:
    filePath: E:\etraffic\server\qytPdf\
    filePath: E:\etraffic\server\qytPdf\