即刻物联

dev
ljw 2026-05-25 13:36:12 +08:00
parent 522233db35
commit e5fbfb5395
16 changed files with 991 additions and 3 deletions

View File

@ -4,6 +4,6 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@Configuration @Configuration
@EnableConfigurationProperties({AppProperties.class, JimiProperties.class}) @EnableConfigurationProperties({AppProperties.class, JimiProperties.class, JikeProperties.class})
public class AppConfiguration { public class AppConfiguration {
} }

View File

@ -0,0 +1,39 @@
package com.njzscloud.supervisory.config;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;
import org.springframework.boot.context.properties.ConfigurationProperties;
@Getter
@Setter
@ToString
@Accessors(chain = true)
@ConfigurationProperties("app.jike")
public class JikeProperties {
/**
* ID
*/
private String appId;
/**
*
*/
private String secretKey;
/**
*
*/
private String sandboxUrl = "https://open-api.test.jkwlw.com.cn";
/**
*
*/
private String prodUrl = "https://open-api.jkwlw.com.cn";
/**
* 使
*/
private Boolean sandbox = true;
public String getEndpoint() {
return Boolean.TRUE.equals(sandbox) ? sandboxUrl : prodUrl;
}
}

View File

@ -12,7 +12,7 @@ import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor @RequiredArgsConstructor
public enum LocalizerCategory implements DictStr { public enum LocalizerCategory implements DictStr {
Tuqiang("Tuqiang", "途强定位器"), Tuqiang("Tuqiang", "途强定位器"),
HangTianZiJin("HangTianZiJin", "航天紫金定位器"), JKWL("JKWL", "即刻物联"),
; ;
private final String val; private final String val;
private final String txt; private final String txt;

View File

@ -1,20 +1,45 @@
package com.njzscloud.supervisory.gps.controller; package com.njzscloud.supervisory.gps.controller;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import com.njzscloud.common.core.utils.R; import com.njzscloud.common.core.utils.R;
import com.njzscloud.supervisory.config.JikeProperties;
import com.njzscloud.supervisory.gps.jike.JikeApiClient;
import com.njzscloud.supervisory.gps.jike.JikeResponse;
import com.njzscloud.supervisory.gps.jike.result.JikeEventResult;
import com.njzscloud.supervisory.gps.jike.result.JikeMediaResult;
import com.njzscloud.supervisory.gps.jike.result.JikeTrackResult;
import com.njzscloud.supervisory.gps.tuqiang.jimi.DeviceLocationGetParam; import com.njzscloud.supervisory.gps.tuqiang.jimi.DeviceLocationGetParam;
import com.njzscloud.supervisory.gps.tuqiang.jimi.DeviceLocationGetResult; import com.njzscloud.supervisory.gps.tuqiang.jimi.DeviceLocationGetResult;
import com.njzscloud.supervisory.gps.tuqiang.jimi.DeviceTrackListParam; import com.njzscloud.supervisory.gps.tuqiang.jimi.DeviceTrackListParam;
import com.njzscloud.supervisory.gps.tuqiang.jimi.DeviceTrackListResult; import com.njzscloud.supervisory.gps.tuqiang.jimi.DeviceTrackListResult;
import com.njzscloud.supervisory.gps.tuqiang.jimi.util.JimiUtil; import com.njzscloud.supervisory.gps.tuqiang.jimi.util.JimiUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/** /**
* GPS * GPS
*/ */
@Slf4j
@RestController @RestController
@RequestMapping("/gps") @RequestMapping("/gps")
public class GPSController { public class GPSController {
@Autowired
private JikeProperties jikeProperties;
/** /**
* *
*/ */
@ -28,7 +53,7 @@ public class GPSController {
} }
/** /**
* *
*/ */
@RequestMapping("/track_list") @RequestMapping("/track_list")
public R<?> trackList(DeviceTrackListParam param) { public R<?> trackList(DeviceTrackListParam param) {
@ -38,4 +63,180 @@ public class GPSController {
} }
return R.failed(); return R.failed();
} }
/**
*
*
* @param imei
* @param stime (: yyyy-MM-dd HH:mm:ss)
* @param etime (: yyyy-MM-dd HH:mm:ss)
* @return {latitude, longitude, direction}
*/
@RequestMapping("/jike_track_list")
public R<?> jikeTrackList(@RequestParam String imei,
@RequestParam String stime,
@RequestParam String etime) {
try {
JikeApiClient client = new JikeApiClient(jikeProperties);
Map<String, String> params = new HashMap<>();
params.put("imei", imei);
params.put("stime", String.valueOf(DateUtil.parse(stime).getTime()));
params.put("etime", String.valueOf(DateUtil.parse(etime).getTime()));
log.info("即刻物联轨迹查询请求: {}", params);
String response = client.doGet("/open-api/gps-trace/list", params);
log.info("即刻物联轨迹查询响应: {}", response);
JikeResponse<List<JikeTrackResult>> result = com.alibaba.fastjson2.JSON.parseObject(
response,
new com.alibaba.fastjson2.TypeReference<JikeResponse<List<JikeTrackResult>>>() {
}
);
if (result.isSuccess()) {
List<TrackPoint> trackPoints = convertToTrackPoints(result.getData());
return R.success(trackPoints);
} else {
log.error("即刻物联轨迹查询失败: " + result.getHeader().getMessage());
return R.failed();
}
} catch (Exception e) {
log.error("即刻物联轨迹查询异常", e);
return R.failed();
}
}
/**
*
*/
private List<TrackPoint> convertToTrackPoints(List<JikeTrackResult> jikeResults) {
if (jikeResults == null || jikeResults.isEmpty()) {
return Collections.emptyList();
}
return jikeResults.stream().map(track -> {
TrackPoint point = new TrackPoint();
// gpsText 格式: "lng,lat"
String gpsText = track.getGpsText();
if (gpsText != null && gpsText.contains(",")) {
String[] parts = gpsText.split(",");
try {
point.setLongitude(Double.parseDouble(parts[0]));
if (parts.length > 1) {
point.setLatitude(Double.parseDouble(parts[1]));
}
} catch (NumberFormatException e) {
log.warn("GPS坐标解析失败: {}", gpsText);
}
}
point.setDirection(track.getDirection() != null ? track.getDirection() : 0);
return point;
}).collect(Collectors.toList());
}
/**
*
*/
@Data
public static class TrackPoint {
private Double latitude;
private Double longitude;
private Integer direction;
}
/**
*
* @param imei
* @param stime (: yyyy-MM-dd HH:mm:ss)
* @param etime (: yyyy-MM-dd HH:mm:ss)
*/
@RequestMapping("/event_list")
public R<?> eventList(@RequestParam String imei,
@RequestParam String stime,
@RequestParam String etime) {
try {
JikeApiClient client = new JikeApiClient(jikeProperties);
Map<String, String> params = new HashMap<>();
params.put("imei", imei);
params.put("eventTypeList", "25840,58648");
params.put("stime", String.valueOf(DateUtil.parse(stime).getTime()));
params.put("etime", String.valueOf(DateUtil.parse(etime).getTime()));
String response = client.doGet("/open-api/v2/event/list", params);
log.info("即刻物联历史报警事件查询响应: {}", response);
JikeResponse<List<JikeEventResult>> result = JSON.parseObject(
response,
new TypeReference<JikeResponse<List<JikeEventResult>>>() {}
);
if (result.isSuccess()) {
List<MediaItem> mediaItems = extractMediaList(result.getData());
return R.success(mediaItems);
} else {
log.error("即刻物联历史报警事件查询失败: " + result.getHeader().getMessage());
return R.failed();
}
} catch (Exception e) {
log.error("即刻物联历史报警事件查询异常", e);
return R.failed();
}
}
/**
* mediaListmediaType
*/
private List<MediaItem> extractMediaList(List<JikeEventResult> events) {
if (events == null || events.isEmpty()) {
return Collections.emptyList();
}
List<MediaItem> allMedia = new ArrayList<>();
for (JikeEventResult event : events) {
if (event.getMediaList() != null) {
for (JikeMediaResult media : event.getMediaList()) {
MediaItem item = new MediaItem();
item.setId(media.getId());
item.setChannel(media.getChannel());
item.setMedia(media.getMedia());
item.setMediaType(media.getMediaType());
item.setMediaTypeText(getMediaTypeText(media.getMediaType()));
allMedia.add(item);
}
}
}
return allMedia;
}
/**
*
* mediaType: -101234
*/
private String getMediaTypeText(Integer mediaType) {
if (mediaType == null) {
return "未知";
}
switch (mediaType) {
case -1: return "未知";
case 0: return "图片";
case 1: return "音频";
case 2: return "视频";
case 3: return "文本";
case 4: return "其它";
default: return "未知";
}
}
/**
*
*/
@Data
public static class MediaItem {
private Long id;
private Integer channel;
private String media;
private Integer mediaType;
private String mediaTypeText;
}
} }

