|
@@ -0,0 +1,249 @@
|
|
|
+package com.jkcredit.location.service.impl;
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.alibaba.fastjson.JSONArray;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.fasterxml.jackson.core.JsonProcessingException;
|
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
+import com.jkcredit.location.constant.CommonConstant;
|
|
|
+import com.jkcredit.location.enums.DigestALGEnum;
|
|
|
+import com.jkcredit.location.model.CommonResponseObject;
|
|
|
+import com.jkcredit.location.model.HistoryLocationRequestObject;
|
|
|
+import com.jkcredit.location.model.HistoryLocationResponseObject;
|
|
|
+import com.jkcredit.location.service.LocationService;
|
|
|
+import com.jkcredit.location.util.ApiDigestUtil;
|
|
|
+import com.jkcredit.location.util.RxUtil;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import okhttp3.*;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.apache.commons.lang3.time.DateUtils;
|
|
|
+import org.apache.commons.logging.Log;
|
|
|
+import org.apache.commons.logging.LogFactory;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
+import org.springframework.data.redis.core.StringRedisTemplate;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import javax.servlet.http.HttpServletRequest;
|
|
|
+import java.io.IOException;
|
|
|
+import java.text.ParseException;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.util.*;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+import java.util.regex.Pattern;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @author xusonglin
|
|
|
+ * @version V1.0
|
|
|
+ **/
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+public class LocationServiceImpl implements LocationService {
|
|
|
+ @Value("${supplier.uid}")
|
|
|
+ private String uid;
|
|
|
+ @Value("${supplier.key}")
|
|
|
+ private String key;
|
|
|
+ @Value("${supplier.vehicleTrajectoryQueryOneUrl}")
|
|
|
+ private String vehicleTrajectoryQueryOneUrl;
|
|
|
+
|
|
|
+ private OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
|
|
|
+ private static final Log CLIENT_CHARGE_LOGGER = LogFactory.getLog("CLIENT_CHARGE_LOGGER");
|
|
|
+ private static final Log ORIGINAL_CHARGE_LOGGER = LogFactory.getLog("ORIGINAL_CHARGE_LOGGER");
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ObjectMapper objectMapper;
|
|
|
+ @Autowired
|
|
|
+ StringRedisTemplate stringRedisTemplate;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public CommonResponseObject historyLocationQuery(String params, HttpServletRequest request) {
|
|
|
+ CommonResponseObject responseObject = new CommonResponseObject();
|
|
|
+ String username = request.getAttribute("username").toString();
|
|
|
+ String transationId = request.getAttribute("transationId").toString();
|
|
|
+ log.info("transationId:{};requestParams:{};user:{}", transationId, params, username);
|
|
|
+ responseObject.setTransationId(transationId);
|
|
|
+ HistoryLocationRequestObject requestObject = JSON.toJavaObject(JSON.parseObject(params),
|
|
|
+ HistoryLocationRequestObject.class);
|
|
|
+ responseObject.setAccessId(requestObject.getAccessId());
|
|
|
+ request.setAttribute("accessId", requestObject.getAccessId());
|
|
|
+ // 参数校验
|
|
|
+ if (!validateRequestParams(responseObject, requestObject)) {
|
|
|
+ return responseObject;
|
|
|
+ }
|
|
|
+ //生成签名
|
|
|
+ Map<String, String> map = new HashMap<>();
|
|
|
+ map.put("vclN", requestObject.getCustomBody().getPlateNum());
|
|
|
+ map.put("qryTm", requestObject.getCustomBody().getTime());
|
|
|
+ map.put("uid", uid);
|
|
|
+ String sign = ApiDigestUtil.execute(map, key, DigestALGEnum.MD5, "UTF-8");
|
|
|
+ map.put("sign", sign);
|
|
|
+ MediaType mediaType = MediaType.parse(org.springframework.http.MediaType.APPLICATION_JSON_UTF8_VALUE);
|
|
|
+ String jsonStr = JSON.toJSONString(map);
|
|
|
+ log.info("transationId:{}, requestOriginalParam:{}", transationId, jsonStr);
|
|
|
+ RequestBody requestBody = RequestBody.create(mediaType, jsonStr);
|
|
|
+ Request okRequest = new Request.Builder().post(requestBody).url(vehicleTrajectoryQueryOneUrl).build();
|
|
|
+ OkHttpClient client = okHttpClient.newBuilder()
|
|
|
+ .sslSocketFactory(RxUtil.createSSLSocketFactory(), new RxUtil.TrustAllManager())
|
|
|
+ .connectTimeout(1500, TimeUnit.MILLISECONDS)
|
|
|
+ .readTimeout(5000, TimeUnit.MILLISECONDS)
|
|
|
+ .writeTimeout(5000, TimeUnit.MILLISECONDS)
|
|
|
+ .build();
|
|
|
+ String responseContext = "";
|
|
|
+ try {
|
|
|
+ Long startTime = System.currentTimeMillis();
|
|
|
+ Response response = client.newCall(okRequest).execute();
|
|
|
+ responseContext = response.body().string();
|
|
|
+ JSONObject responseJson = JSON.parseObject(responseContext);
|
|
|
+ responseJson.remove("data");
|
|
|
+ log.info("transationId:{}, response:{}, costTime:{}", transationId, JSON.toJSONString(responseJson),
|
|
|
+ (System.currentTimeMillis() - startTime));
|
|
|
+ response.close();
|
|
|
+ } catch (IOException ioe) {
|
|
|
+ ioe.printStackTrace();
|
|
|
+ log.error("transationId:{}, exception:{}", transationId, ioe.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ HistoryLocationResponseObject historyLocationResponseObject = objectMapper.readValue(responseContext,
|
|
|
+ HistoryLocationResponseObject.class);
|
|
|
+ if (responseObject != null) {
|
|
|
+ setCarHistoricalTrajectoryResponse(responseObject, historyLocationResponseObject);
|
|
|
+ if (responseObject.getResultCode() == CommonConstant.JK_RETURN_CODE_MATCH) {
|
|
|
+ chargeHandle(requestObject, username, transationId);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ responseObject.setResultCode(CommonConstant.JK_RETURN_CODE_OTHER_ERROR);
|
|
|
+ responseObject.setResultBody(CommonConstant.OTHER_ERROR);
|
|
|
+ }
|
|
|
+ } catch (JsonProcessingException e) {
|
|
|
+ log.error("transationId:{}, exception:{}", transationId, e.getMessage());
|
|
|
+ responseObject.setResultCode(CommonConstant.JK_RETURN_CODE_OTHER_ERROR);
|
|
|
+ responseObject.setResultBody(CommonConstant.OTHER_ERROR);
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("transationId:{}, exception:{}", transationId, e.getMessage());
|
|
|
+ responseObject.setResultCode(CommonConstant.JK_RETURN_CODE_OTHER_ERROR);
|
|
|
+ responseObject.setResultBody(CommonConstant.OTHER_ERROR);
|
|
|
+ }
|
|
|
+ return responseObject;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void chargeHandle(HistoryLocationRequestObject requestObject, String username, String transactionId) throws ParseException {
|
|
|
+ boolean isCharge = true;
|
|
|
+ int monthCount = CommonConstant.CUSTOM_MONTH_LIMIT;
|
|
|
+ SimpleDateFormat monthSdf = new SimpleDateFormat("yyyyMM");
|
|
|
+ SimpleDateFormat daySdf = new SimpleDateFormat("yyyyMMdd");
|
|
|
+ Date current = new Date();
|
|
|
+ // 当前月
|
|
|
+ String monthTime = monthSdf.format(current.getTime());
|
|
|
+ // 当天
|
|
|
+ String dayTime = daySdf.format(current.getTime());
|
|
|
+ // 入参中的查询日期
|
|
|
+ Date queryTime = DateUtils.parseDate(requestObject.getCustomBody().getTime(), CommonConstant.DATE_FORMAT);
|
|
|
+ String queryMonth = monthSdf.format(queryTime);
|
|
|
+ // 判断客户是否计费
|
|
|
+ // 判断 车牌号+待查询时间 在自然月内重复请求是否超过 包月标志位(相同车牌和相同时间参数,一个自然月内最多收 包月标志位 次)
|
|
|
+ long redisMonthCount = stringRedisTemplate.boundHashOps(CommonConstant.MONTH_CHARGE_COUNT)
|
|
|
+ .increment(username + "_" + requestObject.getCustomBody().getPlateNum() + "_" + queryMonth, 1);
|
|
|
+ if (redisMonthCount == 1) {
|
|
|
+ Calendar cal = Calendar.getInstance();
|
|
|
+ cal.setTime(current);
|
|
|
+ int lastDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
|
|
|
+ cal.set(Calendar.DAY_OF_MONTH, lastDay);
|
|
|
+ cal.set(Calendar.HOUR_OF_DAY, 23);
|
|
|
+ cal.set(Calendar.MINUTE, 59);
|
|
|
+ cal.set(Calendar.SECOND, 59);
|
|
|
+ stringRedisTemplate.boundHashOps(CommonConstant.MONTH_CHARGE_COUNT).expireAt(cal.getTime());
|
|
|
+ }
|
|
|
+ if (monthCount != -1 && redisMonthCount > monthCount) {
|
|
|
+ isCharge = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 判断上游是否计费
|
|
|
+ boolean isDataOriginCharge = true;
|
|
|
+ // 判断 车牌号+待查询时间 在自然天内是否重复请求(相同车牌和相同时间参数,当天查询不重复收费)
|
|
|
+ String redisDateKey = requestObject.getCustomBody().getPlateNum() + "_" + queryTime + "_" + dayTime;
|
|
|
+ if (!stringRedisTemplate.boundValueOps(redisDateKey).setIfAbsent("1")) {
|
|
|
+ // 当天相同参数,重复查询,上游不计费
|
|
|
+ isDataOriginCharge = false;
|
|
|
+ } else {
|
|
|
+ stringRedisTemplate.boundValueOps(redisDateKey).expire(1, TimeUnit.DAYS);
|
|
|
+
|
|
|
+ // 判断 车牌号+待查询时间 在自然月内重复请求是否超过10次(相同车牌和相同时间参数,一个自然月内最多收10次)
|
|
|
+ long dataOriginRedisMonthCount = stringRedisTemplate.boundHashOps(CommonConstant.MONTH_CHARGE_COUNT)
|
|
|
+ .increment(requestObject.getCustomBody().getPlateNum() + "_" + queryMonth, 1);
|
|
|
+ if (dataOriginRedisMonthCount == 1) {
|
|
|
+ Calendar cal = Calendar.getInstance();
|
|
|
+ cal.setTime(current);
|
|
|
+ int lastDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
|
|
|
+ cal.set(Calendar.DAY_OF_MONTH, lastDay);
|
|
|
+ cal.set(Calendar.HOUR_OF_DAY, 23);
|
|
|
+ cal.set(Calendar.MINUTE, 59);
|
|
|
+ cal.set(Calendar.SECOND, 59);
|
|
|
+ stringRedisTemplate.boundHashOps(CommonConstant.MONTH_CHARGE_COUNT).expireAt(cal.getTime());
|
|
|
+ }
|
|
|
+ if (dataOriginRedisMonthCount > CommonConstant.ORIGINAL_MONTH_LIMIT) {
|
|
|
+ // 上游不计费
|
|
|
+ isDataOriginCharge = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 上游是否计费标识
|
|
|
+ JSONObject chargeObject = new JSONObject();
|
|
|
+ chargeObject.put("transationId", transactionId);
|
|
|
+ chargeObject.put("isCharge", isDataOriginCharge);
|
|
|
+ ORIGINAL_CHARGE_LOGGER.info(chargeObject.toJSONString());
|
|
|
+
|
|
|
+ chargeObject.put("isCharge", isCharge);
|
|
|
+ chargeObject.put("user", username);
|
|
|
+ CLIENT_CHARGE_LOGGER.info(chargeObject.toJSONString());
|
|
|
+ }
|
|
|
+
|
|
|
+ private CommonResponseObject setCarHistoricalTrajectoryResponse(
|
|
|
+ CommonResponseObject ret, HistoryLocationResponseObject responseObject) {
|
|
|
+ if (responseObject != null
|
|
|
+ && "0000".equals(responseObject.getCode())) {
|
|
|
+ HistoryLocationResponseObject.HistoryLocationResponseInfos responseInfos = responseObject.getData().getInfos().get(0);
|
|
|
+ List<HistoryLocationResponseObject.HistoryLocationResponseDetails> responseDetails = responseInfos.getTrackDetails();
|
|
|
+ // 查询成功,返回结果
|
|
|
+ ret.setResultBody(JSONArray.toJSONString(responseDetails));
|
|
|
+ ret.setResultCode(CommonConstant.JK_RETURN_CODE_MATCH);
|
|
|
+ } else if (responseObject != null
|
|
|
+ && "0001".equals(responseObject.getCode())) {
|
|
|
+ // 查询成功,没有记录
|
|
|
+ ret.setResultCode(CommonConstant.JK_RETURN_CODE_NO_INFO);
|
|
|
+ ret.setResultBody(CommonConstant.RETURN_MESSAGE_60);
|
|
|
+ } else {
|
|
|
+ // 查询错误
|
|
|
+ ret.setResultCode(CommonConstant.JK_RETURN_CODE_OTHER_ERROR);
|
|
|
+ ret.setResultBody(CommonConstant.OTHER_ERROR);
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean validateRequestParams(CommonResponseObject ret,
|
|
|
+ HistoryLocationRequestObject requestObject) {
|
|
|
+ Pattern pattern = Pattern.compile(CommonConstant.DATE_REGEX);
|
|
|
+ Pattern plateNumPattern = Pattern.compile(CommonConstant.CAR_NUMBER_PATTERN);
|
|
|
+ if (StringUtils.isBlank(requestObject.getAccessId())
|
|
|
+ || StringUtils.isBlank(requestObject.getProductId())
|
|
|
+ || requestObject.getCustomBody() == null) {
|
|
|
+ ret.setResultCode(CommonConstant.JK_RETURN_CODE_INVALID_PARAMETER);
|
|
|
+ ret.setResultBody(CommonConstant.INVALID_PARAMETER);
|
|
|
+ return false;
|
|
|
+ } else if (StringUtils.isBlank(requestObject.getCustomBody().getPlateNum())
|
|
|
+ || StringUtils.isBlank(requestObject.getCustomBody().getTime())
|
|
|
+ || !plateNumPattern.matcher(requestObject.getCustomBody().getPlateNum()).matches()
|
|
|
+ || !pattern.matcher(requestObject.getCustomBody().getTime()).matches()) {
|
|
|
+ ret.setResultCode(CommonConstant.JK_RETURN_CODE_INVALID_PARAMETER);
|
|
|
+ ret.setResultBody(CommonConstant.INVALID_PARAMETER);
|
|
|
+ return false;
|
|
|
+ } else if (!requestObject.getProductId().equals(CommonConstant.PRODUCT_ID)) {
|
|
|
+ ret.setResultCode(CommonConstant.JK_RETURN_CODE_INVALID_PARAMETER);
|
|
|
+ ret.setResultBody(CommonConstant.INVALID_PARAMETER);
|
|
|
+ return false;
|
|
|
+ } else {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|