|
@@ -0,0 +1,731 @@
|
|
|
+package com.tokheim.client.manager.factory;
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.alibaba.fastjson.JSONArray;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.tokheim.client.itouch.ClientFactory;
|
|
|
+import com.tokheim.client.utils.*;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+
|
|
|
+import java.io.InputStream;
|
|
|
+import java.io.OutputStream;
|
|
|
+import java.net.InetSocketAddress;
|
|
|
+import java.net.Socket;
|
|
|
+import java.util.*;
|
|
|
+import java.util.concurrent.ExecutorService;
|
|
|
+import java.util.concurrent.Executors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @author xgm
|
|
|
+ * @version 1.0
|
|
|
+ * @date: Created in 8:51 2021/10/12
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+public class SocketFactory {
|
|
|
+
|
|
|
+ private static ExecutorService executorHearService = null;
|
|
|
+
|
|
|
+ private static String HOST;//服务器地址 10
|
|
|
+ private static int PORT;//服务器端口号
|
|
|
+ private static String URL;
|
|
|
+ public static String FILEPATH;
|
|
|
+
|
|
|
+ //多媒体socket ip与port
|
|
|
+ private static String ITOUCHHOST;
|
|
|
+ private static String ITOUCHPORT;
|
|
|
+ private static Map<String, String> nozzleInfoMap = new HashMap<>();
|
|
|
+ private static Map<String, String> configureMap = new HashMap<>();
|
|
|
+
|
|
|
+
|
|
|
+ private static Socket socket = null;
|
|
|
+ public static OutputStream out = null;
|
|
|
+ public static InputStream in = null;
|
|
|
+ private static boolean flag = true;
|
|
|
+ private static String prevPump = "";
|
|
|
+
|
|
|
+ private static String HEARTED = "";
|
|
|
+
|
|
|
+
|
|
|
+ private static String ENV;
|
|
|
+ private static String stationIp = "";
|
|
|
+
|
|
|
+
|
|
|
+ //private static List<String> stationIps = new ArrayList<>();
|
|
|
+ private static Map<String, ClientFactory> clientFactoryMap = new HashMap<>();
|
|
|
+
|
|
|
+ private static String msg_sub2 = "";
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ static {
|
|
|
+ executorHearService = Executors.newFixedThreadPool(5);
|
|
|
+ //getStationIps();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 主函数入口
|
|
|
+ *
|
|
|
+ * @param host 中间件设备socket的Ip地址
|
|
|
+ * @param port 中间件设备socket的端口号
|
|
|
+ * @param url 第三方后台地址
|
|
|
+ * @param filePath 配置文件存储路径
|
|
|
+ * @param env 开发环境变量
|
|
|
+ * @param iTouchHost 多媒体 app socket ip地址
|
|
|
+ * @param iTouchPort 多媒体app 的socket端口号
|
|
|
+ */
|
|
|
+ public synchronized static void sendHeartMsg(String host, Integer port, String url, String filePath, String env, String iTouchHost, String iTouchPort) {
|
|
|
+ /*new Thread(new Runnable() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+
|
|
|
+ }
|
|
|
+ }).start();*/
|
|
|
+ byte buf[] = new byte[1024];
|
|
|
+ try {
|
|
|
+ HOST = host;
|
|
|
+ PORT = port;
|
|
|
+ URL = url;
|
|
|
+ FILEPATH = filePath;
|
|
|
+ ENV = env;
|
|
|
+ ITOUCHHOST = iTouchHost;
|
|
|
+ ITOUCHPORT = iTouchPort;
|
|
|
+ if (socket == null) socket = new Socket(HOST, PORT);
|
|
|
+ if (socket.isClosed()) {
|
|
|
+ socket = null;
|
|
|
+ socket = new Socket();
|
|
|
+ socket.connect(new InetSocketAddress(host, Integer.valueOf(port)), 2000);//超时时间为2秒
|
|
|
+ }
|
|
|
+
|
|
|
+ boolean connected = socket.isConnected();
|
|
|
+ if (connected) {
|
|
|
+ flag = true;
|
|
|
+ out = socket.getOutputStream();
|
|
|
+ in = socket.getInputStream();
|
|
|
+
|
|
|
+ //TODO 该发送数据主要是解决在客户端与服务端正常数据交互的情况下,服务端突然断开的情况
|
|
|
+ if (flag) sendMsg();
|
|
|
+ //启动一个方法检测心跳
|
|
|
+
|
|
|
+
|
|
|
+ while (true) {
|
|
|
+ if (in.available() > 0) {
|
|
|
+ int len = in.read(buf);
|
|
|
+ byte[] real = new byte[len];
|
|
|
+ //解析数据
|
|
|
+ for (int i = 0; i < real.length; i++) {
|
|
|
+ real[i] = buf[i];
|
|
|
+ }
|
|
|
+ //心跳包处理格式
|
|
|
+ //长度 0x11 ip:port
|
|
|
+ String[] strings = ByteUtils.bytesToHexStrings(real);
|
|
|
+ //log.info("接收油机数据--" + Arrays.toString(strings));
|
|
|
+ String msg = Arrays.toString(strings).replaceAll(",", "");
|
|
|
+ //msg 需要去掉 []
|
|
|
+ msg = msg.substring(1, msg.length() - 1);
|
|
|
+
|
|
|
+
|
|
|
+ //协议心跳业务固定包头
|
|
|
+ String heartHeaderPackage = "02 01 01 00 02 60 00 0B 01";
|
|
|
+ String realTimePackage = "02 01 01 00 00 60 00 16 01";
|
|
|
+ String oilHeaderPackage = "02 01 01 00 00 60 00 31 04";
|
|
|
+ //String speechHeaderPackage = "02 01 01 00 00 60 00 08 01";
|
|
|
+
|
|
|
+ //TODO 改进获取 stationIp方法,该情况是黑盒子不往ITouch发送数据,所以注释掉,如果黑盒子往ITouch发送数据则不可注释掉
|
|
|
+ //String[] data = msg.split(" ");
|
|
|
+ //String length_hex = data[0];
|
|
|
+ //int length_ = ByteUtils.hexToDecimal(length_hex);
|
|
|
+ //String[] ipAndPort_ = Arrays.copyOfRange(data, 1, length_ +1);
|
|
|
+ //String s = Arrays.toString(ipAndPort_);
|
|
|
+ //String ipAndPortStr_ = s.substring(1,s.length() - 1).replaceAll(",","");
|
|
|
+ //byte[] bytes_ = ByteUtils.hexToByteArray(ipAndPortStr_);
|
|
|
+ //String value = new String(bytes_);
|
|
|
+ //stationIp = value.substring(0,value.indexOf(":"));
|
|
|
+
|
|
|
+
|
|
|
+ /* //TODO 处理粘包
|
|
|
+ if (msg.contains(heartHeaderPackage)) {
|
|
|
+ String msg_sub = msg.substring(0, msg.indexOf(heartHeaderPackage)); //将粘包数据根据心跳头截取数据
|
|
|
+ String[] msg_arr = msg_sub.split(" "); //主要是想获取数据长度
|
|
|
+ int length = Integer.valueOf(ByteUtils.hexToDecimal(msg_arr[0]));
|
|
|
+ byte[] bytes = ByteUtils.hexToByteArray(msg_sub); //将16进制的字符创转成字节数组
|
|
|
+ byte[] ipAndPort = PackageUtils.getIpAndPort(bytes, length);
|
|
|
+ String ipPort = new String(ipAndPort);//将字节转成字符串
|
|
|
+ stationIp = ipPort.substring(0, ipPort.indexOf(":")); //获取油机ip地址
|
|
|
+ //log.info("油机心跳信息--" + msg);
|
|
|
+ //log.info("油机Ip--" + stationIp);
|
|
|
+ }*/
|
|
|
+
|
|
|
+ System.out.println(stationIp + "--接收油机数据(16进制)--" + msg);
|
|
|
+ //log.info(stationIp + "--接收油机数据(16进制)--" + msg);
|
|
|
+
|
|
|
+ //去掉ip地址与端口-->获取业务头--心跳头 02 01 01 00 02 60 00 0B 01
|
|
|
+ //byte[] newReal = Arrays.copyOfRange(real, length + 1, real.length);
|
|
|
+ //心跳业务包头固定长度为 9
|
|
|
+ //byte[] serverHeader = PackageUtils.getServerHeader(newReal, 9);
|
|
|
+ //String[] serverHeaderString = ByteUtils.bytesToHexStrings(serverHeader);
|
|
|
+
|
|
|
+
|
|
|
+ try {
|
|
|
+ //TODO:将油机原始数据原封不动发送到多媒体中间件
|
|
|
+ /*Map<String,Object> map = new HashMap<>();
|
|
|
+ map.put("msg",msg);
|
|
|
+ JSONObject object = new JSONObject(map);
|
|
|
+ HttpUtils httpUtils = new HttpUtils(false);
|
|
|
+ httpUtils.sendPost3("http://localhost:6682/receive/getData",object);*/
|
|
|
+ //CacheData cacheData = new CacheData();
|
|
|
+ //cacheData.setData(stationIp, ITOUCHPORT, msg);
|
|
|
+
|
|
|
+ //ClientFactory clientFactory = new ClientFactory();
|
|
|
+ //clientFactory.setData(stationIp, ITOUCHPORT, msg);
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error(e.getMessage());
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+
|
|
|
+ //心跳头
|
|
|
+ if (msg.contains(heartHeaderPackage)) {
|
|
|
+ //组装心跳包发送回到服务端
|
|
|
+ //去掉 ip:port 心跳业务包头
|
|
|
+ HEARTED = msg;
|
|
|
+ out.write(real);
|
|
|
+ out.flush();
|
|
|
+ }
|
|
|
+ if (msg.contains(realTimePackage)) {
|
|
|
+ ////System.out.println("加油实时数据: " + Arrays.toString(ByteUtils.bytesToHexStrings(serverHeader)));
|
|
|
+ ////System.out.println("加油实时数据:" + msg);
|
|
|
+ }
|
|
|
+ //加油记录包头,因为加油交易记录会粘包,所以需要转成string使用包含的方法获取交易记录信息
|
|
|
+ if (msg.contains(oilHeaderPackage)) {
|
|
|
+ //System.err.println("原始加油数据--" + msg);
|
|
|
+ //log.info("原始加油数据--" + msg);
|
|
|
+ Map<String, String> fuelMsg = getFuelMsg(msg, oilHeaderPackage);
|
|
|
+ String id = ID.get().next().toString();
|
|
|
+ //String filePath = System.getProperty("user.dir") + "\\configure.json"; //获取文件路径
|
|
|
+
|
|
|
+ //获取配置文件信息
|
|
|
+ //Map<String, String> configureMap = null;
|
|
|
+ /*if (nozzleInfoMap.size() <= 0){
|
|
|
+ configureMap = getConfigure(stationIp, fuelMsg);
|
|
|
+ }else {
|
|
|
+ configureMap.putAll(nozzleInfoMap);
|
|
|
+ }*/
|
|
|
+
|
|
|
+ msg_sub2 = msg.substring(0,msg.lastIndexOf(oilHeaderPackage)); //将粘包数据根据心跳头截取数据
|
|
|
+ String[] msg_arr2 = msg_sub2.split(" "); //主要是想获取数据长度
|
|
|
+ int length2 = Integer.valueOf(ByteUtils.hexToDecimal(msg_arr2[0]));
|
|
|
+ byte[] bytes2 = ByteUtils.hexToByteArray(msg_sub2); //将16进制的字符创转成字节数组
|
|
|
+ byte[] ipAndPort2 = PackageUtils.getIpAndPort(bytes2, length2);
|
|
|
+ String ipPort2 = new String(ipAndPort2);//将字节转成字符串
|
|
|
+ stationIp = ipPort2.substring(0, ipPort2.indexOf(":")); //获取油机ip地址
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ configureMap = getConfigure(stationIp, fuelMsg);
|
|
|
+
|
|
|
+
|
|
|
+ String businessTime = fuelMsg.get("date").trim() + " " + fuelMsg.get("time");//交易时间
|
|
|
+ String refuelTime = fuelMsg.get("date").trim() + " " + fuelMsg.get("time"); //加油时间
|
|
|
+ double quantity = Double.valueOf(fuelMsg.get("rise"));
|
|
|
+ double amount = Double.valueOf(fuelMsg.get("amount"));
|
|
|
+ double oilsPrice = Double.valueOf(fuelMsg.get("price"));
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ //发送加油数据到第三方云平台
|
|
|
+ String oilMsg = "{\"id\": \"" + id + "\"," + //id不能超过40个字节
|
|
|
+ "\"stationId\": \"" + configureMap.get("stationId") + "\"," + //油站Id
|
|
|
+ "\"stationName\": \"" + configureMap.get("stationName") + "\"," + // 油站名称
|
|
|
+ "\"sysDept\": \"" + configureMap.get("sysDept") + "\"," + //部门Id
|
|
|
+ "\"businessTime\": \"" + businessTime + "\"," + //交易时间
|
|
|
+ "\"memberId\": \"\"," + //会员Id
|
|
|
+ "\"memberNo\": \"\"," + //会员编号
|
|
|
+ "\"memberName\": \"\"," + // 持卡人
|
|
|
+ "\"cardNo\": \"\"," + //卡号
|
|
|
+ "\"gunNo\": \"" + configureMap.get("gunNo") + "\"," + // 枪号
|
|
|
+ "\"oils\": \"" + configureMap.get("oils") + "\"," + //油品名称--汽油、柴油
|
|
|
+ "\"oilGrade\": \"" + configureMap.get("oilGrade") + "\"," + //油品等级 92# 93# 98#
|
|
|
+ "\"quantity\": " + quantity + "," + //加油量
|
|
|
+ "\"amount\": " + amount + "," + // 金额
|
|
|
+ "\"payAmount\": 0.0," + //支付金额 1--公众号、2--微信、3--支付宝、4--银联、5--现金、6--加油卡
|
|
|
+ "\"payShop\": \"" + configureMap.get("payShop") + "\"," + // 支付方式 1--公众号、2--微信、3--支付宝、4--银联,5--现金,6--加油卡
|
|
|
+ "\"payState\": \"" + "0" + "\"," + // 支付状态 0--待支付 1--已支付
|
|
|
+ "\"payType\": \"" + configureMap.get("payType") + "\"," + // 支付方式 0--验泵卡、1--员工卡、2--维修卡、4--用户卡
|
|
|
+ "\"refuelTime\": \"" + refuelTime + "\"," + //加油时间
|
|
|
+ "\"dealType\": \"\"," + // 处理类型
|
|
|
+ "\"refuelNum\": 0.0," + //
|
|
|
+ "\"oilsPrice\": " + oilsPrice + "," + // 单价
|
|
|
+ "\"ttc\": \"\"," + //
|
|
|
+ "\"ctc\": \"\"}"; //
|
|
|
+ if (!prevPump.equals(fuelMsg.get("pump"))) {
|
|
|
+ String oilMsgBase64 = Base64.getEncoder().encodeToString(oilMsg.getBytes());
|
|
|
+ //System.err.println("加密后数据:" + oilMsgBase64);
|
|
|
+ byte[] decode = Base64.getDecoder().decode(oilMsgBase64);
|
|
|
+ //System.err.println("解密后数据:" + new String(decode));
|
|
|
+ String sendOilMsg = "{ \"param\": \"" + oilMsgBase64 + "\"}";
|
|
|
+ JSONObject jsonObject = JSON.parseObject(sendOilMsg);
|
|
|
+ System.err.println("云平台数据:" + jsonObject.toString());
|
|
|
+ log.info("ip地址:" + stationIp + "--" + "加油数据:" + JSONObject.toJSONString(fuelMsg));
|
|
|
+ //log.error("加油数据:" + JSONObject.toJSONString(fuelMsg));
|
|
|
+ //log.info("云平台数据:" + jsonObject.toString());
|
|
|
+ //log.error("云平台数据:" + jsonObject.toString());
|
|
|
+ System.out.println("云平台数据(解密):" + new String(decode));
|
|
|
+ log.info("云平台数据(解密):" + new String(decode));
|
|
|
+ String success = "";
|
|
|
+ if (ENV.equals("prod")) { //dev prod
|
|
|
+ String response = HttpUtils.sendPost3(url, jsonObject);
|
|
|
+ System.out.println("响应数据:" + response);
|
|
|
+ log.info("响应数据:" + response);
|
|
|
+ JSONObject js = JSONObject.parseObject(response);
|
|
|
+ success = String.valueOf(js.get("success"));
|
|
|
+ } else {
|
|
|
+ success = "true";
|
|
|
+ }
|
|
|
+ if (Boolean.valueOf(success)) { //云平台响应成功
|
|
|
+ //记录上传泵码
|
|
|
+ prevPump = fuelMsg.get("pump");
|
|
|
+ //应答
|
|
|
+ String reHeader = "02 01 01 00 00 61 00 06 04 " + fuelMsg.get("gunNo") + " 21 " + fuelMsg.get("serialNum") + " 00"; //02 01 01 00 00 61 00 06 04 21 21 00 05 00 //16进制 固定包头 0201010000610006042121000500
|
|
|
+ byte[] bytes = ByteUtils.hexToByteArray(reHeader);
|
|
|
+ out.write(bytes);
|
|
|
+ out.flush();
|
|
|
+ } else { //上传云平台响应失败
|
|
|
+ //记录上传泵码
|
|
|
+ prevPump = fuelMsg.get("pump");
|
|
|
+ //应答
|
|
|
+ String reHeader = "02 01 01 00 00 61 00 06 04 " + fuelMsg.get("gunNo") + " 21 " + fuelMsg.get("serialNum") + " 01"; //02 01 01 00 00 61 00 06 04 21 21 00 05 00 //16进制 固定包头 0201010000610006042121000500
|
|
|
+ byte[] bytes = ByteUtils.hexToByteArray(reHeader);
|
|
|
+ out.write(bytes);
|
|
|
+ out.flush();
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ //log.error("配置文件出错,没有匹配上的ip或者油机泵码不变");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ //System.out.println("服务端已主动断开....");
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error(e.getMessage() + "--" + msg_sub2);
|
|
|
+ log.error(e.getLocalizedMessage());
|
|
|
+ log.error(e.getStackTrace().toString());
|
|
|
+ e.printStackTrace();
|
|
|
+ } finally {
|
|
|
+ restartSocket();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 向油机发送心跳
|
|
|
+ *
|
|
|
+ * 该方法用于处理情景: 在连接正常地数据传输过程中,服务端突然断掉,
|
|
|
+ * 由于客户端没有报异常,所以无法知道 服务端已断掉,故通过不断向服务端发送 0 字节以此确认服务端是否连接
|
|
|
+ * TODO--后面可以通过主动向客户端发送心跳来解决
|
|
|
+ */
|
|
|
+ public static void sendMsg() {
|
|
|
+ /* new Thread(new Runnable() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ try {
|
|
|
+ Thread.sleep(10000);
|
|
|
+ //System.err.println("发送0数据......");
|
|
|
+ if (socket != null && !socket.isClosed()){
|
|
|
+ out.write(ByteUtils.hexToByteArray(HEARTED));
|
|
|
+ out.flush();
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ socket = null; //若发生异常则将socket置为null,后面重新建立新的对象,以确保新的连接
|
|
|
+ out = null;
|
|
|
+ in = null;
|
|
|
+ flag = false;
|
|
|
+ restartSocket();
|
|
|
+ e.printStackTrace();
|
|
|
+ } finally {
|
|
|
+ if (flag) {
|
|
|
+ sendMsg();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }).start();*/
|
|
|
+
|
|
|
+ executorHearService.submit(new Runnable() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ try {
|
|
|
+ Thread.sleep(10000);
|
|
|
+ //System.err.println("发送0数据......");
|
|
|
+ if (socket != null && !socket.isClosed()) {
|
|
|
+ out.write(ByteUtils.hexToByteArray(HEARTED));
|
|
|
+ out.flush();
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ socket = null; //若发生异常则将socket置为null,后面重新建立新的对象,以确保新的连接
|
|
|
+ out = null;
|
|
|
+ in = null;
|
|
|
+ flag = false;
|
|
|
+ restartSocket();
|
|
|
+ e.printStackTrace();
|
|
|
+ } finally {
|
|
|
+ if (flag) {
|
|
|
+ sendMsg();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 加油交易记录解析
|
|
|
+ *
|
|
|
+ * @param msg 加油交易记录,16进制字符串
|
|
|
+ * @param oilHeaderPackage 加油交易记录包头,16进制字符串
|
|
|
+ */
|
|
|
+ public static Map<String, String> getFuelMsg(String msg, String oilHeaderPackage) {
|
|
|
+ try {
|
|
|
+ //msg = msg.substring(msg.indexOf(oilHeaderPackage));
|
|
|
+ //System.out.println("油机加油数据(截取后)--" + msg);
|
|
|
+ //log.info("加油数据(16进制)--" + msg);
|
|
|
+ //拼接 上传交易记录
|
|
|
+ Map<String, String> resMap = new HashMap<>();
|
|
|
+
|
|
|
+ if (msg.contains(oilHeaderPackage)) {
|
|
|
+ msg = msg.substring(msg.indexOf(oilHeaderPackage));
|
|
|
+ //System.out.println(msg);
|
|
|
+ String[] arr = msg.split(" ");
|
|
|
+ String[] heart = Arrays.copyOfRange(arr, 0, 9);//交易记录-固定包头(9)
|
|
|
+ //System.out.println("包头: " + Arrays.toString(heart));
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 恒山加油机:一个加油点只能有一把或两把枪,两把枪的时候不能两把枪同时加油
|
|
|
+ * 外部枪号就是逻辑枪号,外部枪号用于区分加油点有几把枪(1把或2把枪),外部枪号用于油站人员展示使用,关系不大!
|
|
|
+ * 加油点+内部枪号+外部枪号
|
|
|
+ * 如:1+1+1/1+2+2
|
|
|
+ * 加油点1的第一把枪(内部枪号) 加油点1的第二把枪(内部枪号)
|
|
|
+ *
|
|
|
+ */
|
|
|
+ String[] gunNo = Arrays.copyOfRange(arr, 9, 10);//枪号(1)
|
|
|
+
|
|
|
+ for (int i = 0; i < gunNo.length; i++) {
|
|
|
+ //int gunNo_ = ByteUtils.hexToDecimal(gunNo[i]) - ByteUtils.hexToDecimal("20");
|
|
|
+ resMap.put("gunNo", gunNo[i]);
|
|
|
+ //System.out.println("枪号: " + gunNo[i]);
|
|
|
+ }
|
|
|
+ String[] fixedVal = Arrays.copyOfRange(arr, 10, 11);//固定值(1)
|
|
|
+ for (int i = 0; i < fixedVal.length; i++) {
|
|
|
+ //System.out.println("固定值: " + fixedVal[i]);
|
|
|
+ }
|
|
|
+ String[] serialNum = Arrays.copyOfRange(arr, 11, 13);//交易序列号(2)
|
|
|
+ StringBuffer serialNum_Str = new StringBuffer();
|
|
|
+ for (int i = 0; i < serialNum.length; i++) {
|
|
|
+ serialNum_Str.append(serialNum[i]);
|
|
|
+ }
|
|
|
+ resMap.put("serialNum", serialNum_Str.toString());
|
|
|
+ //System.out.println("交易序列号: " + serialNum_Str);
|
|
|
+
|
|
|
+ String[] serialNum2 = Arrays.copyOfRange(arr, 13, 17);//交易序列号(4)
|
|
|
+ StringBuffer serialNum2_Str = new StringBuffer();
|
|
|
+ for (int i = 0; i < serialNum2.length; i++) {
|
|
|
+ serialNum2_Str.append(serialNum2[i]);
|
|
|
+ }
|
|
|
+ //System.out.println("交易序列号2: " + Arrays.toString(serialNum2));
|
|
|
+ String[] amount = Arrays.copyOfRange(arr, 17, 24);//金额数目(7)
|
|
|
+ StringBuffer amount_int = new StringBuffer();
|
|
|
+ StringBuffer amount_frac = new StringBuffer();
|
|
|
+ if (amount[0].equals("05")) { //05--金额标识
|
|
|
+ int flag = ByteUtils.hexToDecimal(amount[1]); //代表金额位数,第二个字节为几表示后续的几个字节均为表示金额的数据
|
|
|
+ int int_part = ByteUtils.hexToDecimal(amount[2]) / 2; //整数部分占据几位
|
|
|
+ int frac_part = (flag - 1) - int_part; //小数部分占据几位(去掉标识位数本身一位和整数位数就是小数位数)
|
|
|
+ for (int i = 1; i <= int_part; i++) {
|
|
|
+ //String flag_00 = amount[i + 2];
|
|
|
+ //if (!flag_00.equals("00")) {
|
|
|
+ amount_int.append(amount[i + 2]);
|
|
|
+ // }
|
|
|
+ }
|
|
|
+ for (int i = 1; i <= frac_part; i++) {
|
|
|
+ amount_frac.append(amount[i + 2 + int_part]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ String amount_ = amount_int + "." + amount_frac;
|
|
|
+ //判断整数是否是0开头,如果是0开头需要去掉0
|
|
|
+ //if (amount_.startsWith("0")) amount_ = amount_.substring(1);
|
|
|
+ //if (amount_.startsWith(".")) amount_ = "0" + amount_;
|
|
|
+ splitVal(amount_);
|
|
|
+
|
|
|
+ resMap.put("amount", DATA);
|
|
|
+ //System.out.println("金额数目: " + amount_);
|
|
|
+
|
|
|
+
|
|
|
+ String[] rise = Arrays.copyOfRange(arr, 24, 31);//加油量(7)
|
|
|
+ StringBuffer rise_int = new StringBuffer();
|
|
|
+ StringBuffer rise_frac = new StringBuffer();
|
|
|
+ if (rise[0].equals("06")) { //06是加油量标识
|
|
|
+ int flag = ByteUtils.hexToDecimal(rise[1]);
|
|
|
+ int int_part = ByteUtils.hexToDecimal(rise[2]) / 2;
|
|
|
+ int frac_part = (flag - 1) - int_part;
|
|
|
+ for (int i = 1; i <= int_part; i++) {
|
|
|
+ //if (!rise[i + 2].equals("00")) {
|
|
|
+ rise_int.append(rise[i + 2]);
|
|
|
+ //}
|
|
|
+ }
|
|
|
+ for (int i = 1; i <= frac_part; i++) {
|
|
|
+ rise_frac.append(rise[i + 2 + int_part]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ String rise_ = rise_int + "." + rise_frac;
|
|
|
+ //if (rise_.startsWith("0")) rise_ = rise_.substring(1); //若是以0开头需要去掉
|
|
|
+ //if (rise_.startsWith(".")) rise_ = "0" + rise_; //若点开头需要在前面添加0
|
|
|
+ splitVal(rise_);
|
|
|
+ if (DATA.startsWith(".")) DATA = "0" + DATA;
|
|
|
+ resMap.put("rise", DATA);
|
|
|
+ //System.out.println("加油量: " + rise_);
|
|
|
+
|
|
|
+
|
|
|
+ String[] price = Arrays.copyOfRange(arr, 31, 37);//单价(6)
|
|
|
+ StringBuffer price_int = new StringBuffer();
|
|
|
+ StringBuffer price_frac = new StringBuffer();
|
|
|
+ if (price[0].equals("07")) { //07标识单价
|
|
|
+ int flag = ByteUtils.hexToDecimal(price[1]);
|
|
|
+ int int_part = ByteUtils.hexToDecimal(price[2]) / 2;
|
|
|
+ int frac_part = (flag - 1) - int_part;
|
|
|
+ for (int i = 1; i <= int_part; i++) {
|
|
|
+ //if (!price[i + 2].equals("00")) {
|
|
|
+ price_int.append(price[i + 2]);
|
|
|
+ //}
|
|
|
+ }
|
|
|
+ for (int i = 1; i <= frac_part; i++) {
|
|
|
+ price_frac.append(price[i + 2 + int_part]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ String price_ = price_int + "." + price_frac;
|
|
|
+ //if (price_.startsWith("0")) price_ = price_.substring(1);
|
|
|
+ //if (price_.startsWith(".")) price_ = "0" + price_;
|
|
|
+ splitVal(price_);
|
|
|
+ if (DATA.startsWith(".")) DATA = "0" + DATA;
|
|
|
+ resMap.put("price", DATA);
|
|
|
+ //System.out.println("单价: " + price_);
|
|
|
+
|
|
|
+ String[] date = Arrays.copyOfRange(arr, 37, 43);//日期(6)
|
|
|
+ StringBuffer dateBuffer = new StringBuffer();
|
|
|
+ if (date[0].equals("CA")) { //日期标识
|
|
|
+ int flag = ByteUtils.hexToDecimal(date[1]);
|
|
|
+ for (int i = 0; i < flag; i++) {
|
|
|
+ dateBuffer.append(date[i + 2]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ char[] chars = dateBuffer.toString().toCharArray();
|
|
|
+ char[] yyyy = Arrays.copyOfRange(chars, 0, 4);
|
|
|
+ char[] mm = Arrays.copyOfRange(chars, 4, 6);
|
|
|
+ char[] rr = Arrays.copyOfRange(chars, 6, 9);
|
|
|
+ String date_ = String.valueOf(yyyy) + "-" + String.valueOf(mm) + "-" + String.valueOf(rr);
|
|
|
+ date_ = date_.trim();
|
|
|
+ resMap.put("date", date_);
|
|
|
+ //System.out.println("日期: " + date_);
|
|
|
+
|
|
|
+
|
|
|
+ String[] time = Arrays.copyOfRange(arr, 43, 48);//时间(5)
|
|
|
+ StringBuffer time_str = new StringBuffer();
|
|
|
+ if (time[0].equals("D5")) {
|
|
|
+ int flag = ByteUtils.hexToDecimal(time[1]);
|
|
|
+ for (int i = 0; i < flag; i++) {
|
|
|
+ time_str.append(time[i + 2] + ":");
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ String time_ = time_str.toString();
|
|
|
+ if (time_.endsWith(":")) time_ = time_.substring(0, time_.lastIndexOf(":"));
|
|
|
+ resMap.put("time", time_);
|
|
|
+ //System.out.println("时间: " + time_);
|
|
|
+
|
|
|
+ String[] pump = Arrays.copyOfRange(arr, 48, 57);//泵码(9)
|
|
|
+ StringBuffer pump_int = new StringBuffer();
|
|
|
+ StringBuffer pump_frac = new StringBuffer();
|
|
|
+ if (pump[0].equals("CD")) { //CD 泵码标识
|
|
|
+ int flag = ByteUtils.hexToDecimal(pump[1]);
|
|
|
+ int int_part = ByteUtils.hexToDecimal(pump[2]) / 2;
|
|
|
+ int frac_part = (flag - 1) - int_part;
|
|
|
+ for (int i = 1; i <= int_part; i++) {
|
|
|
+ //if (!pump[i + 2].equals("00")) {
|
|
|
+ pump_int.append(pump[i + 2]);
|
|
|
+ //}
|
|
|
+
|
|
|
+ }
|
|
|
+ for (int i = 1; i <= frac_part; i++) {
|
|
|
+ pump_frac.append(pump[i + 2 + int_part]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ String pump_ = pump_int + "." + pump_frac;
|
|
|
+ //if (pump_.startsWith("0")) pump_ = pump_.substring(1);
|
|
|
+ //if (pump_.startsWith(".")) pump_ = "0" + pump_;
|
|
|
+ splitVal(pump_);
|
|
|
+ if (DATA.startsWith(".")) DATA = "0" + DATA;
|
|
|
+ resMap.put("pump", DATA);
|
|
|
+ return resMap;
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error(e.getMessage() + "--原始数据--" + msg);
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 重新连接油机
|
|
|
+ */
|
|
|
+ public static void restartSocket() {
|
|
|
+ try {
|
|
|
+ /* if (!socket.isClosed()) {
|
|
|
+ socket.close();
|
|
|
+ }*/
|
|
|
+ //每隔间10s向服务器请求一次以此检查服务器是否已经起来
|
|
|
+ Thread.sleep(10000);
|
|
|
+ System.out.println("重连油机socket.......");
|
|
|
+ if (socket == null) socket = new Socket(HOST, PORT);
|
|
|
+ SocketFactory.sendHeartMsg(HOST, Integer.valueOf(PORT), URL, FILEPATH, ENV, ITOUCHHOST, ITOUCHPORT);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error(e.getMessage());
|
|
|
+ e.printStackTrace();
|
|
|
+ } finally {
|
|
|
+ if (socket == null) {
|
|
|
+ restartSocket();
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 从配置文件获取油枪信息
|
|
|
+ *
|
|
|
+ * @param stationIp 油机Ip地址
|
|
|
+ * @param fuelMsg Map集合键值对
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static Map<String, String> getConfigure(String stationIp, Map<String, String> fuelMsg) {
|
|
|
+ try {
|
|
|
+ Map<String, String> resMap = new HashMap<>();
|
|
|
+ String s = JSONUtils.readJSONFile(FILEPATH);
|
|
|
+ s = s.trim();
|
|
|
+ JSONObject configure = JSONObject.parseObject(s);
|
|
|
+ JSONArray params = configure.getJSONArray("param");
|
|
|
+ String[] nozzles = null;
|
|
|
+ String gunNo = "";
|
|
|
+ String oils = "";
|
|
|
+ String oilGrade = "";
|
|
|
+ String payShop = "";
|
|
|
+ String payType = "";
|
|
|
+ String stationId = "";
|
|
|
+ String stationName = "";
|
|
|
+ String sysDept = "";
|
|
|
+ String ip = "";
|
|
|
+ String iTouchIp = "";
|
|
|
+ for (Object param : params) {
|
|
|
+ String paramStr = String.valueOf(param);
|
|
|
+ JSONObject configureObject = JSONObject.parseObject(paramStr);
|
|
|
+ ip = String.valueOf(configureObject.get("ip"));
|
|
|
+ if (ip.equals(stationIp)) {
|
|
|
+ String nozzle = String.valueOf(configureObject.getJSONObject("configure").get("nozzle"));
|
|
|
+ stationId = String.valueOf(configureObject.getJSONObject("configure").getJSONObject("station").get("stationId"));
|
|
|
+ stationName = String.valueOf(configureObject.getJSONObject("configure").getJSONObject("station").get("stationName"));
|
|
|
+ sysDept = String.valueOf(configureObject.getJSONObject("configure").getJSONObject("station").get("sysDept"));
|
|
|
+ nozzles = nozzle.split(",");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ String gunNum = fuelMsg.get("gunNo");
|
|
|
+ String gunNo_ = String.valueOf(ByteUtils.hexToDecimal(gunNum) - ByteUtils.hexToDecimal("20"));
|
|
|
+ if (nozzles != null) {
|
|
|
+ for (String nozzleInfo : nozzles) {
|
|
|
+ String[] split = nozzleInfo.split("\\+");
|
|
|
+ if (gunNo_.equals(split[0])) {
|
|
|
+ gunNo = split[0]; //枪号
|
|
|
+ if (gunNo.equals(gunNo_)) {
|
|
|
+ oils = split[1]; //油品名称
|
|
|
+ oilGrade = split[2];//油品等级
|
|
|
+ payShop = split[3];//支付方式
|
|
|
+ payType = split[4];//加油卡类型
|
|
|
+
|
|
|
+ if (split.length >= 6) {
|
|
|
+ iTouchIp = split[5];//ITouch ip 地址,显示将该条数据往哪个ITouch屏发送
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ resMap.put("gunNo", gunNo);
|
|
|
+ resMap.put("oils", oils);
|
|
|
+ resMap.put("oilGrade", oilGrade);
|
|
|
+ resMap.put("payShop", payShop);
|
|
|
+ resMap.put("payType", payType);
|
|
|
+ resMap.put("stationId", stationId);
|
|
|
+ resMap.put("stationName", stationName);
|
|
|
+ resMap.put("sysDept", sysDept);
|
|
|
+
|
|
|
+
|
|
|
+ resMap.put("iTouchIp", iTouchIp);
|
|
|
+
|
|
|
+ nozzleInfoMap.putAll(resMap);
|
|
|
+ return resMap;
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public static void getStationIps() {
|
|
|
+ try {
|
|
|
+ String s = JSONUtils.readJSONFile(SocketFactory.FILEPATH);
|
|
|
+ s = s.trim();
|
|
|
+ JSONObject configure = JSONObject.parseObject(s);
|
|
|
+ JSONArray params = configure.getJSONArray("param");
|
|
|
+ for (Object param : params) {
|
|
|
+ String paramStr = String.valueOf(param);
|
|
|
+ JSONObject configureObject = JSONObject.parseObject(paramStr);
|
|
|
+ ClientFactory clientFactory = new ClientFactory();
|
|
|
+ clientFactoryMap.put(String.valueOf(configureObject.get("ip")), clientFactory);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private static String DATA = "";
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将字符串去掉0开头
|
|
|
+ *
|
|
|
+ * @param val 0开头的字符串
|
|
|
+ */
|
|
|
+ public static void splitVal(String val){
|
|
|
+
|
|
|
+ if (val.startsWith("0")){
|
|
|
+ DATA = val.substring(1);
|
|
|
+ }
|
|
|
+ if (DATA.startsWith("0")){
|
|
|
+ splitVal(DATA);
|
|
|
+ }
|
|
|
+
|
|
|
+ //return msg;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+}
|