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

提交代码

parent e0c7be76
package com.ssi.utils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.tuple.MutableTriple;
import org.apache.commons.lang3.tuple.Triple;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Component
public class SpringUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
private static Map<String,Map<String,Object>> localCache = new ConcurrentHashMap<>();
@Override
public void setApplicationContext(ApplicationContext applicationContextParam)
throws BeansException {
applicationContext = applicationContextParam;
}
public static Object getObject(String id) {
Object object = null;
object = applicationContext.getBean(id);
return object;
}
public static <T> T getObject(Class<T> tClass) {
return applicationContext.getBean(tClass);
}
public static Object getBean(String tClass) {
return applicationContext.getBean(tClass);
}
public static void setLocalCache(String topic,String key, Object value) {
Map<String, Object> valMap = localCache.get(topic);
synchronized (SpringUtils.class){
if(MapUtils.isNotEmpty(valMap)){
valMap.put(key,value);
}else {
localCache.put(topic,new HashMap<String,Object>(){{put(key,value);}});
}
}
}
public static Object getValue(String topic,String key){
Map<String, Object> valMap = localCache.get(topic);
if(MapUtils.isNotEmpty(valMap)){
return valMap.get(key);
}
return null;
}
public static void clearStatus(String topic,String key){
Map<String, Object> valMap = localCache.get(topic);
if(MapUtils.isNotEmpty(valMap)){
valMap.remove(key);
}
}
}
package com.ssi.utils;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.Vector;
import org.apache.commons.lang.StringUtils;
import org.springframework.kafka.core.KafkaTemplate;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ssi.constant.URL;
import com.ssi.entity.VmsShipNcl;
import com.ssi.entity.dto.VmsTosOrdersDto;
import com.ssi.response.SSIResponse;
public class TestGetBean {
private Connection connection;
private PreparedStatement UserQuery;
/* mysql url的连接字符串 */
// private static String url = "jdbc:mysql://127.0.0.1:3306/rad?useUnicode=true&characterEncoding=UTF-8";
private static String url = "jdbc:oracle:thin:@//172.16.1.239:1521/test2.coscoyh.com.cn";
// 账号 172.16.1.239:1521/test2.coscoyh.com.cn
private static String user = "XMYH_DCV";
// 密码
private static String password = "coscoyh";
private Vector<String> vector = new Vector<String>();
// mysql jdbc的java包驱动字符串
// private String driverClassName = "com.mysql.jdbc.Driver";
private String driverClassName = "oracle.jdbc.OracleDriver";
// 数据库中的表名
String table = "sys_logs";
// 数据库的列名称
private String[] colnames; // 列名数组
// 列名类型数组
private String[] colTypes;
public TestGetBean() {
try {// 驱动注册
Class.forName(driverClassName);
if (connection == null || connection.isClosed())
// 获得链接
connection = DriverManager.getConnection(url, user, password);
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
System.out.println("Oh,not");
} catch (SQLException e) {
e.printStackTrace();
System.out.println("Oh,not");
}
}
public Connection getConnection() {
return connection;
}
public void setConnection(Connection connection) {
this.connection = connection;
}
public void doAction() {
String sql = "select * from " + table;
try {
PreparedStatement statement = connection.prepareStatement(sql);
// 获取数据库的元数据
ResultSetMetaData metadata = statement.getMetaData();
// 数据库的字段个数
int len = metadata.getColumnCount();
// 字段名称
colnames = new String[len + 1];
// 字段类型 --->已经转化为java中的类名称了
colTypes = new String[len + 1];
for (int i = 1; i <= len; i++) {
// System.out.println(metadata.getColumnName(i)+":"+metadata.getColumnTypeName(i)+":"+sqlType2JavaType(metadata.getColumnTypeName(i).toLowerCase())+":"+metadata.getColumnDisplaySize(i));
// metadata.getColumnDisplaySize(i);
colnames[i] = metadata.getColumnName(i); // 获取字段名称
System.out.println(colnames[i]);
colTypes[i] = sqlType2JavaType(metadata.getColumnTypeName(i)); // 获取字段类型
System.out.println(metadata.getColumnTypeName(i));
System.out.println(colTypes[i]);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
/*
* mysql的字段类型转化为java的类型
*/
private String sqlType2JavaType(String sqlType) {
if (sqlType.equalsIgnoreCase("bit")) {
return "boolean";
} else if (sqlType.equalsIgnoreCase("tinyint")) {
return "byte";
} else if (sqlType.equalsIgnoreCase("smallint")) {
return "short";
} else if (sqlType.equalsIgnoreCase("int")) {
return "int";
} else if (sqlType.equalsIgnoreCase("bigint")) {
return "long";
} else if (sqlType.equalsIgnoreCase("float")) {
return "float";
} else if (sqlType.equalsIgnoreCase("decimal") || sqlType.equalsIgnoreCase("numeric")
|| sqlType.equalsIgnoreCase("real") || sqlType.equalsIgnoreCase("money")
|| sqlType.equalsIgnoreCase("smallmoney")) {
return "double";
} else if (sqlType.equalsIgnoreCase("varchar") || sqlType.equalsIgnoreCase("char")
|| sqlType.equalsIgnoreCase("nvarchar") || sqlType.equalsIgnoreCase("nchar")
|| sqlType.equalsIgnoreCase("text")) {
return "String";
} else if (sqlType.equalsIgnoreCase("datetime") || sqlType.equalsIgnoreCase("date")) {
return "Date";
} else if (sqlType.equalsIgnoreCase("image")) {
return "Blod";
} else if (sqlType.equalsIgnoreCase("timestamp")) {
return "Timestamp";
}
return null;
}
/*
* 获取整个类的字符串并且输出为java文件
*/
public StringBuffer getClassStr() {
// 输出的类字符串
StringBuffer str = new StringBuffer("");
// 获取表类型和表名的字段名
this.doAction();
// 校验
if (null == colnames && null == colTypes)
return null;
// 拼接
str.append("public class " + GetTuoFeng(table) + " {\r\n");
// 拼接属性
for (int index = 1; index < colnames.length; index++) {
str.append(getAttrbuteString(colnames[index], colTypes[index]));
}
// 拼接get,Set方法
for (int index = 1; index < colnames.length; index++) {
str.append(getGetMethodString(colnames[index], colTypes[index]));
str.append(getSetMethodString(colnames[index], colTypes[index]));
}
str.append("}\r\n");
// 输出到文件中
// File file = new File("E:/mengwx/【源码】mysql版本_spring4.0/FHMYSQL/src/com/fh/entity/"+GetTuoFeng(table)+".java");
// BufferedWriter write = null;
//
// try {
// write = new BufferedWriter(new FileWriter(file));
// write.write(str.toString());
// write.close();
// } catch (IOException e) {
//
// e.printStackTrace();
// if (write != null)
// try {
// write.close();
// } catch (IOException e1) {
// e1.printStackTrace();
// }
// }
return str;
}
/*
* 获取字段字符串
*/
public StringBuffer getAttrbuteString(String name, String type) {
if (!check(name, type)) {
System.out.println("类中有属性或者类型为空");
return null;
}
;
String format = String.format(" private %s %s;\n\r", new String[] { type, name });
return new StringBuffer(format);
}
/*
* 校验name和type是否合法
*/
public boolean check(String name, String type) {
if ("".equals(name) || name == null || name.trim().length() == 0) {
return false;
}
if ("".equals(type) || type == null || type.trim().length() == 0) {
return false;
}
return true;
}
/*
* 获取get方法字符串
*/
private StringBuffer getGetMethodString(String name, String type) {
if (!check(name, type)) {
System.out.println("类中有属性或者类型为空");
return null;
}
;
String Methodname = "get" + GetTuoFeng(name);
String format = String.format(" public %s %s(){\n\r", new Object[] { type, Methodname });
format += String.format(" return this.%s;\r\n", new Object[] { name });
format += " }\r\n";
return new StringBuffer(format);
}
// 将名称首字符大写
private String GetTuoFeng(String name) {
name = name.trim();
if (name.length() > 1) {
name = name.substring(0, 1).toUpperCase() + name.substring(1);
} else {
name = name.toUpperCase();
}
return name;
}
/*
* 获取字段的get方法字符串
*/
private Object getSetMethodString(String name, String type) {
if (!check(name, type)) {
System.out.println("类中有属性或者类型为空");
return null;
}
;
String Methodname = "set" + GetTuoFeng(name);
String format = String.format(" public void %s(%s %s){\n\r", new Object[] { Methodname, type, name });
format += String.format(" this.%s = %s;\r\n", new Object[] { name, name });
format += " }\r\n";
return new StringBuffer(format);
}
// public static void main(String[] args) {
// TestGetBean bean = new TestGetBean();
// System.err.println(bean.getClassStr());
// JSONObject param = new JSONObject();
// Integer []aa= {22};
// String []bb= {"19","20"};
// param.put("ids",aa);//区域类型。1桥下,2桥后
// param.put("priority", 1);
// String paramData = JSONObject.toJSONString(param);
// System.out.println("绘制地图区域保存请求发送------"+ paramData);
// String result = RestTemplateUtil.post("http://10.11.10.1:8030/vehicleBuffer/priority" , paramData, null);
// System.out.print(String.format("绘制地图区域保存返回结果:----%s", result));
// JSONObject param = new JSONObject();
// String tempIds="19,2";
//
// List<Integer> tempId = new ArrayList<>();
//
// String[] ids = tempIds.split(",");
// for (String id : ids){
// tempId.add(Integer.parseInt(id));
//
// }
//
// String paramData = JSONObject.toJSONString(tempId);
// System.out.println("绘制地图区域保存请求发送------"+ paramData);
// String result = RestTemplateUtil.post("http://10.11.10.1:8030/vehicleBuffer/delete" , paramData, null);
// System.out.print(String.format("绘制地图区域保存返回结果:----%s", result));
// System.out.println(StringUtils.isNumeric("12,"));
// String Str1 = "P1156756";
// List t = new ArrayList();
// System.out.println(t.size() < 0);
//// VmsShipNcl t=new VmsShipNcl();
// String arg = "";
// System.out.println(JsonUtil.jsonToMap(arg));
// System.out.println();
// param.put("seq",456);//编号
// param.put("lng1",11.11);
// param.put("lat1",12.23);
// param.put("lng2",23.23);
// param.put("lat2",23.2);
// param.put("lng3",23.3);
// param.put("lat3",23.7);
// param.put("lng4",26.2);
// param.put("lat4",24.5);
// param.put("field","F");//场区(E/F)
// param.put("placeType",2);//区域类型。1桥下,2桥后
// param.put("id",19);//区域类型。1桥下,2桥后
// param.put("name","2223");//名称
// param.put("type",1);//类型。1缓冲区;2停车区;3:充电区
// param.put("state",1);//状态。0可用;1不可用(初始状态);2已计划;3有车
//
// String paramData = JSONObject.toJSONString(param);
// System.out.print(String.format("绘制地图区域保存请求发送:----%s", paramData));
// String result = RestTemplateUtil.post("http://10.11.10.1:8030/vehicleBuffer/edit" , paramData, null);
//// String result = RestTemplateUtil.post(String.format("%s%s", "http://10.11.10.1:8030/vehicleBuffer/edit", URL.MAP_EDIT_URL), paramData, null);
// System.out.print("绘制地图区域保存返回结果:------------"+result);
// }
public void testkafa(VmsTosOrdersDto dto) {
// KafkaTemplate<String, String> kafkaTemplate =new KafkaTemplate<String, String>( );
JSONObject param = new JSONObject();
Date date = new Date();
param.put("taskNo", UUID.randomUUID().toString().replace("-", ""));// 任务编号
param.put("seq", UUID.randomUUID().toString().replace("-", ""));// 序号
param.put("taskAssociation", "");// 任务关联
param.put("vin", dto.getVin());// 车辆编号
param.put("taskLocationType", dto.getTaskLocationType());// 任务类型 作业位置类型
// 1-去堆场(装箱或卸箱);2-去停车点(上扭锁,解扭锁,停车);3-去固定停车区;4-去临时停车区;5-去桥吊(装箱或卸箱);6-去充电
param.put("taskType", dto.getTaskType());// 作业类型 1-装箱,2-卸箱
param.put("vehicleTaskType", dto.getVehicleTaskType());// 车辆任务类型 对应着前台 集装箱类型
param.put("portCode", dto.getPortCode());// 港机编码
if (dto.getPortCode().substring(0, 1).equals("1")) {
param.put("portType", "1");// 港机类型
} else {
param.put("portType", "2");// 港机类型
}
param.put("vehicleLocation", dto.getVehicleLocation());// 车辆任务目标地点 对应前台 堆场贝位
param.put("cartonConditon", "0");// 辆当前装箱状态
param.put("containerId", dto.getContainerId());// 集装箱ID
if (dto.getVehicleTaskType().equals("1")) {
param.put("containerType", "40");// 集装箱类型
} else {
param.put("containerType", "20");// 集装箱类型
}
param.put("containerWeight", "1");// 集装箱重量
// param.put("containerPosition","");//集装箱车上位置
// param.put("overSign","");// 作业完成信号
param.put("collectTime", date);// 作业时间
// param.put("voyuageNo","");//艘次编号
param.put("lockLabel", dto.getLockLabel());// 扭锁标签
if (dto.getTaskLocationType().equals("1")) {
param.put("containerLabel", "1");
} else {
param.put("containerLabel", "2");
}
String paramData = JSONObject.toJSONString(param);
// log.info(String.format("绘制地图区域保存请求发送:----%s", paramData));
// this.kafkaTemplate.send(topic, key, data);
}
public static void main(String[] args) {
String mapdata="P1223456780";
System.out.println(Integer.valueOf(mapdata.substring(1)));
// String path="D:\\code/lsz.geojson";
//// String path = JsonTest.class.getClassLoader().getResource("students.json").getPath();
// String s = readJsonFile(path);
// JSONObject jobj = JSON.parseObject(s);
// JSONArray student = jobj.getJSONArray("features");//构建JSONArray数组
// for (int i = 0 ; i < student.size();i++){
// JSONObject key = (JSONObject)student.get(i);
// int stuId= (Integer)key.get("id");
// Object stuName= (Object)key.get("geometry");
//// int stuAge= (Integer)key.get("stuAge");
// JSONObject jsonObject = JSONObject.parseObject(stuName.toString());
//
// for(String str:jsonObject.keySet()) {
// if(str.equals("coordinates")) {
//// jsonObject.get(str);
// System.out.println(stuId+"----"+jsonObject.get(str));
// }
// }
//
// }
// System.out.println(readJsonFile("D:\\code/lsz.geojson"));
}
public static String readJsonFile(String fileName) {
String jsonStr = "";
try {
File jsonFile = new File(fileName);
FileReader fileReader = new FileReader(jsonFile);
Reader reader = new InputStreamReader(new FileInputStream(jsonFile), "utf-8");
int ch = 0;
StringBuffer sb = new StringBuffer();
while ((ch = reader.read()) != -1) {
sb.append((char) ch);
}
fileReader.close();
reader.close();
jsonStr = sb.toString();
return jsonStr;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
\ No newline at end of file
package com.ssi.utils;
public class ToolUtils {
/**
* 转换异常信息为字符串
*
* @param exceptionName 异常名称
* @param exceptionMessage 异常信息
* @param elements 堆栈信息
*/
public static String stackTraceToString(String exceptionName, String exceptionMessage,
StackTraceElement[] elements) {
StringBuffer strbuff = new StringBuffer();
for (StackTraceElement stet : elements) {
strbuff.append(stet + "\n");
}
String message = exceptionName + ":" + exceptionMessage + "\n\t" + strbuff.toString();
return message;
}
}
package com.ssi.utils;
import com.ssi.constant.enums.TaskLocationTypeEnum;
import com.ssi.constant.enums.TaskTypeEnum;
import com.ssi.entity.vo.VehicleVo;
import com.ssi.entity.vo.VmsTosOrdersVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
@Slf4j
public class VehicleDataUtil {
@Value("${client.onlineTime}")
private Long onlineTime;
public Integer checkOnline(Integer state, Long collectime) {
/** 检查终端状态*/
boolean dataOnline = (collectime != null
&& System.currentTimeMillis() - collectime < onlineTime);
boolean isOnline = dataOnline && state == 1;
return isOnline ? 1 : 0;
}
public VehicleVo.vehicleTemp toVehicleTemp(Map<String, Object> realDataMap) {
VehicleVo.vehicleTemp vehicleTemp = new VehicleVo().new vehicleTemp();
vehicleTemp.setVehicleNum(
realDataMap.get("vehicleNum") == null ? null : (String) realDataMap.get("vehicleNum"));
vehicleTemp.setVehicleType(
realDataMap.get("vehicleType") == null ? 0 : (Integer) realDataMap.get("vehicleType"));
vehicleTemp.setVin(realDataMap.get("vin") == null ? null : (String) realDataMap.get("vin"));
vehicleTemp.setSoc((Integer) realDataMap.get("soc"));
vehicleTemp.setFaultStatus(realDataMap.get("equipStatus") == null
? 1 : (Integer) realDataMap.get("equipStatus") == 1 ? 1 : 0);
if (vehicleTemp.getFaultStatus() == 1) {
vehicleTemp.setFaultLevel("一级故障");
}
vehicleTemp.setWorkStatus(
realDataMap.get("workStatus") == null ? 0 : (Integer) realDataMap.get("workStatus"));
Integer onlineStatus = checkOnline(
realDataMap.get("state") == null ? 0 : (Integer) realDataMap.get("state")
, (Long) realDataMap.get("collectTime"));
vehicleTemp.setOnlineStatus(onlineStatus);
vehicleTemp.setWaitOvertimeStatus(realDataMap.get("waitOvertimeStatus") == null ? 0
: (Integer) realDataMap.get("waitOvertimeStatus"));
vehicleTemp.setLowEnergyStatus(
realDataMap.get("lowEnergy") == null || realDataMap.get("soc") == null ? 0
: (Integer) realDataMap.get("soc") < (Integer) realDataMap.get("lowEnergy") ? 1 : 0);
if (onlineStatus == 1) {
VmsTosOrdersVo vmsTosOrders = (VmsTosOrdersVo) realDataMap.get("orderData");
if (vmsTosOrders != null) {
//加个判断subTaskType 0:缓冲区,1 2:扭锁站 其他不改变
String description="";
if(vmsTosOrders.getSubTaskType()==null){
description = generateOrderDescription(vmsTosOrders);
}else{
if (vmsTosOrders.getSubTaskType() == 0){
description="去缓冲区";
}else if(vmsTosOrders.getSubTaskType() == 1 || vmsTosOrders.getSubTaskType()==2){
description="去扭锁站";
}else{
description = generateOrderDescription(vmsTosOrders);
}
}
vmsTosOrders.setOrderDescription(description);
vehicleTemp.setOrderData(vmsTosOrders);
}
}
vehicleTemp.setEmergencyType(
realDataMap.get("emergencyType") == null ? 2 : (Integer) realDataMap.get("emergencyType"));
vehicleTemp.setThreeConfirmStatus((Map) realDataMap.get("threeConfirmStatus"));
return vehicleTemp;
}
public String generateOrderDescription(VmsTosOrdersVo vmsTosOrders) {
if (vmsTosOrders != null) {
try {
Integer taskLocationType = vmsTosOrders.getTaskLocationType();
String containerId = vmsTosOrders.getContainerId();
Integer taskType = vmsTosOrders.getTaskType();
String vehicleLocation = vmsTosOrders.getVehicleLocation();
return generateOrderDescription(taskLocationType, taskType, vehicleLocation, containerId);
} catch (Exception e) {
log.error("生成任务信息描述异常", e);
}
}
return null;
}
public String generateOrderDescription(Map taskOrderInfo) {
if (taskOrderInfo != null) {
try {
Integer taskLocationType = (Integer) taskOrderInfo.get("taskLocationType");
Integer taskType = (Integer) taskOrderInfo.get("taskType");
String vehicleLocation = (String) taskOrderInfo.get("vehicleLocation");
String containerId = (String) taskOrderInfo.get("containerId");
return generateOrderDescription(taskLocationType, taskType, vehicleLocation, containerId);
} catch (Exception e) {
log.error("生成任务信息描述异常", e);
}
}
return null;
}
public String generateTaskLocationDescription(Map taskOrderInfo) {
if (taskOrderInfo != null) {
try {
Integer taskLocationType = (Integer) taskOrderInfo.get("taskLocationType");
String vehicleLocation = (String) taskOrderInfo.get("vehicleLocation");
return generateTaskLocationDescription(taskLocationType, vehicleLocation);
} catch (Exception e) {
log.error("生成任务地点描述异常", e);
}
}
return null;
}
/**
* taskLocationType:任务类型, 1-去堆场(装箱或卸箱);2-去停车点(上扭锁,解扭锁,停车);3-去固定停车区; 4-去临时停车区;5-去桥吊(装箱或卸箱);6-去充电
* taskType:作业类型,1:装箱,2:卸箱,3:充电,4:上扭锁,5:解扭锁,6:停车,7掉头
*/
private String generateOrderDescription(Integer taskLocationType, Integer taskType,
String vehicleLocation, String containerId) {
TaskLocationTypeEnum taskLocationTypeEnum = TaskLocationTypeEnum.find(taskLocationType);
TaskTypeEnum taskTypeEnum = TaskTypeEnum.find(taskType);
String str1 = null;
String str2 = null;
if (StringUtils.isNotBlank(vehicleLocation) && vehicleLocation.length() >= 6) {
str1 = vehicleLocation.substring(0, 3);
str2 = vehicleLocation.substring(3, 6);
}
StringBuilder sb = new StringBuilder();
switch (taskLocationType) {
case 1:
sb.append("去" + str1 + "堆场" + str2 + "贝位");
// .append("将集装箱").append(containerId)
// .append(taskTypeEnum.getDescription());
break;
case 2:
// sb.append(taskLocationTypeEnum.getDescription())
// .append(taskTypeEnum.getDescription());
// break;
case 3:
case 4:
case 6:
sb.append(taskLocationTypeEnum.getDescription());
break;
case 5:
sb.append("去" + str1 + "桥吊" + str2 + "车道");
// .append("将集装箱").append(containerId)
// .append(taskTypeEnum.getDescription());
break;
}
return sb.toString();
}
public String generateTaskLocationDescription(Integer taskLocationType, String vehicleLocation) {
TaskLocationTypeEnum taskLocationTypeEnum = TaskLocationTypeEnum.find(taskLocationType);
String str1 = null;
String str2 = null;
if (StringUtils.isNotBlank(vehicleLocation)) {
str1 = vehicleLocation.substring(0, 3);
str2 = vehicleLocation.substring(3, 6);
}
StringBuilder sb = new StringBuilder();
switch (taskLocationType) {
case 1:
sb.append(str1 + "堆场" + str2 + "贝位");
break;
case 2:
case 3:
case 4:
case 6:
sb.append(taskLocationTypeEnum.getDescription());
break;
case 5:
sb.append(str1 + "桥吊" + str2 + "车道");
break;
}
return sb.toString();
}
}
package com.ssi.utils;
import com.ssi.constant.VehicleConstant;
public class VehicleUtil {
public static boolean isTaskOver(int status) {
if (status == VehicleConstant.FINISH_CHARGING || status == VehicleConstant.FINISH_PACKING
|| status == VehicleConstant.FINISH_CONFIRM) {
return true;
}
return false;
}
}
package com.ssi.utils.grid;
import com.ssi.utils.GpsUtil;
/**
*
* -----------------------------------------------------------------------------------------
* 坐标系 |解释 |使用地图
* -----------------------------------------------------------------------------------------
* WGS84 |地球坐标系,国际上通用的坐标系。设备一般包含GPS芯片或者北斗芯片获取 |GPS/谷歌地图卫星
* |的经纬度为WGS84地理坐标系,最基础的坐标,谷歌地图在非中国地区使用的坐标系 |
* -----------------------------------------------------------------------------------------
* GCJ02 |火星坐标系,是由中国国家测绘局制订的地理信息系统的坐标系统。 |腾讯(搜搜)地图,
* |并要求在中国使用的地图产品使用的都必须是加密后的坐标, |阿里云地图,高德地图,
* |而这套WGS84加密后的坐标就是gcj02。 |谷歌国内地图
* -----------------------------------------------------------------------------------------
* BD09 |百度坐标系,百度在GCJ02的基础上进行了二次加密, |百度地图
* |官方解释是为了进一步保护用户隐私 |
* -----------------------------------------------------------------------------------------
* 小众坐标系 |类似于百度地图,在GCJ02基础上使用自己的加密算法进行二次加密的坐标系 |搜狗地图、图吧地图 等
* -----------------------------------------------------------------------------------------
* 墨卡托坐标 |墨卡托投影以整个世界范围,赤道作为标准纬线,本初子午线作为中央经线,
* |两者交点为坐标原点,向东向北为正,向西向南为负。
* |南北极在地图的正下、上方,而东西方向处于地图的正右、左。
*
* 你可以通过这个工具类将上述坐标系进行互相转换。
*
* 百度地图地图投影采用的依然是Web Mercator投影,地图瓦片的切片规则遵循TMS标准,瓦片坐标原点在经纬度为0的附近,
* 但却做了一定的偏移处理,经测算此偏移量约为(-865,15850),
* 即地图瓦片(0, 0)是从Web Mercator投影坐标系的(-865,15850)点开始的。
*
* 顺便提供百度地图的地图等级从18级到1级
* 18级,1个像素代表1米,17级,1个像素代表2米,16级代表4米,依此类推
* Author: kong
*/
public class Coordtransform {
public static double baiduChange = (Math.PI * 3000.0) / 180.0;
public static double ee = 0.00669342162296594323; //偏心率平方
public static double a = 6378245.0;// # 长半轴
/**
* 长半径a=6378137 米
*/
public static double EARTH_RADIUS = 6378137;
/**
* 短半径b=6356752.3142
*/
public static double b = 6356752.3142;
/**
* 扁率f=1/298.2572236
*/
public static double f = 1 / 298.2572236;
/**
* 已知一点经纬度,方位角,距离,求另一点经纬度
* 通过三角函数求终点坐标-球面坐标系
* </summary>
* <param name="angle">角度</param>
*<param name="startPoint">起点</param>
* <param name="distance">距离(米)</param>
* <returns>终点坐标</returns>
*/
public static double[] getEndPointByTrigonometric(double angle, double[] startPoint, double distance) {
double lon=startPoint[0];
double lat=startPoint[1];
double alpha1 = rad(angle);
double sinAlpha1 = Math.sin(alpha1);
double cosAlpha1 = Math.cos(alpha1);
double tanU1 = (1 - f) * Math.tan(rad(lat));
double cosU1 = 1 / Math.sqrt((1 + tanU1 * tanU1));
double sinU1 = tanU1 * cosU1;
double sigma1 = Math.atan2(tanU1, cosAlpha1);
double sinAlpha = cosU1 * sinAlpha1;
double cosSqAlpha = 1 - sinAlpha * sinAlpha;
double uSq = cosSqAlpha * (EARTH_RADIUS * EARTH_RADIUS - b * b) / (b * b);
double A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
double B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
double cos2SigmaM = 0;
double sinSigma = 0;
double cosSigma = 0;
double sigma = distance / (b * A), sigmaP = 2 * Math.PI;
while (Math.abs(sigma - sigmaP) > 1e-12) {
cos2SigmaM = Math.cos(2 * sigma1 + sigma);
sinSigma = Math.sin(sigma);
cosSigma = Math.cos(sigma);
double deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)
- B / 6 * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM)));
sigmaP = sigma;
sigma = distance / (b * A) + deltaSigma;
}
double tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1;
double lat2 = Math.atan2(sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1,
(1 - f) * Math.sqrt(sinAlpha * sinAlpha + tmp * tmp));
double lambda = Math.atan2(sinSigma * sinAlpha1, cosU1 * cosSigma - sinU1 * sinSigma * cosAlpha1);
double C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
double L = lambda - (1 - C) * f * sinAlpha
* (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));
double[] endPoint=new double[2];
endPoint[0]=lon + deg(L);
endPoint[1]= deg(lat2);
return endPoint;
}
/**
* 度换成弧度
* @param d 度
* @return 弧度
*/
public static double rad(double d) {
return d * Math.PI / 180.0;
}
/**
* 弧度换成度
* @param x 弧度
* @return 度
*/
public static double deg(double x) {
return x * 180 / Math.PI;
}
/**
* 百度坐标系(BD-09)转火星坐标系(GCJ-02)
* 百度——>谷歌、高德
*
* @param lng_BD 百度坐标经度
* @param lat_BD 百度坐标纬度
* @return 转换后的坐标列表形式
*/
public static double[] BD09toGCJ02(double lng_BD, double lat_BD) {
double[] GCJ02 = new double[2];
double x = lng_BD - 0.0065;
double y = lat_BD - 0.006;
double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * baiduChange);
double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * baiduChange);
double gg_lng = z * Math.cos(theta);
double gg_lat = z * Math.sin(theta);
GCJ02[0] = gg_lng;
GCJ02[1] = gg_lat;
return GCJ02;
}
/**
* 火星坐标系(GCJ-02)转百度坐标系(BD-09)
* 谷歌、高德——>百度
*
* @param lng_GCJ
* @param lat_GCJ
* @return 转换后的坐标列表形式
*/
public static double[] GCJ02toBD09(double lng_GCJ, double lat_GCJ) {
double[] BD09 = new double[2];
// """
// 实现GCJ02向BD09坐标系的转换
// :param lng: GCJ02坐标系下的经度
// :param lat: GCJ02坐标系下的纬度
// :return: 转换后的BD09下经纬度
// """
double z = Math.sqrt(lng_GCJ * lng_GCJ + lat_GCJ * lat_GCJ) + 0.00002 * Math.sin(lat_GCJ * Math.PI);
double theta = Math.atan2(lat_GCJ, lng_GCJ) + 0.000003 * Math.cos(lng_GCJ * Math.PI);
double bd_lng = z * Math.cos(theta) + 0.0065;
double bd_lat = z * Math.sin(theta) + 0.006;
BD09[0] = bd_lng;
BD09[1] = bd_lat;
return BD09;
}
/**
* GCJ02(火星坐标系)转GPS84
*
* @param lng_gcj 火星坐标系的经度
* @param lat_gcj 火星坐标系纬度
* @return 转换后的坐标列表形式
*/
public static double[] GCJ02toWGS84(double lng_gcj, double lat_gcj) {
double[] wgs84 = new double[2];
if (outOfChina(lng_gcj, lat_gcj)) {
return new double[]{lng_gcj, lat_gcj};
}
// if out_of_china(lng, lat):
// return [lng, lat]
double dlat = transformlat(lng_gcj - 105.0, lat_gcj - 35.0);
double dlng = transformlng(lng_gcj - 105.0, lat_gcj - 35.0);
double radlat = lat_gcj / 180.0 * Math.PI;
double magic = Math.sin(radlat);
magic = 1 - ee * magic * magic;
double sqrtmagic = Math.sqrt(magic);
dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * Math.PI);
dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * Math.PI);
double mglat = lat_gcj + dlat;
double mglng = lng_gcj + dlng;
return new double[]{lng_gcj * 2 - mglng, lat_gcj * 2 - mglat};
}
/**
* GPS84转GCJ02(火星坐标系)
*
* @param lng_wgs WGS84坐标系的经度
* @param lat_wgs WGS84坐标系纬度
* @return 转换后的GCJ02下经纬度
*/
public static double[] WGS84toGCJ02(double lng_wgs, double lat_wgs) {
if (outOfChina(lng_wgs, lat_wgs)) {
return new double[]{lng_wgs, lat_wgs};
}
double[] GCJ02 = new double[2];
double dlat = transformlat(lng_wgs - 105.0, lat_wgs - 35.0);
double dlng = transformlng(lng_wgs - 105.0, lat_wgs - 35.0);
double radlat = lat_wgs / 180.0 * Math.PI;
double magic = Math.sin(radlat);
magic = 1 - ee * magic * magic;
double sqrtmagic = Math.sqrt(magic);
dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * Math.PI);
dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * Math.PI);
double gcj_lng = lat_wgs + dlat;
double gcj_lat = lng_wgs + dlng;
GCJ02[1] = gcj_lng;
GCJ02[0] = gcj_lat;
return GCJ02;
}
/**
* GPS84 转 墨卡托坐标
*
* @param lng GPS84的经度
* @param lat GPS84纬度
* @return 转换后的坐标列表形式
*/
public static double[] WGS84toMercator(double lng, double lat) {
double x = lng * 20037508.342789 / 180;
double y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);
y = y * 20037508.342789 / 180;
return new double[]{x, y};
}
/**
* 百度坐标系转成通用墨卡托坐标
*
* @param lng
* @param lat
* @return
*/
public static double[] bdtoMercator(double lng, double lat) {
double[] gcj02 = BD09toGCJ02(lng, lat);
double[] wgs84 = GCJ02toWGS84(gcj02[0], gcj02[1]);
double[] mercator = WGS84toMercator(wgs84[0], wgs84[1]);
return mercator;
}
private static double transformlat(double lng, double lat) {
double ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat +
0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng));
ret += (20.0 * Math.sin(6.0 * lng * Math.PI) + 20.0 *
Math.sin(2.0 * lng * Math.PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(lat * Math.PI) + 40.0 *
Math.sin(lat / 3.0 * Math.PI)) * 2.0 / 3.0;
ret += (160.0 * Math.sin(lat / 12.0 * Math.PI) + 320 *
Math.sin(lat * Math.PI / 30.0)) * 2.0 / 3.0;
return ret;
}
private static double transformlng(double lng, double lat) {
double ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng +
0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));
ret += (20.0 * Math.sin(6.0 * lng * Math.PI) + 20.0 *
Math.sin(2.0 * lng * Math.PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(lng * Math.PI) + 40.0 *
Math.sin(lng / 3.0 * Math.PI)) * 2.0 / 3.0;
ret += (150.0 * Math.sin(lng / 12.0 * Math.PI) + 300.0 *
Math.sin(lng / 30.0 * Math.PI)) * 2.0 / 3.0;
return ret;
}
/**
* 判断是否在国内,不在国内不做偏移
*
* @param lng
* @param lat
* @return
*/
public static boolean outOfChina(double lng, double lat) {
return !(lng > 73.66 && lng < 135.05 && lat > 3.86 && lat < 53.55);
}
public static boolean outOfChinaByMercator(double x, double y) {
return !(x > 8199793.7 && x < 1.5E7 && y > 430018.7 && y < 7085388.2);
}
public static void main(String[] args) {
double distance = GpsUtil.getDistance(24.455743, 117.967768, 24.455735, 117.967811);
System.out.println(distance * 1000);
}
}
package com.ssi.utils.grid;
import java.io.Serializable;
public class GridFreeEvent implements Serializable {
private String vid;
private MercatorGrid grid;
public GridFreeEvent(String vid, MercatorGrid grid) {
this.vid = vid;
this.grid = grid;
}
public String getVid() {
return vid;
}
public MercatorGrid getGrid() {
return grid;
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("GridFreeEvent{");
sb.append("vid='").append(vid).append('\'');
sb.append("grid='").append(grid).append('\'');
sb.append('}');
return sb.toString();
}
}
package com.ssi.utils.grid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* 网格对象:
* 包含网格标识点MercatorPoint,订阅用户队列、当前占用用户
* 后续考虑采用触发器的形式 在让给下一个用户时直接告知下一个用户可以开始操作了
*
*/
public class MercatorGrid implements Serializable {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final MercatorPoint point;
//用户占用等待队列
private final ConcurrentLinkedQueue<String> userWaitQueue;
//当前用户
private volatile String currentUser;
public MercatorGrid(MercatorPoint point){
assert point != null : "网格标识点不能为空!";
this.point = point;
this.userWaitQueue = new ConcurrentLinkedQueue<>();
}
/**
* 预定此网格
* @param user id
* @return
*/
public boolean reserve(String user){
String currentUser = getCurrentUser();
if(!user.equals(currentUser)) {
boolean offer = this.userWaitQueue.offer(user);
//当前用户为null时,设置为此用户
getCurrentUser();
logger.debug(String.format("%s 预定占用网格 %s 成功,当前等待用户数:%s",
user, point, userWaitQueue.size()));
return offer;
}
return true;
}
public boolean cancelReserve(String user){
this.userWaitQueue.remove(user);
logger.debug(String.format("取消%s 预定占用网格 %s 成功,当前等待用户数:%s",
user, point, userWaitQueue.size()));
return false;
}
/**
* 获取当前用户
* @return
*/
public String getCurrentUser(){
if(this.currentUser == null){
synchronized (MercatorGrid.class) {
if(this.currentUser == null) {
this.currentUser = this.userWaitQueue.poll();
}
}
}
return this.currentUser;
}
/**
* 释放当前用户, 让给下一个用户
* @param currentUser
* @return
*/
public boolean freeToNext(String currentUser){
if(currentUser.equals(this.currentUser)){
synchronized (MercatorGrid.class){
if(currentUser.equals(this.currentUser)){
this.currentUser = this.userWaitQueue.poll();
logger.debug(String.format("%s 释放网格 %s 成功,当前用户变更为:%s, 目前等待用户数",
currentUser, point, this.currentUser, userWaitQueue.size()));
return true;
}
}
}
logger.error(String.format("%s 非网格 %s 当前用户 %s,无法释放!", currentUser, point, this.currentUser));
return false;
}
public MercatorPoint getPoint() {
return this.point.clone();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MercatorGrid that = (MercatorGrid) o;
return point.equals(that.point);
}
@Override
public int hashCode() {
return point != null ? point.hashCode() : 0;
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("MercatorGrid{");
sb.append("point=").append(point);
sb.append(", userWaitQueueSize=").append(userWaitQueue.size());
sb.append(", currentUser='").append(currentUser).append('\'');
sb.append('}');
return sb.toString();
}
}
package com.ssi.utils.grid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.util.*;
/**
* 四个顶点,按指定距离划分格子,生成网
* @author jechedo
* @time 2022/12/1
*/
public class MercatorNet implements Serializable {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final MercatorPoint pointA;
private final MercatorPoint pointB;
private final MercatorPoint pointC;
private final MercatorPoint pointD;
private final int gridDistance;
private final Map<MercatorPoint, MercatorGrid> gridsMap;
/**
* @param pointA
* @param pointB
* @param pointC
* @param pointD
* @param gridDistance 网格距离, 单位:米
*/
public MercatorNet(MercatorPoint pointA,
MercatorPoint pointB,
MercatorPoint pointC,
MercatorPoint pointD,
int gridDistance){
assert gridDistance > 0 : "gridDistance 必须为大于0的值。";
this.pointA = pointA;
this.pointB = pointB;
this.pointC = pointC;
this.pointD = pointD;
this.gridDistance = gridDistance;
this.gridsMap = new HashMap<>();
//生成网格
createNet();
}
/**
* 生成网格
*
*/
private void createNet(){
this.gridsMap.putAll(searchGrids(this.pointA, this.pointB, this.pointC, this.pointD));
}
private Map<MercatorPoint, MercatorGrid> searchGrids(MercatorPoint pointA,
MercatorPoint pointB,
MercatorPoint pointC,
MercatorPoint pointD){
//根据四个顶点坐标,求网格x与y的最大最小值
List<Double> xs = new ArrayList<>();
xs.add(pointA.getX());
xs.add(pointB.getX());
xs.add(pointC.getX());
xs.add(pointD.getX());
//向上取整, 获取能整除gridDistance 且距离x最大值最近 又大于x最大值的值
double maxX = Math.ceil(Collections.max(xs) / gridDistance) * gridDistance;
//向下取整, 获取能整除gridDistance 且距离x最小值最近 又小于x最小值的值
double minX = Math.floor(Collections.min(xs) / gridDistance) * gridDistance;
List<Double> ys = new ArrayList<>();
ys.add(pointA.getY());
ys.add(pointB.getY());
ys.add(pointC.getY());
ys.add(pointD.getY());
//向上取整, 获取能整除gridDistance 且距离y最大值最近 又大于y最大值的值
double maxY = Math.ceil(Collections.max(ys) / gridDistance) * gridDistance;
//向下取整, 获取能整除gridDistance 且距离y最小值最近 又小于y最小值的值
double minY = Math.floor(Collections.min(ys) / gridDistance) * gridDistance;
return searchGrids(maxX, minX, maxY,minY);
}
private Map<MercatorPoint, MercatorGrid> searchGrids(double maxX, double minX, double maxY, double minY){
Map<MercatorPoint, MercatorGrid> gridsMap = new HashMap<>();
//x方向 网格个数
double gridXNum = (maxX - minX) / this.gridDistance;
//x方向 网格个数
double gridYNum = (maxY - minY) / this.gridDistance;
//生成网格, 取网格左下角的点的坐标作为网格标识
double x;
double y;
MercatorPoint point;
for (int i = 0; i < gridXNum; i++) {
x = minX + this.gridDistance * i;
for (int j = 0; j < gridYNum; j++) {
y = minY + this.gridDistance * j;
point = new MercatorPoint(x, y);
//设置网格状态
gridsMap.put(point, getMercatorGrid(point));
}
}
return gridsMap;
}
public int getNetGridSize(){
return this.gridsMap.size();
}
public Collection<MercatorGrid> getChildGrids(MercatorPoint pointA,
MercatorPoint pointB,
MercatorPoint pointC,
MercatorPoint pointD){
return searchGrids(pointA, pointB, pointC,pointD).values();
}
public Collection<MercatorGrid> getChildGrids(double maxX, double minX, double maxY, double minY){
maxX = Math.ceil(maxX / gridDistance) * gridDistance;
minX = Math.floor(minX / gridDistance) * gridDistance;
maxY = Math.ceil(maxY / gridDistance) * gridDistance;
minY = Math.floor(minY / gridDistance) * gridDistance;
return searchGrids(maxX, minX, maxY, minY).values();
}
public MercatorGrid getMercatorGrid(MercatorPoint point){
return this.gridsMap.getOrDefault(point, new MercatorGrid(point));
}
public static void main(String[] args) {
double[] a = Coordtransform.WGS84toMercator(117.964504, 24.454129);
MercatorPoint pointA = new MercatorPoint(a[0], a[1]);
double[] b = Coordtransform.WGS84toMercator(117.98918, 24.449011);
MercatorPoint pointB = new MercatorPoint(b[0], b[1]);
double[] c = Coordtransform.WGS84toMercator(117.990382, 24.453953);
MercatorPoint pointC = new MercatorPoint(c[0], c[1]);
double[] d = Coordtransform.WGS84toMercator(117.965813, 24.458992);
MercatorPoint pointD = new MercatorPoint(d[0], d[1]);
MercatorNet mercatorNet = new MercatorNet(pointA, pointB, pointC, pointD, 5);
Collection<MercatorGrid> grids = mercatorNet.getChildGrids(1.3132610797736611E7, 1.3132030377911612E7, 2809111.607682695, 2808734.2196206213);
grids.forEach((grid -> {
grid.reserve("912");
System.out.println(mercatorNet.getMercatorGrid(grid.getPoint()) + " -- " + grid);
}));
System.out.println(mercatorNet.getNetGridSize() + " -- " + grids.size());
/* System.out.println( " ---" );
double[] aa = Coordtransform.WGS84toMercator(117.967487, 24.456316);
MercatorPoint pointAA = new MercatorPoint(aa[0], aa[1]);
System.out.println(pointAA);
double[] bb = Coordtransform.WGS84toMercator(117.97225, 24.455418);
MercatorPoint pointBB = new MercatorPoint(bb[0], bb[1]);
System.out.println(pointBB);
double[] cc = Coordtransform.WGS84toMercator(117.971735, 24.45323);
MercatorPoint pointCC = new MercatorPoint(cc[0], cc[1]);
System.out.println(pointCC);
double[] dd = Coordtransform.WGS84toMercator(117.967036, 24.454148);
MercatorPoint pointDD = new MercatorPoint(dd[0], dd[1]);
System.out.println(pointDD);*/
}
}
package com.ssi.utils.grid;
import java.io.Serializable;
/**
* 网格标识点对象:
* x,y 为 墨卡托坐标
*/
public class MercatorPoint implements Serializable {
private double x;
private double y;
public MercatorPoint(double x, double y){
assert Coordtransform.outOfChinaByMercator(x, y): "坐标点位必须在中国国内。";
this.x = x;
this.y = y;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public MercatorPoint clone(){
return new MercatorPoint(x, y);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MercatorPoint that = (MercatorPoint) o;
if (Double.compare(that.x, x) != 0) return false;
return Double.compare(that.y, y) == 0;
}
@Override
public int hashCode() {
int result;
long temp;
temp = Double.doubleToLongBits(x);
result = (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(y);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("[");
sb.append("x=").append(x);
sb.append(", y=").append(y);
sb.append(']');
return sb.toString();
}
}
package com.ssi.utils.grid;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.util.*;
/**
* 车辆数据,即网格用户
*/
public class MercatorVehicle implements Serializable {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final String vid;
private final EventBus eventBus;
private Set<MercatorGrid> grids = new HashSet<>();
//车辆实时数据
private MercatorPoint point;
private List<MercatorGrid> waitGrids = new ArrayList<>();
private Integer versionNo;
private long timeStamp;
private double speed;
private boolean isActive =false;
public MercatorVehicle(EventBus eventBus, String vid, Collection<MercatorGrid> grids,
MercatorPoint point, double speed, long timeStamp){
this.vid = vid;
this.eventBus = eventBus;
update(grids, point, speed, timeStamp);
}
public int waitGridSize(){
return this.waitGrids.size();
}
public boolean update(Collection<MercatorGrid> grids,
MercatorPoint point, double speed, long timeStamp){
int waitGridSize = waitGridSize();
//无等待 则可执行更新
if(waitGridSize > 0){
freeAllWaitGrids();
}
Iterator<MercatorGrid> iterator = this.grids.iterator();
MercatorGrid next;
while (iterator.hasNext()){
next = iterator.next();
if(!grids.contains(next)){
//注销占用,让位给下一约定车辆, 并移除
if(next.freeToNext(this.vid)){
String currentUser = next.getCurrentUser();
if(currentUser != null) {
//通知对应车辆
this.eventBus.post(new GridFreeEvent(this.vid, next));
}
}
iterator.remove();
}
}
StringBuilder sb = new StringBuilder();
grids.forEach(grid -> {
if(this.grids.add(grid)){
//添加成功,则为新占用网格
grid.reserve(vid);
String currentUser = grid.getCurrentUser();
//检查网格当前用户是否为本车, 不是本车则将网格记录到等待队列
if(!this.vid.equals(currentUser)){
sb.append(currentUser).append(" ");
this.waitGrids.add(grid);
// this.eventBus.post(new GridFreeEvent(currentUser, grid));
}
}
});
this.point = point;
this.speed = speed;
this.timeStamp = timeStamp;
logger.info(String.format("车辆%s更新网格集合成功,占用网格数:%s, 等待网格数:%s, speed:%s, timeStamp: %s,等待网格占有者:[%s].",
this.vid, this.grids.size(), waitGridSize(), speed, timeStamp,sb));
return true;
}
public void freeWaitGrid(String frontVid, MercatorGrid grid){
this.waitGrids.remove(grid);
if(!this.grids.contains(grid))
grid.freeToNext(this.vid);
if(waitGridSize()==0){
this.isActive = true;
}
logger.info(String.format("车辆%s 释放网格%s,当前车辆%s占用,移出等待集合, 当前等待网格数:%s", frontVid, grid, this.vid, waitGridSize()));
}
public void freeOwnedGrids(){
this.grids.forEach((grid)->{
if(!this.waitGrids.contains(grid)){
grid.freeToNext(vid);
}
});
grids.clear();
}
public void freeAllWaitGrids(){
this.waitGrids.forEach((grid)->{
if(vid.equalsIgnoreCase(grid.getCurrentUser())){
grid.freeToNext(vid);
}else {
grid.cancelReserve(vid);
}
});
this.waitGrids.clear();
}
public void freeAll(){
Iterator<MercatorGrid> iterator = this.grids.iterator();
MercatorGrid next;
while (iterator.hasNext()){
next = iterator.next();
if(this.waitGrids.contains(next)){
next.cancelReserve(this.vid);
}else{
if(next.freeToNext(this.vid)){
String currentUser = next.getCurrentUser();
if(currentUser != null) {
//通知对应车辆
this.eventBus.post(new GridFreeEvent(this.vid, next));
}
}
}
iterator.remove();
}
this.waitGrids.clear();
}
public String getVid() {
return vid;
}
public int getGridsSize() {
return grids.size();
}
public Integer getVersionNo() {
return versionNo;
}
public void setVersionNo(Integer versionNo) {
this.versionNo = versionNo;
}
public boolean isActive() {
return isActive;
}
public void setActive(boolean active) {
isActive = active;
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("MercatorVehicle{");
sb.append("vid='").append(vid).append('\'');
sb.append('}');
return sb.toString();
}
}
package com.ssi.utils.grid;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import com.ssi.entity.dto.Point;
import com.ssi.kafka.listener.VehicleRealTimeInfoListener;
import com.ssi.utils.FieldUtil;
import com.ssi.utils.SpringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
public class RealTimeVehicleSchedule {
private final Logger logger = LoggerFactory.getLogger(getClass());
private volatile static RealTimeVehicleSchedule VEHICLE_SCHEDULE;
/** 地图角度修正系数,原北向为0,实际东向为0, 逆时针为正*/
private static final double deltAngle = 450.0;
private final MercatorNet mercatorNet;
private final Map<String, MercatorVehicle> vehicleMap;
private final EventBus eventBus;
private RealTimeVehicleSchedule(){
this.mercatorNet = createTestNet();
this.vehicleMap = new HashMap<>();
this.eventBus = new EventBus("GridFree");
//注册监听到eventBus
this.eventBus.register(this);
}
private MercatorNet createTestNet(){
//测试用 从高德地图中拾取的厦门远海的四个顶点坐标
double[] wgs84 = Coordtransform.GCJ02toWGS84(117.964504, 24.454129);
double[] a = Coordtransform.WGS84toMercator(wgs84[0], wgs84[1]);
MercatorPoint pointA = new MercatorPoint(a[0], a[1]);
wgs84 = Coordtransform.GCJ02toWGS84(117.98918, 24.449011);
double[] b = Coordtransform.WGS84toMercator(wgs84[0], wgs84[1]);
MercatorPoint pointB = new MercatorPoint(b[0], b[1]);
wgs84 = Coordtransform.GCJ02toWGS84(117.990382, 24.453953);
double[] c = Coordtransform.WGS84toMercator(wgs84[0], wgs84[1]);
MercatorPoint pointC = new MercatorPoint(c[0], c[1]);
wgs84 = Coordtransform.GCJ02toWGS84(117.965813, 24.458992);
double[] d = Coordtransform.WGS84toMercator(wgs84[0], wgs84[1]);
MercatorPoint pointD = new MercatorPoint(d[0], d[1]);
return new MercatorNet(pointA, pointB, pointC, pointD, 2);
}
public static RealTimeVehicleSchedule getInstance(){
if(VEHICLE_SCHEDULE == null) {
synchronized (RealTimeVehicleSchedule.class){
if(VEHICLE_SCHEDULE == null){
VEHICLE_SCHEDULE = new RealTimeVehicleSchedule();
}
}
}
return VEHICLE_SCHEDULE;
}
/**
* 车辆实时数据
* @param vehicleDataMap key:车辆唯一标识, value:实时数据
* 其中实时数据需包含字段有:location[longitude、latitude]、speed、direction, collectTime,isOnline
*/
public void pushRealTimeVehicleData(Map<String, Map<String, Object>> vehicleDataMap){
if(vehicleDataMap != null){
Set<Map.Entry<String, Map<String, Object>>> entrySet = vehicleDataMap.entrySet();
String vid;
Map<String, Object> data;
for (Map.Entry<String, Map<String, Object>> entry : entrySet) {
data = entry.getValue();
vid = String.format("%s-%s", data.get("vehicleNum"), entry.getKey());
//处理9子开头的车,并排除950
if( !vid.startsWith("9") || vid.startsWith("950") || !data.containsKey("location")){
continue;
}
updateOrCreateVehicle(vid, data);
}
}
}
/**
*
* @param vehicleDataMap
*/
public void pushSingleVehicleData(Map<String, Object> vehicleDataMap){
if(vehicleDataMap != null){
String vid = String.format("%s-%s", vehicleDataMap.get("vehicleNum"), vehicleDataMap.get("vin"));
//处理9子开头的车,并排除950
if( !vid.startsWith("9") || vid.startsWith("950") || !vehicleDataMap.containsKey("location")){
return;
}
updateOrCreateVehicle(vid, vehicleDataMap);
}
}
private void updateOrCreateVehicle(String vid, Map<String, Object> data){
Object collectTime = data.get("collectTime");
Object direction = data.get("direction");
Object speed = data.get("speed");
data.put("closeArea","");
String isOnline = String.valueOf(data.get("isOnline"));
Integer versionNo = (Integer)data.get("versionNo");
try {
VehicleRealTimeInfoListener listener = SpringUtils.getObject(VehicleRealTimeInfoListener.class);
double sp = Double.parseDouble(String.valueOf(speed));
double[] location = (double[]) data.get("location");
double direc = Double.parseDouble(String.valueOf(direction)) / 100;
MercatorPoint point = getPoint(location[0], location[1]);
MercatorVehicle vehicle = this.vehicleMap.get(vid);
Collection<MercatorGrid> grids = null;
if(vehicle == null){
if("1".equals(isOnline) && sp > 0) {
grids = getGrids(data, location[0], location[1], deltAngle-direc);
vehicle = new MercatorVehicle(this.eventBus, vid, grids, point, Double.parseDouble(String.valueOf(speed)),
Long.parseLong(String.valueOf(collectTime)));
vehicle.setVersionNo(versionNo);
this.vehicleMap.put(vid, vehicle);
}
}else{
//在线,且运动中,则进行网格占用更新,否则全部释放
if("1".equals(isOnline) && (sp > 0 || vehicle.waitGridSize()>0 || vehicle.isActive())) {
grids = getGrids(data, location[0], location[1], deltAngle-direc);
vehicle.update(grids, point, Double.parseDouble(String.valueOf(speed)),
Long.parseLong(String.valueOf(collectTime)));
vehicle.setVersionNo(versionNo);
if(sp>0) vehicle.setActive(false);
}else{//非等待中车辆
//车辆已下线 或车辆已停车 释放所有网格
vehicle.freeAll();
}
}
if(Objects.isNull(vehicle)){
return;
}
listener.invokeForOrder(vehicle);
if(vehicle.waitGridSize()>0||(sp==0&&!vehicle.isActive()&&!listener.isContainVin(vid))){//解决关联方停止车辆速度为0,未下命令但为停止状态,
//车辆暂停任务释放已拥有区域,解决死锁和区域资源占用
vehicle.freeOwnedGrids();
data.put("closeArea","");
}
}catch (Exception e){
logger.error(String.format("创建或更新 %s 的MercatorVehicle对象失败:" +
"speed: %s, direction: %s, collectTime: %s", vid, speed, direction, collectTime), e);
}
}
private Collection<MercatorGrid> getGrids( Map<String, Object> data, double lng, double lat, double direc){
double[] startPoint = {lng, lat};
double[] delt = adapterAreaSize(startPoint,direc);
//寻找车辆当前点,沿车头方向10米的点
double[] pointO = Coordtransform.getEndPointByTrigonometric(direc, startPoint, 1);
//pointO,沿车头方向20米的点
double[] pointE = Coordtransform.getEndPointByTrigonometric(direc, pointO, delt[1]);
//pointO,沿车头方向垂直90°方向5米的点,
double[] pointA = Coordtransform.getEndPointByTrigonometric(direc + 90, pointO, delt[0]);
double[] mercatorA = Coordtransform.WGS84toMercator(pointA[0], pointA[1]);
//pointO,沿车头方向垂直270°方向5米的点,
double[] pointD = Coordtransform.getEndPointByTrigonometric(direc + 270, pointO, delt[0]);
double[] mercatorD = Coordtransform.WGS84toMercator(pointD[0], pointD[1]);
//pointE,沿车头方向垂直90°方向5米的点,
double[] pointB = Coordtransform.getEndPointByTrigonometric(direc + 90, pointE, delt[0]);
double[] mercatorB = Coordtransform.WGS84toMercator(pointB[0], pointB[1]);
//pointE,沿车头方向垂直270°方向5米的点,
double[] pointC = Coordtransform.getEndPointByTrigonometric(direc + 270, pointE, delt[0]);
double[] mercatorC = Coordtransform.WGS84toMercator(pointC[0], pointC[1]);
List<String> closeArea = new ArrayList<>();
closeArea.add(pointA[0]+","+pointA[1]);
closeArea.add(pointB[0]+","+pointB[1]);
closeArea.add(pointC[0]+","+pointC[1]);
closeArea.add(pointD[0]+","+pointD[1]);
data.put("closeArea",closeArea);
/* //测试用
startPoint = Coordtransform.WGS84toGCJ02(startPoint[0], startPoint[1]);
pointA = Coordtransform.WGS84toGCJ02(pointA[0], pointA[1]);
pointB = Coordtransform.WGS84toGCJ02(pointB[0], pointB[1]);
pointC = Coordtransform.WGS84toGCJ02(pointC[0], pointC[1]);
pointD = Coordtransform.WGS84toGCJ02(pointD[0], pointD[1]);
System.out.println(String.format("%s: [%s,%s],[%s,%s],[%s,%s],[%s,%s],[%s,%s]", vid, startPoint[0], startPoint[1], pointA[0], pointA[1], pointB[0], pointB[1], pointC[0], pointC[1], pointD[0], pointD[1]));
*/
//根据车头前方的矩形安全区域的四个顶点墨卡托坐标 查找所占用的网格
return this.mercatorNet.getChildGrids(new MercatorPoint(mercatorA[0], mercatorA[1]),
new MercatorPoint(mercatorB[0], mercatorB[1]),
new MercatorPoint(mercatorC[0], mercatorC[1]),
new MercatorPoint(mercatorD[0], mercatorD[1]));
}
private double[] adapterAreaSize(double[] startPoint,double direction) {
//判断直行的角度范围
boolean isStraight = (direction > 276 && direction < 285) || (direction > 367 && direction <376 ) || (direction > 96 && direction < 105) || (direction > 187 && direction < 196);
if(FieldUtil.isCrossArea(new Point(startPoint[0],startPoint[1]))){
return new double[]{2,5};
}else if(!isStraight&& FieldUtil.isSpecialArea(new Point(startPoint[0],startPoint[1]))){
return new double[]{7,32};
}else if(!isStraight){
return new double[]{7,22};
}
return new double[]{2,16};
}
private MercatorPoint getPoint(double longitude, double latitude){
double[] mercator = Coordtransform.WGS84toMercator(longitude, latitude);
return new MercatorPoint(mercator[0], mercator[1]);
}
public void clearOutVersionVehicle(Integer versionNo){
assert versionNo>-1:"版本号不能小于0";
List<String> outVersionList = new ArrayList<>();
this.vehicleMap.forEach((k,v) -> {
if(v.getVersionNo()<versionNo-240){
outVersionList.add(k);
}
});
for (String vin:outVersionList){
MercatorVehicle remove = vehicleMap.remove(vin);
remove.freeAll();
}
}
@Subscribe
public void listener(GridFreeEvent event){
String vid = event.getGrid().getCurrentUser();
MercatorVehicle vehicle = this.vehicleMap.get(vid);
if(vehicle != null){
vehicle.freeWaitGrid(event.getVid(), event.getGrid());
}else{
event.getGrid().freeToNext(vid);
}
}
}
package com.ssi.utils.telaidian;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
* AES工具
*/
public class AESOperator {
private static final String DEFAULT_CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
/**
* @param src
* @param AESSecret
* @param AESSecretIv
* @return
* @throws Exception
*/
public static String encrypt(String src, String AESSecret, String AESSecretIv) throws Exception {
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
SecretKeySpec secretKeySpec = new SecretKeySpec(AESSecret.getBytes(), "AES");
IvParameterSpec iv = new IvParameterSpec(AESSecretIv.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, iv);
byte[] encrypted = cipher.doFinal(src.getBytes("utf-8"));
return new BASE64Encoder().encode(encrypted).replaceAll("\r|\n", "");
}
/**
* 解密
*
* @param src
* @return
* @throws Exception
*/
public static String decrypt(String src, String AESSecret, String AESSecretIV) throws Exception {
SecretKeySpec secretKeySpec = new SecretKeySpec(AESSecret.getBytes("ASCII"), "AES");
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
IvParameterSpec iv = new IvParameterSpec(AESSecretIV.getBytes());
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, iv);
return new String(cipher.doFinal(new BASE64Decoder().decodeBuffer(src)), "utf-8");
}
}
package com.ssi.utils.telaidian;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ConnectorStatusInfo {
/**
* 0:离网
* 1:空闲
* 2:占用(未充电)
* 3:占用(充电中)
* 4:占用(预约锁定)
* 255:故障
*/
public final static int STATUS_0 = 0;
public final static int STATUS_1 = 1;
public final static int STATUS_2 = 2;
public final static int STATUS_3 = 3;
public final static int STATUS_4 = 4;
public final static int STATUS_255 = 255;
/**
* 0:未知
* 10:空闲
* 50:占用
*/
public final static int PARKSTATUS_0 = 0;
public final static int PARKSTATUS_10 = 10;
public final static int PARKSTATUS_50 = 50;
/**
* 0:未知
* 10:已解锁
* 50:已上锁
*/
public final static int LOCKSTATUS_0 = 0;
public final static int LOCKSTATUS_10 = 10;
public final static int LOCKSTATUS_50 = 50;
private String ConnectorID;
private Integer Status;
private Integer ParkStatus;
private Integer LockStatus;
@JsonIgnore
public boolean isAway() {
return Status == STATUS_0;
}
@JsonIgnore
public boolean isFree() {
return Status == STATUS_1;
}
@JsonIgnore
public boolean isOccupation() {
return Status == STATUS_2;
}
@JsonIgnore
public boolean isCharging() {
return Status == STATUS_3;
}
@JsonIgnore
public boolean isReserveLocked() {
return Status == STATUS_4;
}
@JsonIgnore
public boolean isTrouble() {
return Status == STATUS_255;
}
@JsonIgnore
public boolean isUnconnectedStatus() {
return isAway() || isFree();
}
@JsonIgnore
public boolean isConnectedStatus() {
return !isUnconnectedStatus();
}
}
package com.ssi.utils.telaidian;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 充电设备状态刷新调度任务
*/
@Component
@ConditionalOnProperty(prefix = "app.context.charging-schedule", value = "enable", matchIfMissing = true)
public class DeviceStatusSchedule {
private Logger logger = LoggerFactory.getLogger(getClass());
public static final String LOG_PREFIX_TELAIDIAN = "[Telaidian]";
private static final String CHARGING_PILE_INFO_REDIS_PREFIX = "harbor:charging:pile:info:";
private boolean lock = false;
@Autowired
private Gson gson;
private JsonParser jsonParser = new JsonParser();
@Autowired
private TelaidianRequestTpl telaidianRequestTpl;
@Autowired
/**
* 调度任务
*/
// @Scheduled(cron = "${telaidian.status-refresh.cron}")
private void refreshDeviceStatus() {
if (lock) {
return;
}
try {
lock = true;
JSONObject statusMap = queryDeviceStatus();
if ("0".equalsIgnoreCase(statusMap.getString("Ret"))) {
List<ConnectorStatusInfo> connectorStatusInfoList = new ArrayList<>();
String data = statusMap.getString("Data");
JsonObject jsonObject = jsonParser.parse(data).getAsJsonObject();
JsonArray stationStatusArray = jsonObject.getAsJsonArray("StationStatusInfos");
if (stationStatusArray != null) {
for (JsonElement stationStatusEl : stationStatusArray) {
JsonArray connectorStatusArray = stationStatusEl.getAsJsonObject().getAsJsonArray("ConnectorStatusInfos");
if (connectorStatusArray != null) {
for (JsonElement connectorStatusEl : connectorStatusArray) {
ConnectorStatusInfo connectorStatusInfo = gson.fromJson(connectorStatusEl.getAsJsonObject(),
ConnectorStatusInfo.class);
connectorStatusInfoList.add(connectorStatusInfo);
}
}
}
}
updateChargingPileInfoInRedis(connectorStatusInfoList);
// logger.debug(LOG_PREFIX_TELAIDIAN + appContext.objToJsonStr(connectorStatusInfoList));
} else {
logger.warn(LOG_PREFIX_TELAIDIAN + gson.toJson(statusMap));
}
} catch (Exception e) {
logger.error(LOG_PREFIX_TELAIDIAN + "Fail to refresh device status from telaidian.", e);
} finally {
lock = false;
}
}
/**
* 更新状态
*
* @param connectorStatusInfoList
* @throws Exception
*/
private void updateChargingPileInfoInRedis(List<ConnectorStatusInfo> connectorStatusInfoList) throws Exception {
for (ConnectorStatusInfo connectorStatusInfo : connectorStatusInfoList) {
}
}
/**
* 查询状态
*
* @return
* @throws Exception
*/
private JSONObject queryDeviceStatus() throws Exception {
String methodName = "query_station_status";
Map<String, Object> paramMap = new HashMap<>();
List<String> stationIdList = new ArrayList<>();
stationIdList.add("3502050037");
paramMap.put("StationIDs", stationIdList);
return telaidianRequestTpl.queryData(paramMap, methodName, 3);
}
}
package com.ssi.utils.telaidian;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* HMacMD5工具
*/
public class HMacMD5 {
/**
* 计算参数的md5信息
*
* @param str 待处理的字节数组
* @return md5摘要信息
* @throws NoSuchAlgorithmException
*/
private static byte[] md5(byte[] str) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(str);
return md.digest();
}
/**
* 将待加密数据data,通过密钥key,使用hmac-md5算法进行加密,然后返回加密结果。 参照rfc2104 HMAC算法介绍实现。
*
* @param key 密钥
* @param data 待加密数据
* @return 加密结果
* @throws NoSuchAlgorithmException
*/
public static byte[] getHmacMd5Bytes(byte[] key, byte[] data)
throws NoSuchAlgorithmException {
/*
* HmacMd5 calculation formula: H(K XOR opad, H(K XOR ipad, text))
* HmacMd5 计算公式:H(K XOR opad, H(K XOR ipad, text))
* H代表hash算法,本类中使用MD5算法,K代表密钥,text代表要加密的数据 ipad为0x36,opad为0x5C。
*/
int length = 64;
byte[] ipad = new byte[length];
byte[] opad = new byte[length];
for (int i = 0; i < 64; i++) {
ipad[i] = 0x36;
opad[i] = 0x5C;
}
byte[] actualKey = key; // Actual key.
byte[] keyArr = new byte[length]; // Key bytes of 64 bytes length
/*
* If key's length is longer than 64,then use hash to digest it and use
* the result as actual key. 如果密钥长度,大于64字节,就使用哈希算法,计算其摘要,作为真正的密钥。
*/
if (key.length > length) {
actualKey = md5(key);
}
for (int i = 0; i < actualKey.length; i++) {
keyArr[i] = actualKey[i];
}
/*
* append zeros to K 如果密钥长度不足64字节,就使用0x00补齐到64字节。
*/
if (actualKey.length < length) {
for (int i = actualKey.length; i < keyArr.length; i++)
keyArr[i] = 0x00;
}
/*
* calc K XOR ipad 使用密钥和ipad进行异或运算。
*/
byte[] kIpadXorResult = new byte[length];
for (int i = 0; i < length; i++) {
kIpadXorResult[i] = (byte) (keyArr[i] ^ ipad[i]);
}
/*
* append "text" to the end of "K XOR ipad" 将待加密数据追加到K XOR ipad计算结果后面。
*/
byte[] firstAppendResult = new byte[kIpadXorResult.length + data.length];
for (int i = 0; i < kIpadXorResult.length; i++) {
firstAppendResult[i] = kIpadXorResult[i];
}
for (int i = 0; i < data.length; i++) {
firstAppendResult[i + keyArr.length] = data[i];
}
/*
* calc H(K XOR ipad, text) 使用哈希算法计算上面结果的摘要。
*/
byte[] firstHashResult = md5(firstAppendResult);
/*
* calc K XOR opad 使用密钥和opad进行异或运算。
*/
byte[] kOpadXorResult = new byte[length];
for (int i = 0; i < length; i++) {
kOpadXorResult[i] = (byte) (keyArr[i] ^ opad[i]);
}
/*
* append "H(K XOR ipad, text)" to the end of "K XOR opad" 将H(K XOR
* ipad, text)结果追加到K XOR opad结果后面
*/
byte[] secondAppendResult = new byte[kOpadXorResult.length
+ firstHashResult.length];
for (int i = 0; i < kOpadXorResult.length; i++) {
secondAppendResult[i] = kOpadXorResult[i];
}
for (int i = 0; i < firstHashResult.length; i++) {
secondAppendResult[i + keyArr.length] = firstHashResult[i];
}
/*
* H(K XOR opad, H(K XOR ipad, text)) 对上面的数据进行哈希运算。
*/
byte[] hmacMd5Bytes = md5(secondAppendResult);
return hmacMd5Bytes;
}
public static String getHmacMd5Str(String key, String data) {
String result = "";
try {
byte[] keyByte = key.getBytes("UTF-8");
byte[] dataByte = data.getBytes("UTF-8");
byte[] hmacMd5Byte = getHmacMd5Bytes(keyByte, dataByte);
StringBuffer md5StrBuff = new StringBuffer();
for (int i = 0; i < hmacMd5Byte.length; i++) {
if (Integer.toHexString(0xFF & hmacMd5Byte[i]).length() == 1)
md5StrBuff.append("0").append(
Integer.toHexString(0xFF & hmacMd5Byte[i]));
else
md5StrBuff.append(Integer
.toHexString(0xFF & hmacMd5Byte[i]));
}
result = md5StrBuff.toString().toUpperCase();
} catch (Exception e) {
// logger.error("error getHmacMd5Str()",e);
e.printStackTrace();
}
return result;
}
}
\ No newline at end of file
package com.ssi.utils.telaidian;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 特来电请求工具模板
*/
@Component
public class TelaidianRequestTpl {
protected Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private RestTemplate restTemplate;
private int tokenCount = 0;
@Autowired
private Gson gson;
private JsonParser parser = new JsonParser();
@Value("${telaidian.operator-id-telaidian}")
private String operatorIdOfTelaidian;
@Value("${telaidian.operator-id-xmg}")
private String operatorIdOfXmg;
@Value("${telaidian.assign-key}")
private String assignKey;
@Value("${telaidian.operator-secret}")
private String operatorSecret;
@Value("${telaidian.AES-key}")
private String AESSecretOfXmg;
@Value("${telaidian.AES-vector}")
private String AESSecretIVOfXmg;
@Value("${telaidian.AES-key}")
private String AESSecretOfTelaidian;
@Value("${telaidian.AES-vector}")
private String AESSecretIVOfTelaidian;
@Value("${telaidian.base-url}")
private String baseUrl;
/**
* 获取token
*
* @param url
* @return
* @throws Exception
*/
public String getToken(String url) throws Exception {
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("OperatorID", operatorIdOfXmg);
paramMap.put("OperatorSecret", operatorSecret);
Map<String, Object> returnBody = sendRest(gson.toJson(paramMap), null, url);
if (!("0").equals(String.valueOf(returnBody.get("Ret")))) {
logger.warn(DeviceStatusSchedule.LOG_PREFIX_TELAIDIAN + gson.toJson(returnBody));
throw new Exception("Fail to get token from telaidian.");
}
String data = AESOperator.decrypt(returnBody.get("Data").toString(), AESSecretOfXmg, AESSecretIVOfXmg);
JsonObject jsonObject = parser.parse(data).getAsJsonObject();
if (jsonObject.get("SuccStat") != null && jsonObject.get("SuccStat").getAsDouble() != 0.0) {
logger.warn(DeviceStatusSchedule.LOG_PREFIX_TELAIDIAN + jsonObject.toString());
throw new Exception("Fail to get token from telaidian.");
}
return jsonObject.get("AccessToken").getAsString();
}
/**
* 执行发送请求
*
* @param params
* @param token
* @param url
* @return
* @throws Exception
*/
public Map<String, Object> sendRest(String params, String token, String url) throws Exception {
String Data = AESOperator.encrypt(params, AESSecretOfXmg, AESSecretIVOfXmg);
String TimeStamp = DateFormatUtils.format(new Date(), "yyyyMMddHHmmss");
String Seq = "0001";
HttpHeaders headers = new HttpHeaders();
MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
headers.setContentType(type);
headers.add("Accept", MediaType.APPLICATION_JSON.toString());
headers.add("Authorization", token == null ? "Bearer Token" : "Bearer " + token);
JsonObject jsonObj = new JsonObject();
jsonObj.addProperty("OperatorID", operatorIdOfXmg);
jsonObj.addProperty("Data", Data);
jsonObj.addProperty("TimeStamp", TimeStamp);
jsonObj.addProperty("Seq", Seq);
jsonObj.addProperty("Sig", getSig(Data, TimeStamp, Seq));
logger.debug(DeviceStatusSchedule.LOG_PREFIX_TELAIDIAN + "接口[" + url + "]下发报文:" + jsonObj.toString() +
",下发的token为:" + token);
HttpEntity<String> requestEntity = new HttpEntity<>(jsonObj.toString(), headers);
Object obj = null;
try {
obj = restTemplate.postForObject(url, requestEntity, Object.class);
} catch (RestClientException e) {
logger.error(DeviceStatusSchedule.LOG_PREFIX_TELAIDIAN + "访问错误:" + e.getMessage());
}
if (obj instanceof String) {
Map<String, Object> map = new HashMap<>();
map = gson.fromJson(obj.toString(), map.getClass());
if (map.get("Ret").toString().equals("0.0")) {
map.put("Ret", "0");
}
return map;
} else {
Map<String, Object> object = restTemplate.postForObject(url, requestEntity, LinkedHashMap.class);
return object;
}
}
/**
* 获取请求签名
*
* @param Data
* @param TimeStamp
* @param Seq
* @return
*/
private String getSig(String Data, String TimeStamp, String Seq) {
StringBuilder builder = new StringBuilder();
builder.append(operatorIdOfXmg).append(Data).append(TimeStamp).append(Seq);
return HMacMD5.getHmacMd5Str(assignKey, builder.toString());
}
/**
* 查询数据
*
* @param params
* @param methodName
* @param retryNums
* @return
* @throws Exception
*/
public JSONObject queryData(String params, String methodName, int retryNums) throws Exception {
JSONObject result = new JSONObject();
if (retryNums <= 0) {
logger.error(DeviceStatusSchedule.LOG_PREFIX_TELAIDIAN + "token连续3次认证失败.");
throw new Exception("token连续3次认证失败.");
}
String token = getToken(baseUrl + "query_token");
Map<String, Object> qryResult = sendRest(params, token, baseUrl + methodName);
/* retry */
String retStr = qryResult.get("Ret").toString();
if ("4002".equals(retStr)) {
return queryData(params, methodName, retryNums - 1);
}
if (!"0".equals(retStr)) {
result.put("Ret", retStr);
result.put("Msg", qryResult.get("Msg").toString());
return result;
}
String data = AESOperator.decrypt(qryResult.get("Data").toString(), AESSecretOfXmg, AESSecretIVOfXmg);
result.put("Ret", "0");
result.put("Data", data);
return result;
}
public JSONObject queryData(Map<String, Object> paramMap, String methodName,
int retryNums) throws Exception {
return queryData(gson.toJson(paramMap), methodName, retryNums);
}
}
package com.ssi.websocket;
import com.alibaba.fastjson.JSON;
import com.ssi.entity.FaultRecord;
import org.apache.commons.collections4.map.PassiveExpiringMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Date;
import java.util.concurrent.CopyOnWriteArraySet;
/**
*
* 异常推送websocket
*/
@ServerEndpoint("/abnormalWebSocket")
@Component
public class AbnormalWebSocketServer {
private final static Logger log = LoggerFactory.getLogger(AbnormalWebSocketServer.class);
//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int onlineCount = 0;
//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
private static CopyOnWriteArraySet<AbnormalWebSocketServer> webSocketSet = new CopyOnWriteArraySet<AbnormalWebSocketServer>();
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
//忽略消息存储map
private PassiveExpiringMap<String,Date> ignoreMap = new PassiveExpiringMap<>(180*1000);
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session) {
this.session = session;
webSocketSet.add(this); //加入set中
addOnlineCount(); //在线数加1
log.info("有新窗口开始监听:" + session.getId() + ",当前在线人数为" + getOnlineCount());
try {
sendMessage("连接成功");
} catch (IOException e) {
log.error("websocket IO异常");
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
webSocketSet.remove(this); //从set中删除
subOnlineCount(); //在线数减1
log.info("有一连接关闭!当前在线人数为" + getOnlineCount());
}
/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息
*/
@OnMessage
public void onMessage(String message, Session session) {
log.info("收到来自窗口" + session.getId() + "的信息:" + message);
FaultRecord faultRecord = JSON.parseObject(message, FaultRecord.class);
addIgnoreMessage(faultRecord);
}
public void addIgnoreMessage(FaultRecord faultRecord){
String vin = faultRecord.getVin();
String fmi = faultRecord.getFmi();
String spn = faultRecord.getSpn();
String key = vin + ":" + fmi + ":" + spn;
ignoreMap.put(key,new Date());
}
public boolean ignoreMessage(FaultRecord faultRecord){
String vin = faultRecord.getVin();
String fmi = faultRecord.getFmi();
String spn = faultRecord.getSpn();
String key = vin + ":" + fmi + ":" + spn;
if(!ignoreMap.isEmpty()){
Date date = ignoreMap.get(key);
if(date != null){
ignoreMap.put(key,date);
return true;
}
}
return false;
}
/**
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
log.error("发生错误",error);
}
/**
* 实现服务器主动推送
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
AbnormalWebSocketServer.onlineCount++;
}
public static synchronized void subOnlineCount() {
AbnormalWebSocketServer.onlineCount--;
}
public static void sendInfo(String message) {
log.info("异常推送websocket收到信息:" + message);
//群发消息
for (AbnormalWebSocketServer item : webSocketSet) {
try {
item.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void sendFaultRecord(FaultRecord faultRecord) {
//群发消息
for (AbnormalWebSocketServer item : webSocketSet) {
try {
if(!item.ignoreMessage(faultRecord)){
item.sendMessage(JSON.toJSONString(faultRecord));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
package com.ssi.websocket;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ssi.entity.VmsCranePadBind;
import com.ssi.service.VmsCranePadBindService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* 吊具APP任务推送websocket
* @author zhangly
* @since 2020-02-10
* 相当于ws协议的Controller
*/
@ServerEndpoint("/craneAppWebSocketServer/{padMac}")
@Component
public class CraneAppWebSocketServer {
private final static Logger log = LoggerFactory.getLogger(CraneAppWebSocketServer.class);
@Autowired
private VmsCranePadBindService vmsCranePadBindService;
//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int onlineCount = 0;
//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
private static CopyOnWriteArraySet<CraneAppWebSocketServer> webSocketSet = new CopyOnWriteArraySet<CraneAppWebSocketServer>();
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
//接收sid
private String sid = "";
private String padMac = "";
private String craneNo = "";
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("sid") String sid, @PathParam("padMac") String padMac) {
this.session = session;
webSocketSet.add(this); //加入set中
addOnlineCount(); //在线数加1
log.info("有新窗口开始监听:" + sid + ",当前在线人数为" + getOnlineCount());
this.sid = sid;
this.padMac = padMac;
try {
sendMessage("连接成功");
} catch (IOException e) {
log.error("websocket IO异常");
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
webSocketSet.remove(this); //从set中删除
subOnlineCount(); //在线数减1
log.info("有一连接关闭!当前在线人数为" + getOnlineCount());
}
/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息
*/
@OnMessage
public void onMessage(String message, Session session) {
JSONObject messageJson = JSONObject.parseObject(message);
String padMac = messageJson.getString("padMac");
//群发消息
for (CraneAppWebSocketServer item : webSocketSet) {
try {
if(item.session.getId().equals(session.getId())){
VmsCranePadBind crane = vmsCranePadBindService.getOne(new LambdaQueryWrapper<VmsCranePadBind>()
.eq(VmsCranePadBind::getPadMac, padMac));
this.craneNo = crane.getCraneNo();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
log.error("发生错误");
error.printStackTrace();
}
/**
* 实现服务器主动推送
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static CopyOnWriteArraySet<CraneAppWebSocketServer> getWebSocketSet(){
return webSocketSet;
}
public String getCraneNo(){
return this.craneNo;
}
public String getPadMac(){
return this.padMac;
}
public static synchronized void addOnlineCount() {
CraneAppWebSocketServer.onlineCount++;
}
public static synchronized void subOnlineCount() {
CraneAppWebSocketServer.onlineCount--;
}
public void sendInfo() {
log.info("桥吊APP推送任务信息:");
}
}
package com.ssi.websocket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* 吊具实时信息websocket
*/
@ServerEndpoint("/craneWebSocket")
@Component
public class CraneInfoWebSocketServer {
private final static Logger log = LoggerFactory.getLogger(CraneInfoWebSocketServer.class);
//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int onlineCount = 0;
//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
private static CopyOnWriteArraySet<CraneInfoWebSocketServer> webSocketSet = new CopyOnWriteArraySet<CraneInfoWebSocketServer>();
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
private String craneNo;
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session) {
this.session = session;
webSocketSet.add(this); //加入set中
addOnlineCount(); //在线数加1
log.info("CraneWebSocketServer有新窗口开始监听:" + session.getId() + ",当前在线人数为" + getOnlineCount());
try {
sendMessage("连接成功");
} catch (IOException e) {
log.error("CraneWebSocketServer websocket IO异常");
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
webSocketSet.remove(this); //从set中删除
subOnlineCount(); //在线数减1
log.info("CraneWebSocketServer有一连接关闭!当前在线人数为" + getOnlineCount());
}
/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息
*/
@OnMessage
public void onMessage(String message, Session session) {
log.info("CraneWebSocketServer收到来自窗口" + session.getId() + "的信息:" + message);
this.craneNo = message;
}
/**
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
log.error("CraneInfoWebSocketServer发生错误", error);
}
/**
* 实现服务器主动推送
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
CraneInfoWebSocketServer.onlineCount++;
}
public static synchronized void subOnlineCount() {
CraneInfoWebSocketServer.onlineCount--;
}
public static CopyOnWriteArraySet<CraneInfoWebSocketServer> getWebSocketSet() {
return webSocketSet;
}
public String getCraneNo() {
return craneNo;
}
}
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