add:实现计价功能功能

master
msb_89821 2 years ago
parent 4cb15bf386
commit abeb57e19a

@ -3,6 +3,9 @@ package com.mashibing.sendserver;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication @SpringBootApplication
@EnableDiscoveryClient @EnableDiscoveryClient

@ -32,6 +32,24 @@
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>
3.3.2
</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
<plugins> <plugins>

@ -2,6 +2,9 @@ package com.mashibing.service.map;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
/** /**
* Copyright© 2020.10.20 by .All rights reserved. * Copyright© 2020.10.20 by .All rights reserved.
@ -17,8 +20,14 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
* <br><b>Date:</b> 2022/10/22 16:32 * <br><b>Date:</b> 2022/10/22 16:32
*/ */
@SpringBootApplication @SpringBootApplication
@EnableDiscoveryClient
public class ServiceMapApplication { public class ServiceMapApplication {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(ServiceMapApplication.class,args); SpringApplication.run(ServiceMapApplication.class,args);
} }
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
} }

@ -1,10 +1,16 @@
package com.mashibing.service.map.service; package com.mashibing.service.map.service;
import com.alibaba.fastjson.JSON; import com.mashibing.constant.AmapConfigConstants;
import com.mashibing.dto.AddressLatiLong; import com.mashibing.dto.AddressLatiLong;
import com.mashibing.dto.DistanceResult; import com.mashibing.dto.DistanceResult;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
/** /**
* Copyright© 2020.10.20 by .All rights reserved. * Copyright© 2020.10.20 by .All rights reserved.
@ -25,11 +31,73 @@ public class DistanceService {
private static final String reqPath = "/v3/direction/driving"; private static final String reqPath = "/v3/direction/driving";
@Value("${amap.key}")
private String amapKey;
@Value("${amap.url}")
private String url;
@Autowired
private RestTemplate restTemplate;
public DistanceResult queryDistanceResult(AddressLatiLong addressLatiLong){ public DistanceResult queryDistanceResult(AddressLatiLong addressLatiLong){
log.info("调高德服务商获取距离 参数={}", JSON.toJSONString(addressLatiLong)); // 组装请求调用url
StringBuilder urlBuild = new StringBuilder();
urlBuild.append(url+reqPath);
urlBuild.append("?");
urlBuild.append("origin="+addressLatiLong.getOriginLong()+","+addressLatiLong.getOriginLati());
urlBuild.append("&");
urlBuild.append("destination="+addressLatiLong.getDestinationLong()+","+addressLatiLong.getDestinationLati());
urlBuild.append("&");
urlBuild.append("extensions=base");
urlBuild.append("&");
urlBuild.append("output=json");
urlBuild.append("&");
urlBuild.append("key="+amapKey);
log.info(urlBuild.toString());
// 调用高德接口
log.info("高德地图:路径规划,请求信息:"+urlBuild.toString());
ResponseEntity<String> directionEntity = restTemplate.getForEntity(urlBuild.toString(), String.class);
String directionString = directionEntity.getBody();
log.info("高德地图:路径规划,返回信息:"+directionString);
// 解析接口
DistanceResult directionResponse = parseDirectionEntity(directionString);
return directionResponse;
}
private DistanceResult parseDirectionEntity(String directionString){
DistanceResult directionResponse = null;
try {
// 最外层
JSONObject result = JSONObject.fromObject(directionString);
if(result.has(AmapConfigConstants.STATUS)) {
int status = result.getInt(AmapConfigConstants.STATUS);
if (status == 1){
if (result.has(AmapConfigConstants.ROUTE)){
JSONObject routeObject = result.getJSONObject(AmapConfigConstants.ROUTE);
JSONArray pathsArray = routeObject.getJSONArray(AmapConfigConstants.PATHS);
JSONObject pathObject = pathsArray.getJSONObject(0);
directionResponse = new DistanceResult();
DistanceResult distanceResult =new DistanceResult(); if (pathObject.has(AmapConfigConstants.DISTANCE)){
int distance = pathObject.getInt(AmapConfigConstants.DISTANCE);
directionResponse.setDistance(distance);
}
if (pathObject.has(AmapConfigConstants.DURATION)){
int duration = pathObject.getInt(AmapConfigConstants.DURATION);
directionResponse.setDuration(duration);
}
}
}
}
}catch (Exception e){
return distanceResult;
} }
return directionResponse;
}
} }

@ -9,8 +9,13 @@ spring:
server-addr: 127.0.0.1:8848 server-addr: 127.0.0.1:8848
application: application:
name: service-map name: service-map
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://10.2.23.46:3306/service-map?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true
username: root
password: 1qaz@WSX
gaodeMap: amap:
key: 595148d3d09d60942adaaacf7dfb95aa key: 595148d3d09d60942adaaacf7dfb95aa
url: https://restapi.amap.com url: https://restapi.amap.com

@ -32,6 +32,22 @@
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>
3.3.2
</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>
<plugins> <plugins>

@ -2,6 +2,10 @@ package com.mashibing.service.price;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
/** /**
* Copyright© 2020.10.20 by .All rights reserved. * Copyright© 2020.10.20 by .All rights reserved.
@ -17,9 +21,18 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
* <br><b>Date:</b> 2022/10/22 11:30 * <br><b>Date:</b> 2022/10/22 11:30
*/ */
@SpringBootApplication @SpringBootApplication
@EnableDiscoveryClient
public class ServicePriceApplication { public class ServicePriceApplication {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(ServicePriceApplication.class, args); SpringApplication.run(ServicePriceApplication.class, args);
} }
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
} }