View File

@ -0,0 +1,231 @@
package com.njzscloud.supervisory.gps.jike;
import com.njzscloud.supervisory.config.JikeProperties;
import com.njzscloud.supervisory.gps.jike.support.JikeSignUtil;
import lombok.extern.slf4j.Slf4j;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.TreeMap;
/**
* HTTP
*/
@Slf4j
public class JikeApiClient {
private final JikeProperties properties;
public JikeApiClient(JikeProperties properties) {
this.properties = properties;
}
/**
* GET
* @param uri /open-api/gps-trace/list
* @param queryString carNum=A12345&stime=1746777600000&etime=1746864000000
*/
public String doGet(String uri, String queryString) throws Exception {
String endpoint = properties.getEndpoint();
String url = endpoint + uri;
long timestamp = System.currentTimeMillis();
String appId = properties.getAppId();
String secret = properties.getSecretKey();
// 计算参数签名 - 使用原始值(不编码)
String paramMd5 = JikeSignUtil.buildParamSignature(queryString);
// 计算最终签名 - GET请求不包含body-signature
String finalSign = JikeSignUtil.buildGetFinalSignature(appId, paramMd5, secret, timestamp);
log.info("Jike GET request queryString: {}", queryString);
log.info("Jike param-signature: {}", paramMd5);
log.info("Jike final-signature: {}", finalSign);
// 构建URL参数值需要URL编码
String finalUrl = url;
if (queryString != null && !queryString.isEmpty()) {
StringBuilder encodedUrl = new StringBuilder(url).append("?");
String[] pairs = queryString.split("&");
for (int i = 0; i < pairs.length; i++) {
if (i > 0) {
encodedUrl.append("&");
}
String pair = pairs[i];
int eqIdx = pair.indexOf("=");
if (eqIdx > 0) {
String key = pair.substring(0, eqIdx);
String value = pair.substring(eqIdx + 1);
encodedUrl.append(key).append("=").append(URLEncoder.encode(value, "UTF-8"));
} else {
encodedUrl.append(pair);
}
}
finalUrl = encodedUrl.toString();
}
log.info("Jike GET final url: {}", finalUrl);
HttpURLConnection conn = (HttpURLConnection) new URL(finalUrl).openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(10000);
conn.setReadTimeout(30000);
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("x-jk-appid", appId);
conn.setRequestProperty("x-jk-timestamp", String.valueOf(timestamp));
conn.setRequestProperty("x-jk-param-signature", paramMd5);
conn.setRequestProperty("x-jk-signature", finalSign);
return readResponse(conn);
}
/**
* GET - 使Map
*/
public String doGet(String uri, Map<String, String> params) throws Exception {
if (params == null || params.isEmpty()) {
return doGet(uri, (String) null);
}
// 先排序,再构建字符串
TreeMap<String, String> sorted = new TreeMap<>();
for (Map.Entry<String, String> entry : params.entrySet()) {
if (entry.getValue() == null || entry.getValue().isEmpty()) {
continue;
}
sorted.put(entry.getKey(), entry.getValue());
}
String endpoint = properties.getEndpoint();
String url = endpoint + uri;
long timestamp = System.currentTimeMillis();
String appId = properties.getAppId();
String secret = properties.getSecretKey();
// 构建URL参数值需要URL编码
StringBuilder urlSb = new StringBuilder(url).append("?");
boolean first = true;
for (Map.Entry<String, String> entry : sorted.entrySet()) {
if (!first) {
urlSb.append("&");
}
urlSb.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(), "UTF-8"));
first = false;
}
String finalUrl = urlSb.toString();
// 计算参数签名 - 使用原始值(不编码),按文档说明
StringBuilder signSb = new StringBuilder();
first = true;
for (Map.Entry<String, String> entry : sorted.entrySet()) {
if (!first) {
signSb.append("&");
}
signSb.append(entry.getKey()).append("=").append(entry.getValue());
first = false;
}
String signQueryString = signSb.toString();
String paramMd5 = JikeSignUtil.buildParamSignature(signQueryString);
// 计算最终签名 - GET请求不包含body-signature
String finalSign = JikeSignUtil.buildGetFinalSignature(appId, paramMd5, secret, timestamp);
log.info("Jike GET request queryString (for sign): {}", signQueryString);
log.info("Jike GET final url: {}", finalUrl);
log.info("Jike param-signature: {}", paramMd5);
log.info("Jike final-signature: {}", finalSign);
HttpURLConnection conn = (HttpURLConnection) new URL(finalUrl).openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(10000);
conn.setReadTimeout(30000);
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("x-jk-appid", appId);
conn.setRequestProperty("x-jk-timestamp", String.valueOf(timestamp));
conn.setRequestProperty("x-jk-param-signature", paramMd5);
conn.setRequestProperty("x-jk-signature", finalSign);
return readResponse(conn);
}
/**
* POST
*/
public String doPost(String uri, Map<String, String> params, String jsonBody) throws Exception {
String endpoint = properties.getEndpoint();
String url = endpoint + uri;
log.info("Jike POST request: {}, body: {}", url, jsonBody);
long timestamp = System.currentTimeMillis();
String appId = properties.getAppId();
String secret = properties.getSecretKey();
// 计算body签名
String bodyMd5 = JikeSignUtil.md5Hex(jsonBody);
// 计算参数签名(POST时body参与签名)
String paramMd5 = JikeSignUtil.buildPostParamSignature(params, bodyMd5);
// 计算最终签名
String finalSign = JikeSignUtil.buildFinalSignature(appId, bodyMd5, paramMd5, secret, timestamp);
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setConnectTimeout(10000);
conn.setReadTimeout(30000);
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
conn.setRequestProperty("x-jk-appid", appId);
conn.setRequestProperty("x-jk-timestamp", String.valueOf(timestamp));
conn.setRequestProperty("x-jk-param-signature", paramMd5);
conn.setRequestProperty("x-jk-body-signature", bodyMd5);
conn.setRequestProperty("x-jk-signature", finalSign);
if (jsonBody != null && !jsonBody.isEmpty()) {
try (OutputStream os = conn.getOutputStream()) {
os.write(jsonBody.getBytes(StandardCharsets.UTF_8));
}
}
return readResponse(conn);
}
private String buildUrl(String baseUrl, Map<String, String> params) throws Exception {
if (params == null || params.isEmpty()) {
return baseUrl;
}
StringBuilder sb = new StringBuilder(baseUrl).append("?");
boolean first = true;
for (Map.Entry<String, String> entry : params.entrySet()) {
if (entry.getValue() == null || entry.getValue().isEmpty()) {
continue;
}
if (!first) {
sb.append("&");
}
sb.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(), "UTF-8"));
first = false;
}
return sb.toString();
}
private String readResponse(HttpURLConnection conn) throws Exception {
int code = conn.getResponseCode();
InputStream is = (code >= 200 && code < 400) ? conn.getInputStream() : conn.getErrorStream();
StringBuilder sb = new StringBuilder();
try (BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
String line;
while ((line = br.readLine()) != null) {
sb.append(line).append("\n");
}
}
return sb.toString();
}
}

