diff --git a/ebike-common/pom.xml b/ebike-common/pom.xml index ca49f67c..05170cc3 100644 --- a/ebike-common/pom.xml +++ b/ebike-common/pom.xml @@ -37,6 +37,20 @@ influxdb-client-java 6.10.0 + + + + org.locationtech.jts + jts-core + 1.19.0 + + + + org.osgeo + proj4j + 0.1.0 + + diff --git a/ebike-common/src/main/java/com/cdzy/common/utils/CoordinateUtil.java b/ebike-common/src/main/java/com/cdzy/common/utils/CoordinateUtil.java index b9037810..ef6b5f80 100644 --- a/ebike-common/src/main/java/com/cdzy/common/utils/CoordinateUtil.java +++ b/ebike-common/src/main/java/com/cdzy/common/utils/CoordinateUtil.java @@ -1,5 +1,12 @@ package com.cdzy.common.utils; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.GeometryFactory; +import org.locationtech.jts.geom.LineString; +import org.osgeo.proj4j.*; + +import java.util.List; + /** * 坐标转换工具类。 * @@ -104,4 +111,78 @@ public class CoordinateUtil { return GCJ02ToBD(gcj02); } + private static final CRSFactory crsFactory = new CRSFactory(); + + /** + * GCJ-02 → WGS84 + * 输入的坐标点必须是GCJ-02坐标系的经纬度。 + * + * @param lon 经度 + * @param lat 纬度 + * @return WGS84坐标 + */ + public static Double[] GCJ02ToWGS84(double lon, double lat) { + // 使用Proj4j进行坐标转换(需添加Proj4j依赖) + CoordinateReferenceSystem gcj02 = crsFactory.createFromName("EPSG:4490"); // 国家2000坐标系(近似GCJ-02) + CoordinateReferenceSystem wgs84 = crsFactory.createFromName("EPSG:4326"); + CoordinateTransform transform = new CoordinateTransformFactory().createTransform(gcj02, wgs84); + + ProjCoordinate src = new ProjCoordinate(lon, lat); + ProjCoordinate dst = new ProjCoordinate(); + transform.transform(src, dst); + return new Double[]{dst.x, dst.y}; + } + + /** + * GCJ-02 → WGS84 + * 输入的坐标点必须是GCJ-02坐标系的经纬度。 + * + * @param lon 经度 + * @param lat 纬度 + * @return WGS84坐标 + */ + public static Coordinate gcj02ToWgs84(double lon, double lat) { + // 使用Proj4j进行坐标转换(需添加Proj4j依赖) + CoordinateReferenceSystem gcj02 = crsFactory.createFromName("EPSG:4490"); // 国家2000坐标系(近似GCJ-02) + CoordinateReferenceSystem wgs84 = crsFactory.createFromName("EPSG:4326"); + CoordinateTransform transform = new CoordinateTransformFactory().createTransform(gcj02, wgs84); + + ProjCoordinate src = new ProjCoordinate(lon, lat); + ProjCoordinate dst = new ProjCoordinate(); + transform.transform(src, dst); + return new Coordinate(dst.x, dst.y); + } + + private static final GeometryFactory geometryFactory = new GeometryFactory(); + + /** + * 计算路径总长度(单位:米) + * 输入的坐标点必须是WGS84坐标系的经纬度。 + * + * @param points 坐标点列表,每个点为[经度, 纬度] + * @return 总长度(米) + */ + public static Double calculateTotalDistance(List points) { + // 转换坐标并构建线串 + LineString lineString = convertToLineString(points); + + // 使用JTS计算几何距离(需确保坐标系为投影坐标系) + return lineString.getLength(); + } + + /** + * 转换坐标点列表为LineString + * + * @param points 坐标点列表 + * @return LineString对象 + */ + private static LineString convertToLineString(List points) { + Coordinate[] coords = new Coordinate[points.size()]; + for (int i = 0; i < points.size(); i++) { + Double[] p = points.get(i); + Coordinate wgs84Coord = gcj02ToWgs84(p[0], p[1]); // GCJ-02转WGS84 + coords[i]= new Coordinate(wgs84Coord.x, wgs84Coord.y); + } + return geometryFactory.createLineString(coords); + } } diff --git a/ebike-feign/src/main/java/com/ebike/feign/clients/OperateFeignClient.java b/ebike-feign/src/main/java/com/ebike/feign/clients/OperateFeignClient.java index b344286e..51ec82e2 100644 --- a/ebike-feign/src/main/java/com/ebike/feign/clients/OperateFeignClient.java +++ b/ebike-feign/src/main/java/com/ebike/feign/clients/OperateFeignClient.java @@ -4,6 +4,7 @@ import com.cdzy.common.model.EbikeTracking; import com.cdzy.common.model.JsonResult; import com.cdzy.common.model.ReqBatchRegionDto; import com.ebike.feign.model.res.ReqEbikeSiteQuery; +import com.ebike.feign.model.res.ReqEbikeTrackingDto; import com.ebike.feign.model.res.ReqUserOperateDto; import com.ebike.feign.model.res.ResFeignEbikeSysRcostsetDto; import com.ebike.feign.model.rsp.FeignEbikeRegionDto; @@ -69,6 +70,15 @@ public interface OperateFeignClient { @PostMapping("ebikeTracking/save") JsonResult saveEbikeTracking(@RequestBody EbikeTracking ebikeTracking); + /** + * 车辆轨迹查询。 + * + * @param reqEbikeTrackingDto 查询参数 + * @return List + */ + @PostMapping("ebikeTracking/query") + JsonResult queryEbikeTracking(@RequestBody ReqEbikeTrackingDto reqEbikeTrackingDto); + /** * 获取运营区详情。 * diff --git a/ebike-operate/src/main/java/com/cdzy/ebikeoperate/model/dto/request/ReqEbikeTrackingDto.java b/ebike-feign/src/main/java/com/ebike/feign/model/res/ReqEbikeTrackingDto.java similarity index 94% rename from ebike-operate/src/main/java/com/cdzy/ebikeoperate/model/dto/request/ReqEbikeTrackingDto.java rename to ebike-feign/src/main/java/com/ebike/feign/model/res/ReqEbikeTrackingDto.java index a27abbdf..25b0677f 100644 --- a/ebike-operate/src/main/java/com/cdzy/ebikeoperate/model/dto/request/ReqEbikeTrackingDto.java +++ b/ebike-feign/src/main/java/com/ebike/feign/model/res/ReqEbikeTrackingDto.java @@ -1,4 +1,4 @@ -package com.cdzy.ebikeoperate.model.dto.request; +package com.ebike.feign.model.res; import jakarta.validation.constraints.NotBlank; import lombok.AllArgsConstructor; diff --git a/ebike-operate/src/main/java/com/cdzy/ebikeoperate/model/dto/response/EbikeTrackingDto.java b/ebike-feign/src/main/java/com/ebike/feign/model/rsp/EbikeTrackingDto.java similarity index 85% rename from ebike-operate/src/main/java/com/cdzy/ebikeoperate/model/dto/response/EbikeTrackingDto.java rename to ebike-feign/src/main/java/com/ebike/feign/model/rsp/EbikeTrackingDto.java index 24199fca..0a9fd0fa 100644 --- a/ebike-operate/src/main/java/com/cdzy/ebikeoperate/model/dto/response/EbikeTrackingDto.java +++ b/ebike-feign/src/main/java/com/ebike/feign/model/rsp/EbikeTrackingDto.java @@ -1,11 +1,15 @@ -package com.cdzy.ebikeoperate.model.dto.response; +package com.ebike.feign.model.rsp; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; import java.io.Serializable; import java.time.LocalDateTime; @Data +@NoArgsConstructor +@AllArgsConstructor public class EbikeTrackingDto implements Serializable { /** diff --git a/ebike-gateway/src/main/resources/application-dev.yml b/ebike-gateway/src/main/resources/application-dev.yml index 8aa4a4a4..e3bf31f3 100644 --- a/ebike-gateway/src/main/resources/application-dev.yml +++ b/ebike-gateway/src/main/resources/application-dev.yml @@ -52,6 +52,12 @@ spring: - Path=/operate/** filters: - StripPrefix=1 + - id: ebike-payment + uri: lb://ebike-payment + predicates: + - Path=/payment/** + filters: + - StripPrefix=1 data: # redis配置 redis: diff --git a/ebike-operate/src/main/java/com/cdzy/ebikeoperate/controller/EbikeTrackingController.java b/ebike-operate/src/main/java/com/cdzy/ebikeoperate/controller/EbikeTrackingController.java index 496dbcc2..03f80060 100644 --- a/ebike-operate/src/main/java/com/cdzy/ebikeoperate/controller/EbikeTrackingController.java +++ b/ebike-operate/src/main/java/com/cdzy/ebikeoperate/controller/EbikeTrackingController.java @@ -6,8 +6,8 @@ import com.cdzy.ebikeoperate.model.pojo.EbikeSiteRegion; import com.cdzy.ebikeoperate.service.EbikeSiteRegionService; import com.cdzy.ebikeoperate.utils.RedisUtil; import com.ebike.feign.model.res.ReqEbikeSiteQuery; -import com.cdzy.ebikeoperate.model.dto.request.ReqEbikeTrackingDto; -import com.cdzy.ebikeoperate.model.dto.response.EbikeTrackingDto; +import com.ebike.feign.model.res.ReqEbikeTrackingDto; +import com.ebike.feign.model.rsp.EbikeTrackingDto; import com.cdzy.ebikeoperate.service.EbikeTrackingService; import com.ebike.feign.model.rsp.EbikeSiteInfo; import lombok.extern.slf4j.Slf4j; diff --git a/ebike-operate/src/main/java/com/cdzy/ebikeoperate/service/EbikeTrackingService.java b/ebike-operate/src/main/java/com/cdzy/ebikeoperate/service/EbikeTrackingService.java index aeeddb7b..231dbd6b 100644 --- a/ebike-operate/src/main/java/com/cdzy/ebikeoperate/service/EbikeTrackingService.java +++ b/ebike-operate/src/main/java/com/cdzy/ebikeoperate/service/EbikeTrackingService.java @@ -1,8 +1,8 @@ package com.cdzy.ebikeoperate.service; import com.cdzy.common.model.EbikeTracking; -import com.cdzy.ebikeoperate.model.dto.request.ReqEbikeTrackingDto; -import com.cdzy.ebikeoperate.model.dto.response.EbikeTrackingDto; +import com.ebike.feign.model.res.ReqEbikeTrackingDto; +import com.ebike.feign.model.rsp.EbikeTrackingDto; import java.util.List; diff --git a/ebike-operate/src/main/java/com/cdzy/ebikeoperate/service/impl/EbikeTrackingServiceImpl.java b/ebike-operate/src/main/java/com/cdzy/ebikeoperate/service/impl/EbikeTrackingServiceImpl.java index 61edab9b..aa437d97 100644 --- a/ebike-operate/src/main/java/com/cdzy/ebikeoperate/service/impl/EbikeTrackingServiceImpl.java +++ b/ebike-operate/src/main/java/com/cdzy/ebikeoperate/service/impl/EbikeTrackingServiceImpl.java @@ -4,10 +4,9 @@ import com.cdzy.common.model.EbikeTracking; import com.cdzy.common.model.JsonResult; import com.cdzy.common.utils.ConvertUtil; import com.cdzy.ebikeoperate.model.dto.EbikeTrackingConfg; -import com.cdzy.ebikeoperate.model.dto.request.ReqEbikeTrackingDto; -import com.cdzy.ebikeoperate.model.dto.response.EbikeTrackingDto; +import com.ebike.feign.model.res.ReqEbikeTrackingDto; +import com.ebike.feign.model.rsp.EbikeTrackingDto; import com.cdzy.ebikeoperate.service.EbikeTrackingService; -import com.cdzy.common.utils.CoordinateUtil; import com.ebike.feign.clients.MaintenanceFeignClient; import com.influxdb.annotations.Measurement; import com.influxdb.client.InfluxDBClient; @@ -21,7 +20,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.time.*; -import java.time.format.DateTimeFormatter; import java.util.List; import java.util.StringJoiner; diff --git a/ebike-payment/src/main/java/com/cdzy/payment/config/GeoCodingConfig.java b/ebike-payment/src/main/java/com/cdzy/payment/config/GeoCodingConfig.java new file mode 100644 index 00000000..f4f272fd --- /dev/null +++ b/ebike-payment/src/main/java/com/cdzy/payment/config/GeoCodingConfig.java @@ -0,0 +1,22 @@ +package com.cdzy.payment.config; + +import com.cdzy.payment.utils.GeoCodingUtil; +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Setter +@Getter +@Configuration +@ConfigurationProperties(prefix = "geo-coding") +public class GeoCodingConfig { + private String apiUrl; + private String accessKey; + + @Bean + public GeoCodingUtil geoCodingUtil() { + return new GeoCodingUtil(apiUrl, accessKey); + } +} diff --git a/ebike-payment/src/main/java/com/cdzy/payment/service/EbikePaymentService.java b/ebike-payment/src/main/java/com/cdzy/payment/service/EbikePaymentService.java index 2f00177e..b79cec7a 100644 --- a/ebike-payment/src/main/java/com/cdzy/payment/service/EbikePaymentService.java +++ b/ebike-payment/src/main/java/com/cdzy/payment/service/EbikePaymentService.java @@ -2,11 +2,13 @@ package com.cdzy.payment.service; import com.cdzy.payment.model.dto.OrderDetailInfo; import com.cdzy.payment.model.dto.ResOrderInfoDto; +import com.cdzy.payment.model.dto.ResRefundOrderInfo; import com.mybatisflex.core.service.IService; import com.cdzy.payment.model.entity.EbikePayment; import com.wechat.pay.java.service.payments.model.Transaction; import java.util.List; +import java.util.Map; /** * 用户订单支付记录 服务层。 @@ -53,5 +55,5 @@ public interface EbikePaymentService extends IService { * @param orderId 退款id * @return 订单详情 */ - OrderDetailInfo getOrderDetail(String orderId); + Map getOrderDetail(String orderId); } diff --git a/ebike-payment/src/main/java/com/cdzy/payment/service/impl/EbikePaymentServiceImpl.java b/ebike-payment/src/main/java/com/cdzy/payment/service/impl/EbikePaymentServiceImpl.java index 92c67e91..8c6fa2a3 100644 --- a/ebike-payment/src/main/java/com/cdzy/payment/service/impl/EbikePaymentServiceImpl.java +++ b/ebike-payment/src/main/java/com/cdzy/payment/service/impl/EbikePaymentServiceImpl.java @@ -1,11 +1,10 @@ package com.cdzy.payment.service.impl; -import com.cdzy.payment.model.dto.OrderDetailInfo; -import com.cdzy.payment.model.dto.ResOrderInfoDto; import com.cdzy.payment.model.enums.PayMethod; import com.cdzy.payment.utils.StringUtils; import com.ebike.feign.clients.OrdersFeignClient; import com.ebike.feign.model.res.ResFeignOrderPaymentDto; +import com.mybatisflex.core.query.QueryMethods; import com.mybatisflex.core.query.QueryWrapper; import com.mybatisflex.spring.service.impl.ServiceImpl; import com.cdzy.payment.model.entity.EbikePayment; @@ -13,11 +12,15 @@ import com.cdzy.payment.mapper.EbikePaymentMapper; import com.cdzy.payment.service.EbikePaymentService; import com.wechat.pay.java.service.payments.model.Transaction; import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.util.List; +import java.util.Map; import static com.cdzy.payment.model.entity.table.EbikePaymentTableDef.EBIKE_PAYMENT; +import static com.cdzy.payment.model.entity.table.EbikeUserOrdersTableDef.EBIKE_USER_ORDERS; +import static com.cdzy.payment.model.entity.table.EbikeUserTableDef.EBIKE_USER; import static com.mybatisflex.core.constant.FuncName.*; /** @@ -26,6 +29,7 @@ import static com.mybatisflex.core.constant.FuncName.*; * @author dingchao * @since 2025-04-24 */ +@Slf4j @Service public class EbikePaymentServiceImpl extends ServiceImpl implements EbikePaymentService{ @@ -84,10 +88,23 @@ public class EbikePaymentServiceImpl extends ServiceImpl orderDto.setDurationCost(orderDto.getDurationCost() + detailDto.getUnitPrice()); - case 2 -> - orderDto.setDispatchFeeOutOperateArea(orderDto.getParkingAreaOutDispatchFee() + detailDto.getUnitPrice()); - case 3 -> - orderDto.setParkingAreaOutDispatchFee(orderDto.getParkingAreaOutDispatchFee() + detailDto.getUnitPrice()); + case 2 -> orderDto.setDispatchFeeOutOperateArea(orderDto.getParkingAreaOutDispatchFee() + detailDto.getUnitPrice()); + case 3 -> orderDto.setParkingAreaOutDispatchFee(orderDto.getParkingAreaOutDispatchFee() + detailDto.getUnitPrice()); case 6 -> orderDto.setStartupCost(orderDto.getStartupCost() + detailDto.getUnitPrice()); } } @@ -600,7 +608,152 @@ public class WxPayServiceImpl implements WxPayService { @Override public ResRefundOrderInfo queryRefundApplyOrderById(String orderId) { - return null; + Map recDetail = ebikePaymentService.getOrderDetail(orderId); + if (recDetail == null) { + log.error("{} 订单不存在", orderId); + return null; + } + + ResRefundOrderInfo orderInfo = new ResRefundOrderInfo(); + // 订单信息 + OrderInfo order = new OrderInfo(); + BeanUtils.copyProperties(recDetail, order); + + // 用户信息 + UserInfo userInfo = new UserInfo(); + BeanUtils.copyProperties(recDetail, orderInfo); + orderInfo.setUserInfo(userInfo); + // 车辆基本信息 + EbikeBikeBaseInfo bike = null; + JsonResult bikeInfo = maintenanceFeignClient.getBikeBaseInfoByCode(order.getBikeCode()); + if (bikeInfo.getCode() == Code.SUCCESS) { + bike = JSON.parseObject(JSONObject.toJSONString(bikeInfo.getData()), EbikeBikeBaseInfo.class); + }else { + log.error("获取车辆基本信息失败,车辆编码: {}", order.getBikeCode()); + } + + // 借用信息 + BorrowingInfo borrowingInfo = new BorrowingInfo(); + BeanUtils.copyProperties(recDetail, borrowingInfo); + Double[] borrowLocation = getBikeLocation(borrowingInfo.getBorrowCarCoordinate()); + if (bike != null) { + if (borrowLocation != null) { + ReqEbikeSiteQuery siteQuery = new ReqEbikeSiteQuery(); + siteQuery.setLatitude(borrowLocation[0]); + siteQuery.setLongitude(borrowLocation[1]); + siteQuery.setAreaId(Long.parseLong(bike.getReginId())); + JsonResult siteInfo = operateFeignClient.querySite(siteQuery); + if (siteInfo.getCode() == Code.SUCCESS) { + EbikeSiteInfo site = JSON.parseObject(JSONObject.toJSONString(siteInfo.getData()), EbikeSiteInfo.class); + borrowingInfo.setBorrowSite(site.getSiteName()); + }else { + log.error("获取车辆骑行站点信息失败,订单编号: {}", orderId); + } + } + } + // 借车地址 + if(borrowLocation != null){ + JSONObject location = new JSONObject(); + location.put("lng", borrowLocation[0]); + location.put("lat", borrowLocation[1]); + JSONObject address = geoCodingUtil.getLocationToAddress(location); + if(address!= null){ + borrowingInfo.setBorrowAddress(address.getString("detail")); + order.setStartRegion(address.getString("district")); + } + } + orderInfo.setBorrowingInfo(borrowingInfo); + // 还车信息 + ReturnInfo returnInfo = new ReturnInfo(); + BeanUtils.copyProperties(recDetail, returnInfo); + Double[] returnLocation = getBikeLocation(returnInfo.getReturnCarCoordinate()); + if (bike != null) { + if (returnLocation != null) { + ReqEbikeSiteQuery siteQuery = new ReqEbikeSiteQuery(); + siteQuery.setLatitude(returnLocation[0]); + siteQuery.setLongitude(returnLocation[1]); + siteQuery.setAreaId(Long.parseLong(bike.getReginId())); + JsonResult siteInfo = operateFeignClient.querySite(siteQuery); + if (siteInfo.getCode() == Code.SUCCESS) { + EbikeSiteInfo site = JSON.parseObject(JSONObject.toJSONString(siteInfo.getData()), EbikeSiteInfo.class); + returnInfo.setReturnSite(site.getSiteName()); + }else { + log.error("获取车辆还车站点信息失败,订单编号: {}", orderId); + } + } + } + // 还车地址 + if(returnLocation != null){ + JSONObject location = new JSONObject(); + location.put("lng", returnLocation[0]); + location.put("lat", returnLocation[1]); + JSONObject address = geoCodingUtil.getLocationToAddress(location); + if(address!= null){ + returnInfo.setReturnAddress(address.getString("detail")); + order.setEndRegion(address.getString("district")); + } + } + // 骑行时长 + if (order.getUnLockTime() != null && order.getLockTime() != null) { + order.setCyclingDuration(String.valueOf(Duration.between(order.getUnLockTime(), order.getLockTime()).toMinutes())); + } + // 轨迹里程 + if (order.getUnLockTime() != null && order.getLockTime() != null&& order.getBikeCode()!=null) { + ReqEbikeTrackingDto trackingDto = new ReqEbikeTrackingDto(); + trackingDto.setEbikeCode(order.getBikeCode()); + trackingDto.setStartTime(order.getUnLockTime()); + trackingDto.setEndTime(order.getLockTime()); + trackingDto.setInterval("30s"); + JsonResult tracking = operateFeignClient.queryEbikeTracking(trackingDto); + if (tracking.getCode() == Code.SUCCESS) { + List trackingList = JSON.parseArray(JSONObject.toJSONString(tracking.getData()), EbikeTrackingDto.class); + List trackingPoints = new ArrayList<>(trackingList.stream().map(t -> new Double[]{t.getLatitude(), t.getLongitude()}).toList()); + if (borrowLocation!=null){ + trackingPoints.add(0, borrowLocation); + } + if (returnLocation!=null){ + trackingPoints.add(returnLocation); + } + Double distance = CoordinateUtil.calculateTotalDistance(trackingPoints); + if (distance > 1000) { + order.setTrajectoryMileage(String.format("%.3f公里", distance)); + }else { + order.setTrajectoryMileage(String.format("%d米", Math.round(distance))); + } + }else { + log.error("获取车辆轨迹信息失败,订单编号: {}", orderId); + } + + } + orderInfo.setOrderInfo(order); + orderInfo.setReturnInfo(returnInfo); + + // 支付信息 + PayInfo payInfo = new PayInfo(); + BeanUtils.copyProperties(recDetail, payInfo); + orderInfo.setPayInfo(payInfo); + // 支付详情 + OrderDetailInfo detailInfo = new OrderDetailInfo(); + BeanUtils.copyProperties(recDetail, detailInfo); + detailInfo.setDiscountAmount(detailInfo.getTotalAmount() - detailInfo.getActualAmount()); + //查询订单, orderFeingClient.getOrderById(orderId) + JsonResult result = ordersFeignClient.getPaymentDetails(Long.valueOf(orderId)); + if (result.getCode() != 200) { + EbikePaymentDto paymentDto = JSON.parseObject(JSONObject.toJSONString(result.getData()), EbikePaymentDto.class); + for (PayDetailDto detailDto : paymentDto.getDetail().getGoodsDetail()) { + //1-骑行时长费 2-运营区调度费用 3-停车区调度费用 4-高峰时段出行费用 5-高峰日出行费用 6-起步费用 + switch (detailDto.getItemType()) { + case 1, 4, 5 -> detailInfo.setDurationCost(detailInfo.getDurationCost() + detailDto.getUnitPrice()); + case 2 -> detailInfo.setDispatchFeeOutOperateArea(detailInfo.getParkingAreaOutDispatchFee() + detailDto.getUnitPrice()); + case 3 -> detailInfo.setParkingAreaOutDispatchFee(detailInfo.getParkingAreaOutDispatchFee() + detailDto.getUnitPrice()); + case 6 -> detailInfo.setStartupCost(detailInfo.getStartupCost() + detailDto.getUnitPrice()); + } + } + } + + orderInfo.setOrderDetailInfo(detailInfo); + + return orderInfo; } @Override @@ -609,6 +762,21 @@ public class WxPayServiceImpl implements WxPayService { return null; } + + /** + * 获取车辆经纬度 + * + * @param coordinate 坐标 + * @return 经纬度 + */ + private Double[] getBikeLocation(String coordinate){ + String[] split = coordinate.split(","); + if (split.length == 2) { + return new Double[]{Double.valueOf(split[0]), Double.valueOf(split[1])}; + } + return null; + } + /** * 打印日志 * diff --git a/ebike-payment/src/main/java/com/cdzy/payment/utils/GeoCodingUtil.java b/ebike-payment/src/main/java/com/cdzy/payment/utils/GeoCodingUtil.java new file mode 100644 index 00000000..4bfdf140 --- /dev/null +++ b/ebike-payment/src/main/java/com/cdzy/payment/utils/GeoCodingUtil.java @@ -0,0 +1,121 @@ +package com.cdzy.payment.utils; + +import com.alibaba.fastjson2.JSONObject; +import lombok.extern.slf4j.Slf4j; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.springframework.stereotype.Service; + +import java.util.Arrays; + +/** + * 地址解析、反解析工具类。 + * + * @author dingchao + * @date 2025/4/3 + * @modified by: + */ +@Slf4j +@Service +public class GeoCodingUtil { + private final static String LOCATION_TO_ADDRESS = "location"; + private final static String ADDRESS_TO_LOCATION = "address"; + + private final String url; + private final String accessKey; + private final OkHttpClient client; + + /** + * 地理编码工具类构造函数。 + * 目前实现的腾讯地图webservice + * + * @param apiUrl + * @param accessKey + */ + public GeoCodingUtil(String apiUrl, String accessKey) { + this.url = apiUrl; + this.accessKey = accessKey; + this.client = new OkHttpClient(); + } + + /** + * 输入经纬度,返回地址。 + * + * @param location 经纬度 + * @return 地址 + */ + public JSONObject getLocationToAddress(JSONObject location) { + Request request = new Request.Builder() + .url(url + "/?"+LOCATION_TO_ADDRESS+"=" + String.format("%f,%f", location.getDouble("lat"), location.getDouble("lng")) + "&key=" + accessKey) + .build(); + try(Response response = client.newCall(request).execute()) { + if(response.isSuccessful()) { + if (response.body()!= null) { + String result = response.body().string(); + JSONObject jsonObject = JSONObject.parseObject(result); + if (jsonObject.getInteger("status") == 0) { + JSONObject address = new JSONObject(); + String detail = jsonObject.getJSONObject("result").getJSONObject("formatted_addresses").getString("standard_address"); + address.put("detail", detail); + String district = jsonObject.getJSONObject("result").getJSONObject("ad_info").getString("district"); + address.put("district", district); + String adcode = jsonObject.getJSONObject("result").getJSONObject("ad_info").getString("adcode"); + address.put("adcode", adcode); + return address; + } + logError("地址解析失败==>{}", jsonObject.getString("message")); + return null; + } + logError("地址解析失败==>{}", response.message()); + return null; + } + logError("地址解析失败==>{}", response.message()); + return null; + } catch (Exception e) { + logError("地址解析失败==>{}", e.getMessage() + Arrays.toString(e.getStackTrace())); + return null; + } + } + + + /** + * 输入地址,返回经纬度(GCJ02)。 + * + * @param address 地址 + * @return 经纬度 + */ + public JSONObject getAddressToLocation(String address) { + Request request = new Request.Builder() + .url(url + "/?"+ADDRESS_TO_LOCATION+"=" + address + "&key=" + accessKey) + .build(); + try(Response response = client.newCall(request).execute()) { + if(response.isSuccessful()) { + if (response.body() != null) { + String result = response.body().string(); + JSONObject jsonObject = JSONObject.parseObject(result); + if (jsonObject.getInteger("status") == 0) { + return jsonObject.getJSONObject("result").getJSONObject("location"); + }else{ + logError("位置解析失败==>{}", jsonObject.getString("message")); + return null; + } + }else{ + logError("位置解析失败==>{}", response.message()); + return null; + } + }else{ + logError("位置解析失败==>{}", response.message()); + return null; + } + } catch (Exception e) { + logError("位置解析失败==>{}", e.getMessage() + Arrays.toString(e.getStackTrace())); + return null; + } + } + + + private void logError(String errDesc, String errorMessage) { + log.error(errDesc, errorMessage); + } +} diff --git a/ebike-payment/src/main/resources/application-dev.yml b/ebike-payment/src/main/resources/application-dev.yml index 406c966e..ba14885a 100644 --- a/ebike-payment/src/main/resources/application-dev.yml +++ b/ebike-payment/src/main/resources/application-dev.yml @@ -31,6 +31,22 @@ spring: max-lifetime: 1800000 mybatis-flex: mapper-locations: classpath:mapper/*.xml +sa-token: + # token 名称(同时也是 cookie 名称) + token-name: Authorization + # token 有效期(单位:秒) 默认30天,-1 代表永久有效 + timeout: 2592000 + # token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结 + active-timeout: -1 + # 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录) + is-concurrent: true + # 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token) + is-share: true + # token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik) + token-style: random-32 + # 是否输出操作日志 + is-log: true + payment: wx-pay: app-id: wx327d788d7bd6eddf @@ -50,18 +66,6 @@ task-scheduler-pool: threadNamePrefix: task-scheduled- waitForTasksToCompleteOnShutdown: true awaitTerminationSeconds: 30 -sa-token: - # token 名称(同时也是 cookie 名称) - token-name: Authorization - # token 有效期(单位:秒) 默认30天,-1 代表永久有效 - timeout: 2592000 - # token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结 - active-timeout: -1 - # 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录) - is-concurrent: true - # 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token) - is-share: true - # token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik) - token-style: random-32 - # 是否输出操作日志 - is-log: true \ No newline at end of file +geo-coding: + api-url: https://apis.map.qq.com/ws/geocoder/v1 + access-key: BECBZ-EJIEQ-LUU5N-B5ISQ-3TLMZ-BXFLG \ No newline at end of file