@ -0,0 +1,28 @@
package com.mashibing.service.price.feign;
import com.mashibing.dto.AddressLatiLong;
import com.mashibing.dto.DistanceResult;
import com.mashibing.dto.ResponseResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* Copyright© 2020.10.20 by .All rights reserved.
* 1.
* 2.
* 3.使.
*
* @packageName: com.mashibing.service.price.feign
* @description:
* @author: nod
* @create: 2022-10-24
*/
@FeignClient("service-map")
public interface ServiceMapClient {
@RequestMapping(value = "/queryDistanceResult" ,method = RequestMethod.POST)
public ResponseResult<DistanceResult> queryDistanceResult(@RequestBody AddressLatiLong addressLatiLong);
}

@ -0,0 +1,20 @@
package com.mashibing.service.price.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mashibing.dto.PriceRule;
import org.apache.ibatis.annotations.Mapper;
/**
* Copyright© 2020.10.20 by .All rights reserved.
* 1.
* 2.
* 3.使.
*
* @packageName: com.mashibing.service.price.mapper
* @description:
* @author: nod
* @create: 2022-10-24
*/
@Mapper
public interface PriceRuleMapper extends BaseMapper<PriceRule> {
}

@ -0,0 +1,133 @@
package com.mashibing.service.price.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.mashibing.constant.CommonStatusEnum;
import com.mashibing.dto.AddressLatiLong;
import com.mashibing.dto.DistanceResult;
import com.mashibing.dto.PriceRule;
import com.mashibing.dto.ResponseResult;
import com.mashibing.response.ForecastPriceResponse;
import com.mashibing.service.price.feign.ServiceMapClient;
import com.mashibing.service.price.mapper.PriceRuleMapper;
import com.mashibing.util.BigDecimalUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
@Service
@Slf4j
public class ForecastPriceService {
@Resource
private ServiceMapClient serviceMapClient;
@Resource
private PriceRuleMapper priceRuleMapper;
public ResponseResult forecastPrice(String depLongitude, String depLatitude, String destLongitude, String destLatitude,
String cityCode, String vehicleType){
log.info("出发地经度:"+depLongitude);
log.info("出发地纬度:"+depLatitude);
log.info("目的地经度:"+destLongitude);
log.info("目的地纬度:"+destLatitude);
log.info("调用地图服务,查询距离和时长");
AddressLatiLong forecastPriceDTO = new AddressLatiLong();
forecastPriceDTO.setDestinationLong(depLongitude);
forecastPriceDTO.setDestinationLati(depLatitude);
forecastPriceDTO.setOriginLong(destLongitude);
forecastPriceDTO.setOriginLati(destLatitude);
ResponseResult<DistanceResult> direction = serviceMapClient.queryDistanceResult(forecastPriceDTO);
Integer distance = direction.getData().getDistance();
Integer duration = direction.getData().getDuration();
log.info(("距离:"+distance+",时长:"+duration));
log.info("读取计价规则");
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("city_code",cityCode);
queryWrapper.eq("vehicle_type",vehicleType);
queryWrapper.orderByDesc("fare_version");
List<PriceRule> priceRules = priceRuleMapper.selectList(queryWrapper);
if (priceRules.size() == 0){
return ResponseResult.fail(CommonStatusEnum.PRICE_RULE_EMPTY.getCode(),CommonStatusEnum.PRICE_RULE_EMPTY.getMessage());
}
PriceRule priceRule = priceRules.get(0);
log.info("根据距离、时长和计价规则,计算价格");
double price = getPrice(distance, duration, priceRule);
ForecastPriceResponse forecastPriceResponse = new ForecastPriceResponse();
forecastPriceResponse.setPrice(price);
forecastPriceResponse.setCityCode(cityCode);
forecastPriceResponse.setVehicleType(vehicleType);
forecastPriceResponse.setFareType(priceRule.getFareType());
forecastPriceResponse.setFareVersion(priceRule.getFareVersion());
return ResponseResult.success(forecastPriceResponse);
}
/**
*
* @param distance
* @param duration
* @param priceRule
* @return
*/
private double getPrice(Integer distance , Integer duration,PriceRule priceRule){
double price = 0;
// 起步价
double startFare = priceRule.getStartFare();
price = BigDecimalUtils.add(price,startFare);
// 里程费
// 总里程 m
double distanceMile = BigDecimalUtils.divide(distance,1000);
// 起步里程
double startMile = (double)priceRule.getStartMile();
double distanceSubtract = BigDecimalUtils.substract(distanceMile,startMile);
// 最终收费的里程数 km
double mile = distanceSubtract<0?0:distanceSubtract;
// 计程单价 元/km
double unitPricePerMile = priceRule.getUnitPricePerMile();
// 里程价格
double mileFare = BigDecimalUtils.multiply(mile,unitPricePerMile);
price = BigDecimalUtils.add(price,mileFare);
// 时长费
// 时长的分钟数
double timeMinute = BigDecimalUtils.divide(duration,60);
// 计时单价
double unitPricePerMinute = priceRule.getUnitPricePerMinute();
// 时长费用
double timeFare = BigDecimalUtils.multiply(timeMinute,unitPricePerMinute);
price = BigDecimalUtils.add(price,timeFare);
BigDecimal priceBigDecimal = new BigDecimal(price);
priceBigDecimal = priceBigDecimal.setScale(2,BigDecimal.ROUND_HALF_UP);
return priceBigDecimal.doubleValue();
}
// public static void main(String[] args) {
// PriceRule priceRule = new PriceRule();
// priceRule.setUnitPricePerMile(1.8);
// priceRule.setUnitPricePerMinute(0.5);
// priceRule.setStartFare(10.0);
// priceRule.setStartMile(3);
//
// System.out.println(getPrice(6500,1800,priceRule));
// }
}