View File

@ -0,0 +1,28 @@
package com.njzscloud.supervisory.gps.jike;
import lombok.Data;
import lombok.experimental.Accessors;
/**
*
*/
@Data
@Accessors(chain = true)
public class JikeResponse<T> {
private Header header;
private T data;
@Data
public static class Header {
private Integer code;
private String message;
private String requestId;
private Long ts;
private String rts;
}
public boolean isSuccess() {
return header != null && header.getCode() != null && header.getCode() == 0;
}
}

View File

@ -0,0 +1,162 @@
package com.njzscloud.supervisory.gps.jike.controller;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import com.njzscloud.common.core.utils.R;
import com.njzscloud.supervisory.config.JikeProperties;
import com.njzscloud.supervisory.gps.jike.JikeApiClient;
import com.njzscloud.supervisory.gps.jike.JikeResponse;
import com.njzscloud.supervisory.gps.jike.result.JikeMediaResult;
import com.njzscloud.supervisory.gps.jike.result.JikeTrackResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
*/
@Slf4j
@RestController
@RequestMapping("/gps/jike")
public class JikeTestController {
private final JikeProperties jikeProperties;
public JikeTestController(JikeProperties jikeProperties) {
this.jikeProperties = jikeProperties;
}
/**
*
*/
@RequestMapping("/ping")
public R<?> ping() {
try {
JikeApiClient client = new JikeApiClient(jikeProperties);
String response = client.doGet("/open-api/health/ping1", "");
log.info("Jike ping response: {}", response);
return R.success(JSON.parseObject(response));
} catch (Exception e) {
log.error("Jike ping error", e);
return R.failed();
}
}
/**
*
* /open-api/gps-trace/list
*
* @param carNum
* @param stime (: yyyy-MM-dd HH:mm:ss)
* @param etime (: yyyy-MM-dd HH:mm:ss)
*/
@RequestMapping("/track_list_test")
public R<?> trackListTest(
@RequestParam(required = false) String carNum,
@RequestParam(required = false) String imei,
@RequestParam String stime,
@RequestParam String etime) {
try {
JikeApiClient client = new JikeApiClient(jikeProperties);
Map<String, String> params = new HashMap<>();
if (carNum != null && !carNum.isEmpty()) {
params.put("carNum", carNum);
}
if (imei != null && !imei.isEmpty()) {
params.put("imei", imei);
}
// 转换为毫秒时间戳
params.put("stime", String.valueOf(DateUtil.parse(stime).getTime()));
params.put("etime", String.valueOf(DateUtil.parse(etime).getTime()));
log.info("Jike track list request params: {}", params);
String response = client.doGet("/open-api/gps-trace/list", params);
log.info("Jike track list response: {}", response);
JikeResponse<List<JikeTrackResult>> result = JSON.parseObject(
response,
new TypeReference<JikeResponse<List<JikeTrackResult>>>() {}
);
if (result.isSuccess()) {
return R.success(result.getData());
} else {
log.error("调用失败: " + result.getHeader().getMessage());
return R.failed();
}
} catch (Exception e) {
log.error("Jike track list error", e);
return R.failed();
}
}
/**
*
* /open-api/event/interval/media
*
* @param carNum
* @param stime (: yyyy-MM-dd HH:mm:ss)
* @param etime (: yyyy-MM-dd HH:mm:ss)
*/
@RequestMapping("/media_list_test")
public R<?> mediaListTest(
@RequestParam(required = false) String carNum,
@RequestParam(required = false) String imei,
@RequestParam String stime,
@RequestParam String etime) {
try {
JikeApiClient client = new JikeApiClient(jikeProperties);
Map<String, String> params = new HashMap<>();
if (carNum != null && !carNum.isEmpty()) {
params.put("carNum", carNum);
}
if (imei != null && !imei.isEmpty()) {
params.put("imei", imei);
}
// 转换为毫秒时间戳
params.put("stime", String.valueOf(DateUtil.parse(stime).getTime()));
params.put("etime", String.valueOf(DateUtil.parse(etime).getTime()));
// 构建参数字符串
StringBuilder sb = new StringBuilder();
boolean first = true;
for (Map.Entry<String, String> entry : params.entrySet()) {
if (!first) {
sb.append("&");
}
sb.append(entry.getKey()).append("=").append(entry.getValue());
first = false;
}
String queryString = sb.toString();
log.info("Jike media list queryString: {}", queryString);
String response = client.doGet("/open-api/event/interval/media", queryString);
log.info("Jike media list response: {}", response);
JikeResponse<List<JikeMediaResult>> result = JSON.parseObject(
response,
new TypeReference<JikeResponse<List<JikeMediaResult>>>() {}
);
if (result.isSuccess()) {
return R.success(result.getData());
} else {
log.error("调用失败: " + result.getHeader().getMessage());
return R.failed();
}
} catch (Exception e) {
log.error("Jike media list error", e);
return R.failed();
}
}
}

