Commit 07602a7b authored by kang.nie@inzymeits.com's avatar kang.nie@inzymeits.com
Browse files

提交代码

parent e0c7be76
package com.ssi.mapper;
import com.ssi.entity.VmsVehicleAlertProcess;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @Entity com.ssi.entity.VmsVehicleAlertProcess
*/
public interface VmsVehicleAlertProcessMapper extends BaseMapper<VmsVehicleAlertProcess> {
}
package com.ssi.mapper;
import com.ssi.entity.VmsVehicle;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ssi.entity.dto.VmsVehicleDto;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
/**
* 车辆表
*
* @author zhang liyao
* @email
* @date 2020-07-08 15:38:37
*/
@Mapper
public interface VmsVehicleMapper extends BaseMapper<VmsVehicle> {
/**
* 根据vin获取车辆以及远控台信息
* @param vin
* @return
*/
VmsVehicleDto queryVehicleByVin(@Param("vin") String vin);
Map getVmsCranePosMapInfo(@Param("name") String name);
List<Map>getVmsVehicle();
}
package com.ssi.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ssi.entity.VmsVehicleOperateTask;
import org.apache.ibatis.annotations.Mapper;
/**
* 车辆运营数据统计表
*
* @author zhang liyao
* @email
* @date 2020-07-16 09:32:59
*/
@Mapper
public interface VmsVehicleOperateTaskMapper extends BaseMapper<VmsVehicleOperateTask> {
}
package com.ssi.model;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* @author 成东
* @since 2022-02-23 16:29
*/
@NoArgsConstructor
@Getter
@Setter
public class CraneInfoRedis {
private String portCode;
private Integer portType; //港机类型(1:桥吊 2:场吊)
private Long collectTime;
private Object lockStatus;
private Double height;
private Object hoistStatus;
private Double trolleyPos;
private Double mainHoistPos;
private Integer twistlockLocked;
private Integer pinsLanded;
private String spreaderSize;
private Integer trolleyForward;
private Integer trolleyBackward;
private Integer mainHoistUp;
private Integer mainHoistDown;
private Integer gantryForward;
private Integer gantryBackward;
private Double lon;
private Double lat;
}
package com.ssi.model;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.ActionFuture;
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest;
import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheResponse;
import org.elasticsearch.action.admin.indices.stats.IndexStats;
import org.elasticsearch.action.admin.indices.stats.IndicesStatsRequest;
import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.DeleteByQueryAction;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.Days;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
/**
* Description:
*
* @author LiXiaoCong
* @version 2019/1/17 15:07
*/
@Component
@Slf4j
public class ElasticSearchMetaModel {
private final static DateTimeZone TIME_ZONE = DateTimeZone.forID("Asia/Shanghai");
@Autowired
private TransportClient transportClient;
public Map<String, IndexStats> getIndicesStats() {
ActionFuture<IndicesStatsResponse> isr = transportClient.admin().indices()
.stats(new IndicesStatsRequest().all());
return isr.actionGet().getIndices();
}
public List<String> getIndices() {
return Lists.newArrayList(getIndicesStats().keySet());
}
public boolean exist(String index) {
List<String> indexs = getIndices();
return indexs == null ? false : indexs.contains(index);
}
public String[] selectExist(String... indexs) {
return selectExist(Sets.newHashSet(indexs));
}
public String[] selectExist(Collection<String> indexs) {
List<String> all = getIndices();
if (all == null) {
all = Lists.newArrayList();
}
indexs.retainAll(all);
return indexs.toArray(new String[indexs.size()]);
}
public SearchRequestBuilder newSearchRequestBuilderInDayIndex(Long startTime,
Long stopTime,
String indexBase,
int defaultDayPeriod,
boolean defaultContainsToday) {
return newSearchRequestBuilderInDayIndex(startTime, stopTime, indexBase,
defaultDayPeriod, defaultContainsToday, "day");
}
public SearchRequestBuilder newSearchRequestBuilderInDayIndex(Long startTime,
Long stopTime,
String indexBase,
int defaultDayPeriod,
boolean defaultContainsToday,
String indexRule) {
SearchRequestBuilder requestBuilder = null;
if (indexRule == null) {
requestBuilder = transportClient.prepareSearch(indexBase);
} else if (startTime == null && stopTime == null) {
requestBuilder = transportClient.prepareSearch(String.format("%s_2*", indexBase));
} else {
String[] indexs = getIndexs(startTime, stopTime, indexBase, defaultDayPeriod,
defaultContainsToday, indexRule);
if (indexs.length > 0) {
log.info(String.format("查询es的索引有:%s", Lists.newArrayList(indexs)));
requestBuilder = transportClient.prepareSearch(indexs);
}
}
return requestBuilder;
}
public String[] getIndexs(Long startTime,
Long stopTime,
String indexBase,
int defaultDayPeriod,
boolean defaultContainsToday) {
return getIndexs(startTime, stopTime, indexBase, defaultDayPeriod, defaultContainsToday, "day");
}
public String[] getIndexs(Long startTime,
Long stopTime,
String indexBase,
int defaultDayPeriod,
boolean defaultContainsToday,
String indexRule) {
if (indexRule == null) {
return new String[]{indexBase};
}
DateTime stopDate;
if (stopTime == null) {
DateTime now = DateTime.now(TIME_ZONE);
if (defaultContainsToday) {
stopDate = now;
} else {
stopDate = now.minusDays(1);
}
} else {
stopDate = new DateTime(stopTime.longValue(), TIME_ZONE);
}
DateTime startDate = (startTime == null ? stopDate.minusDays(defaultDayPeriod)
: new DateTime(startTime.longValue(), TIME_ZONE));
List<String> indexList = new ArrayList<>();
String[] indexs;
int days = Days.daysBetween(startDate, stopDate).getDays();
Set<String> indexSet = new HashSet<>();
if (days >= 0) {
for (int i = 0; i <= days; i++) {
try {
switch (indexRule.toLowerCase()) {
//按年分区
case "year":
indexSet.add(String.format("%s_%s*",
indexBase, startDate.plusDays(i).toString("yyyy")));
break;
//按月分区
case "month":
indexSet.add(String.format("%s_%s*",
indexBase, startDate.plusDays(i).toString("yyyyMM")));
break;
//按天分区
case "day":
indexList.add(String.format("%s_%s*",
indexBase, startDate.plusDays(i).toString("yyyyMMdd")));
break;
default:
indexSet.add(indexBase);
}
} catch (Exception e) {
}
}
indexList.addAll(indexSet);
indexs = indexList.toArray(new String[indexList.size()]);
} else {
indexs = new String[0];
}
log.info("查询索引有:indexs = " + Lists.newArrayList(indexs).toString());
return indexs;
}
/**
* 清空指定索引的缓存
*
* @param indexName 索引名
* @return 清空结果
*/
public boolean clearIndicesCache(String... indexName) {
ClearIndicesCacheResponse response;
try {
response = transportClient.admin().indices()
.clearCache(new ClearIndicesCacheRequest(indexName)
//.fieldDataCache(true)
.queryCache(true)
).actionGet();
if (response.getFailedShards() > 0) {
return false;
}
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
public String[] deleteIndexByIds(List<Map<String, Object>> deleteMaps) {
String[] idArray = null;
if (deleteMaps != null) {
Set<String> indexs = Sets.newHashSet();
Set<String> ids = Sets.newHashSet();
deleteMaps.forEach(deleteMap -> {
String id = String.valueOf(deleteMap.get("id"));
String index = String.valueOf(deleteMap.get("index"));
String table = String.valueOf(deleteMap.get("table"));
if (id != null && index != null && table != null) {
ids.add(id);
indexs.add(index);
}
});
String[] indices = indexs.toArray(new String[indexs.size()]);
idArray = ids.toArray(new String[ids.size()]);
if (indices.length > 0) {
DeleteByQueryAction.INSTANCE.newRequestBuilder(transportClient)
.filter(QueryBuilders.termsQuery("id", ids))
.source(indices)
.get();
clearIndicesCache(indices);
}
}
return idArray;
}
}
package com.ssi.model;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ssi.config.ElasticsearchConfig;
import com.ssi.utils.GeoPosTransformUtil;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Description:
*
* @author LiXiaoCong
* @version 2019/3/1 16:56
*/
@Slf4j
public class ElasticSearchModel {
private final Logger logger = LoggerFactory.getLogger(ElasticSearchMetaModel.class);
@Autowired
protected TransportClient transportClient;
@Autowired
protected ElasticSearchMetaModel elasticSearchMetaModel;
@Autowired
protected ElasticsearchConfig elasticsearchConfig;
protected BoolQueryBuilder createBooleanQueryBuilderWithChinaLocation() {
return createBooleanQueryBuilderWithChinaLocation("longitude", "latitude");
}
protected BoolQueryBuilder createBooleanQueryBuilderWithChinaLocation(String longitudeField,
String latitudeField) {
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//中国经纬度
boolQueryBuilder.must(QueryBuilders.rangeQuery(longitudeField).gte(73).lt(135));
boolQueryBuilder.must(QueryBuilders.rangeQuery(latitudeField).gte(4).lt(53));
return boolQueryBuilder;
}
protected Map<String, Object> extractSearchHits(SearchHits hits) {
return extractSearchHits(hits, null, null, null);
}
protected Map<String, Object> extractSearchHits(SearchHits hits,
String posType) {
return extractSearchHits(hits, posType, "longitude", "latitude");
}
protected List<Map<String, Object>> extractSearchHits(SearchHit[] hits,
String posType,
String longitudeField,
String latitudeField) {
List<Map<String, Object>> maps = Arrays.stream(hits).map(hit -> {
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
if (posType != null) {
locationTypeChange(sourceAsMap, posType, longitudeField, latitudeField);
}
return sourceAsMap;
}).collect(Collectors.toList());
return maps;
}
protected Map<String, Object> extractSearchHits(SearchHits hits,
String posType,
String longitudeField,
String latitudeField) {
Map<String, Object> res;
long totalHits = hits.getTotalHits();
if (totalHits > 0) {
res = Maps.newHashMapWithExpectedSize(3);
res.put("total", totalHits);
List<Map<String, Object>> maps = extractSearchHits(hits.getHits(), posType, longitudeField,
latitudeField);
res.put("records", maps);
res.put("size", maps.size());
} else {
res = emptySearchHitResult();
}
return res;
}
protected Map<String, Object> emptySearchHitResult() {
Map<String, Object> res = Maps.newHashMapWithExpectedSize(3);
res.put("total", 0);
res.put("records", Lists.newArrayList());
res.put("size", 0);
return res;
}
protected void locationTypeChange(Map<String, Object> sourceAsMap,
String toType,
String longitudeField,
String latitudeField) {
Object longitudeObj = sourceAsMap.get(longitudeField);
Object latitudeObj = sourceAsMap.get(latitudeField);
if (latitudeObj != null && longitudeObj != null) {
double longitude = Double.parseDouble(longitudeObj.toString());
double latitude = Double.parseDouble(latitudeObj.toString());
double[] doubles = null;
switch (toType) {
//百度
case "bd09":
doubles = GeoPosTransformUtil.wgs84tobd09(longitude, latitude);
break;
//高德
case "gcj02":
doubles = GeoPosTransformUtil.wgs84togcj02(longitude, latitude);
break;
}
if (doubles != null) {
sourceAsMap.put(longitudeField, doubles[0]);
sourceAsMap.put(latitudeField, doubles[1]);
}
}
}
/**
* 移动过来的
*/
protected SearchRequestBuilder newSearchRequestBuilder(Long startTime, Long endTime) {
return newSearchRequestBuilder(startTime, endTime, elasticsearchConfig.getTypeName());
}
protected SearchRequestBuilder newSearchRequestBuilder(Long startTime, Long endTime,
String typeName) {
SearchRequestBuilder requestBuilder;
if (startTime == null && endTime == null) {
requestBuilder = transportClient.prepareSearch(String.format("%s_2*", typeName));
} else {
String[] indexs = getIndexs(startTime, endTime);
if (indexs.length == 0) {
requestBuilder = transportClient.prepareSearch(String.format("%s_2*", typeName));
logger.warn(String.format("在时间范围[%s,%s]内不存在%s的索引。", startTime, endTime, typeName));
} else {
requestBuilder = transportClient.prepareSearch(indexs);
}
}
return requestBuilder.setTypes(typeName);
}
protected String[] getIndexs(Long startTime, Long endTime) {
return elasticSearchMetaModel.getIndexs(startTime, endTime,
elasticsearchConfig.getTypeName(), 7, true);
}
}
package com.ssi.model;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.Set;
/**
* Description:
*
* @author LiXiaoCong
* @version 2019/10/17 9:38
*/
@Component
@Slf4j
public class RedisConfigModel {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Value("${cism.redis.config.prefix:cism:config}")
private String configRedisPrefix;
@Value("${cism.redis.config.group:extra}")
private String defaultGroup;
public void setConfig(String group, String key, String value) {
if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(value)) {
stringRedisTemplate.opsForHash()
.put(String.format("%s:%s", configRedisPrefix, group), key, value);
}
}
public void setConfig(String key, String value) {
setConfig(defaultGroup, key, value);
}
public void setConfig(String group, Map<String, String> configMap) {
if (configMap != null && !configMap.isEmpty()) {
HashOperations<String, String, String> hashOperations = stringRedisTemplate.opsForHash();
hashOperations.putAll(String.format("%s:%s", configRedisPrefix, group), configMap);
}
}
public void setConfig(Map<String, String> configMap) {
setConfig(defaultGroup, configMap);
}
public String getConfigWithDefault(String key, String defaultValue) {
return getConfigWithDefault(defaultGroup, key, defaultValue);
}
public String getConfigWithDefault(String group, String key, String defaultValue) {
String value = getConfig(group, key);
if (value == null) {
value = defaultValue;
}
return value;
}
public String getConfig(String group, String key) {
if (StringUtils.isNotBlank(group) && StringUtils.isNotBlank(key)) {
HashOperations<String, String, String> hashOperations = stringRedisTemplate.opsForHash();
return hashOperations.get(String.format("%s:%s", configRedisPrefix, group), key);
} else {
return null;
}
}
public String getConfig(String key) {
return getConfig(defaultGroup, key);
}
public Map<String, String> getConfigs(Set<String> keys) {
return getConfigs(defaultGroup, keys);
}
public Map<String, String> getConfigs(String group, Set<String> keys) {
Map<String, String> configs = Maps.newHashMap();
if (keys != null && !keys.isEmpty()) {
keys.forEach(key -> {
String config = getConfig(group, key);
if (config != null) {
configs.put(key, config);
}
});
}
return configs;
}
public void deteles(String group, String... keys) {
if (StringUtils.isNotBlank(group) && keys.length > 0) {
HashOperations<String, String, String> hashOperations = stringRedisTemplate.opsForHash();
hashOperations.delete(String.format("%s:%s", configRedisPrefix, group), keys);
}
}
public void deteles(String... keys) {
deteles(defaultGroup, keys);
}
}
package com.ssi.model;
import com.google.common.base.Strings;
import com.ssi.utils.JsonUtil;
import java.util.Collection;
import java.util.HashMap;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.GeoRadiusResponse;
import redis.clients.jedis.GeoUnit;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.geo.GeoRadiusParam;
import redis.clients.util.Pool;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Description:
*
* @author LiXiaoCong
* @version 2019/7/12 15:37
*/
@Slf4j
public class RedisDataModel {
private Pool pool;
public RedisDataModel(Pool pool) {
this.pool = pool;
}
public String get(String key) {
String json = null;
if (!Strings.isNullOrEmpty(key)) {
Jedis jedis = null;
try {
jedis = getJedis();
json = jedis.get(key);
} catch (Exception e) {
log.error(String.format("读取%s失败", key), e);
} finally {
close(jedis);
}
}
return json;
}
public Map<String, Object> getJson2Map(String key) {
Map<String, Object> map = null;
if (!Strings.isNullOrEmpty(key)) {
Jedis jedis = null;
try {
jedis = getJedis();
String json = jedis.get(key);
if (!Strings.isNullOrEmpty(json)) {
map = JsonUtil.jsonToMap(json);
}
} catch (Exception e) {
log.error(String.format("读取%s失败", key), e);
} finally {
close(jedis);
}
}
return map;
}
public Set<String> keys(String key) {
Set<String> keys = null;
if (!Strings.isNullOrEmpty(key)) {
Jedis jedis = null;
try {
jedis = getJedis();
keys = jedis.keys(key);
} catch (Exception e) {
log.error(String.format("获取所有前缀为%s的key失败。", key), e);
} finally {
close(jedis);
}
}
return keys;
}
public List<String> mget(String... key) {
List<String> keys = null;
if (key != null) {
Jedis jedis = null;
try {
jedis = getJedis();
keys = jedis.mget(key);
} catch (Exception e) {
log.error(String.format("获取所有前缀为%s的key失败。", key), e);
} finally {
close(jedis);
}
}
return keys;
}
public Map<String, Object> mgetForMap(Collection<String> key) {
val value = mget(key.toArray(new String[0]));
assert value != null;
assert value.size() == key.size();
Map<String, Object> map = new HashMap<>();
int i = 0;
for (String k : key) {
map.put(k, value.get(i));
i++;
}
return map;
}
public Map<String, Object> getJson2Map(String key, String field) {
Map<String, Object> map = null;
if (!Strings.isNullOrEmpty(key)) {
Jedis jedis = null;
try {
jedis = getJedis();
//String json = jedis.hget(key, field);
String redisKey = String.format("%s,%s", key, field);
String json = jedis.get(redisKey);
if (!Strings.isNullOrEmpty(json)) {
map = JsonUtil.jsonToMap(json);
}
} catch (Exception e) {
log.error(String.format("读取%s$%s失败", key, field), e);
} finally {
close(jedis);
}
}
return map;
}
public Map<String, Object> hgetJson2Map(String key, String field) {
Map<String, Object> map = null;
if (!Strings.isNullOrEmpty(key)) {
Jedis jedis = null;
try {
jedis = getJedis();
String json = jedis.hget(key, field);
//String redisKey = String.format("%s,%s",key,field);
// String json = jedis.get(redisKey);
if (!Strings.isNullOrEmpty(json)) {
map = JsonUtil.jsonToMap(json);
}
} catch (Exception e) {
log.error(String.format("读取%s$%s失败", key, field), e);
} finally {
close(jedis);
}
}
return map;
}
public void hset(String key, String field, String value) {
if (!Strings.isNullOrEmpty(key)) {
Jedis jedis = null;
try {
jedis = getJedis();
jedis.hset(key, field, value);
} catch (Exception e) {
log.error(String.format("存储%s,%s,%s失败", key, field, value), e);
} finally {
close(jedis);
}
}
}
public boolean set(String key, String value) {
if (!Strings.isNullOrEmpty(key) && !Strings.isNullOrEmpty(value)) {
Jedis jedis = null;
try {
jedis = getJedis();
jedis.set(key, value);
return true;
} catch (Exception e) {
log.error(String.format("读取%s失败", key), e);
} finally {
close(jedis);
}
}
return false;
}
public boolean del(String key) {
if (!Strings.isNullOrEmpty(key)) {
Jedis jedis = null;
try {
jedis = getJedis();
Long l = jedis.del(key);
return true;
} catch (Exception e) {
log.error(String.format("读取%s失败", key), e);
} finally {
close(jedis);
}
}
return false;
}
public void close(Jedis jedis) {
if (jedis != null) {
try {
jedis.close();
} catch (Exception e) {
}
}
}
public Jedis getJedis() {
Jedis jedis = null;
try {
jedis = (Jedis) pool.getResource();
} catch (Exception e) {
log.error("获取jedis实体失败。"+e.getMessage(),e);
}
return jedis;
}
public String getMember(String key, double longitude, double latitude, double radius) {
String memberByString = null;
Jedis jedis = null;
try {
long l = System.currentTimeMillis();
jedis = getJedis();
GeoRadiusParam geoRadiusParam = GeoRadiusParam.geoRadiusParam();
geoRadiusParam.sortAscending().count(1);
List<GeoRadiusResponse> georadius
= jedis.georadius(key, longitude, latitude, radius, GeoUnit.M, geoRadiusParam);
if (georadius != null && !georadius.isEmpty()) {
memberByString = georadius.get(0).getMemberByString();
}
log.debug(String.format("从redis中获取高程数据耗时:%s", (System.currentTimeMillis() - l)));
} catch (Exception e) {
log.error(String.format("读取%s失败", key), e);
} finally {
close(jedis);
}
return memberByString;
}
public boolean set(String key, String value, Long expireTime) {
if (!Strings.isNullOrEmpty(key) && !Strings.isNullOrEmpty(value)) {
Jedis jedis = null;
try {
jedis = getJedis();
jedis.set(key, value);
jedis.expire(key, expireTime.intValue());
return true;
} catch (Exception e) {
log.error(String.format("读取%s失败", key), e);
} finally {
close(jedis);
}
}
return false;
}
}
package com.ssi.model;
import com.alibaba.fastjson.JSONObject;
import com.ssi.constant.URL;
import com.ssi.constant.VehicleConstant;
import com.ssi.constant.enums.Status;
import com.ssi.entity.VmsTosOrders;
import com.ssi.entity.dto.SwitchAutoParamDto;
import com.ssi.entity.dto.TelecontrolParamDto;
import com.ssi.response.SSIResponse;
import com.ssi.utils.RestTemplateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* @author ZhangLiYao
* @version 1.0
* @date 2020/7/23 10:23
*/
@Component
@Slf4j
public class TelecontrolModel {
@Value("${command-url}")
private String commandUrl;
@Value("${harbor.remote.vehicle_status}")
private String remoteControlStatusKeyPrefix;
@Value("${harbor.remote.overtime}")
private String debugAppOvertimePrefix;
@Value("${harbor.remote.overtimeTime}")
private long overtimeTime;
@Value("${harbor.remote.controlInfo}")
private String controlInfo;
@Value("${harbor.remote.socketOvertime}")
private String socketOvertimePrefix;
@Value("${harbor.remote.socketOvertimeTime}")
private long socketOvertimeTime;
@Value("${harbor.remote.throttleBrakeOperationValue}")
private String throttleBrakeOperationValuePrefix;
@Value("${harbor.remote.emergencyParking}")
private String emergencyParkingKeyPrefix;
@Value("${harbor.remote.autoPilot}")
private String autoPilotKeyPrefix;
@Value("${vehicle.latestData.redis.prefix}")
private String vehicleInfo;
@Value("${order.latestOrderKeyPrefix:harbor:command:status}")
private String latestOrderKeyPrefix;
@Autowired
private RedisDataModel redisDataModel;
public SSIResponse vehicleTelecontrol(TelecontrolParamDto telecontrolParamDto) {
SSIResponse ssiResponse = null;
try {
String error = handleParam(telecontrolParamDto);
if (StringUtils.isNotBlank(error)) {
ssiResponse = SSIResponse.no(error);
return ssiResponse;
}
if (!emergencyCheck(telecontrolParamDto)) {
ssiResponse = SSIResponse.no("车辆紧停中,请先解除紧停再操作!");
return ssiResponse;
}
//校验退出接管时,车速和油门是否为0
if (this.checkThrottle(telecontrolParamDto)){
ssiResponse = SSIResponse.no("车速或油门不为0,退出接管失败!");
return ssiResponse;
}
//添加当前任务信息
this.addCurrentTaskInfo(telecontrolParamDto);
this.addZeroedValue(telecontrolParamDto);
String paramData = JSONObject.toJSONString(telecontrolParamDto);
log.info(String.format("app遥控车辆指令请求发送:----%s", paramData));
String result = RestTemplateUtil.post(String.format("%s%s", commandUrl, URL.TELECONTROL_URL), paramData, null);
log.info(String.format("app遥控车辆指令请求发送返回结果:----%s", result));
ssiResponse = handleResult(result,telecontrolParamDto);
} catch (Exception e) {
log.error("请求失败:", e);
ssiResponse = SSIResponse.no("请求失败");
} finally {
//退出接管失败持续下发
if (ssiResponse.getCode() == -1 && telecontrolParamDto.getControlType() == 1 && telecontrolParamDto.getOperationValue() == 2) {
ssiResponse = continueCloseControl(telecontrolParamDto);
}
}
this.handleOvertime(telecontrolParamDto, ssiResponse);
this.setLastThrottleBrakeOperationValue(telecontrolParamDto, ssiResponse);
return ssiResponse;
}
private void addCurrentTaskInfo(TelecontrolParamDto telecontrolParamDto) {
Map<String, Object> json2Map = redisDataModel.getJson2Map(String.format("%s:%s", latestOrderKeyPrefix, telecontrolParamDto.getVin()));
JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(json2Map));
VmsTosOrders vmsTosOrders = JSONObject.toJavaObject(jsonObject, VmsTosOrders.class);
telecontrolParamDto.setTaskId(vmsTosOrders.getTaskNo().concat(",").concat(vmsTosOrders.getTaskNoMapping()));
}
//校验退出接管时,车速和油门是否为0
private boolean checkThrottle(TelecontrolParamDto teleDto) {
if (teleDto.getControlType() != VehicleConstant.TELE_CONTROL_TYPE_TAKE_OVER
|| teleDto.getOperationValue() !=2){
return false;
}
String controlCache = redisDataModel.get(controlInfo + ":" + teleDto.getVin());
if (StringUtils.isBlank(controlCache)){
return false;
}
JSONObject controlJson = JSONObject.parseObject(controlCache);
//获取油门值
if(controlJson.get("7") != null && controlJson.getInteger("7") > 0){
return true;
}
//获取车速
String vehicleCache = redisDataModel.get(vehicleInfo + ":" + teleDto.getVin()+"-harbor_D00A");
if (StringUtils.isBlank(vehicleCache)){
return false;
}
JSONObject vehicleJson = JSONObject.parseObject(vehicleCache);
if (vehicleJson.get("speed") != null && vehicleJson.getDouble("speed") > 0){
return true;
}
return false;
}
/**
* 处理回话超时
* @param telecontrolParamDto
* @param ssiResponse
*/
public void handleOvertime(TelecontrolParamDto telecontrolParamDto, SSIResponse ssiResponse) {
boolean isTakeOverCommand = TelecontrolParamDto.isTakeOverCommand(telecontrolParamDto);
boolean isCancelTakeOver = TelecontrolParamDto.isCancelTakeOverCommand(telecontrolParamDto);
String vin = telecontrolParamDto.getVin();
String appMac = telecontrolParamDto.getAppMac();
if (vin != null && appMac != null) {
int code = ssiResponse.getCode();
if (isCancelTakeOver && (code == Status.SUCCESS.getCode())) {
redisDataModel.del(debugAppOvertimePrefix + ":" + vin + ":" + appMac);
}
if ((!isCancelTakeOver && !isTakeOverCommand) || (isTakeOverCommand && (code == Status.SUCCESS.getCode()))) {
redisDataModel.set(debugAppOvertimePrefix + ":" + vin + "&" + appMac, "1", overtimeTime);
}
}
}
/**
* 油门到刹车 刹车到油门 要添加置0标识
*
* @param telecontrolParamDto
*/
public void addZeroedValue(TelecontrolParamDto telecontrolParamDto) {
Integer operationType = telecontrolParamDto.getOperationType();
// 7: 油门刹车操作
if (operationType == 7) {
Integer zeroed = telecontrolParamDto.getZeroed();
//已经有置0标识值则不处理
if (zeroed == 0) {
Integer currentOperationValue = telecontrolParamDto.getOperationValue();
int lastOperationValue = getLastThrottleBrakeOperationValue(telecontrolParamDto.getVin());
if (currentOperationValue > 0 && lastOperationValue < 0) {
telecontrolParamDto.setZeroed(1);
}
if (currentOperationValue < 0 && lastOperationValue > 0) {
telecontrolParamDto.setZeroed(-1);
}
}
}
}
/**
* 获取上一个油门刹车OperationValue的值
*
* @param vin
*/
public int getLastThrottleBrakeOperationValue(String vin) {
String val = redisDataModel.get(throttleBrakeOperationValuePrefix + ":" + vin);
if (StringUtils.isNotBlank(val)) {
return Integer.parseInt(val);
}
return 0;
}
/**
* 设置最新的油门刹车OperationValue的值
*
* @param telecontrolParamDto
*/
public void setLastThrottleBrakeOperationValue(TelecontrolParamDto telecontrolParamDto, SSIResponse ssiResponse) {
Integer operationType = telecontrolParamDto.getOperationType();
boolean success = ssiResponse.getCode() == Status.SUCCESS.getCode();
// 7: 油门刹车操作
if (operationType == 7 && success) {
String vin = telecontrolParamDto.getVin();
Integer operationValue = telecontrolParamDto.getOperationValue();
redisDataModel.set(throttleBrakeOperationValuePrefix + ":" + vin, String.valueOf(operationValue));
}
}
/**
* 退出接管失败再重试三次
* @param telecontrolParamDto
* @return
*/
private SSIResponse continueCloseControl(TelecontrolParamDto telecontrolParamDto) {
int tryTimes = 3;
int count = 0;
SSIResponse ssiResponse = null;
do {
try {
String paramData = JSONObject.toJSONString(telecontrolParamDto);
String result = RestTemplateUtil.post(String.format("%s%s", commandUrl, URL.TELECONTROL_URL), paramData, null);
ssiResponse = handleResult(result,telecontrolParamDto);
count++;
} catch (Exception e) {
log.error("重复请求请求失败:", e);
ssiResponse = SSIResponse.no("请求失败");
}
} while (ssiResponse.getCode() == -1 && count < tryTimes);
return ssiResponse;
}
private String handleParam(TelecontrolParamDto telecontrolParamDto) {
if (telecontrolParamDto.getControlType() == 2 && telecontrolParamDto.getOperationType() == null) {
return "常规操作,操作类型不能为空";
}
return null;
}
private SSIResponse handleResult(String result,TelecontrolParamDto teleDto) {
JSONObject jsonObject = JSONObject.parseObject(result);
String code = jsonObject.getJSONObject("status").getString("code");
String details = jsonObject.getJSONObject("status").getString("details");
if (!"0000".equals(code)) {
log.error(details);
return SSIResponse.no(details);
}
if (StringUtils.isNotBlank(jsonObject.getString("data"))) {
String ADCUStatus = jsonObject.getJSONObject("data").getString("ADCUStatus");
if ("1".equals(ADCUStatus)) {
log.error("ADCU正在控车");
return SSIResponse.no("ADCU正在控车");
}
}
if (teleDto.getControlType() == VehicleConstant.TELE_CONTROL_TYPE_TAKE_OVER){
String info = redisDataModel.get(controlInfo + ":" + teleDto.getVin());
return SSIResponse.ok(info);
}else {
String info = redisDataModel.get(controlInfo + ":" + teleDto.getVin());
JSONObject operJson = null;
if (StringUtils.isBlank(info)){
operJson = new JSONObject();
}else {
operJson = JSONObject.parseObject(info);
}
if(teleDto.getOperationType() == 1 || teleDto.getOperationType() == 6){
operJson.put(String.valueOf(6),2);
}else if(teleDto.getOperationType() != 7 || teleDto.getOperationType() < 0){
operJson.put(String.valueOf(teleDto.getOperationType()),teleDto.getOperationValue());
}
redisDataModel.set(controlInfo + ":" + teleDto.getVin(),operJson.toString());
}
/* String dataResult = jsonObject.getJSONObject("data").getString("result");
if (!"1".equals(dataResult)
&& !"17".equals(dataResult)
&& !"33".equals(dataResult)
&& !"49".equals(dataResult)) {
log.error(String.format("指令执行失败"));
return SSIResponse.no("指令执行失败");
}*/
return SSIResponse.ok();
}
public Map getControlStatus(String vin) {
String key = String.format("%s:%s", remoteControlStatusKeyPrefix, vin);
return redisDataModel.getJson2Map(key);
}
public Map getEmergencyStatus(String vin) {
String key = String.format("%s:%s", emergencyParkingKeyPrefix, vin);
return redisDataModel.getJson2Map(key);
}
public Map getAutoPilotStatus(String vin) {
String key = String.format("%s:%s", autoPilotKeyPrefix, vin);
return redisDataModel.getJson2Map(key);
}
public SSIResponse breakVehicle(String vin) {
TelecontrolParamDto paramDto = new TelecontrolParamDto();
paramDto.setVin(vin);
paramDto.setControlType(2);
paramDto.setOperationType(7);
paramDto.setOperationValue(-75);
paramDto.setZeroed(-1);
return vehicleTelecontrol(paramDto);
}
public void setOrRefreshSocketOvertime(String sessionId, String vin) {
redisDataModel.set(socketOvertimePrefix + ":" + sessionId + ":" + vin, vin, socketOvertimeTime);
}
public void deleteSocketOvertime(String sessionId, String vin) {
redisDataModel.del(socketOvertimePrefix + ":" + sessionId + ":" + vin);
}
/**
* 除取消接管操作外,紧停状态下其他操作不能操作
* @param telecontrolParamDto
* @return
*/
public boolean emergencyCheck(TelecontrolParamDto telecontrolParamDto) {
Integer controlType = telecontrolParamDto.getControlType();
Integer operationValue = telecontrolParamDto.getOperationValue();
//除取消接管操作外,紧停状态下其他操作不能操作
if (!(controlType == 1 && operationValue == 2)) {
String vin = telecontrolParamDto.getVin();
String key = String.format("%s:%s", emergencyParkingKeyPrefix, vin);
Map<String, Object> eMap = redisDataModel.getJson2Map(key);
if (eMap != null) {
Integer emergencyStatus = (Integer) eMap.get("emergencyStatus");
if (emergencyStatus == 1) {
return false;
}
}
}
return true;
}
/**
* 切换自动驾驶
* @return
*/
public SSIResponse switchAutopilot(SwitchAutoParamDto paramDto) {
String result = RestTemplateUtil.post(String.format("%s%s", commandUrl, URL.SWITCHAUTO_URL),
JSONObject.toJSONString(paramDto), null);
return handleResult(result);
}
private SSIResponse handleResult(String result) {
JSONObject jsonObject = JSONObject.parseObject(result);
String code = jsonObject.getJSONObject("status").getString("code");
String details = jsonObject.getJSONObject("status").getString("details");
if (!"0000".equals(code)) {
log.error(details);
return SSIResponse.no(details);
}
return SSIResponse.ok();
}
}
package com.ssi.model;
import com.alicp.jetcache.anno.CacheRefresh;
import com.alicp.jetcache.anno.Cached;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ssi.entity.VmsVehicle;
import com.ssi.mapper.VehicleTboxMapper;
import com.ssi.mapper.VmsVehicleMapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* Description: jetcahe 一般配置在Model层或service接口层
*
* @author LiXiaoCong
* @version 2019/8/20 14:00
*/
@Component
public class VehicleBaseInfoModel {
@Autowired
private VehicleTboxMapper vehicleTboxMapper;
@Autowired
private VmsVehicleMapper vehicleMapper;
@Cached(name = "mlVehicleBaseInfoModel:getVehicleBaseInfo", expire = 120, timeUnit = TimeUnit.MINUTES)
@CacheRefresh(refresh = 5, stopRefreshAfterLastAccess = 1440, timeUnit = TimeUnit.MINUTES)
public Map<String, Object> getVehicleBaseInfo(@Param("vin") String vin) {
return vehicleTboxMapper.getVehicleBaseInfo(vin);
}
// @Cached(name = "mlVehicleBaseInfoModel:getAllVehicleInfo", expire = 120, timeUnit = TimeUnit.MINUTES)
// @CacheRefresh(refresh = 5, stopRefreshAfterLastAccess = 1440, timeUnit = TimeUnit.MINUTES)
public List<VmsVehicle> getAllVehicleInfo() {
List<VmsVehicle> list = vehicleMapper.selectList(null);
return list;
}
}
package com.ssi.model;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ssi.constant.enums.VmsTosOrderStatusEnum;
import com.ssi.entity.ScrollTrackLocationEntity;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.ssi.entity.vo.TaskStatusHistory;
import com.ssi.response.SSIResponse;
import com.ssi.utils.ElasticSearchUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchScrollRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.Scroll;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/*
* 默认index 名称 和type 名称一致。
* */
@Component
@Slf4j
public class VehicleElasticSearchModel extends ElasticSearchModel {
public SSIResponse searchAllTrackLocations(String vin, String indexName, String indexRule,
Set<String> columns, String timeField, Long startTime,
Long stopTime, String posType) {
SearchRequestBuilder searchRequestBuilder = elasticSearchMetaModel.newSearchRequestBuilderInDayIndex(
startTime,
stopTime, indexName, 1, true, indexRule);
Map<String, Object> res = Maps.newHashMap();
if (searchRequestBuilder != null) {
int size = 10000;
SearchResponse searchResponse;
searchResponse = getSearchResponse(columns, searchRequestBuilder, timeField, vin, startTime,
stopTime, size);
long total = 0l;
List<Map<String, Object>> trips = Lists.newArrayList();
SearchHits hits = searchResponse.getHits();
SearchHit[] searchHits = hits.getHits();
//movingAveragePoints(searchHits, 10);
filterJumpPoint(searchHits);
while (searchHits != null && searchHits.length > 0) {
long hitsTotal = hits.getTotalHits();
List<Map<String, Object>> hitsTrip = Arrays.stream(searchHits).parallel().filter(hit -> {
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
if (sourceAsMap.get("abnormal") != null && (int) sourceAsMap.get("abnormal") == 1) {
return false;
}
return true;
}).map(hit -> {
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
if (posType != null) {
locationTypeChange(sourceAsMap, posType, "longitude", "latitude");
}
return sourceAsMap;
}).collect(Collectors.toList());
trips.addAll(hitsTrip);
if (searchHits.length == size) {
searchResponse = transportClient.prepareSearchScroll(searchResponse.getScrollId())
.setScroll(TimeValue.timeValueMinutes(5)).get();
searchHits = searchResponse.getHits().getHits();
} else {
break;
}
}
res.put("total", total);
res.put("records", trips);
} else {
res.put("total", 0L);
res.put("records", Lists.newArrayList());
}
return SSIResponse.ok(res.get("records"));
// return res;
}
/**
* 移动平均轨迹平滑方法
*/
public void movingAveragePoints(SearchHit[] searchHits, int length) {
for (int i = length - 1; i < searchHits.length; i++) {
Double sumLon = 0d;
Double sumLat = 0d;
for (int j = 0; j < length; j++) {
SearchHit hit = searchHits[i - j];
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
Double longitude = Double.parseDouble(sourceAsMap.get("longitude").toString());
Double latitude = Double.parseDouble(sourceAsMap.get("latitude").toString());
sumLon += longitude;
sumLat += latitude;
}
Double avgLon = sumLon / length;
Double avgLat = sumLat / length;
SearchHit searchHit = searchHits[i - length + 1];
Map<String, Object> sourceAsMap = searchHit.getSourceAsMap();
sourceAsMap.put("longitude", avgLon);
sourceAsMap.put("latitude", avgLat);
double[] newLocation = {avgLon, avgLat};
sourceAsMap.put("location", newLocation);
}
}
/**
* 轨迹跳点过滤
*/
public void filterJumpPoint(SearchHit[] searchHits) {
SearchHit last1 = null;
for (int i = 1; i < searchHits.length; i++) {
SearchHit hit = searchHits[i];
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
Long collectTime = Long.parseLong(sourceAsMap.get("collectTime").toString());
Double longitude = Double.parseDouble(sourceAsMap.get("longitude").toString());
Double latitude = Double.parseDouble(sourceAsMap.get("latitude").toString());
if (last1 == null) {
last1 = hit;
} else {
Long lastCollectTime1 = Long.parseLong(
last1.getSourceAsMap().get("collectTime").toString());
long diffTime = collectTime - lastCollectTime1;
if (diffTime == 0) {
diffTime = 1000L;
}
Double lastlongitude1 = Double.parseDouble(
last1.getSourceAsMap().get("longitude").toString());
Double lastLatitude1 = Double.parseDouble(
last1.getSourceAsMap().get("latitude").toString());
double diffLon = longitude - lastlongitude1;
double diffLat = latitude - lastLatitude1;
if (Math.abs(diffLat * 1000000) > 15 * diffTime / 1000) {
sourceAsMap.put("abnormal", 1);
continue;
}
if (Math.abs(diffLon * 100000) > 1.7 * diffTime / 1000) {
sourceAsMap.put("abnormal", 1);
continue;
}
last1 = hit;
}
}
}
private SearchResponse getSearchResponse(Set<String> columns,
SearchRequestBuilder searchRequestBuilder,
String timeField, String vin, Long startTime, Long stopTime, int size) {
if (columns != null && columns.size() > 0) {
//确保行程关键字段不缺失
columns.add("id");
columns.add("vin");
columns.add(timeField);
columns.add("longitude");
columns.add("latitude");
searchRequestBuilder.setFetchSource(columns.toArray(new String[columns.size()]), null);
}
BoolQueryBuilder queryBuilder = createBooleanQueryBuilderWithChinaLocation();
queryBuilder.mustNot(QueryBuilders.termQuery("keyOnStatus", -1));
if (vin != null) {
queryBuilder.must(QueryBuilders.termQuery("vin", vin));
}
RangeQueryBuilder rangeQueryBuilder = ElasticSearchUtil.createRangeQueryBuilder(timeField,
startTime, stopTime);
if (rangeQueryBuilder != null) {
queryBuilder.must(rangeQueryBuilder);
}
return searchRequestBuilder.setQuery(queryBuilder)
.addSort(timeField, SortOrder.ASC)
.setScroll(TimeValue.timeValueMinutes(5))
.setSize(size)
.get();
}
/**
* 深分页轨迹查询
*/
public SSIResponse searchScrollTrackLocations(String indexName, String indexRule,
String timeField, ScrollTrackLocationEntity scrollTrackLocationEntity) {
Map<String, Object> res = Maps.newHashMap();
long t = System.currentTimeMillis();
String[] indexs = elasticSearchMetaModel.getIndexs(scrollTrackLocationEntity.getStartTime(),
scrollTrackLocationEntity.getStopTime(), indexName, 1, true, indexRule);
if (indexs.length > 0) {
SearchResponse searchResponse;
if (scrollTrackLocationEntity.getScrollId() == null) {
SearchRequestBuilder requestBuilder = transportClient.prepareSearch(indexs)
.setTypes(indexName);
//设置筛选条件
BoolQueryBuilder queryBuilder =
addQueryCondition(createBooleanQueryBuilderWithChinaLocation(),
scrollTrackLocationEntity.getVin(), timeField,
scrollTrackLocationEntity.getStartTime(),
scrollTrackLocationEntity.getStopTime());
queryBuilder.mustNot(QueryBuilders.termQuery("keyOnStatus", -1));
requestBuilder.setQuery(queryBuilder);
//设置抓取字段
String[] columns = scrollTrackLocationEntity.getColumns();
Set<String> returnColumns = Sets.newHashSet("vin", timeField, "longitude", "latitude",
"collectTime");
if (columns != null) {
Arrays.stream(columns).forEach(returnColumns::add);
}
requestBuilder.setFetchSource(returnColumns.toArray(new String[returnColumns.size()]),
null);
//检查是否需要排序
if (scrollTrackLocationEntity.isSortByTime()) {
requestBuilder.addSort(timeField, SortOrder.ASC);
} else {
requestBuilder.addSort(FieldSortBuilder.DOC_FIELD_NAME, SortOrder.ASC);
}
requestBuilder.setScroll(TimeValue.timeValueMinutes(5));
requestBuilder.setSize(scrollTrackLocationEntity.getMaxSizePartition());
searchResponse = requestBuilder.get();
} else {
searchResponse = transportClient.prepareSearchScroll(
scrollTrackLocationEntity.getScrollId())
.setScroll(TimeValue.timeValueMinutes(5)).get();
}
List<Map<String, Object>> maps = Lists.newLinkedList();
//遍历结果
SearchHits hits = searchResponse.getHits();
SearchHit[] hitArray = hits.getHits();
Map<String, Object> sourceAsMap;
//跳点步长
int stepLength = scrollTrackLocationEntity.getStepLength();
for (int i = 0; i < hitArray.length; i = i + stepLength) {
sourceAsMap = hitArray[i].getSourceAsMap();
if (scrollTrackLocationEntity.getPosType() != null) {
locationTypeChange(sourceAsMap, scrollTrackLocationEntity.getPosType(), "longitude",
"latitude");
}
maps.add(sourceAsMap);
}
if (maps.size() > 0) {
res.put("total", hits.totalHits);
res.put("records", maps);
res.put("size", maps.size());
} else {
res = emptySearchHitResult();
}
res.put("over", (hitArray.length == 0) || (hitArray.length == hits.totalHits));
res.put("scrollId", searchResponse.getScrollId());
}
return SSIResponse.ok(res);
// return res;
}
private BoolQueryBuilder addQueryCondition(BoolQueryBuilder builder, String vin, String timeField,
Long startTime, Long stopTime) {
if (vin != null) {
builder.must(QueryBuilders.termsQuery("vin", vin));
}
if (startTime != null || stopTime != null) {
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(timeField);
if (startTime != null) {
rangeQueryBuilder.gte(startTime);
}
if (stopTime != null) {
rangeQueryBuilder.lte(stopTime);
}
builder.must(rangeQueryBuilder);
}
return builder;
}
public Map<String, Object> getOfflineVehicleList(String indexName, String timeField,
String vehicleCompany,
String vehicleType, Integer offlineDays, int page, int size) {
SearchRequestBuilder searchRequestBuilder = transportClient.prepareSearch(
String.format("%s_latest", indexName));
RangeQueryBuilder rangeQueryBuilder = null;
BoolQueryBuilder queryBuilder = createBooleanQueryBuilderWithChinaLocation();
if (offlineDays != null) {
rangeQueryBuilder = QueryBuilders.rangeQuery(timeField);
Long endTime = System.currentTimeMillis() - offlineDays * 24 * 60 * 60 * 1000;
rangeQueryBuilder.lte(endTime);
}
if (rangeQueryBuilder != null) {
queryBuilder.must(rangeQueryBuilder);
}
if (StringUtils.isNotBlank(vehicleType)) {
queryBuilder.must(QueryBuilders.termQuery("vehicleType", vehicleType));
}
if (StringUtils.isNotBlank(vehicleCompany)) {
queryBuilder.must(QueryBuilders.termQuery("vehicleCompany", vehicleCompany));
}
int start = (page - 1) * 10;
SearchResponse searchResponse = searchRequestBuilder.setQuery(queryBuilder)
.addSort(timeField, SortOrder.ASC)
.setSize(size)
.setFrom(start)
.get();
return extractSearchHits(searchResponse.getHits());
}
/**
* 获取任务历史数据
*/
public List<TaskStatusHistory> searchTaskHistory(String taskNo, String year) {
SearchRequestBuilder requestBuilder = transportClient.prepareSearch(
"harbor_order_status_" + year).setTypes("harbor_order_status");
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.termQuery("sn", taskNo));
boolQueryBuilder.must(QueryBuilders.existsQuery("status"));
Set<String> returnColumns = Sets.newHashSet("vin", "sn", "status", "collectTime",
"errorMessage");
SearchResponse response = requestBuilder.setQuery(boolQueryBuilder)
.setFetchSource(returnColumns.toArray(new String[returnColumns.size()]), null)
.addSort("collectTime", SortOrder.ASC)
.get();
SearchHit[] hits = response.getHits().getHits();
List<TaskStatusHistory> list = Stream.of(hits).map(hit -> {
String sourceAsString = hit.getSourceAsString();
TaskStatusHistory taskStatusHistory = JSON.parseObject(sourceAsString,
TaskStatusHistory.class);
VmsTosOrderStatusEnum anEnum = VmsTosOrderStatusEnum.find(taskStatusHistory.getStatus());
if (anEnum != null) {
taskStatusHistory.setStatusDescription(anEnum.getDescription());
}
return taskStatusHistory;
}).collect(Collectors.toList());
return list;
}
/**
* 批量获取任务历史数据
*/
public Map<String, List<TaskStatusHistory>> searchTaskHistory(List<String> taskNoList,
String year) {
SearchRequestBuilder requestBuilder = transportClient.prepareSearch(
"harbor_order_status_" + year).setTypes("harbor_order_status");
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.termsQuery("sn", taskNoList));
boolQueryBuilder.must(QueryBuilders.existsQuery("status"));
Set<String> returnColumns = Sets.newHashSet("vin", "sn", "status", "collectTime",
"errorMessage");
Scroll scroll = new Scroll(TimeValue.timeValueMinutes(10L));
SearchResponse response = requestBuilder.setQuery(boolQueryBuilder)
.setFetchSource(returnColumns.toArray(new String[returnColumns.size()]), null)
.addSort("collectTime", SortOrder.ASC)
.setScroll(scroll)
.setSize(2000)
.get();
//结果集为升序排序
SearchHit[] hits = response.getHits().getHits();
Map<String, List<TaskStatusHistory>> statusMap = new HashMap<>();
boolean needContinue = true;
while (hits != null && hits.length > 0 && needContinue) {
for (SearchHit hit : hits) {
String sourceAsString = hit.getSourceAsString();
TaskStatusHistory taskStatusHistory = JSON.parseObject(sourceAsString,
TaskStatusHistory.class);
VmsTosOrderStatusEnum anEnum = VmsTosOrderStatusEnum.find(taskStatusHistory.getStatus());
if (anEnum != null) {
taskStatusHistory.setStatusDescription(anEnum.getDescription());
}else{
//移除未知状态
continue;
}
if (statusMap.get(taskStatusHistory.getSn()) == null) {
List<TaskStatusHistory> list = new ArrayList<>();
list.add(taskStatusHistory);
statusMap.put(taskStatusHistory.getSn(), list);
} else {
List<TaskStatusHistory> list = statusMap.get(taskStatusHistory.getSn());
list.add(taskStatusHistory);
statusMap.put(taskStatusHistory.getSn(), list);
}
}
if (hits.length == 2000) {
response = transportClient.prepareSearchScroll(response.getScrollId())
.setScroll(TimeValue.timeValueMinutes(5)).get();
hits = response.getHits().getHits();
} else {
needContinue = false;
}
}
transportClient.prepareClearScroll();
return statusMap;
}
/**
* 获取车辆最近车况数据
*/
public Map searchLatestVehicleData(String vin) {
SearchRequestBuilder requestBuilder = transportClient.prepareSearch("vms_igv_vehicle_latest")
.setTypes("vms_igv_vehicle");
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.termQuery("vin", vin));
SearchResponse response = requestBuilder.setQuery(boolQueryBuilder)
.get();
SearchHit[] hits = response.getHits().getHits();
if (hits != null && hits.length > 0) {
SearchHit hit = hits[0];
String jsonStr = hit.getSourceAsString();
JSONObject object = JSON.parseObject(jsonStr);
return object;
}
return null;
}
}
package com.ssi.model;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ssi.constant.RedisKey;
import com.ssi.constant.VehicleConstant;
import com.ssi.constant.enums.VmsTosOrderStatusEnum;
import com.ssi.entity.VmsIndividuationConfig;
import com.ssi.entity.dto.Point;
import com.ssi.mapper.VmsIndividuationConfigMapper;
import com.ssi.utils.ConfigUtils;
import com.ssi.utils.FieldUtil;
import com.ssi.utils.JsonUtil;
import com.ssi.utils.VehicleDataUtil;
import com.sun.prism.shader.Solid_TextureYV12_AlphaTest_Loader;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.math3.util.MathUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
/**
* description:
*
* @author WangHD
* @version 1.0
* @date 2020/3/20 0020 9:59
*/
@Component
@EnableScheduling
@Slf4j
public class VehicleLatestDataModel {
@Value("${vehicle.latestData.redis.prefix:ivccs:vms:vehicle:latest}")
private String latestRedisKeyPrefix;
@Value("${vehicle.latestData.redis.postfix:harbor_D00A}")
private String latestRedisKeyPostfix;
@Value("${vehicle.latestData.redis.001postfix:harbor_D001}")
private String latestRedisKeyD001Postfix;
@Value("${vehicle.latestData.redis.002postfix:harbor_D002}")
private String latestRedisKeyD002Postfix;
@Value("${vehicle.status.redis.keyPrefix:harbor:vehicle:online}")
private String statusRedisKeyPrefix;
@Value("${order.latestOrderKeyPrefix:harbor:command:status}")
private String latestOrderKeyPrefix;
@Value("${harbor.command.vehicle_path_keyPrefix}")
private String vehiclePathKeyPrefix;
@Value("${harbor.vehicle.confirm_status_prefix}")
private String harborVehicleConfirmStatusPrefix;
@Value("${vehicle.cache.key:ivccs:vms:vehicle:cache}")
private String vehicleCacheKey;
@Value("${harbor.remote.emergencyParking}")
private String vehicleEmergencyCacheKey;
@Value("${vehicle.latestData.redis.preLocationFix}")
private String preLocationFix;
@Value("${harbor.command.info_key:harbor:command:vin:info}")
private String infoKeyPrefix;
@Value("${harbor.vehicle.onstatusKey:harbor:vehicle:onstatus}")
private String onstatusKey;
@Value("${harbor.vehicle.onlineKey:harbor:vehicle:online}")
private String onlineKey;
@Value("${harbor.command.twenty_foot:harbor:command:twenty_foot:order_latest_five}")
private String orderLatestFiveKey;
@Value("${client.onlineTime:60000}")
private Long onlineTime;
/**
* 用于判断在这个时长里面的任务是否推送到前端
*/
@Value("${client.pushTime:1800000}")
private Long pushTime;
@Autowired
private VehicleBaseInfoModel vehicleInfoModel;
@Autowired
private RedisDataModel singleNodeModel;
@Autowired
private RedisDataModel redisDataModel;
@Autowired
private VehicleDataUtil vehicleDataUtil;
@Autowired
private VmsIndividuationConfigMapper individuationConfigMapper;
private static Map<String, Map<String, Object>> vehicleStatusMap = Maps.newHashMap();
/**
* 停车时经纬度跳变处理
*/
private Map<String, String> lastMap = Maps.newConcurrentMap();
private static Object STATUS_LOCK = new Object();
public List<Map<String, Object>> getOnlineData(String key) {
List<Map<String, Object>> listMap = new ArrayList<>();
List<String> keyList = Splitter.on(",").omitEmptyStrings().trimResults().splitToList(key);
List<String> keyList2 = Lists.newArrayList(keyList);
if (!keyList.isEmpty()) {
try {
Set<String> keySet = redisDataModel.keys(String.format("%s:*", latestRedisKeyPrefix));
Set<String> filterVins = keySet.stream()
.map(r -> r.replaceAll(String.format("%s:*", latestRedisKeyPrefix), ""))
.collect(Collectors.toSet());
//取交集 有最新数据车辆
keyList.retainAll(filterVins);
//取差集 无最新数据车辆
keyList2.removeAll(keyList);
if (keyList.size() > 0) {
//生成最新数据的Keys
keyList = keyList.stream()
.map(r -> String.format("%s:%s", latestRedisKeyPrefix, r))
.collect(Collectors.toList());
List<String> mget = redisDataModel.mget(keyList.toArray(new String[keyList.size()]));
int size = mget.size();
String vin;
Integer status;
Map<String, Object> record;
Map<String, Object> statusMap;
Map<String, Object> vehicleInfo;
for (int i = 0; i < size; i++) {
record = JsonUtil.jsonToMap(mget.get(i));
vin = String.valueOf(record.get("vin"));
synchronized (STATUS_LOCK) {
statusMap = vehicleStatusMap.get(vin);
status = statusMap == null ? 0 : (Integer) statusMap.getOrDefault("state", 0);
}
if (1 == status) {
record.put("isOnline", "在线");
//在线行驶中
Double speed = ConfigUtils.getAsDoubleWithDefault(record, "gpsSpeed", 0.0);
if (speed > 0.0) {
record.put("isOnline", "在线,行驶中");
}
} else {
record.put("isOnline", "离线");
}
vehicleInfo = vehicleInfoModel.getVehicleBaseInfo(vin);
if (vehicleInfo != null) {
record.put("plateNo", vehicleInfo.get("plate_no"));
record.put("vehicleType", vehicleInfo.get("vehicle_type"));
}
listMap.add(record);
}
}
if (!keyList2.isEmpty()) {
keyList2.stream().forEach(vin -> {
Map<String, Object> record = Maps.newHashMap();
record.put("vin", vin);
record.put("isOnline", "离线");
Map<String, Object> vehicleInfo = vehicleInfoModel.getVehicleBaseInfo(vin);
if (vehicleInfo != null) {
record.put("plateNo", vehicleInfo.get("plate_no"));
record.put("vehicleType", vehicleInfo.get("vehicle_type"));
}
listMap.add(record);
});
}
} catch (Exception e) {
log.error(String.format("读取%s失败", key), e);
}
}
return listMap;
}
public Object getVehicleStatus(String vins, Integer status) {
List<Map<String, Object>> resultList = Lists.newArrayList();
try {
List<String> keys = getLatestDataKeys(vins, true);
List<String> recordJsons = redisDataModel.mget(keys.toArray(new String[keys.size()]));
resultList = recordJsons.stream().map(json -> {
Map<String, Object> record = JsonUtil.jsonToMap(json);
String vin = (String) record.get("vin");
Integer online;
synchronized (STATUS_LOCK) {
Map<String, Object> statusMap = vehicleStatusMap.get(vin);
online = statusMap == null ? 0 : (Integer) statusMap.getOrDefault("state", 0);
}
if (online == 1) {
Double speed = ConfigUtils.getAsDoubleWithDefault(record, "speed", 0.0);
if (speed > 0.0) {
record.put("vehicleStatus", "在线,行驶中");
record.put("vehicleStatusCode", 2);
} else {
record.put("vehicleStatus", "在线");
record.put("vehicleStatusCode", 1);
}
} else {
record.put("vehicleStatus", "离线");
record.put("vehicleStatusCode", 0);
}
return record;
}).collect(Collectors.toList());
if (status != null && status >= 0 && status <= 2) {
resultList = resultList.stream().filter(record -> {
Integer vehicleStatusCode = ConfigUtils.getAsIntegerWithDefault(record, "vehicleStatusCode", -1);
return status.equals(vehicleStatusCode);
}).collect(Collectors.toList());
}
} catch (Exception e) {
log.error("查询车辆状态异常", e);
}
return resultList;
}
private List<String> getLatestDataKeys(String vins, boolean emptyForAll) {
List<String> keys = Lists.newArrayList();
if (StringUtils.isNotBlank(vins)) {
String[] split = vins.split(",");
for (String vin : split) {
keys.add(String.format("%s:%s", latestRedisKeyPrefix, vin.trim()));
}
}
if (keys.isEmpty() && emptyForAll) {
String prefix = String.format("%s:*", latestRedisKeyPrefix);
keys.addAll(redisDataModel.keys(prefix));
}
return keys;
}
private Map<String, Map<String, Object>> readLatestStatusFromRedis(Map<String, String> keysMap) {
Map<String, Map<String, Object>> res = Maps.newHashMap();
keysMap.entrySet().parallelStream().forEach(entry -> {
//数据获取
String redisKey = entry.getValue();
// Map<String, Object> record = redisModel.getJson2Map(redisKey);
Map<String, Object> record = new HashMap<>();
String state = redisDataModel.get(redisKey);
if (StringUtils.isNotBlank(state)) {
record.put("state", Integer.parseInt(state));
}
res.put(entry.getKey(), record);
});
return res;
}
@Scheduled(fixedRateString = "${spring.websocket.scheduled.time:1000}")
public Map<String, Map<String, Object>> allRealTimeStatus() {
Map<String, Map<String, Object>> res;
String prefixStatus = String.format("%s:*", statusRedisKeyPrefix);
Set<String> keyStatus = redisDataModel.keys(prefixStatus);
if (keyStatus != null && !keyStatus.isEmpty()) {
Map<String, String> keysMap = Maps.newHashMap();
keyStatus.stream().forEach(key -> {
String vin = key.replace(String.format("%s:", statusRedisKeyPrefix), "");
keysMap.put(vin, key);
});
res = readLatestStatusFromRedis(keysMap);
} else {
res = Maps.newHashMap();
}
synchronized (STATUS_LOCK) {
vehicleStatusMap = res;
}
return res;
}
public Map<String, Map<String, Object>> allRealTimeData(boolean checkRepeat) {
Map<String, Map<String, Object>> res;
//获取所有vin
String prefix = String.format("%s:*", latestRedisKeyPrefix);
Set<String> keysUnResolveRepeat = redisDataModel.keys(prefix);
Set<String> vins = keysUnResolveRepeat.stream().map(key -> {
key = key.replace(String.format("%s:", latestRedisKeyPrefix), "");
key = key.substring(0, key.indexOf("-"));
return key;
}).collect(Collectors.toSet());
//拼接所有类型key
if (vins != null && !vins.isEmpty()) {
Map<String, Map<String, String>> keysMap = Maps.newHashMap();
vins.stream().forEach(key -> {
//判断车辆是否禁用
Map<String, Object> vehicleInfoRecord = redisDataModel.hgetJson2Map(vehicleCacheKey, key);
if(vehicleInfoRecord == null || vehicleInfoRecord.get("status") == null
|| (Integer)vehicleInfoRecord.get("status") == 1){
return;
}
Map<String, String> keyPreMap = Maps.newHashMap();
keyPreMap.put("vin", key);
keyPreMap.put("latestKey", String.format("%s:%s-%s", latestRedisKeyPrefix, key, latestRedisKeyPostfix));
keyPreMap.put("d001Key", String.format("%s:%s-%s", latestRedisKeyPrefix, key, latestRedisKeyD001Postfix));
keyPreMap.put("d002Key", String.format("%s:%s-%s", latestRedisKeyPrefix, key, latestRedisKeyD002Postfix));
keyPreMap.put("orderKey", String.format("%s:%s", latestOrderKeyPrefix, key));
keyPreMap.put("vehiclePathKey", String.format("%s:%s", vehiclePathKeyPrefix, key));
keyPreMap.put("threeConfirmStatus", String.format("%s:%s", harborVehicleConfirmStatusPrefix, key));
keyPreMap.put("emergencyTypeKey", String.format("%s:%s", vehicleEmergencyCacheKey, key));
keyPreMap.put("onstatusKey",String.format("%s:%s",onstatusKey,key));
keyPreMap.put("onlineKey",String.format("%s:%s",onlineKey,key));
keyPreMap.put("orderLatestFiveKey", String.format("%s:%s", "harbor:command:twenty_foot:order_latest_five", key));//双小箱数据
keysMap.put(key, keyPreMap);
});
res = readLatestDataFromRedis(keysMap, checkRepeat);
} else {
res = Maps.newHashMap();
}
return res;
}
public Map<String, Map<String, Object>> getVehicleRunData() {
Map<String, Map<String, Object>> res = Maps.newHashMap();
//获取所有vin
String prefix = String.format("%s:*", latestRedisKeyPrefix);
Set<String> keysUnResolveRepeat = redisDataModel.keys(prefix);
Set<String> vins = keysUnResolveRepeat.stream().map(key -> {
key = key.replace(String.format("%s:", latestRedisKeyPrefix), "");
key = key.substring(0, key.indexOf("-"));
return key;
}).collect(Collectors.toSet());
//拼接所有类型key
if (vins != null && !vins.isEmpty()) {
vins.stream().forEach(key -> {
//判断车辆是否禁用
Map<String, Object> vehicleInfoRecord = redisDataModel.hgetJson2Map(vehicleCacheKey, key);
if(vehicleInfoRecord == null || vehicleInfoRecord.get("status") == null
|| (Integer)vehicleInfoRecord.get("status") == 1){
return;
}
String latestKey = String.format("%s:%s-%s", latestRedisKeyPrefix, key, latestRedisKeyPostfix);
Map<String, Object> record = redisDataModel.getJson2Map(latestKey);
String emergencyParking = String.format("%s:%s", vehicleEmergencyCacheKey, key);
Map<String, Object> emergencyStatusMap = redisDataModel.getJson2Map(emergencyParking);
Integer emergencyStatus = 2;
if (emergencyStatusMap != null) {
emergencyStatus = (Integer) emergencyStatusMap.get("emergencyStatus");
}
if (record != null && !record.isEmpty() && checkAndAppendStatus(record) == 1) {
record.put("vehicleNum", vehicleInfoRecord == null ? null : vehicleInfoRecord.get("vehicleNum"));
record.put("emergencyStatus", emergencyStatus);
res.put(key,record);
}
});
}
return res;
}
public Map<String, Map<String, Object>> readLatestDataFromRedis(Map<String, Map<String, String>> keysMap, boolean checkRepeat) {
Map<String, Map<String, Object>> res = Maps.newHashMap();
keysMap.entrySet().parallelStream().forEach(entry -> {
Map<String, String> redisKeyMap = entry.getValue();
String vin = redisKeyMap.get("vin");
String latestKey = redisKeyMap.get("latestKey");
String orderKey = redisKeyMap.get("orderKey");
String vehiclePathKey = redisKeyMap.get("vehiclePathKey");
String threeConfirmStatusKey = redisKeyMap.get("threeConfirmStatus");
String emergencyTypeKey = redisKeyMap.get("emergencyTypeKey");
String obuStatus = redisDataModel.get(redisKeyMap.get("onstatusKey"));
String onlineStatus = redisDataModel.get(redisKeyMap.get("onlineKey"));
String craneNo = redisDataModel.get(RedisKey.VEHICLE_TO_CRANE.getKeyPrefix().concat(vin));
orderLatestFiveKey=redisKeyMap.get("orderLatestFiveKey");
String infoKey=String.format("%s:%s",infoKeyPrefix,vin);
String vehicleMap = redisDataModel.get(infoKey);
vehicleMap = StringUtils.isNotBlank(vehicleMap) ? vehicleMap :singleNodeModel.get(infoKey);
Integer vehicleType = 1; //1:X69B ,2:X69C,3:有人集卡两秒
if(vehicleMap != null) {//判断redis是否存在,不存在则查询数据库
JSONObject jsonObject = JSONObject.parseObject(vehicleMap);
vehicleType =jsonObject.getInteger("vehicleType");
}
Map<String, Object> record = redisDataModel.getJson2Map(latestKey);
//record 不为空, 且状态为在线状态
if(vehicleType == 3){
record = redisDataModel.getJson2Map(latestKey);
if (record != null && !record.isEmpty() && checkAndAppendStatus(record) == 1) {
Map<String, Object> newRecord=Maps.newHashMap();
record.remove("originalMsg");
Map<String, Object> vehicleInfoRecord = singleNodeModel.hgetJson2Map(vehicleCacheKey, vin);
String vehiclePath = null;
if (!repeatCheck(entry.getKey(), record, checkRepeat)) {
double[] locaction = parseLocation(record);
if (locaction != null) {//有人集卡暂时不需要任务描述,可以不用推送到前端,减少前端缓存,以后需要可和前端商量需要的字段
newRecord.put("isOnline",1);
newRecord.put("clientStatus",record.get("clientStatus"));
newRecord.put("vin",record.get("vin"));
newRecord.put("vehicleType",vehicleInfoRecord == null ? vehicleType : vehicleInfoRecord.get("vehicleType"));
newRecord.put("vehicleNum", vehicleInfoRecord == null ? null : vehicleInfoRecord.get("vehicleNum"));
newRecord.put("latitude",record.get("latitude"));
newRecord.put("preLocation",record.get("preLocation"));
newRecord.put("longitude",record.get("longitude"));
newRecord.put("gear",record.get("gear"));
newRecord.put("altitude",record.get("altitude"));
newRecord.put("speed",record.get("speed"));
newRecord.put("location", locaction);
newRecord.put("collectTime",record.get("collectTime"));
newRecord.put("soc",record.get("soc"));
newRecord.put("totalMile",record.get("totalMile"));
res.put(entry.getKey(), newRecord);
}
}
}
}else if (record != null && !record.isEmpty()){
Map<String, Object> newRecord=Maps.newHashMap();
record.remove("originalMsg");
Map<String, Object> orderRecord = redisDataModel.getJson2Map(orderKey);
Map<String, Object> vehicleInfoRecord = redisDataModel.hgetJson2Map(vehicleCacheKey, vin);
Map<String, Object> vehicleEmergencyRecord = redisDataModel.getJson2Map(emergencyTypeKey);
Map<String, Object> newOrderRecord=new HashMap<>();
newRecord.put("stopExceed",0);
if (!repeatCheck(entry.getKey(), record, checkRepeat)) {
double[] location = parseLocation(record);
if (location == null){
location = new double[]{119.968264,24.458783};//117.9682640,24.4587837
newOrderRecord.put("msg","定位偏移,超出范围");
// newRecord.put("stopExceed",1);
}
if(orderRecord != null){
int status = (Integer) orderRecord.get("status");
//车辆到达目的地之后不推送规划路径;判断任务是否过期,过期之后不推送路径规划
if ((status == VehicleConstant.PATH_PLANNING || status == VehicleConstant.START_TASK)
&& (System.currentTimeMillis() - Long.valueOf(orderRecord.get("collectTime").toString()) < VehicleConstant.ORDER_EXPIRATION_TIME)){
String vehiclePath = redisDataModel.get(vehiclePathKey);
//添加任务规划点
newOrderRecord.put("vehiclePath", JSONObject.parse(vehiclePath));
}
//计算任务是否等待超时
BigDecimal taskTime = calTime(orderRecord.get("startTime"),orderRecord.get("endTime"));
if ((status == VehicleConstant.OBU_RECEIVED || status == VehicleConstant.ADCU_RECEIVED)
&& taskTime != null && taskTime.compareTo(BigDecimal.valueOf(180)) > 0){
newOrderRecord.put("msg","任务等待超时");
}
//判断到达目的地车辆,是否状态异常
Integer subTaskType = Objects.isNull(orderRecord.get("subTaskType")) ? null : (Integer) orderRecord.get("subTaskType");
Long lastTime = Objects.nonNull(orderRecord.get("updateTime")) ? (Long) orderRecord.get("updateTime") : null;
Long currentTime = System.currentTimeMillis();
VmsIndividuationConfig overtimeValue = individuationConfigMapper.selectOne(new LambdaUpdateWrapper<VmsIndividuationConfig>().eq(VmsIndividuationConfig::getConfigKey,"wait_overtime_energy_key"));
Integer valueType = 300000;
if(Objects.nonNull(overtimeValue)){
valueType = 60000*Integer.valueOf(overtimeValue.getConfigValue());
}
/* if(status==3&&currentTime-lastTime>valueType&&(subTaskType == null || subTaskType == 3 || subTaskType == 4 || subTaskType == 6 || subTaskType == 8 || subTaskType == 10 || subTaskType == 12)){
newRecord.put("stopExceed",1);
}*/
orderRecord.put("estimatedArriveTime", LocalDateTime.now().plus(10, ChronoUnit.MINUTES));
//添加任务描述
String description = vehicleDataUtil.generateOrderDescription(orderRecord);
//判断subTaskType:0去缓冲区1,2 去扭锁站 其他用查询出来的
if (Objects.nonNull(subTaskType)){//判断subTaskType redis是否存在
// int subTaskType = (Integer) orderRecord.get("subTaskType");
if (subTaskType == 0){
newOrderRecord.put("orderDescription","去缓冲区");
}else if(subTaskType ==1 || subTaskType==2){
newOrderRecord.put("orderDescription","去扭锁站");
}else{
newOrderRecord.put("orderDescription",description);
}
}else{
newOrderRecord.put("orderDescription",description);
}
//设置双小箱任务数据取第二小箱状态 0:不生效,1生效
newOrderRecord.put("doubleBoxStatus",0);
Object containerInfos = orderRecord.get("containerInfos");
if(Objects.nonNull(containerInfos)){
JSONArray containerInfos1 = (JSONArray) containerInfos;
if(containerInfos1.size()>1&&status==49&&orderRecord.get("taskLocationType")!=null&&(Integer) orderRecord.get("taskLocationType")==1){//双小箱任务&&停稳锁死&&目的地是堆场
newOrderRecord.put("doubleBoxStatus",1);
}
}
newOrderRecord.put("containerInfos", orderRecord.get("containerInfos")==null?new JSONArray():orderRecord.get("containerInfos"));
newOrderRecord.put("vehicleLocation",orderRecord.get("vehicleLocation")==null?"":orderRecord.get("vehicleLocation"));
newOrderRecord.put("vehicleTaskLabel",orderRecord.get("vehicleTaskLabel") == null ?"":orderRecord.get("vehicleTaskLabel"));
newOrderRecord.put("taskType",orderRecord.get("taskType") == null ?"":orderRecord.get("taskType"));
newOrderRecord.put("taskNo",orderRecord.get("taskNo")==null?"":orderRecord.get("taskNo"));
newOrderRecord.put("vin",orderRecord.get("vin")==null?"":orderRecord.get("vin"));
newOrderRecord.put("longitude",orderRecord.get("longitude") == null?"":orderRecord.get("longitude"));
newOrderRecord.put("vehicleTaskType",orderRecord.get("vehicleTaskType") == null?"":orderRecord.get("vehicleTaskType"));
newOrderRecord.put("targetType",orderRecord.get("targetType") == null?"":orderRecord.get("targetType"));
newOrderRecord.put("lockLabel",orderRecord.get("lockLabel") == null?"":orderRecord.get("lockLabel") );
newOrderRecord.put("status",orderRecord.get("status") == null?"":orderRecord.get("status"));
newOrderRecord.put("taskLocationType",orderRecord.get("taskLocationType")==null ? "" : orderRecord.get("taskLocationType"));
newOrderRecord.put("collectTime",orderRecord.get("collectTime")== null?"":orderRecord.get("collectTime"));
newOrderRecord.put("taskSource",orderRecord.get("taskSource")== null?"":orderRecord.get("taskSource"));
newOrderRecord.put("goShipCraneLaneStatus",orderRecord.get("goShipCraneLaneStatus")== null?"":orderRecord.get("goShipCraneLaneStatus"));
newOrderRecord.put("msg",orderRecord.get("msg")== null?"":orderRecord.get("msg"));
newOrderRecord.put("parkingAreaNo",orderRecord.get("parkingAreaNo"));
}else{//没值的话也要给前端空字符串不然前端会崩
newOrderRecord.put("vehicleLocation","");
newOrderRecord.put("vehicleTaskLabel","");
newOrderRecord.put("taskType","");
newOrderRecord.put("taskNo","");
newOrderRecord.put("vin","");
newOrderRecord.put("longitude","");
newOrderRecord.put("vehicleTaskType","");
newOrderRecord.put("targetType","");
newOrderRecord.put("lockLabel","");
newOrderRecord.put("status","");
newOrderRecord.put("taskLocationType","");
newOrderRecord.put("vehiclePath","");
newOrderRecord.put("collectTime","");
newOrderRecord.put("taskSource","");
newOrderRecord.put("containerInfos", new JSONArray());
newOrderRecord.put("doubleBoxStatus",0);
newOrderRecord.put("parkingAreaNo","");
}
//onlineStatus这个数据是在redis里面,判断是否在线方法1上线0下线
if ((onlineStatus != null && onlineStatus.equals("1")&&obuStatus!=null&&obuStatus.equals("1"))){
newRecord.put("isOnline",1);
}else{
newRecord.put("isOnline",0);
}
newRecord.put("clientStatus",record.get("clientStatus"));
newRecord.put("vin",record.get("vin"));
newRecord.put("craneNo",StringUtils.isNotBlank(craneNo)?craneNo:"");
newRecord.put("vehicleType",vehicleInfoRecord == null ? "" : vehicleInfoRecord.get("vehicleType"));
newRecord.put("vehicleNum", vehicleInfoRecord == null ? "" : vehicleInfoRecord.get("vehicleNum"));
newRecord.put("gear",record.get("gear"));
newRecord.put("altitude",record.get("altitude"));
newRecord.put("speed",record.get("speed"));
//判断当前的任务时间是否超过配置的时长,超过不推送数据
newRecord.put("direction",record==null?"":record.get("direction"));
if (!"".equals(newOrderRecord.get("collectTime")) && checkTime(newOrderRecord) == 1) {
newRecord.put("orderData", newOrderRecord);
newRecord.put("status", VmsTosOrderStatusEnum.find(Integer.valueOf(newOrderRecord.get("status")+""))==null?"":VmsTosOrderStatusEnum.find(Integer.valueOf(newOrderRecord.get("status")+"")).getDescription());
Integer vehicleTaskLabel = (Integer)newOrderRecord.get("vehicleTaskLabel");
Object o = Objects.isNull(vehicleTaskLabel) ? newRecord.put("vinFlag", 1) :
(1==vehicleTaskLabel ? newRecord.put("vinFlag", 3) :
(2==vehicleTaskLabel ? newRecord.put("vinFlag", 4) : newRecord.put("vinFlag", 5)));
} else {
newRecord.put("orderData", "");
newRecord.put("craneNo","");
newRecord.put("status","-");//没有订单就没有订单状态
Object o = (Integer) newRecord.get("isOnline") == 0 ? newRecord.put("vinFlag", 0) : newRecord.put("vinFlag", 2);
}
newRecord.put("collectTime",record.get("collectTime"));
newRecord.put("soc",record.get("soc"));
//判断车辆的速度是否为0,速度为0的情况,判断车辆位置信息
newRecord.put("location", location);
//以上的字段都是重新封装成前端需要的字段,如需要其他字段可在record这里面获取,orderRecord这个map里面是redis里面全部的任务信息字段
res.put(entry.getKey(), newRecord);
}
}
});
return res;
}
private BigDecimal calTime(Object startTime, Object endTime) {
if (startTime != null) {
Long startDate = (Long) startTime;
BigDecimal timeSeconds = null;
if(endTime == null){
timeSeconds = new BigDecimal(System.currentTimeMillis() - startDate).divide(new BigDecimal(1000), 0, BigDecimal.ROUND_CEILING);
}else{
Long endDate = (Long) endTime;
timeSeconds = new BigDecimal(endDate - startDate).divide(new BigDecimal(1000), 0, BigDecimal.ROUND_CEILING);
}
return timeSeconds;
}
return null;
}
private String formatTime(BigDecimal seconds) {
int sec = seconds.intValue();
if(sec < 0 ){
return "0秒";
}
StringBuilder sb = new StringBuilder();
if (sec < 60) {
sb.append(seconds + "秒");
}else if (sec >= 60 && sec < 3600) {
int m = sec/60;
int s = sec%60;
sb.append(m + "分");
if(s > 0){
sb.append(s + "秒");
}
}else {
int h = sec/3600;
int m = (sec%3600)/60;
int s = (sec%3600)%60;
sb.append(h + "小时");
if(m > 0){
sb.append(m + "分");
}
if(s > 0){
sb.append(s + "秒");
}
}
return sb.toString();
}
private boolean repeatCheck(String vin, Map<String, Object> record, boolean checkRepeat) {
boolean repeat = false;
if (checkRepeat) {
Object speed = record.get("speed");
// if(speed != null && (Float)speed <= 0){
// return false;
// }
Object collectTime = record.get("collectTime");
Object latitude = record.get("latitude");
Object longitude = record.get("longitude");
String format = String.format("%s,%s,%s", collectTime, latitude, longitude);
repeat = (format.equals(lastMap.get(vin)));
if (!repeat) {
lastMap.put(vin, format);
}
}
// return repeat;
return false;
}
private int checkAndAppendStatus(Map<String, Object> record) {
Integer status;
synchronized (STATUS_LOCK) {
Map<String, Object> statusMap = vehicleStatusMap.get(record.get("vin"));
status = statusMap == null ? -1 : (Integer) statusMap.getOrDefault("state", -1);
}
Long time = ConfigUtils.getAsLong(record, "collectTime");
/** 检查终端状态*/
boolean dataOnline = (time != null && System.currentTimeMillis() - time < onlineTime);
boolean isOnline = dataOnline; //&& status == 1;
record.put("clientStatus", isOnline ? "在线" : "离线");
record.put("state", isOnline ? 1 : 0);
return isOnline ? 1 : 0;
}
/**
* 检查当前时间是否在半个小时内时间orderData里面的字段
* */
private int checkTime(Map<String, Object> record) {
Long time = ConfigUtils.getAsLong(record, "collectTime");
/** 检查当前时间是否在半个小时内*/
boolean dataOnline = (time != null && System.currentTimeMillis() - time < pushTime);
return dataOnline ? 1 : 0;
}
private double[] parseLocation(Map<String, Object> record) {
Double longitude = ConfigUtils.getAsDoubleWithDefault(record, "longitude", 0.0);
Double latitude = ConfigUtils.getAsDoubleWithDefault(record, "latitude", 0.0);
double[] location = null;
//中国境内
if (longitude < 135 && longitude >= 73 && latitude >= 4 && latitude < 53) {
BigDecimal longitudeDecimal = new BigDecimal(longitude);
longitudeDecimal = longitudeDecimal.setScale(6, BigDecimal.ROUND_DOWN);
BigDecimal latitudeDecimal = new BigDecimal(latitude);
latitudeDecimal= latitudeDecimal.setScale(6, BigDecimal.ROUND_DOWN);
location = new double[]{longitudeDecimal.doubleValue(), latitudeDecimal.doubleValue()};
} else {
// log.warn(String.format("记录中的经纬度不在国内: %s", record));
}
return location;
}
public String getLatestRedisKeyPrefix() {
return latestRedisKeyPrefix;
}
public String getLatestRedisKeyPostfix() {
return latestRedisKeyPostfix;
}
public String getLatestRedisKeyD001Postfix() {
return latestRedisKeyD001Postfix;
}
public String getLatestRedisKeyD002Postfix() {
return latestRedisKeyD002Postfix;
}
public RedisDataModel getRedisModel() {
return redisDataModel;
}
public String getStatusRedisKeyPrefix() {
return statusRedisKeyPrefix;
}
public VehicleBaseInfoModel getVehicleInfoModel() {
return vehicleInfoModel;
}
}
package com.ssi.model;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.EvictingQueue;
import com.google.common.collect.Maps;
import com.ssi.constant.RedisKey;
import com.ssi.constant.enums.VmsTosOrderStatusEnum;
import com.ssi.entity.dto.Point;
import com.ssi.kafka.listener.VehicleRealTimeInfoListener;
import com.ssi.service.platform.WebSocketDataService;
import com.ssi.utils.*;
import com.ssi.utils.grid.RealTimeVehicleSchedule;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import reactor.util.function.Tuple2;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
/**
* Description:
*
* @author LiXiaoCong
* @version 2019/11/11 11:26
*/
@Slf4j
@Component
@ConditionalOnProperty(name = "spring.websocket.pushInPool.enable", havingValue = "true")
public class VehicleSocketDataCacheQueueModel {
private static final Object LOCK = new Object();
@Value("${spring.websocket.scheduled.cache.max:20}")
private int maxCacheSize;
@Value("${spring.websocket.scheduled.push.threshold:1}")
private int pushThreshold;
@Value("${spring.websocket.point.degree.threshold:90.0}")
private double degreeThreshold;
@Value("${spring.websocket.scheduled.time:1000}")
private int pushRate;
@Value("${vehicle.latestData.redis.preLocationFix:ivccs:vms:vehicle:preLocation}")
private String preLocationFix;
@Value("${order.latestOrderKeyPrefix:harbor:command:status}")
private String latestOrderKeyPrefix;
@Value("${ivccs.vehicle.latestData.redis.prefix:ivccs:vms:vehicle:latest}")
private String latestRedisKeyPrefix;
@Value("${vehicle.latestData.redis.postfix:harbor_D00A}")
private String realPostfix;
@Autowired
private RedisDataModel redisDataModel;
@Autowired
private VehicleBaseInfoModel vehicleBaseInfoModel;
@Autowired
private VehicleDataUtil vehicleDataUtil;
@Autowired
private WebSocketDataService webSocketDataService;
private final ExecutorService executorService = new ThreadPoolExecutor(1,1,0, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<>(10),new ThreadPoolExecutor.DiscardOldestPolicy());
private final Map<String, VehicleDataCachePool> cachePoolMaps = Maps.newConcurrentMap();
private final Map<String, JSONObject> gpsSpeedMap = Maps.newConcurrentMap();
@Autowired
private VehicleRealTimeInfoListener vehicleRealTimeInfoListener;
private AtomicInteger versionNo = new AtomicInteger(0);
/**
* 设置车辆的最新数据
*/
@Scheduled(fixedRateString = "${spring.websocket.scheduled.pool.time:500}")
private void scheduledSendInfoMage() {
Map<String, Map<String, Object>> messages = webSocketDataService.realTimeDataAll();
if (messages != null && messages.size() > 0) {
vehicleRealTimeInfoListener.clearOutVersionVehicle(versionNo.get());
messages.forEach((vin, record) -> {
record.put("versionNo",versionNo.getAndIncrement()<Integer.MAX_VALUE-1?versionNo.get():versionNo.getAndSet(0));
getCachePool(vin).pushData(record);
});
}
}
public Map<String, Map<String, Object>> getAllVehicleData() {
Map<String, Map<String, Object>> messages = Maps.newHashMap();
this.cachePoolMaps.forEach((vin, pool) -> {
Map<String, Object> data = pool.getData();
if (data != null) {
messages.put(vin, data);
}
});
return messages;
}
private VehicleDataCachePool getCachePool(String vin) {
VehicleDataCachePool vehicleDataCachePool = this.cachePoolMaps.get(vin);
if (vehicleDataCachePool == null) {
synchronized (LOCK) {
if (vehicleDataCachePool == null) {
vehicleDataCachePool = new VehicleDataCachePool(vin);
this.cachePoolMaps.put(vin, vehicleDataCachePool);
}
}
}
return vehicleDataCachePool;
}
private class VehicleDataCachePool {
private final String vin;
private final EvictingQueue<Map<String, Object>> evictingQueue;
private int dataFrequency;
private AtomicBoolean canPush = new AtomicBoolean(false);
private Map<String, Object> preMap;
//速度不为0缓存位置信息
private Map<String, Object> preWithSpeedMap;
private VehicleDataCachePool(String vin) {
this.vin = vin;
/* Temporarily not find infomation of vehicle. */
// Map<String, Object> vehicleBaseInfo = vehicleBaseInfoModel.getVehicleBaseInfo(vin);
//
// Object dataFrequency = vehicleBaseInfo.get("dataFrequency");
// if(dataFrequency != null){
// this.dataFrequency = Integer.parseInt(dataFrequency.toString());
// }else{
this.dataFrequency = 1000;
// }
if (this.dataFrequency < pushRate) {
this.dataFrequency = pushRate;
}
this.evictingQueue = EvictingQueue.create(maxCacheSize);
}
private void pushData(Map<String, Object> map) {
boolean valid = isValid(map);
//航向角计算
//addLastLocationInfo(map, valid);
calculateNextLocationByDirection(map);
if("ON".equals(redisDataModel.get(RedisKey.DYNAMIC_FENCE_SWITCH.getKeyPrefix()))){
//处理封闭区冲突
vehicleRealTimeInfoListener.processVehicleCloseArea(map);
}
//处理异常信息
// processVehcileErrorMsg(map);
this.evictingQueue.add(map);
if (!this.canPush.get()) {
this.canPush.set(size() >= pushThreshold);
}
}
private void processVehcileErrorMsg(Map<String, Object> record) {
JSONObject jsonObject = new JSONObject();
Double speed = (Double) record.get("speed");
//V2X异常
String v2xStr = redisDataModel.get(RedisKey.ERROR_V2X_INFO.getKeyPrefix().concat(vin));
if(StringUtils.isNotBlank(v2xStr)){
JSONObject v2xObj = JSON.parseObject(v2xStr);
if(System.currentTimeMillis() - v2xObj.getLong("time")<30000){
record.put("vinFlag",1);
jsonObject.put("v2xError",v2xObj.getString("description"));
}
/* if(StringUtils.isNotBlank(v2xObj.getString("description"))){
jsonObject.put("v2xError",v2xObj.getString("description"));
}*/
}
//三级告警
String tosStr = redisDataModel.get(RedisKey.ERROR_TOS_INFO.getKeyPrefix().concat(vin));
if(StringUtils.isNotBlank(tosStr)){
JSONObject tosObj = JSON.parseObject(tosStr);
jsonObject.put("v2xError",tosObj.getString("faultName"));
}
//平台异常
StringBuilder sb = new StringBuilder("");
Map<String, Object> vehicleEmergencyRecord = redisDataModel.getJson2Map(RedisKey.EMERGENCY_PARKING.getKeyPrefix().concat(vin));
if(MapUtils.isNotEmpty(vehicleEmergencyRecord)){
Integer emergencyStatus = (Integer)vehicleEmergencyRecord.get("emergencyStatus");
if(1==emergencyStatus){
record.put("vinFlag",1);
sb.append("车辆紧急急停 ");
}
}
Object stopExceed = record.get("stopExceed");
if(Objects.nonNull(stopExceed)&&1 == (Integer) stopExceed){
record.put("vinFlag",1);
sb.append("车辆停止超时 ");
}
Object dynamicFenceAlert = SpringUtils.getValue("DYNAMIC_FENCE_ALERT", vin);
if(Objects.nonNull(dynamicFenceAlert)){
record.put("vinFlag",1);
sb.append("封闭区触发任务暂停 ");
}
jsonObject.put("platError",sb.toString());
//TOS异常
Map<String, Object> json2Map = redisDataModel.getJson2Map(RedisKey.VMS_TOS_ORDER.getKeyPrefix().concat(vin));
if(MapUtils.isNotEmpty(json2Map)){
JSONObject lastedOrder = new JSONObject();
lastedOrder.put("startTime",json2Map.get("collectTime"));
lastedOrder.put("lockLabel",json2Map.get("lockLabel"));
lastedOrder.put("portCode",json2Map.get("portCode"));
lastedOrder.put("containerSize",json2Map.get("containerSize"));
lastedOrder.put("containerPosition",json2Map.get("containerPosition"));
Integer subTaskType = Objects.isNull(json2Map.get("subTaskType")) ? null : (Integer) json2Map.get("subTaskType");
String description = vehicleDataUtil.generateOrderDescription(json2Map);
//判断subTaskType:0去缓冲区1,2 去扭锁站 其他用查询出来的
if (Objects.nonNull(subTaskType)&&subTaskType == 0){
lastedOrder.put("orderDescription","去缓冲区");
}else if(Objects.nonNull(subTaskType)&&(subTaskType ==1 || subTaskType==2)){
lastedOrder.put("orderDescription","去扭锁站");
}else{
lastedOrder.put("orderDescription",description);
}
jsonObject.put("tosError",lastedOrder);
}
record.put("errorMsg",jsonObject);
}
private synchronized void calculateNextLocationByDirection(Map<String, Object> map) {
//获取航向角
if(Objects.isNull(map.get("direction"))){
return;
}
try{
double direction = Double.parseDouble(String.valueOf(map.get("direction")))/100;
Double speed = Double.parseDouble(String.valueOf(map.get("speed")));
double[] location = (double[]) map.get("location");
int decLabel = 0;
if(speed<=0){
fixSpeedByGps(map);
Double gpsSpeed = Double.parseDouble(String.valueOf(map.get("speed")));
if(gpsSpeed<=0){
direction = 168.96;
decLabel = 1;
if(FieldUtil.isPortraitField(new Point(location[0],location[1]))){
direction = 77.43;
decLabel = 2;
}
}
JSONObject old = gpsSpeedMap.get(vin);
if(Objects.nonNull(old)){
location = (double[])old.get("realLocation");
map.put("location",old.get("realLocation"));
}
}else {
gpsSpeedMap.remove(vin);
}
//计算航向坐标
String[] strings = GeoPosTransformUtil.calLocationByDistanceAndLocationAndDirection(direction, location[0], location[1], 3);
map.put("nextLocation",strings);
map.put("decLabel",decLabel);
}catch (Exception e){
log.info("=====>{}",e.getMessage());
return;
}
}
private void fixSpeedByGps(Map<String, Object> map) {
try {
String vin = String.valueOf(map.get("vin"));
double[] location = (double[]) map.get("location");
long collectTime = System.currentTimeMillis(); //(long) map.get("collectTime");
JSONObject old = gpsSpeedMap.get(vin);
if (Objects.isNull(old)) {
JSONObject newObj = new JSONObject();
newObj.put("realLocation",location);
newObj.put("location",location);
newObj.put("collectTime",collectTime);
newObj.put("lastUpdateTime",collectTime);
gpsSpeedMap.put(vin, newObj);
return;
}
Long oldCollectTime = old.getLong("collectTime");
Long lastUpdateTime = old.getLong("lastUpdateTime");
double[] oldLocation = (double[])old.get("location");
BigDecimal bigDecimal= null;
if(collectTime-oldCollectTime<600&&(location[0]!=oldLocation[0]||location[1]!=oldLocation[1])){
long deltTime = collectTime - oldCollectTime;
double distance = GpsUtil.getDistance(oldLocation[0], oldLocation[1], location[0], location[1]);
if(distance>0.0003&&deltTime>0){
bigDecimal = new BigDecimal(distance / (deltTime /1000.0/3600.0));
bigDecimal = bigDecimal.setScale(2, RoundingMode.HALF_UP);
log.info("vin:{}====>{},{},speed:{}",vin,distance,deltTime/1000.0/3600.0,bigDecimal.doubleValue());
map.put("speed",bigDecimal.doubleValue());
old.put("lastUpdateTime",collectTime);
old.put("realLocation",location);
}
}
if(Objects.isNull(bigDecimal)&&(collectTime-lastUpdateTime)>5*60*1000){//速度为0计算是否超时
Object o = StringUtils.isNotBlank(String.valueOf(map.get("orderData")))? map.put("stopExceed", 1) : null;
}
old.put("location",location);
old.put("collectTime",collectTime);
}catch (Exception e){
log.error("fixSpeedByGps occur error:",e);
}
}
private Map<String, Object> getData() {
Map<String, Object> poll = null;
if (this.canPush.get()) {
try {
if (!this.evictingQueue.isEmpty()) {
poll = this.evictingQueue.poll();
if (poll != null) {
poll.put("poolSize", size());
checkNetError(poll);
}
} else {
this.canPush.set(false);
}
} catch (Exception e) {
log.error(String.format("获取%s数据失败。", vin), e);
}
}
return poll;
}
private int size() {
return this.evictingQueue.size();
}
private void addLastLocationInfo(Map<String, Object> map, boolean valid) {
//上一个点的坐标及前一坐标
String location = redisDataModel.get(String.format("%s:%s", preLocationFix, map.get("vin")));
Map<String, Object> status = redisDataModel.getJson2Map(String.format("%s:%s", latestOrderKeyPrefix, map.get("vin")));
Map<String, Object> realMap = redisDataModel.getJson2Map(String.format("%s:%s-%s", latestRedisKeyPrefix, map.get("vin"), realPostfix));
map.put("status",status==null?"-": VmsTosOrderStatusEnum.find(Integer.valueOf(status.get("status")+""))==null?"":VmsTosOrderStatusEnum.find(Integer.valueOf(status.get("status")+"")).getDescription());
map.put("direction",realMap==null?"-":realMap.get("direction"));
// 上一个点的坐标
Double lastLongitude = null;
Double lastLatitude = null;
if (StringUtils.isNotBlank(location)) {
JSONObject locationMap = JSON.parseObject(location);
lastLongitude = locationMap.getDouble("longitude");
lastLatitude = locationMap.getDouble("latitude");
}
//当前点坐标
double speed = Double.parseDouble(map.getOrDefault("speed", "0").toString());
Double longitude = ConfigUtils.getAsDoubleWithDefault(map, "longitude", null);
Double latitude = ConfigUtils.getAsDoubleWithDefault(map, "latitude", null);
if (speed != 0 && valid) {
if (longitude != null && latitude != null) {
Map<String, Object> preWithSpeedMapTemp = new HashMap<>();
preWithSpeedMapTemp.put("longitude", longitude);
preWithSpeedMapTemp.put("latitude", latitude);
preWithSpeedMapTemp.put("lastLongitude", lastLongitude);
preWithSpeedMapTemp.put("lastLatitude", lastLatitude);
redisDataModel.set(String.format("%s:%s", preLocationFix, map.get("vin")),
JSON.toJSONString(preWithSpeedMapTemp));
preWithSpeedMap = preWithSpeedMapTemp;
map.put("preLocation", new double[]{lastLongitude, lastLatitude});
}
} else {
if (preWithSpeedMap != null) {
Double longitude1 = ConfigUtils.getAsDoubleWithDefault(preWithSpeedMap, "longitude",
null);
Double latitude1 = ConfigUtils.getAsDoubleWithDefault(preWithSpeedMap, "latitude", null);
Double longitude2 = ConfigUtils.getAsDoubleWithDefault(preWithSpeedMap, "lastLongitude",
null);
Double latitude2 = ConfigUtils.getAsDoubleWithDefault(preWithSpeedMap, "lastLatitude",
null);
if (longitude1 != null && latitude1 != null) {
map.put("location", new double[]{longitude1, latitude1});
}
if (longitude1 != null && latitude1 != null) {
map.put("preLocation",getEndPointByTrigonometric(Double.valueOf(realMap.get("direction")+""),new double[]{longitude1, latitude1},0.0001));
}
}
}
}
private boolean isValid(Map<String, Object> map) {
boolean valid = true;
try {
if (preMap != null) {
//检查位置和速度
String prelocation = String.format("%s,%s", preMap.get("latitude"),
preMap.get("longitude"));
String location = String.format("%s,%s", map.get("latitude"), map.get("longitude"));
double speed = Double.parseDouble(map.getOrDefault("speed", "0").toString());
valid = !(prelocation.equals(location) && speed != 0);
if (!valid) {
// log.warn(String.format("车辆%s数据无效:\n (prelocation = %s, location = %s, speed = %s)",
// vin, prelocation, location, speed));
long currentTime = (long) map.get("collectTime");
long preTime = (long) preMap.get("collectTime");
//统计无效数据
preMap.put("validCount",
(long) preMap.getOrDefault("validCount", 0L) + (currentTime - preTime));
preMap.put("speed", speed);
}
}
if (valid) {
preMap = map;
}
} catch (Exception e) {
log.error("数据检查异常。", e);
valid = false;
}
return valid;
}
private void checkNetError(Map<String, Object> current) {
Map<String, Object> next = this.evictingQueue.peek();
try {
long validCount = 0;
if (preMap != null) {
validCount = (long) preMap.getOrDefault("validCount", 0L);
}
if (next != null) {
//检查是否存在掉包行为
long currentTime = (long) current.get("collectTime");
long nextTime = (long) next.get("collectTime");
//网络延迟
if ((nextTime - currentTime) >= this.dataFrequency * 1.2 + validCount) {
current.put("netError", true);
}
} else if (validCount <= 0) {
//避免一直传无效数据的情况
double speed = Double.parseDouble(current.getOrDefault("speed", "0").toString());
if (speed > 0) {
current.put("netError", true);
}
}
} catch (Exception e) {
log.error(String.format("检查%s掉包行为失败...", vin), e);
}
}
}
private static double[] getEndPointByTrigonometric(double angle, double[] startPoint, double distance)
{
double[] endPoint = new double[2];
//角度转弧度
double radian = (angle * Math.PI) / 180;
//计算新坐标 r 就是两者的距离
endPoint[0] = startPoint[0] + distance * Math.cos(radian);
endPoint[1] = startPoint[1] + distance * Math.sin(radian);
return endPoint;
}
private Runnable asyncProcessRoutingConflict(Map<String, Map<String, Object>> messages){
return ()->vehicleRealTimeInfoListener.processRoutingConflict(messages);
}
}
package com.ssi.model;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.Map;
/**
* Description: 股份数据增加车辆到达报警触发 arrivedStatus = 1 可能会错过
* <p>
* 修改逻辑查询逻辑: 存在变化再往后发 车辆下线不发
*
* @author LiXiaoCong
* @version 2019/9/20 11:48
*/
@Component
@EnableScheduling
@Slf4j
public class WebSocketDataServiceModel {
@Value("${spring.webscoket.checkRepate:false}")
private boolean checkRepate;
@Autowired
private VehicleLatestDataModel vehicleLatestDataModel;
/**
* 停车时经纬度跳变处理
*/
private Map<String, String> lastMap = Maps.newConcurrentMap();
public Map<String, Map<String, Object>> realTimeData(Collection<String> vins) {
return realTimeData(vins, checkRepate);
}
public Map<String, Map<String, Object>> realTimeData(Collection<String> vins,
boolean checkRepeat) {
Map<String, Map<String, Object>> res;
if (vins != null && !vins.isEmpty()) {
String latestRedisKeyPrefix = vehicleLatestDataModel.getLatestRedisKeyPrefix();
String latestRedisKeyPostfix = vehicleLatestDataModel.getLatestRedisKeyPostfix();
String latestRedisKeyD001Postfix = vehicleLatestDataModel.getLatestRedisKeyPrefix();
String latestRedisKeyD002Postfix = vehicleLatestDataModel.getLatestRedisKeyPrefix();
Map<String, Map<String, String>> keysMap = Maps.newHashMap();
vins.stream().forEach(key -> {
Map<String, String> keyPreMap = Maps.newHashMap();
keyPreMap.put("latestKey",
String.format("%s:%s-%s", latestRedisKeyPrefix, key, latestRedisKeyPostfix));
keyPreMap.put("d001Key",
String.format("%s:%s-%s", latestRedisKeyPrefix, key, latestRedisKeyD001Postfix));
keyPreMap.put("d002Key",
String.format("%s:%s-%s", latestRedisKeyPrefix, key, latestRedisKeyD002Postfix));
keysMap.put(key, keyPreMap);
});
res = vehicleLatestDataModel.readLatestDataFromRedis(keysMap, checkRepeat);
} else {
res = Maps.newHashMap();
}
return res;
}
public Map<String, Map<String, Object>> realTimeDataAll(boolean checkRepeat) {
return vehicleLatestDataModel.allRealTimeData(checkRepeat);
}
public Map<String, Map<String, Object>> getVehicleRunData() {
return vehicleLatestDataModel.getVehicleRunData();
}
}
package com.ssi.mqtt;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ssi.constant.VehicleConstant;
import com.ssi.entity.dto.VmsVehicleDto;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
@Slf4j
public class MQTTPublishClient {
//定义MQTT的ID,可以在MQTT服务配置中指定
private String clientid;
private String mqttCAPath;
private String mqttName;
private String mqttPassword;
private String mqttUrl;
private MqttClient client;
@Setter
@Getter
private MqttTopic mqttTopic;
/**
* 构造函数
*/
public MQTTPublishClient(String host, String serverId, String mqttCAPath,
String mqttName, String mqttPassword, String mqttUrl) {
log.info("MQTTPublishClient instance");
this.clientid = serverId;
this.mqttCAPath = mqttCAPath;
this.mqttName = mqttName;
this.mqttPassword = mqttPassword;
this.mqttUrl = mqttUrl;
// MemoryPersistence设置clientid的保存形式,默认为以内存保存
try {
if (client == null) {
client = new MqttClient(host, clientid, new MemoryPersistence());
}
} catch (MqttException e) {
e.printStackTrace();
}
connect();
}
/**
* 用来连接服务器
*/
private void connect() {
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(true);
// 设置超时时间
options.setConnectionTimeout(20);
// 设置会话心跳时间
options.setKeepAliveInterval(10);
// options.setAutomaticReconnect(true);//设置自动重连
try {
options.setSocketFactory(SslUtil.getSocketFactory(mqttCAPath, "/UserProfile/ca/client.crt",
"/UserProfile/ca/client.key", "123456"));
client.setCallback(new PublishCallback());
client.connect(options);
} catch (Exception e) {
e.printStackTrace();
}
}
public void mqttRequest(VmsVehicleDto vehicle, String cntType) {
try {
//发送mqtt请求
MqttMessage message = new MqttMessage();
JSONObject msgObj = new JSONObject();
msgObj.put("devType", "web");
msgObj.put("cntType", cntType);
JSONObject dataObj = new JSONObject();
dataObj.put("name", mqttName);
dataObj.put("password", mqttPassword);
dataObj.put("sn", vehicle.getVinSSI());
JSONArray cameraArray = new JSONArray();
String vehicleNum = vehicle.getVehicleNum().substring(vehicle.getVehicleNum().length() - 1);
if (VehicleConstant.START_PUSHER.equals(cntType)) {
for (int i = 0; i < 5; i++) {
JSONObject cameraObj = new JSONObject();
cameraObj.put("url", mqttUrl + vehicleNum + "_" + i);
cameraObj.put("status", "disable");
if (i == 2) {
cameraObj.put("status", "enable");
}
cameraArray.add(cameraObj);
}
dataObj.put("camera", cameraArray);
msgObj.put("startPusherData", dataObj);
} else {
for (int i = 0; i < 5; i++) {
JSONObject cameraObj = new JSONObject();
cameraObj.put("url", "");
cameraObj.put("status", "disable");
cameraArray.add(cameraObj);
}
dataObj.put("camera", cameraArray);
msgObj.put("stopPusherData", dataObj);
}
message.setPayload(msgObj.toJSONString().getBytes("UTF-8"));
message.setQos(0);
message.setRetained(false);
this.publish("ssiweb", message);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
//发送消息并获取回执
void publish(String topic, MqttMessage message) throws MqttPersistenceException,
MqttException, InterruptedException {
log.info("publish topic: " + topic);
mqttTopic = client.getTopic(topic);
MqttDeliveryToken token = mqttTopic.publish(message);
token.waitForCompletion();
log.info("message is published completely! "
+ token.isComplete());
log.info("messageId:" + token.getMessageId());
token.getResponse();
if (client.isConnected()) {
client.disconnect(10000);
}
log.info("Disconnected: delivery token \"" + token.hashCode()
+ "\" received: " + token.isComplete());
}
}
package com.ssi.mqtt;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
@Slf4j
public class MQTTSubcribeClient {
public String HOST;
private MqttClient client;
private MqttConnectOptions options;
public MQTTSubcribeClient(String host, String clientid, String mqttCAPath) {
try {
this.HOST = host;
log.info("MQTTSubcribeClient instanced");
// host为主机名,clientid即连接MQTT的客户端ID,一般以唯一标识符表示,MemoryPersistence设置clientid的保存形式,默认为以内存保存
client = new MqttClient(HOST, clientid, new MemoryPersistence());
// MQTT的连接设置
options = new MqttConnectOptions();
// 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,设置为true表示每次连接到服务器都以新的身份连接
options.setCleanSession(false);
// 设置超时时间 单位为秒
options.setConnectionTimeout(20);
// 设置会话心跳时间 单位为秒 服务器会每隔5秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
options.setKeepAliveInterval(10);
options.setAutomaticReconnect(true);//设置自动重连
// 设置回调
try {
options.setSocketFactory(SslUtil.getSocketFactory(mqttCAPath, "/UserProfile/ca/client.crt",
"/UserProfile/ca/client.key", "123456"));
} catch (Exception e) {
e.printStackTrace();
}
client.setCallback(new SubcribeCallBack());
client.connect(options);
//订阅消息
String[] topic1 = {"ssiweb"};
client.subscribe(topic1);
} catch (MqttException e) {
e.printStackTrace();
}
}
}
package com.ssi.mqtt;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttMessage;
@Slf4j
public class PublishCallback implements MqttCallbackExtended {
@Override
public void connectionLost(Throwable cause) {
// 连接丢失后,一般在这里面进行重连
log.info("[PublishCallback] 连接断开");
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
log.info("deliveryComplete---------" + token.isComplete());
}
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
}
@Override
public void connectComplete(boolean b, String s) {
log.info("connected");
}
}
\ No newline at end of file
package com.ssi.mqtt;
import java.io.InputStreamReader;
import java.security.KeyStore;
import java.security.Security;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMReader;
import org.springframework.core.io.ClassPathResource;
public class SslUtil {
public static SSLSocketFactory getSocketFactory(final String caCrtFile, final String crtFile,
final String keyFile,
final String password) throws Exception {
Security.addProvider(new BouncyCastleProvider());
// load CA certificate
PEMReader reader = new PEMReader(
new InputStreamReader(new ClassPathResource(caCrtFile).getInputStream()));
X509Certificate caCert = (X509Certificate) reader.readObject();
reader.close();
// load client certificate
// reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(crtFile)))));
// X509Certificate cert = (X509Certificate)reader.readObject();
// reader.close();
// load client private key
// reader = new PEMReader(
// new InputStreamReader(new ByteArrayInputStream(Files.readAllBytes(Paths.get(keyFile)))),
// new PasswordFinder() {
// @Override
// public char[] getPassword() {
// return password.toCharArray();
// }
// }
// );
// KeyPair key = (KeyPair)reader.readObject();
// reader.close();
// CA certificate is used to authenticate server
KeyStore caKs = KeyStore.getInstance(KeyStore.getDefaultType());
caKs.load(null, null);
caKs.setCertificateEntry("ca-certificate", caCert);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
tmf.init(caKs);
// client key and certificates are sent to server so it can authenticate us
// KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
// ks.load(null, null);
// ks.setCertificateEntry("certificate", cert);
// ks.setKeyEntry("private-key", key.getPrivate(), password.toCharArray(), new java.security.cert.Certificate[]{cert});
// KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
// kmf.init(ks, password.toCharArray());
// finally, create SSL socket factory
SSLContext context = SSLContext.getInstance("TLSv1.2");
context.init(null, tmf.getTrustManagers(), null);
return context.getSocketFactory();
}
}
package com.ssi.mqtt;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttMessage;
@Slf4j
public class SubcribeCallBack implements MqttCallbackExtended {
@Override
public void connectionLost(Throwable throwable) {
log.warn("client lost connection,reconnecting");
}
@Override
public void messageArrived(String s, MqttMessage mqttMessage) throws Exception {
try {
// subscribe后得到的消息会执行到这里面
log.info("接收消息主题 : " + s);
log.info("接收消息Qos : " + mqttMessage.getQos());
log.info("接收消息内容 : " + new String(mqttMessage.getPayload()));
String str = mqttMessage.toString();
log.info("从MQTT收到的消息为:" + str + " ;TOPIC:" + s);
} catch (Exception e) {
log.error("SubcribeCallBack error:" + e.getMessage());
e.printStackTrace();
}
}
@Override
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
log.info("deliveryComplete---------" + iMqttDeliveryToken.isComplete());
}
@Override
public void connectComplete(boolean b, String s) {
log.info("receive connectted");
}
}
package com.ssi.mqtt;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import java.util.HashMap;
import java.util.Map;
public class TestSSLPublish {
public static void main(String[] args) throws Exception {
//mqtt发送端
MQTTPublishClient mqttClientSend = new MQTTPublishClient("ssl://10.11.10.28:1884",
"mqttx_8b1e19a2", "C://Users/hekai/Desktop/ca_cidi.pem",
"", "", "");
MqttMessage message = new MqttMessage();
JSONObject msgObj = new JSONObject();
msgObj.put("devType", "web");
msgObj.put("cntType", "startPusher");
JSONObject dataObj = new JSONObject();
dataObj.put("name", "ssiweb");
dataObj.put("password", "ssiweb123456");
dataObj.put("sn", "CSU100FB21080030");
JSONObject cameraObj = new JSONObject();
cameraObj.put("url", "rtmp://10.11.10.28/live/2_2");
cameraObj.put("status", "enable");
JSONArray cameraArray = new JSONArray();
cameraArray.add(cameraObj);
dataObj.put("camera", cameraArray);
msgObj.put("startPusherData", dataObj);
message.setPayload(msgObj.toJSONString().getBytes("UTF-8"));
message.setQos(0);
message.setRetained(false);
System.out.println("MQTT发送消息");
mqttClientSend.publish("ssiweb", message);
}
}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment