package com.ruoyi.web.controller.system; import java.util.*; import java.text.SimpleDateFormat; import java.text.ParseException; import java.io.IOException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import com.ruoyi.system.domain.*; import com.ruoyi.system.service.*; import com.ruoyi.common.config.TencentMapConfig; import com.ruoyi.common.config.BaiduMapConfig; import com.ruoyi.common.config.TiandituMapConfig; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.ruoyi.common.annotation.Anonymous; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.utils.http.HttpUtils; /** * 车辆GPS坐标Controller */ @RestController @RequestMapping("/system/gps") public class VehicleGpsController extends BaseController { @Autowired private IVehicleGpsService vehicleGpsService; @Autowired private ITbVehicleOrderService tbVehicleOrderService; @Autowired private IDispatchOrdService dispatchOrdService; @Autowired private ITbOrdersService tbOrdersService; @Autowired private IGpsCollectService gpsCollectService; @Autowired private IVehicleInfoService vehicleInfoService; @Autowired private ICmsGpsCollectService cmsGpsCollectService; @Autowired private TencentMapConfig tencentMapConfig; @Autowired private BaiduMapConfig baiduMapConfig; @Autowired private TiandituMapConfig tiandituMapConfig; /** * 查询车辆GPS坐标列表 */ @PreAuthorize("@ss.hasPermi('system:gps:list')") @GetMapping("/list") public TableDataInfo list(VehicleGps vehicleGps) { startPage(); // String vehicleNo=vehicleGps.getVehicleNo(); // String beginTime=vehicleGps.getBeginTime(); // String endTime=vehicleGps.getEndTime(); // return this.getAnonymousTracks(vehicleNo,beginTime,endTime); // // // 设置按时间倒序排序 vehicleGps.setOrderByColumn("collect_time"); vehicleGps.setIsAsc("desc"); List list = vehicleGpsService.selectVehicleGpsList(vehicleGps); return getDataTable(list); } @Anonymous(needSign=true) @GetMapping("/anonymousList") public TableDataInfo anonymousList(VehicleGps vehicleGps) { if(vehicleGps.getOrderId()==null) { return getDataTable(new ArrayList<>()); } //查询订单 TbVehicleOrder tbVehicleOrder = tbVehicleOrderService.selectTbVehicleOrderById(vehicleGps.getOrderId()); if(tbVehicleOrder==null) { return getDataTable(new ArrayList<>()); } if(!Objects.equals(tbVehicleOrder.getStatus(), "0")) { //非0表示订单完成了。 try { TbOrders tbOrders = tbOrdersService.selectTbOrdersByOrderID(vehicleGps.getOrderId()); if (tbOrders == null) { return getDataTable(new ArrayList<>()); } DispatchOrd dispatchOrd = dispatchOrdService.selectDispatchOrdByServiceOrdIDDt(tbOrders.getServiceOrdID()); if (dispatchOrd == null) { return getDataTable(new ArrayList<>()); } String vehicleNo = tbVehicleOrder.getVehicle(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String beginTime= sdf.format(dispatchOrd.getDispatchOrdStartDate()); String endTime= sdf.format(dispatchOrd.getDispatchOrdUpdateTime()); //如果订单没完成, endTime为当前时间;如何订单已经完成了,用订单的结束时间。 return this.getAnonymousTracks(vehicleNo,beginTime,endTime); // Map params = new HashMap<>(); // params.put("beginTime", dispatchOrd.getDispatchOrdStartDate()); // params.put("endTime", dispatchOrd.getDispatchOrdUpdateTime()); // // vehicleGps.setVehicleNo(tbVehicleOrder.getVehicle()); // startPage(); // // 设置按时间倒序排序 // vehicleGps.setOrderByColumn("collect_time"); // vehicleGps.setIsAsc("desc"); // List list = vehicleGpsService.selectVehicleGpsList(vehicleGps); // return getDataTable(list); } catch (Exception ex) { logger.error("已完成的订单查询地图异常:{}",ex.getMessage()); return getDataTable(new ArrayList<>()); } }else{ TbOrders tbOrders = tbOrdersService.selectTbOrdersByOrderID(vehicleGps.getOrderId()); if (tbOrders == null) { return getDataTable(new ArrayList<>()); } DispatchOrd dispatchOrd = dispatchOrdService.selectDispatchOrdByServiceOrdIDDt(tbOrders.getServiceOrdID()); if (dispatchOrd == null) { return getDataTable(new ArrayList<>()); } String vehicleNo = tbVehicleOrder.getVehicle(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String beginTime= sdf.format(dispatchOrd.getDispatchOrdStartDate()); String endTime= sdf.format(new Date()); logger.info("查询车辆轨迹:车辆号:{}, 开始时间:{}, 结束时间:{}", vehicleNo, beginTime, endTime); return this.getAnonymousTracks(vehicleNo,beginTime,endTime); // // vehicleGps.setVehicleNo(tbVehicleOrder.getVehicle()); // startPage(); // // 设置按时间倒序排序 // vehicleGps.setOrderByColumn("collect_time"); // vehicleGps.setIsAsc("desc"); // List list = vehicleGpsService.selectVehicleGpsList(vehicleGps); // return getDataTable(list); } } /** * 导出车辆GPS坐标列表 */ @PreAuthorize("@ss.hasPermi('system:gps:export')") @Log(title = "车辆GPS坐标", businessType = BusinessType.EXPORT) @GetMapping("/export") public AjaxResult export(VehicleGps vehicleGps) { // 设置按时间倒序排序 vehicleGps.setOrderByColumn("collect_time"); vehicleGps.setIsAsc("desc"); List list = vehicleGpsService.selectVehicleGpsList(vehicleGps); ExcelUtil util = new ExcelUtil(VehicleGps.class); return util.exportExcel(list, "车辆GPS坐标数据"); } /** * 获取车辆GPS坐标详细信息 */ @PreAuthorize("@ss.hasPermi('system:gps:query')") @GetMapping(value = "/{gpsId}") public AjaxResult getInfo(@PathVariable("gpsId") Long gpsId) { return success(vehicleGpsService.selectVehicleGpsById(gpsId)); } /** * 新增车辆GPS坐标 */ @PreAuthorize("@ss.hasPermi('system:gps:add')") @Log(title = "车辆GPS坐标", businessType = BusinessType.INSERT) @PostMapping public AjaxResult add(@RequestBody VehicleGps vehicleGps) { return toAjax(vehicleGpsService.insertVehicleGps(vehicleGps)); } /** * 修改车辆GPS坐标 */ @PreAuthorize("@ss.hasPermi('system:gps:edit')") @Log(title = "车辆GPS坐标", businessType = BusinessType.UPDATE) @PutMapping public AjaxResult edit(@RequestBody VehicleGps vehicleGps) { return toAjax(vehicleGpsService.updateVehicleGps(vehicleGps)); } /** * 删除车辆GPS坐标 */ @PreAuthorize("@ss.hasPermi('system:gps:remove')") @Log(title = "车辆GPS坐标", businessType = BusinessType.DELETE) @DeleteMapping("/{gpsIds}") public AjaxResult remove(@PathVariable Long[] gpsIds) { return toAjax(vehicleGpsService.deleteVehicleGpsByIds(gpsIds)); } /** * 查询车辆历史轨迹 */ @PreAuthorize("@ss.hasPermi('system:gps:query')") @GetMapping("/tracks") public TableDataInfo getTracks(String vehicleNo, String beginTime, String endTime) { return getAnonymousTracks(vehicleNo, beginTime, endTime); } /** * 匿名查询车辆历史轨迹 */ @Anonymous() @GetMapping("/anonymousTracks") public TableDataInfo getAnonymousTracks(String vehicleNo, String beginTime, String endTime) { try { // 通过车牌号获取设备ID VehicleInfo vehicleInfo = vehicleInfoService.selectVehicleInfoByPlateNumber(vehicleNo); if (vehicleInfo == null) { // throw new Error("未找到该车辆对应的GPS设备"); return getDataTable(new ArrayList<>()); } // 处理开始时间 beginTime = beginTime.replace("T", " "); if (beginTime.split(":").length == 2) { // 只有小时和分钟 beginTime += ":00"; } // 处理结束时间 // endTime = endTime.replace("T", " ").replace(" ","%20"); endTime = endTime.replace("T", " "); if (endTime.split(":").length == 2) { // 只有小时和分钟 endTime += ":59"; } List trackPoints = new ArrayList<>(); //如果平台是cms,则调用cms的接口 if(vehicleInfo.getPlatformCode().equals("CMS")) { CmsTrackDetailResponse response = cmsGpsCollectService.queryTrackDetail( vehicleInfo.getDeviceId(), // 设备号 beginTime, // 开始时间 endTime, // 结束时间 null, // 距离(可选) null, // 停车时长(可选) 1, // 解析地理位置 null, // 当前页码(可选) null, // 每页记录数(可选) 2 // 地图类型(2:百度地图) ); if (response.getResult() != 0) { throw new Error("查询CMS轨迹失败"); } // 转换CMS轨迹点为统一格式 if (response.getTracks() != null) { for (CmsTrackDetailResponse.CmsTrackPoint point : response.getTracks()) { GpsTrackPoint trackPoint = new GpsTrackPoint(); trackPoint.setVehicleNo(point.getVid()); trackPoint.setDeviceId(point.getId()); //经度纬度为空时,跳过 if(point.getMlng()==null || point.getMlat()==null) { continue; } // 经度,使用三元运算符 trackPoint.setLongitude(point.getMlng() != null ? Double.parseDouble(point.getMlng()) : 0.0); // 纬度,使用三元运算符 trackPoint.setLatitude(point.getMlat() != null ? Double.parseDouble(point.getMlat()) : 0.0); // 速度,直接使用int转double trackPoint.setSpeed(point.getSp() > 0 ? (double)point.getSp() : 0.0); // 方向,使用三元运算符处理 trackPoint.setCourse(point.getFt() > 0 ? point.getFt() : 0); // ACC状态,使用三元运算符处理 trackPoint.setAccStatus(point.getAc() > 0 ? point.getAc() : 0); // 在线状态,使用三元运算符处理 trackPoint.setOnlineStatus(point.getNet() > 0 ? point.getNet() : 0); trackPoint.setAddress(point.getPs()); // 上报时间,直接使用字符串 trackPoint.setReportTime(point.getGt() != null ? point.getGt() : new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); trackPoints.add(trackPoint); } } } else { // 构建查询请求 GpsTrackQueryRequest request = new GpsTrackQueryRequest(); request.setDeviceid(vehicleInfo.getDeviceId()); request.setBegintime(beginTime); request.setEndtime(endTime); request.setTimezone(8); // 中国时区 logger.info("查询车辆轨迹:车辆号:{}, 设备ID:{}, 开始时间:{}, 结束时间:{}", vehicleNo, vehicleInfo.getDeviceId(), beginTime, endTime); // 查询轨迹 GpsTrackQueryResponse response = gpsCollectService.queryTracks(request); if (response.getStatus() != 0) { logger.error("查询轨迹失败,状态码:{}, 错误信息:{}", response.getStatus(), response.getCause()); throw new Error("查询轨迹失败:" + (response.getCause() != null ? response.getCause() : "未知错误")); } // 转换GPS51轨迹点为统一格式 if (response.getRecords() != null) { for (GpsTrackPoint point : response.getRecords()) { GpsTrackPoint trackPoint = new GpsTrackPoint(); trackPoint.setVehicleNo(vehicleNo); trackPoint.setDeviceId(vehicleInfo.getDeviceId()); trackPoint.setLongitude(point.getLongitude()); // 经度 trackPoint.setLatitude(point.getLatitude()); // 纬度 trackPoint.setSpeed(point.getSpeed()); // 速度 trackPoint.setCourse(point.getCourse()); // 方向 trackPoint.setReportTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(point.getUpdatetime()))); // 上报时间 trackPoints.add(trackPoint); } } } //转换成List List vehicleGpsList = new ArrayList<>(); for(GpsTrackPoint trackPoint : trackPoints) { VehicleGps vehicleGps = new VehicleGps(); vehicleGps.setVehicleNo(trackPoint.getVehicleNo()); vehicleGps.setDeviceId(trackPoint.getDeviceId()); vehicleGps.setLongitude(trackPoint.getLongitude()); vehicleGps.setLatitude(trackPoint.getLatitude()); vehicleGps.setSpeed(trackPoint.getSpeed()); //方向 vehicleGps.setDirection(Double.valueOf(trackPoint.getCourse())); //地址 vehicleGps.setAddress(trackPoint.getAddress()); vehicleGps.setCollectTime(trackPoint.getReportTime()); //GPS平台处理时间 vehicleGps.setPlatformProcessTime(trackPoint.getReportTime()); vehicleGps.setDeviceReportTime(trackPoint.getReportTime()); vehicleGpsList.add(vehicleGps); } //时间倒序排序 vehicleGpsList.sort(Comparator.comparing(VehicleGps::getDeviceReportTime).reversed()); //返回车辆Gps列表 return getDataTable(vehicleGpsList); // return success(vehicleGpsList); } catch (Exception e) { logger.error("查询车辆轨迹异常", e); throw new Error("查询车辆轨迹失败:" + e.getMessage()); } } /** * 腾讯地图地址搜索接口代理 */ @Anonymous() @GetMapping("/address/search") public AjaxResult searchAddress(String keyword, String region) { try { // 构建腾讯地图搜索API URL String url = "https://apis.map.qq.com/ws/place/v1/search"; String params = "keyword=" + URLEncoder.encode(keyword, StandardCharsets.UTF_8.toString()) + "&boundary=region(" + (region != null ? region : "广州") + ")" + "&key=" + tencentMapConfig.getKey(); // 发送HTTP请求 String response = HttpUtils.sendGet(url, params); // 返回结果 return AjaxResult.success("查询成功", response); } catch (Exception e) { logger.error("地址搜索失败", e); return AjaxResult.error("地址搜索失败:" + e.getMessage()); } } /** * 腾讯地图逆地址解析接口代理 */ @Anonymous() @GetMapping("/address/geocoder") public AjaxResult reverseGeocoder(Double lat, Double lng) { try { // 检查参数 logger.info("逆地址解析请求参数: lat={}, lng={}", lat, lng); if (lat == null || lng == null) { logger.warn("参数不完整,缺少经纬度坐标: lat={}, lng={}", lat, lng); return AjaxResult.error("参数不完整,缺少经纬度坐标"); } // 检查参数有效性 if (Double.isNaN(lat) || Double.isNaN(lng) || Double.isInfinite(lat) || Double.isInfinite(lng)) { logger.warn("参数无效,经纬度坐标包含非法值: lat={}, lng={}", lat, lng); return AjaxResult.error("参数无效,经纬度坐标格式错误"); } // 构建腾讯地图逆地址解析API URL String url = "https://apis.map.qq.com/ws/geocoder/v1/"; String params = "location=" + lat + "," + lng + "&key=" + tencentMapConfig.getKey() + "&get_poi=1"; // 发送HTTP请求 String response = HttpUtils.sendGet(url, params); // 返回结果 return AjaxResult.success("查询成功", response); } catch (Exception e) { logger.error("逆地址解析失败: lat={}, lng={}", lat, lng, e); return AjaxResult.error("逆地址解析失败:" + e.getMessage()); } } /** * 腾讯地图路线规划接口代理(计算两点间距离) */ @Anonymous() @GetMapping("/route/distance") public AjaxResult calculateDistance(Double fromLat, Double fromLng, Double toLat, Double toLng) { try { // 检查参数 if (fromLat == null || fromLng == null || toLat == null || toLng == null) { return AjaxResult.error("参数不完整,缺少起点或终点坐标"); } // 构建腾讯地图路线规划API URL String url = "https://apis.map.qq.com/ws/distance/v1/"; String params = "mode=driving" + "&from=" + fromLat + "," + fromLng + "&to=" + toLat + "," + toLng + "&key=" + tencentMapConfig.getKey(); // 发送HTTP请求 String response = HttpUtils.sendGet(url, params); // 返回结果 return AjaxResult.success("计算成功", response); } catch (Exception e) { logger.error("距离计算失败", e); return AjaxResult.error("距离计算失败:" + e.getMessage()); } } /** * 百度地图地理编码接口代理(地址转坐标) */ @Anonymous() @GetMapping("/baidu/geocoding") public AjaxResult baiduGeocoding(String address, String city) { try { // 检查参数 if (address == null || address.trim().isEmpty()) { return AjaxResult.error("参数不完整,缺少地址信息"); } // 构建百度地图地理编码API URL String url = "https://api.map.baidu.com/geocoding/v3/"; String params = "address=" + URLEncoder.encode(address, StandardCharsets.UTF_8.toString()) + (city != null && !city.trim().isEmpty() ? "&city=" + URLEncoder.encode(city, StandardCharsets.UTF_8.toString()) : "") + "&output=json" + "&ak=" + baiduMapConfig.getAk(); logger.info("百度地图地理编码请求: address={}, city={}", address, city); // 发送HTTP请求 String response = HttpUtils.sendGet(url, params); // 返回结果 return AjaxResult.success("查询成功", response); } catch (Exception e) { logger.error("百度地图地理编码失败", e); return AjaxResult.error("地理编码失败:" + e.getMessage()); } } /** * 百度地图路线规划接口代理(计算两个坐标之间的驾车距离) */ @Anonymous() @GetMapping("/baidu/route/driving") public AjaxResult baiduRouteDriving(String origin, String destination) { try { // 检查参数 if (origin == null || origin.trim().isEmpty() || destination == null || destination.trim().isEmpty()) { return AjaxResult.error("参数不完整,缺少起点或终点坐标"); } // 验证坐标格式(纬度,经度) String[] originParts = origin.split(","); String[] destParts = destination.split(","); if (originParts.length != 2 || destParts.length != 2) { return AjaxResult.error("坐标格式错误,应为:纬度,经度"); } // 构建百度地图路线规划API URL String url = "https://api.map.baidu.com/directionlite/v1/driving"; String params = "origin=" + origin + "&destination=" + destination + "&ak=" + baiduMapConfig.getAk(); logger.info("百度地图路线规划请求: origin={}, destination={}", origin, destination); // 发送HTTP请求 String response = HttpUtils.sendGet(url, params); // 返回结果 return AjaxResult.success("计算成功", response); } catch (Exception e) { logger.error("百度地图路线规划失败", e); return AjaxResult.error("路线规划失败:" + e.getMessage()); } } /** * 百度地图计算两个地址之间的距离(组合接口:地址转坐标 + 路线规划) */ @Anonymous() @GetMapping("/baidu/distance/byAddress") public AjaxResult baiduDistanceByAddress(String fromAddress, String fromCity, String toAddress, String toCity) { try { // 检查参数 if (fromAddress == null || fromAddress.trim().isEmpty() || toAddress == null || toAddress.trim().isEmpty()) { return AjaxResult.error("参数不完整,缺少起点或终点地址"); } logger.info("开始计算地址距离: fromAddress={}, fromCity={}, toAddress={}, toCity={}", fromAddress, fromCity, toAddress, toCity); // 第一步:起点地址转坐标 String geocodingUrl1 = "https://api.map.baidu.com/geocoding/v3/"; String geocodingParams1 = "address=" + URLEncoder.encode(fromAddress, StandardCharsets.UTF_8.toString()) + (fromCity != null && !fromCity.trim().isEmpty() ? "&city=" + URLEncoder.encode(fromCity, StandardCharsets.UTF_8.toString()) : "") + "&output=json" + "&ak=" + baiduMapConfig.getAk(); String geocodingResponse1 = HttpUtils.sendGet(geocodingUrl1, geocodingParams1); logger.info("起点地理编码响应: {}", geocodingResponse1); // 解析起点坐标 com.alibaba.fastjson2.JSONObject geocodingJson1 = com.alibaba.fastjson2.JSONObject.parseObject(geocodingResponse1); if (geocodingJson1.getInteger("status") != 0) { logger.error("起点地理编码失败: {}", geocodingResponse1); return AjaxResult.error("起点地址解析失败"); } com.alibaba.fastjson2.JSONObject location1 = geocodingJson1.getJSONObject("result").getJSONObject("location"); double fromLat = location1.getDouble("lat"); double fromLng = location1.getDouble("lng"); logger.info("起点坐标: lat={}, lng={}", fromLat, fromLng); // 第二步:终点地址转坐标 String geocodingUrl2 = "https://api.map.baidu.com/geocoding/v3/"; String geocodingParams2 = "address=" + URLEncoder.encode(toAddress, StandardCharsets.UTF_8.toString()) + (toCity != null && !toCity.trim().isEmpty() ? "&city=" + URLEncoder.encode(toCity, StandardCharsets.UTF_8.toString()) : "") + "&output=json" + "&ak=" + baiduMapConfig.getAk(); String geocodingResponse2 = HttpUtils.sendGet(geocodingUrl2, geocodingParams2); logger.info("终点地理编码响应: {}", geocodingResponse2); // 解析终点坐标 com.alibaba.fastjson2.JSONObject geocodingJson2 = com.alibaba.fastjson2.JSONObject.parseObject(geocodingResponse2); if (geocodingJson2.getInteger("status") != 0) { logger.error("终点地理编码失败: {}", geocodingResponse2); return AjaxResult.error("终点地址解析失败"); } com.alibaba.fastjson2.JSONObject location2 = geocodingJson2.getJSONObject("result").getJSONObject("location"); double toLat = location2.getDouble("lat"); double toLng = location2.getDouble("lng"); logger.info("终点坐标: lat={}, lng={}", toLat, toLng); // 第三步:调用路线规划接口计算距离 String routeUrl = "https://api.map.baidu.com/directionlite/v1/driving"; String origin = fromLat + "," + fromLng; String destination = toLat + "," + toLng; String routeParams = "origin=" + origin + "&destination=" + destination + "&ak=" + baiduMapConfig.getAk(); logger.info("路线规划请求: origin={}, destination={}", origin, destination); String routeResponse = HttpUtils.sendGet(routeUrl, routeParams); logger.info("路线规划响应: {}", routeResponse); // 解析距离结果 com.alibaba.fastjson2.JSONObject routeJson = com.alibaba.fastjson2.JSONObject.parseObject(routeResponse); if (routeJson.getInteger("status") != 0) { logger.error("路线规划失败: {}", routeResponse); return AjaxResult.error("路线规划失败"); } // 提取距离信息(单位:米) com.alibaba.fastjson2.JSONObject result = routeJson.getJSONObject("result"); com.alibaba.fastjson2.JSONArray routes = result.getJSONArray("routes"); if (routes == null || routes.isEmpty()) { logger.error("未找到路线信息"); return AjaxResult.error("未找到路线信息"); } com.alibaba.fastjson2.JSONObject route = routes.getJSONObject(0); int distance = route.getInteger("distance"); // 距离,单位:米 int duration = route.getInteger("duration"); // 时长,单位:秒 logger.info("计算成功: 距离={}米, 时长={}秒", distance, duration); // 构建返回结果 Map resultMap = new HashMap<>(); resultMap.put("distance", distance); // 距离(米) resultMap.put("duration", duration); // 时长(秒) resultMap.put("distanceKm", String.format("%.1f", distance / 1000.0)); // 距离(公里) resultMap.put("durationMin", duration / 60); // 时长(分钟) // 起点坐标 Map fromLocation = new HashMap<>(); fromLocation.put("lat", fromLat); fromLocation.put("lng", fromLng); resultMap.put("fromLocation", fromLocation); // 终点坐标 Map toLocation = new HashMap<>(); toLocation.put("lat", toLat); toLocation.put("lng", toLng); resultMap.put("toLocation", toLocation); return AjaxResult.success("计算成功", resultMap); } catch (Exception e) { logger.error("计算地址距离失败", e); return AjaxResult.error("计算距离失败:" + e.getMessage()); } } /** * 百度地图地址搜索提示API(输入联想) * Place Suggestion API - 用于地址输入时的智能提示 */ @Anonymous() @GetMapping("/baidu/place/suggestion") public AjaxResult baiduPlaceSuggestion(String query, String region) { try { // 检查参数 if (query == null || query.trim().isEmpty()) { return AjaxResult.error("参数不完整,缺少搜索关键词"); } // 构建百度地图 Place Suggestion API URL String url = "https://api.map.baidu.com/place/v2/suggestion"; String params = "query=" + URLEncoder.encode(query, StandardCharsets.UTF_8.toString()) + (region != null && !region.trim().isEmpty() ? "®ion=" + URLEncoder.encode(region, StandardCharsets.UTF_8.toString()) : "") + "&output=json" + "&ak=" + baiduMapConfig.getAk(); logger.info("百度地图地址搜索提示请求: query={}, region={}", query, region); // 发送HTTP请求 String response = HttpUtils.sendGet(url, params); logger.debug("百度地图地址搜索提示响应: {}", response); // 解析响应 com.alibaba.fastjson2.JSONObject jsonResponse = com.alibaba.fastjson2.JSONObject.parseObject(response); if (jsonResponse.getInteger("status") != 0) { logger.error("地址搜索提示失败: {}", response); return AjaxResult.error("地址搜索失败"); } // 提取提示列表 com.alibaba.fastjson2.JSONArray results = jsonResponse.getJSONArray("result"); if (results == null || results.isEmpty()) { logger.info("未找到匹配的地址"); return AjaxResult.success("查询成功", new ArrayList<>()); } // 构建返回结果 List> suggestions = new ArrayList<>(); for (int i = 0; i < results.size(); i++) { com.alibaba.fastjson2.JSONObject item = results.getJSONObject(i); Map suggestion = new HashMap<>(); suggestion.put("name", item.getString("name")); // 名称 suggestion.put("address", item.getString("address")); // 地址 suggestion.put("province", item.getString("province")); // 省 suggestion.put("city", item.getString("city")); // 市 suggestion.put("district", item.getString("district")); // 区 suggestion.put("uid", item.getString("uid")); // 地点UID // 经纬度信息 com.alibaba.fastjson2.JSONObject location = item.getJSONObject("location"); if (location != null) { Map locationMap = new HashMap<>(); locationMap.put("lat", location.getDouble("lat")); locationMap.put("lng", location.getDouble("lng")); suggestion.put("location", locationMap); } suggestions.add(suggestion); } logger.info("地址搜索提示成功: 找到{} 条结果", suggestions.size()); return AjaxResult.success("查询成功", suggestions); } catch (Exception e) { logger.error("地址搜索提示失败", e); return AjaxResult.error("地址搜索失败:" + e.getMessage()); } } // ==================== 天地图接口 ==================== /** * 天地图地理编码接口代理(地址转坐标) * 文档:https://lbs.tianditu.gov.cn/server/geocoding.html */ @Anonymous() @GetMapping("/tianditu/geocoding") public AjaxResult tiandituGeocoding(String address) { try { // 检查参数 if (address == null || address.trim().isEmpty()) { return AjaxResult.error("参数不完整,缺少地址信息"); } // 构建天地图地理编码API URL String url = "http://api.tianditu.gov.cn/geocoder"; String params = "ds={\"keyWord\":\"" + address + "\"}&tk=" + tiandituMapConfig.getTk(); logger.info("天地图地理编码请求: address={}", address); // 发送HTTP请求 String response = HttpUtils.sendGet(url, params); // 返回结果 return AjaxResult.success("查询成功", response); } catch (Exception e) { logger.error("天地图地理编码失败", e); return AjaxResult.error("地理编码失败:" + e.getMessage()); } } /** * 天地图逆地理编码接口代理(坐标转地址) * 文档:https://lbs.tianditu.gov.cn/server/geocoding.html */ @Anonymous() @GetMapping("/tianditu/reverseGeocoding") public AjaxResult tiandituReverseGeocoding(Double lon, Double lat) { try { // 检查参数 if (lat == null || lon == null) { return AjaxResult.error("参数不完整,缺少经纬度坐标"); } // 检查参数有效性 if (Double.isNaN(lat) || Double.isNaN(lon) || Double.isInfinite(lat) || Double.isInfinite(lon)) { return AjaxResult.error("参数无效,经纬度坐标格式错误"); } // 构建天地图逆地理编码API URL String url = "http://api.tianditu.gov.cn/geocoder"; String params = "postStr={\"lon\":" + lon + ",\"lat\":" + lat + ",\"ver\":1}" + "&type=geocode" + "&tk=" + tiandituMapConfig.getTk(); logger.info("天地图逆地理编码请求: lon={}, lat={}", lon, lat); // 发送HTTP请求 String response = HttpUtils.sendGet(url, params); // 返回结果 return AjaxResult.success("查询成功", response); } catch (Exception e) { logger.error("天地图逆地理编码失败: lon={}, lat={}", lon, lat, e); return AjaxResult.error("逆地理编码失败:" + e.getMessage()); } } /** * 天地图地点搜索接口代理(POI搜索) * 文档:https://lbs.tianditu.gov.cn/server/search.html */ @Anonymous() @GetMapping("/tianditu/place/search") public AjaxResult tiandituPlaceSearch(String keyWord, String queryType, String level, String mapBound, Integer start, Integer count) { try { // 检查参数 if (keyWord == null || keyWord.trim().isEmpty()) { return AjaxResult.error("参数不完整,缺少搜索关键词"); } // 设置默认值 if (queryType == null || queryType.trim().isEmpty()) { queryType = "1"; // 1-普通搜索,7-周边搜索 } if (start == null) { start = 0; } if (count == null) { count = 10; } // 构建天地图POI搜索API URL String url = "http://api.tianditu.gov.cn/search"; StringBuilder paramsBuilder = new StringBuilder(); paramsBuilder.append("postStr={\"keyWord\":\"").append(keyWord).append("\""); paramsBuilder.append(",\"queryType\":\"").append(queryType).append("\""); if (level != null && !level.trim().isEmpty()) { paramsBuilder.append(",\"level\":\"").append(level).append("\""); } if (mapBound != null && !mapBound.trim().isEmpty()) { paramsBuilder.append(",\"mapBound\":\"").append(mapBound).append("\""); } paramsBuilder.append(",\"start\":\"").append(start).append("\""); paramsBuilder.append(",\"count\":\"").append(count).append("\""); paramsBuilder.append("}" ); paramsBuilder.append("&type=query"); paramsBuilder.append("&tk=").append(tiandituMapConfig.getTk()); String params = paramsBuilder.toString(); logger.info("天地图POI搜索请求: keyWord={}, queryType={}", keyWord, queryType); // 发送HTTP请求 String response = HttpUtils.sendGet(url, params); // 返回结果 return AjaxResult.success("查询成功", response); } catch (Exception e) { logger.error("天地图POI搜索失败", e); return AjaxResult.error("POI搜索失败:" + e.getMessage()); } } /** * 天地图路线规划接口代理(驾车路径规划) * 文档:https://lbs.tianditu.gov.cn/server/drive.html */ @Anonymous() @GetMapping("/tianditu/route/driving") public AjaxResult tiandituRouteDriving(String orig, String dest, String mid, String style) { try { // 检查参数 if (orig == null || orig.trim().isEmpty() || dest == null || dest.trim().isEmpty()) { return AjaxResult.error("参数不完整,缺少起点或终点坐标"); } // 验证坐标格式(经度,纬度) String[] origParts = orig.split(","); String[] destParts = dest.split(","); if (origParts.length != 2 || destParts.length != 2) { return AjaxResult.error("坐标格式错误,应为:经度,纬度"); } // 设置默认值 if (style == null || style.trim().isEmpty()) { style = "0"; // 0-推荐,1-避开高速 } // 构建天地图驾车路径规划API URL String url = "http://api.tianditu.gov.cn/drive"; StringBuilder paramsBuilder = new StringBuilder(); paramsBuilder.append("postStr={\"orig\":\"").append(orig).append("\""); paramsBuilder.append(",\"dest\":\"").append(dest).append("\""); if (mid != null && !mid.trim().isEmpty()) { paramsBuilder.append(",\"mid\":\"").append(mid).append("\""); } paramsBuilder.append(",\"style\":\"").append(style).append("\""); paramsBuilder.append("}" ); paramsBuilder.append("&tk=").append(tiandituMapConfig.getTk()); String params = paramsBuilder.toString(); logger.info("天地图驾车路径规划请求: orig={}, dest={}", orig, dest); // 发送HTTP请求 String response = HttpUtils.sendGet(url, params); // 返回结果 return AjaxResult.success("计算成功", response); } catch (Exception e) { logger.error("天地图驾车路径规划失败", e); return AjaxResult.error("路径规划失败:" + e.getMessage()); } } /** * 天地图计算两个地址之间的距离(组合接口:地址转坐标 + 路径规划) */ @Anonymous() @GetMapping("/tianditu/distance/byAddress") public AjaxResult tiandituDistanceByAddress(String fromAddress, String toAddress) { try { // 检查参数 if (fromAddress == null || fromAddress.trim().isEmpty() || toAddress == null || toAddress.trim().isEmpty()) { return AjaxResult.error("参数不完整,缺少起点或终点地址"); } logger.info("开始计算地址距离: fromAddress={}, toAddress={}", fromAddress, toAddress); // 第一步:起点地址转坐标 String geocodingUrl1 = "http://api.tianditu.gov.cn/geocoder"; String geocodingParams1 = "ds={\"keyWord\":\"" + fromAddress + "\"}" + "&tk=" + tiandituMapConfig.getTk(); String geocodingResponse1 = HttpUtils.sendGet(geocodingUrl1, geocodingParams1); logger.info("起点地理编码响应: {}", geocodingResponse1); // 解析起点坐标 com.alibaba.fastjson2.JSONObject geocodingJson1 = com.alibaba.fastjson2.JSONObject.parseObject(geocodingResponse1); if (!"0".equals(geocodingJson1.getString("status"))) { logger.error("起点地理编码失败: {}", geocodingResponse1); return AjaxResult.error("起点地址解析失败"); } com.alibaba.fastjson2.JSONObject location1 = geocodingJson1.getJSONObject("location"); if (location1 == null) { return AjaxResult.error("起点地址未找到对应坐标"); } double fromLon = location1.getDouble("lon"); double fromLat = location1.getDouble("lat"); logger.info("起点坐标: lon={}, lat={}", fromLon, fromLat); // 第二步:终点地址转坐标 String geocodingUrl2 = "http://api.tianditu.gov.cn/geocoder"; String geocodingParams2 = "ds={\"keyWord\":\"" + toAddress + "\"}" + "&tk=" + tiandituMapConfig.getTk(); String geocodingResponse2 = HttpUtils.sendGet(geocodingUrl2, geocodingParams2); logger.info("终点地理编码响应: {}", geocodingResponse2); // 解析终点坐标 com.alibaba.fastjson2.JSONObject geocodingJson2 = com.alibaba.fastjson2.JSONObject.parseObject(geocodingResponse2); if (!"0".equals(geocodingJson2.getString("status"))) { logger.error("终点地理编码失败: {}", geocodingResponse2); return AjaxResult.error("终点地址解析失败"); } com.alibaba.fastjson2.JSONObject location2 = geocodingJson2.getJSONObject("location"); if (location2 == null) { return AjaxResult.error("终点地址未找到对应坐标"); } double toLon = location2.getDouble("lon"); double toLat = location2.getDouble("lat"); logger.info("终点坐标: lon={}, lat={}", toLon, toLat); // 第三步:调用路径规划接口计算距离 String routeUrl = "http://api.tianditu.gov.cn/drive"; String orig = fromLon + "," + fromLat; String dest = toLon + "," + toLat; String routeParams = "postStr={\"orig\":\"" + orig + "\",\"dest\":\"" + dest + "\",\"style\":\"0\"}" + "&tk=" + tiandituMapConfig.getTk(); logger.info("路径规划请求: orig={}, dest={}", orig, dest); String routeResponse = HttpUtils.sendGet(routeUrl, routeParams); logger.info("路径规划响应: {}", routeResponse); // 解析距离结果 com.alibaba.fastjson2.JSONObject routeJson = com.alibaba.fastjson2.JSONObject.parseObject(routeResponse); if (!"0".equals(routeJson.getString("status"))) { logger.error("路径规划失败: {}", routeResponse); return AjaxResult.error("路径规划失败"); } // 提取距离信息 com.alibaba.fastjson2.JSONObject result = routeJson.getJSONObject("result"); if (result == null) { logger.error("路径规划结果为空"); return AjaxResult.error("路径规划失败"); } com.alibaba.fastjson2.JSONArray routes = result.getJSONArray("routes"); if (routes == null || routes.isEmpty()) { logger.error("未找到路线信息"); return AjaxResult.error("未找到路线信息"); } com.alibaba.fastjson2.JSONObject route = routes.getJSONObject(0); double distance = route.getDoubleValue("distance"); // 距离,单位:米 double duration = route.getDoubleValue("duration"); // 时长,单位:秒 logger.info("计算成功: 距离={}米, 时长={}秒", distance, duration); // 构建返回结果 Map resultMap = new HashMap<>(); resultMap.put("distance", (int)distance); // 距离(米) resultMap.put("duration", (int)duration); // 时长(秒) resultMap.put("distanceKm", String.format("%.1f", distance / 1000.0)); // 距离(公里) resultMap.put("durationMin", (int)(duration / 60)); // 时长(分钟) // 起点坐标 Map fromLocation = new HashMap<>(); fromLocation.put("lon", fromLon); fromLocation.put("lat", fromLat); resultMap.put("fromLocation", fromLocation); // 终点坐标 Map toLocation = new HashMap<>(); toLocation.put("lon", toLon); toLocation.put("lat", toLat); resultMap.put("toLocation", toLocation); return AjaxResult.success("计算成功", resultMap); } catch (Exception e) { logger.error("计算地址距离失败", e); return AjaxResult.error("计算距离失败:" + e.getMessage()); } } /** * 天地图输入提示接口代理(地址联想) * 文档:https://lbs.tianditu.gov.cn/server/suggestion.html */ @Anonymous() @GetMapping("/tianditu/place/suggestion") public AjaxResult tiandituPlaceSuggestion(String keyWord, String region, String city, Integer count) { try { // 检查参数 if (keyWord == null || keyWord.trim().isEmpty()) { return AjaxResult.error("参数不完整,缺少搜索关键词"); } // 设置默认值 if (count == null) { count = 10; } // 构建天地图输入提示API URL String url = "http://api.tianditu.gov.cn/search"; StringBuilder paramsBuilder = new StringBuilder(); paramsBuilder.append("postStr={\"keyWord\":\"").append(keyWord).append("\""); if (region != null && !region.trim().isEmpty()) { paramsBuilder.append(",\"region\":\"").append(region).append("\""); } if (city != null && !city.trim().isEmpty()) { paramsBuilder.append(",\"city\":\"").append(city).append("\""); } paramsBuilder.append(",\"count\":\"").append(count).append("\""); paramsBuilder.append("}" ); paramsBuilder.append("&type=suggest"); paramsBuilder.append("&tk=").append(tiandituMapConfig.getTk()); String params = paramsBuilder.toString(); logger.info("天地图输入提示请求: keyWord={}, region={}", keyWord, region); // 发送HTTP请求 String response = HttpUtils.sendGet(url, params); logger.debug("天地图输入提示响应: {}", response); // 解析响应 com.alibaba.fastjson2.JSONObject jsonResponse = com.alibaba.fastjson2.JSONObject.parseObject(response); if (!"0".equals(jsonResponse.getString("status"))) { logger.error("输入提示失败: {}", response); return AjaxResult.error("地址搜索失败"); } // 提取提示列表 com.alibaba.fastjson2.JSONArray results = jsonResponse.getJSONArray("suggests"); if (results == null || results.isEmpty()) { logger.info("未找到匹配的地址"); return AjaxResult.success("查询成功", new ArrayList<>()); } // 构建返回结果 List> suggestions = new ArrayList<>(); for (int i = 0; i < results.size(); i++) { com.alibaba.fastjson2.JSONObject item = results.getJSONObject(i); Map suggestion = new HashMap<>(); suggestion.put("name", item.getString("name")); // 名称 suggestion.put("address", item.getString("address")); // 地址 suggestion.put("province", item.getString("province")); // 省 suggestion.put("city", item.getString("city")); // 市 suggestion.put("district", item.getString("district")); // 区 // 经纬度信息 com.alibaba.fastjson2.JSONObject location = item.getJSONObject("location"); if (location != null) { Map locationMap = new HashMap<>(); locationMap.put("lon", location.getDouble("lon")); locationMap.put("lat", location.getDouble("lat")); suggestion.put("location", locationMap); } suggestions.add(suggestion); } logger.info("地址搜索提示成功: 找到{}条结果", suggestions.size()); return AjaxResult.success("查询成功", suggestions); } catch (Exception e) { logger.error("地址搜索提示失败", e); return AjaxResult.error("地址搜索失败:" + e.getMessage()); } } }