View File

@ -0,0 +1,36 @@
package com.njzscloud.supervisory.gps.jike.result;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
/**
*
*/
@Data
@Accessors(chain = true)
public class JikeEventResult {
private Long ukid;
private Long eventId;
private String orgRoot;
private String orgCode;
private Long truckId;
private String carNum;
private String imei;
private Integer eventType;
private String eventTypeText;
private Long eventTime;
private Long eventEndTime;
private Long orderId;
private Integer eventState;
private List<JikeMediaResult> mediaList;
private Integer speed;
private Double lon;
private Double lat;
private String address;
private Long transportId;
private String transportBusinessId;
private String extend;
}

View File

@ -0,0 +1,20 @@
package com.njzscloud.supervisory.gps.jike.result;
import lombok.Data;
import lombok.experimental.Accessors;
/**
*
*/
@Data
@Accessors(chain = true)
public class JikeMediaResult {
private Long id;
private Integer channel;
private Integer logicChannel;
private String media;
private Integer mediaType;
private String createTime;
private String updateTime;
}

View File

@ -0,0 +1,28 @@
package com.njzscloud.supervisory.gps.jike.result;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.experimental.Accessors;
/**
*
*/
@Data
@Accessors(chain = true)
public class JikeTrackResult {
private Long id;
private Long truckId;
private String imei;
private String carNum;
private String orgRoot;
private String orgCode;
private String gpsText;
private Integer speed;
private String address;
private Integer direction;
private Integer valid;
private String gpsTime;
private String createTime;
private String extend;
}