@ -0,0 +1,62 @@
package com.mashibing.constant;
public class AmapConfigConstants {
/**
*
*/
public static final String DIRECTION_URL = "https://restapi.amap.com/v3/direction/driving";
/**
*
*/
public static final String DISTRICT_URL = "https://restapi.amap.com/v3/config/district";
/**
*
*/
public static final String SERVICE_ADD_URL = "https://tsapi.amap.com/v1/track/service/add";
/**
*
*/
public static final String TERMINAL_ADD = "https://tsapi.amap.com/v1/track/terminal/add";
/**
*
*/
public static final String TRACK_ADD = "https://tsapi.amap.com/v1/track/trace/add";
/**
*
*/
public static final String POINT_UPLOAD = "https://tsapi.amap.com/v1/track/point/upload";
/**
*
*/
public static final String TERMINAL_AROUNDSEARCH = "https://tsapi.amap.com/v1/track/terminal/aroundsearch";
/**
* json key
*/
public static final String STATUS = "status";
public static final String ROUTE = "route";
public static final String PATHS = "paths";
public static final String DISTANCE = "distance";
public static final String DURATION = "duration";
public static final String DISTRICTS = "districts";
public static final String ADCODE = "adcode";
public static final String NAME = "name";
public static final String LEVEL = "level";
public static final String STREET = "street";
}