View File

@ -0,0 +1,77 @@
package com.njzscloud.supervisory.gps.jike.support;
import cn.hutool.extra.spring.SpringUtil;
import com.njzscloud.common.http.constant.HttpMethod;
import com.njzscloud.common.http.interceptor.RequestInterceptor;
import com.njzscloud.supervisory.config.JikeProperties;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
/**
* -
*/
public class JikeRequestInterceptor implements RequestInterceptor {
@Override
public Object[] process(HttpMethod method, String url, Object[] args) {
JikeProperties jikeProperties = SpringUtil.getBean(JikeProperties.class);
String appId = jikeProperties.getAppId();
String secret = jikeProperties.getSecretKey();
// 获取时间戳
long timestamp = System.currentTimeMillis();
// 构建请求头
Map<String, String> headers = new HashMap<>();
headers.put("x-jk-appid", appId);
headers.put("x-jk-timestamp", String.valueOf(timestamp));
// 处理参数签名
String paramMd5 = "";
String bodyMd5 = "";
if (args != null && args.length > 0) {
Object param = args[0];
if (param instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, String> params = (Map<String, String>) param;
if (method == HttpMethod.GET) {
// GET请求: x-jk-param-signature = MD5(参数拼接)
paramMd5 = JikeSignUtil.buildParamSignature(params);
headers.put("x-jk-param-signature", paramMd5);
} else if (method == HttpMethod.POST) {
// POST请求: 需要body签名
if (args.length > 1 && args[1] instanceof String) {
bodyMd5 = JikeSignUtil.md5Hex((String) args[1]);
}
headers.put("x-jk-body-signature", bodyMd5);
// POST带body时,body参与签名
paramMd5 = JikeSignUtil.buildPostParamSignature(params, bodyMd5);
headers.put("x-jk-param-signature", paramMd5);
}
}
} else {
// 无参数时
headers.put("x-jk-param-signature", "");
if (method == HttpMethod.POST) {
headers.put("x-jk-body-signature", "");
}
}
// 计算最终签名
String finalSign = JikeSignUtil.buildFinalSignature(appId, bodyMd5, paramMd5, secret, timestamp);
headers.put("x-jk-signature", finalSign);
// 返回 headers 和原始参数
Object[] result = new Object[args != null ? args.length + 1 : 2];
result[0] = headers;
for (int i = 0; i < (args != null ? args.length : 0); i++) {
result[i + 1] = args[i];
}
return result;
}
}

View File

@ -0,0 +1,136 @@
package com.njzscloud.supervisory.gps.jike.support;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import lombok.extern.slf4j.Slf4j;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.TreeMap;
/**
*
*/
@Slf4j
public class JikeSignUtil {
/**
* GET - Map
* x-jk-param-signature = MD5(k=v)
* x-jk-signature = MD5(x-jk-appid={appId}&x-jk-param-signature={paramSign}&x-jk-secret={secret}&x-jk-timestamp={timestamp})
*/
public static String buildParamSignature(Map<String, String> params) {
if (params == null || params.isEmpty()) {
return "";
}
TreeMap<String, String> sorted = new TreeMap<>();
for (Map.Entry<String, String> entry : params.entrySet()) {
String v = entry.getValue();
if (v == null || v.isEmpty()) {
continue;
}
sorted.put(entry.getKey(), v);
}
if (sorted.isEmpty()) {
return "";
}
StringBuilder sb = new StringBuilder();
boolean first = true;
for (Map.Entry<String, String> entry : sorted.entrySet()) {
if (!first) {
sb.append("&");
}
sb.append(entry.getKey()).append("=").append(entry.getValue());
first = false;
}
String result = sb.toString();
log.debug("Jike param-signature origin: {}", result);
return DigestUtil.md5Hex(result, CharsetUtil.CHARSET_UTF_8);
}
/**
* GET -
* queryString carNum=A12345&stime=xxx&etime=xxx
*/
public static String buildParamSignature(String queryString) {
if (queryString == null || queryString.isEmpty()) {
return "";
}
log.debug("Jike param-signature origin: {}", queryString);
return DigestUtil.md5Hex(queryString, CharsetUtil.CHARSET_UTF_8);
}
/**
* POST
* x-jk-body-signature = MD5(body)
* x-jk-param-signature = MD5(k=v, body=md5(body))
* x-jk-signature = MD5(x-jk-appid={appId}&x-jk-body-signature={bodySign}&x-jk-param-signature={paramSign}&x-jk-secret={secret}&x-jk-timestamp={timestamp})
*/
public static String buildPostParamSignature(Map<String, String> params, String bodyMd5) {
TreeMap<String, String> sorted = new TreeMap<>();
if (params != null) {
for (Map.Entry<String, String> entry : params.entrySet()) {
String v = entry.getValue();
if (v == null || v.isEmpty()) {
continue;
}
sorted.put(entry.getKey(), v);
}
}
sorted.put("body", StrUtil.emptyToDefault(bodyMd5, ""));
StringBuilder sb = new StringBuilder();
boolean first = true;
for (Map.Entry<String, String> entry : sorted.entrySet()) {
if (!first) {
sb.append("&");
}
sb.append(entry.getKey()).append("=").append(entry.getValue());
first = false;
}
String result = sb.toString();
log.debug("Jike POST param-signature origin: {}", result);
return DigestUtil.md5Hex(result, CharsetUtil.CHARSET_UTF_8);
}
/**
* bodyMD5
*/
public static String md5Hex(String content) {
if (content == null || content.isEmpty()) {
return "";
}
return DigestUtil.md5Hex(content, CharsetUtil.CHARSET_UTF_8);
}
/**
* GETbody-signature
*/
public static String buildGetFinalSignature(String appId, String paramMd5, String secret, long timestamp) {
String finalContent = String.format(
"x-jk-appid=%s&x-jk-param-signature=%s&x-jk-secret=%s&x-jk-timestamp=%d",
appId,
StrUtil.emptyToDefault(paramMd5, ""),
secret,
timestamp
);
log.debug("Jike GET final-signature origin: {}", finalContent);
return DigestUtil.md5Hex(finalContent, StandardCharsets.UTF_8);
}
/**
* POSTbody-signature
*/
public static String buildFinalSignature(String appId, String bodyMd5, String paramMd5, String secret, long timestamp) {
String finalContent = String.format(
"x-jk-appid=%s&x-jk-body-signature=%s&x-jk-param-signature=%s&x-jk-secret=%s&x-jk-timestamp=%d",
appId,
StrUtil.emptyToDefault(bodyMd5, ""),
StrUtil.emptyToDefault(paramMd5, ""),
secret,
timestamp
);
log.debug("Jike POST final-signature origin: {}", finalContent);
return DigestUtil.md5Hex(finalContent, StandardCharsets.UTF_8);
}
}