@ -5,9 +5,75 @@ import lombok.Getter;
public enum CommonStatusEnum { public enum CommonStatusEnum {
/**
* 1000-1099
*/
VERIFICATION_CODE_ERROR(1099,"验证码不正确"),
/**
* Token1100-1199
*/
TOKEN_ERROR(1199,"token错误"),
/**
* 1200-1299
*/
USER_NOT_EXISTS(1200,"当前用户不存在"),
/**
* :1300-1399
*/
PRICE_RULE_EMPTY(1300,"计价规则不存在"),
PRICE_RULE_EXISTS(1301,"计价规则已存在,不允许添加"),
PRICE_RULE_NOT_EDIT(1302,"计价规则没有变化"),
PRICE_RULE_CHANGED(1303,"计价规则有变化"),
/**
* 1400-1499
*/
MAP_DISTRICT_ERROR(1400,"请求地图错误"),
/**
* 1500-1599
*/
DRIVER_CAR_BIND_NOT_EXISTS(1500,"司机和车辆绑定关系不存在"),
DRIVER_NOT_EXITST(1501,"司机不存在"),
DRIVER_CAR_BIND_EXISTS(1502,"司机和车辆绑定关系已存在,请勿重复绑定"),
DRIVER_BIND_EXISTS(1503,"司机已经被绑定了,请勿重复绑定"),
CAR_BIND_EXISTS(1504,"车辆已经被绑定了,请勿重复绑定"),
CITY_DRIVER_EMPTY(1505,"当前城市没有可用的司机"),
AVAILABLE_DRIVER_EMPTY(1506,"可用的司机为空"),
/**
* 1600-1699
*/
ORDER_GOING_ON(1600,"有正在进行的订单"),
/**
*
*/
DEVICE_IS_BLACK(1601,"该设备超过下单次数"),
CITY_SERVICE_NOT_SERVICE(1602,"当前城市不提供叫车服务"),
SUCCESS(1,"SUCCESS"), SUCCESS(1,"SUCCESS"),
FAIL(0,"FAIL"); FAIL(0,"FAIL");
@Getter @Getter
private int code; private int code;
@Getter @Getter

@ -21,8 +21,8 @@ public class DistanceResult {
private Integer distance; private Integer distance;
private Integer duration; private Integer duration;
public DistanceResult(Integer distance, Integer duration) { // public DistanceResult(Integer distance, Integer duration) {
this.distance = distance; // this.distance = distance;
this.duration = duration; // this.duration = duration;
} // }
} }

@ -0,0 +1,60 @@
package com.mashibing.dto;
import lombok.Data;
import java.io.Serializable;
/**
* <p>
*
* </p>
*
* @author cpf
* @since 2022-10-11
*/
@Data
public class PriceRule implements Serializable {
private static final long serialVersionUID = 1L;
/**
*
*/
private String cityCode;
/**
*
*/
private String vehicleType;
/**
*
*/
private Double startFare;
/**
*
*/
private Integer startMile;
/**
*
*/
private Double unitPricePerMile;
/**
*
*/
private Double unitPricePerMinute;
/**
* 1
*/
private Integer fareVersion;
/**
*
*/
private String fareType;
}

@ -0,0 +1,17 @@
package com.mashibing.response;
import lombok.Data;
@Data
public class ForecastPriceResponse {
private double price;
private String cityCode;
private String vehicleType;
private String fareType;
private Integer fareVersion;
}

@ -0,0 +1,59 @@
package com.mashibing.util;
import java.math.BigDecimal;
public class BigDecimalUtils {
/**
*
* @param v1
* @param v2
* @return
*/
public static double add(double v1 , double v2){
BigDecimal b1 = BigDecimal.valueOf(v1);
BigDecimal b2 = BigDecimal.valueOf(v2);
return b1.add(b2).doubleValue();
}
/**
*
* @param v1
* @param v2
* @return
*/
public static double substract(double v1,double v2){
BigDecimal b1 = BigDecimal.valueOf(v1);
BigDecimal b2 = BigDecimal.valueOf(v2);
return b1.subtract(b2).doubleValue();
}
/**
*
* @param v1
* @param v2
* @return
*/
public static double multiply(double v1,double v2){
BigDecimal b1 = BigDecimal.valueOf(v1);
BigDecimal b2 = BigDecimal.valueOf(v2);
return b1.multiply(b2).doubleValue();
}
/**
*
* @param v1
* @param v2
* @return
*/
public static double divide(int v1, int v2){
if (v2 <= 0){
throw new IllegalArgumentException("除数非法");
}
BigDecimal b1 = BigDecimal.valueOf(v1);
BigDecimal b2 = BigDecimal.valueOf(v2);
return b1.divide(b2,2,BigDecimal.ROUND_HALF_UP).doubleValue();
}
}
Loading…
Cancel
Save