View File

@ -554,4 +554,15 @@ public class OrderPagingResult {
* *
*/ */
private String roleName; private String roleName;
/**
* gps
*/
private String gps;
/**
*
*/
private String localizerCategory;
} }

View File

@ -37,6 +37,7 @@ import com.njzscloud.supervisory.biz.pojo.entity.*;
import com.njzscloud.supervisory.biz.service.*; import com.njzscloud.supervisory.biz.service.*;
import com.njzscloud.supervisory.constant.Constant; import com.njzscloud.supervisory.constant.Constant;
import com.njzscloud.supervisory.device.pojo.entity.DeviceLocalizerEntity; import com.njzscloud.supervisory.device.pojo.entity.DeviceLocalizerEntity;
import com.njzscloud.supervisory.device.service.DeviceLocalizerService;
import com.njzscloud.supervisory.discount.pojo.DiscountManageEntity; import com.njzscloud.supervisory.discount.pojo.DiscountManageEntity;
import com.njzscloud.supervisory.discount.service.DiscountManageService; import com.njzscloud.supervisory.discount.service.DiscountManageService;
import com.njzscloud.supervisory.expense.contant.*; import com.njzscloud.supervisory.expense.contant.*;
@ -124,6 +125,7 @@ public class OrderInfoService extends ServiceImpl<OrderInfoMapper, OrderInfoEnti
private final HsoaService hsoaService; private final HsoaService hsoaService;
private final DictItemService dictItemService; private final DictItemService dictItemService;
private final AtomicBoolean test_thread_running = new AtomicBoolean(false); private final AtomicBoolean test_thread_running = new AtomicBoolean(false);
private final DeviceLocalizerService deviceLocalizerService;
Thread test_thread = null; Thread test_thread = null;
@Value("${app.check-gps:false}") @Value("${app.check-gps:false}")
private boolean checkGps; private boolean checkGps;
@ -1907,6 +1909,15 @@ public class OrderInfoService extends ServiceImpl<OrderInfoMapper, OrderInfoEnti
result.setRoleName(roleEntity.getRoleName()); result.setRoleName(roleEntity.getRoleName());
} }
} }
if (!Strings.isNullOrEmpty(result.getGps())) {
List<DeviceLocalizerEntity> list = deviceLocalizerService.list(Wrappers.lambdaQuery(DeviceLocalizerEntity.class).
eq(DeviceLocalizerEntity::getTerminalId, result.getGps())
.eq(DeviceLocalizerEntity::getDeleted, Boolean.FALSE));
if (null != list && !list.isEmpty()) {
result.setLocalizerCategory(list.get(0).getLocalizerCategory().getVal());
}
}
return result; return result;
} }

View File

@ -31,6 +31,7 @@ spring:
- /wechatTemplateMessage/key - /wechatTemplateMessage/key
- /hsoa/push_order - /hsoa/push_order
- /operationManual/appShow - /operationManual/appShow
- /gps/**
app: app:
default-place: default-place:
province: 340000 province: 340000
@ -103,3 +104,9 @@ hsoa:
base-url: http://60.173.195.121:9908 base-url: http://60.173.195.121:9908
username: chuz_trajectory username: chuz_trajectory
password: e9t2YsgM5ug%2FkpIZpMdY9e9uXq60jyEQ30zQX%2BBzphI%3D password: e9t2YsgM5ug%2FkpIZpMdY9e9uXq60jyEQ30zQX%2BBzphI%3D
# 即刻物联
app.jike:
appId: appid_wvsey5zyk2wqt0
secretKey: s7xejsskalwqjyqptekgahrdcpkcfwa
sandbox: false

View File

@ -100,6 +100,7 @@
e.tare_weight history_tare_weight, e.tare_weight history_tare_weight,
p.txt truck_category, p.txt truck_category,
e.picture truck_picture, e.picture truck_picture,
e.gps,
f.user_id driver_user_id, f.user_id driver_user_id,
f.driver_name, f.driver_name,
f.phone driver_phone, f.phone driver_phone,