Browse Source

Merge branch 'jwy_csdj' of http://47.100.114.196:3001/jwy/aeon_sender into zhczh_c

zhczh_c
zhczyx@163.com 1 month ago
parent
commit
127c9ea474
  1. 61
      src/main/java/com/techsor/datacenter/sender/components/CommonOpt.java
  2. 4
      src/main/java/com/techsor/datacenter/sender/dao/CompanyInfoDao.java
  3. 31
      src/main/java/com/techsor/datacenter/sender/dao/DeviceDao.java
  4. 58
      src/main/java/com/techsor/datacenter/sender/dao/F10Dao.java
  5. 16
      src/main/java/com/techsor/datacenter/sender/entitiy/company/TopCompanyInfo.java
  6. 91
      src/main/java/com/techsor/datacenter/sender/entitiy/f10/F10ProcessingData.java
  7. 156
      src/main/java/com/techsor/datacenter/sender/service/F10Service.java
  8. 110
      src/test/java/com/techsor/datacenter/sender/f10/F10FullParser320.java
  9. 68
      src/test/java/com/techsor/datacenter/sender/f10/SochiData.java
  10. 202
      src/test/java/com/techsor/datacenter/sender/f10/SochiDataParser.java
  11. 1
      src/test/java/com/techsor/datacenter/sender/f10/data200-2.txt
  12. 1
      src/test/java/com/techsor/datacenter/sender/f10/data200.txt
  13. 1
      src/test/java/com/techsor/datacenter/sender/f10/data320.txt

61
src/main/java/com/techsor/datacenter/sender/components/CommonOpt.java

@ -8,6 +8,7 @@ import com.techsor.datacenter.sender.dao.DeviceDao;
import com.techsor.datacenter.sender.dto.RedisAlarmDTO;
import com.techsor.datacenter.sender.entitiy.DeviceEntity;
import com.techsor.datacenter.sender.entitiy.company.CompanyEntity;
import com.techsor.datacenter.sender.entitiy.company.TopCompanyInfo;
import com.techsor.datacenter.sender.utils.HttpUtil;
import org.slf4j.Logger;
@ -65,7 +66,7 @@ public class CommonOpt {
try{
companyId = companyInfoDao.getTopCompanyId(companyId)+"";
}catch (Exception e){
log.error("Get top companyId Error:",e.getMessage(),e.fillInStackTrace());
log.error("Get top companyId Error: {}",e.getMessage(),e.fillInStackTrace());
}
log.info("GetTopCompanyId:"+companyId);
return companyId;
@ -101,6 +102,64 @@ public class CommonOpt {
return companyId;
}
public TopCompanyInfo getCompanyIdByDevicePrefix(String prefix) {
String redisKey = "f10:deviceCompanyMapping";
String companyId = (String) redisTemplate.opsForHash().get(redisKey, prefix);
if (companyId==null){
//Try from mysql
companyId = getCompanyIdByDevicePrefixFromAllDB(prefix);
if (companyId.equals("")){
log.error("Can't find topCompanyId for deviceId prefix: "+prefix+", Please notice if this device is not login on platform.");
return null;
}else{
//Update redis cache
redisTemplate.opsForHash().put(redisKey, prefix, companyId);
}
}
String topCompanyId = "";
try{
topCompanyId = companyInfoDao.getTopCompanyId(companyId)+"";
}catch (Exception e){
log.error("Get top companyId Error: {}",e.getMessage(),e.fillInStackTrace());
}
log.info("GetTopCompanyId:"+topCompanyId);
TopCompanyInfo topCompanyInfo = new TopCompanyInfo();
topCompanyInfo.setSelfCompanyId(companyId);
topCompanyInfo.setTopCompanyId(topCompanyId);
return topCompanyInfo;
}
private String getCompanyIdByDevicePrefixFromAllDB(String prefix) {
String companyId = "";
List<CompanyEntity> companyEntityList = companyInfoDao.getCompanyList();
for (CompanyEntity companyItem : companyEntityList){
String tempCompanyId = "";
log.info("[getCompanyIdByDevicePrefixFromAllDB] companyId:"+companyItem.getId().toString());
if (companyItem.getParentId()==-1 || companyItem.getParentId()==1){
tempCompanyId = companyItem.getId().toString();
}else{
log.info("[getCompanyIdByDevicePrefixFromAllDB] Not level 1 company. skip.");
continue;
}
//只处理一级企业
log.info("[getCompanyIdByDevicePrefixFromAllDB] prefix:"+prefix+" , comanyId:"+tempCompanyId);
List<DeviceEntity> deviceList = deviceDao.getDeviceInfoByDevicePrefixWithDB(prefix,tempCompanyId);
if (deviceList.size()<=0){
log.info("[getCompanyIdByDevicePrefixFromAllDB] deviceList size is 0");
continue;
}else{
log.info("[getCompanyIdByDevicePrefixFromAllDB] companyId get! Value:"+tempCompanyId);
companyId=tempCompanyId;
break;
}
}
log.info("GetCompanyId:"+companyId);
return companyId;
}
public void handleTargetUrl(JSONObject respObject, Map<String, Object> keys) {
if (keys.containsKey("needTransfer") && "true".equalsIgnoreCase(keys.get("needTransfer").toString())) {
String targetData = JSONObject.toJSONString(keys.get("rawData"));

4
src/main/java/com/techsor/datacenter/sender/dao/CompanyInfoDao.java

@ -21,7 +21,7 @@ public class CompanyInfoDao {
@Cacheable(value = "CompanyInfoDao::getCompanyList",key = "'CompanyList'")
public List<CompanyEntity> getCompanyList() {
// String sql="SELECT id,parent_id,company_name,bearer_token,third_api_host FROM data_center_admin.basic_company;";
String sql="SELECT id,parent_id,company_name,bearer_token,third_api_host FROM data_center_aeon_admin.basic_company;";
String sql="SELECT id,parent_id,company_name,bearer_token,third_api_host FROM data_center_aeon_admin.basic_company where flag != 1 ;";
List<CompanyEntity> dataList = jdbcTemplate.query(sql,
(rs, rowNum) -> {
CompanyEntity item = new CompanyEntity();
@ -57,7 +57,7 @@ public class CompanyInfoDao {
}
}
@Cacheable(value = "CompanyInfoDao::getCompanyList",key = "#companyId")
@Cacheable(value = "CompanyInfoDao::getTopCompanyId",key = "#companyId")
public long getTopCompanyId(String companyId) {
String sql="SELECT "

31
src/main/java/com/techsor/datacenter/sender/dao/DeviceDao.java

@ -206,7 +206,36 @@ public class DeviceDao {
return dataList;
}
// Get the corresponding WS client ID based on the device ID
@Cacheable(value = "DeviceDao::getDeviceInfoByDevicePrefixWithDB", key = "#prefix + '::' + #companyId")
public List<DeviceEntity> getDeviceInfoByDevicePrefixWithDB(String prefix,String companyId){
if (StringUtils.isEmpty(prefix)){
return new ArrayList<>();
}
String sql = "";
sql = "SELECT id,company_id,device_id,device_sn,type_id,space_id,building_id,device_name,"
+ "project_id,floor_id,asset_id "
+ "FROM data_center_aeon_" + companyId + ".device_info "
+ "WHERE device_id LIKE '" + prefix.replace("_", "\\_") + "%' "
+ "AND flag != 1";
List<DeviceEntity> dataList = jdbcTemplate.query(sql,
(rs, rowNum) -> {
DeviceEntity item = new DeviceEntity();
item.setId(rs.getInt("id"));
item.setCompanyId(rs.getLong("company_id"));
item.setDeviceId(rs.getString("device_id"));
item.setDeviceSN(rs.getString("device_sn"));
item.setTypeId(rs.getInt("type_id"));
item.setSpaceId(rs.getLong("space_id"));
item.setBuildingId(rs.getLong("building_id"));
item.setDeviceName(rs.getString("device_name"));
item.setProjectId(rs.getLong("project_id"));
item.setFloorId(rs.getLong("floor_id"));
item.setAssetId(rs.getLong("asset_id"));
return item;
});
return dataList;
}
@Cacheable(value = "DeviceDao::getDeviceInfoByDeviceIdWithDB", key = "#deviceId + '::' + #companyId")
public List<DeviceEntity> getDeviceInfoByDeviceIdWithDB(String deviceId,String companyId){
if (StringUtils.isEmpty(deviceId)){

58
src/main/java/com/techsor/datacenter/sender/dao/F10Dao.java

@ -1,6 +1,7 @@
package com.techsor.datacenter.sender.dao;
import com.techsor.datacenter.sender.entitiy.f10.F10JournalLog;
import com.techsor.datacenter.sender.entitiy.f10.F10ProcessingData;
import jakarta.annotation.Resource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
@ -79,4 +80,61 @@ public class F10Dao {
f10JournalLog.getAlertHistoryId()
);
}
public void insertF10ProcessingData(F10ProcessingData f10ProcessingData) {
String sql = "INSERT IGNORE INTO f10_processing_log (" +
"gateway_id, company_id, raw_hex, raw_text, serial_no, mode, " +
"signal_seq, receive_date, receive_time, " +
"tel_time, tel_operator, command_time, cancel_time, controller_name, " +
"arrival_time, field_action_name, action_content, finish_time, writer, " +
"category_no, category_name, physical_address, contract_no, " +
"transfer_flag, incident_flag, reserved_field20, " +
"created_at, created_time, receive_timestamp" +
") VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
jdbcTemplate.update(sql,
// ===== 基础字段 =====
f10ProcessingData.getGatewayId(),
f10ProcessingData.getCompanyId(),
// 你的实体里目前没有这几个字段
f10ProcessingData.getRawHex(), // raw_hex
f10ProcessingData.getRawText(), // raw_text
f10ProcessingData.getSignalSeq(), // serial_no
f10ProcessingData.getMode(), // mode
// ===== F10 措置数据 =====
f10ProcessingData.getSignalSeq(),
f10ProcessingData.getReceiveDate(),
f10ProcessingData.getReceiveTime(),
f10ProcessingData.getTelTime(),
f10ProcessingData.getTelOperator(),
f10ProcessingData.getCommandTime(),
f10ProcessingData.getCancelTime(),
f10ProcessingData.getControllerName(),
f10ProcessingData.getArrivalTime(),
f10ProcessingData.getFieldActionName(),
f10ProcessingData.getActionContent(),
f10ProcessingData.getFinishTime(),
f10ProcessingData.getWriter(),
f10ProcessingData.getCategoryNo(),
f10ProcessingData.getCategoryName(),
f10ProcessingData.getPhysicalAddress(),
f10ProcessingData.getContractNo(),
f10ProcessingData.getTransferFlag(),
f10ProcessingData.getIncidentFlag(),
f10ProcessingData.getReservedField20(),
// ===== 时间 =====
f10ProcessingData.getCreatedAt(),
new java.sql.Timestamp(f10ProcessingData.getCreatedAt()),
f10ProcessingData.getReceiveTimestamp()
);
}
}

16
src/main/java/com/techsor/datacenter/sender/entitiy/company/TopCompanyInfo.java

@ -0,0 +1,16 @@
package com.techsor.datacenter.sender.entitiy.company;
import lombok.Data;
import java.io.Serializable;
@Data
public class TopCompanyInfo implements Serializable {
private String topCompanyId;
private String selfCompanyId;
}

91
src/main/java/com/techsor/datacenter/sender/entitiy/f10/F10ProcessingData.java

@ -0,0 +1,91 @@
package com.techsor.datacenter.sender.entitiy.f10;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class F10ProcessingData {
/** 1 信号通番 */
private String signalSeq;
/** 2 受信日付 yyyyMMdd */
private String receiveDate;
/** 3 受信時刻 HHmmss */
private String receiveTime;
/** 4 電話連絡時刻 */
private String telTime;
/** 5 電話対応者名 */
private String telOperator;
/** 6 指令時刻 */
private String commandTime;
/** 7 指令中止時刻 */
private String cancelTime;
/** 8 管制官名 */
private String controllerName;
/** 9 現着時刻 */
private String arrivalTime;
/** 10 現場対処名 */
private String fieldActionName;
/** 11 措置内容 */
private String actionContent;
/** 12 完了時刻 */
private String finishTime;
/** 13 記入者 */
private String writer;
/** 14 措置分類番号 */
private String categoryNo;
/** 15 措置分類名称 */
private String categoryName;
/** 16 物理アドレス */
private String physicalAddress;
/** 17 契約先番号 */
private String contractNo;
/** 18 転送フラグ */
private String transferFlag;
/** 19 発生事故記録書の有無 */
private String incidentFlag;
/** 20 予備領域(0x20 padding / optional field) */
private String reservedField20;
// ===== 主键 =====
private Long id;
// ===== 设备 =====
private String gatewayId;
private Long companyId;
// ===== 原始数据 =====
private String rawHex;
private String rawText;
// ===== 报文头 =====
private String serialNo;
private String mode;
private Long createdAt; // 毫秒时间戳
private LocalDateTime createdTime; // 标准时间
// 接收时间戳(JST)
private Long receiveTimestamp;
}

156
src/main/java/com/techsor/datacenter/sender/service/F10Service.java

@ -9,7 +9,9 @@ import com.techsor.datacenter.sender.dao.DeviceDao;
import com.techsor.datacenter.sender.dao.F10Dao;
import com.techsor.datacenter.sender.entitiy.DeviceEntity;
import com.techsor.datacenter.sender.entitiy.DynamodbEntity;
import com.techsor.datacenter.sender.entitiy.company.TopCompanyInfo;
import com.techsor.datacenter.sender.entitiy.f10.F10JournalLog;
import com.techsor.datacenter.sender.entitiy.f10.F10ProcessingData;
import com.techsor.datacenter.sender.entitiy.f10.RedisStreamEntity;
import com.techsor.datacenter.sender.utils.RedisUtils;
import jakarta.annotation.Resource;
@ -52,12 +54,86 @@ public class F10Service {
public void handle(RedisStreamEntity rawEntity) {
String hexLog = rawEntity.getHexRawData().trim();
byte[] src = hexStringToByteArray(hexLog);
//(STX:1 + Serial:4 + Mode:2 + 正文:320 + ETX:1)
if (src.length < 328) {
log.warn("原始报文长度不足328字节");
return;
//(STX:1 + Serial:4 + Mode:2 + 正文:320或者200 + ETX:1)
if (328 == src.length) {
handle308(rawEntity);
} else if (208 == src.length) {
handle208(rawEntity);
} else {
log.warn("原始报文长度不是328或者208字节");
}
}
private void handle208(RedisStreamEntity rawEntity) {
try {
long currentTs = System.currentTimeMillis();
F10ProcessingData f10ProcessingData = parse208(rawEntity.getHexRawData());
f10ProcessingData.setCreatedAt(currentTs);
//前缀_26契約先番号_4チャンネル番号
//前缀还没定,先【26契約先番号_4チャンネル番号】
f10ProcessingData.setGatewayId(f10ProcessingData.getContractNo());
long receivedCurrentTs = parseToTimestamp(f10ProcessingData.getReceiveDate(), f10ProcessingData.getReceiveTime());
f10ProcessingData.setReceiveTimestamp(receivedCurrentTs);
String redisKey = getLatestProcessingKey(f10ProcessingData.getGatewayId());
// 从 Redis 取值
String latestTsStr = redisUtils.get(redisKey);
Long latestTs = null;
if (latestTsStr != null) {
try {
latestTs = Long.parseLong(latestTsStr);
} catch (Exception e) {
log.error("Redis数据异常,无法转换为Long: key={}, value={}", redisKey, latestTsStr);
}
}
boolean isExpired = false;
// ===== 判断逻辑 =====
if (latestTs == null) {
// 首次
redisUtils.add(redisKey, String.valueOf(receivedCurrentTs));
} else {
if (receivedCurrentTs > latestTs) {
// 新数据
redisUtils.add(redisKey, String.valueOf(receivedCurrentTs));
} else if (receivedCurrentTs == latestTs) {
// 重复数据 → 直接丢弃
log.warn("重复处理,丢弃 deviceId={}", f10ProcessingData.getGatewayId());
return;
} else {
// 旧数据 → 标记过期
isExpired = true;
}
}
TopCompanyInfo topCompanyInfo= commonOpt.getCompanyIdByDevicePrefix(f10ProcessingData.getGatewayId() + "_");
if (topCompanyInfo==null || "0".equals(topCompanyInfo.getTopCompanyId())){
log.error("no companyId is found========================>>>> {}",f10ProcessingData.getGatewayId());
return;
}
DataSourceContextHolder.clearCurrentDataSourceKey();
DataSourceContextHolder.setCurrentDataSourceKey("dataSourceForCompany_"+topCompanyInfo.getTopCompanyId());
log.info("Use datasource for company:"+topCompanyInfo.getTopCompanyId());
Long companyId = Long.valueOf(topCompanyInfo.getSelfCompanyId());
f10ProcessingData.setCompanyId(companyId);
f10Dao.insertF10ProcessingData(f10ProcessingData);
} catch (Exception e) {
log.error("F10解析入库失败", e);
}
}
private String getLatestProcessingKey(String deviceId) {
return "f10:latest_processing:" + deviceId;
}
private void handle308(RedisStreamEntity rawEntity) {
try {
long currentTs = System.currentTimeMillis();
@ -142,6 +218,78 @@ public class F10Service {
return "f10:latest_alarm:" + deviceId;
}
public static F10ProcessingData parse208(String hexLog) {
byte[] src = hexStringToByteArray(hexLog);
F10ProcessingData d = new F10ProcessingData();
int offset = 0;
// 跳过 STX
offset += 1;
String serialNo = new String(Arrays.copyOfRange(src, offset, offset + 4), SHIFT_JIS);
String mode = new String(Arrays.copyOfRange(src, offset, offset + 2), SHIFT_JIS);
int bodyStart = 7;
int bodyEnd = src.length - 1;
byte[] body = Arrays.copyOfRange(src, bodyStart, bodyEnd);
String rawText = new String(body, SHIFT_JIS).trim();
d .setRawHex(hexLog);
d .setRawText(rawText);
d .setSerialNo(serialNo);
d .setMode(mode);
offset = 7;
d.setSignalSeq(getTargetData(src, offset, 9)); offset += 9;
d.setReceiveDate(getTargetData(src, offset, 8)); offset += 8;
d.setReceiveTime(getTargetData(src, offset, 6)); offset += 6;
d.setTelTime(getTargetData(src, offset, 6)); offset += 6;
d.setTelOperator(getTargetData(src, offset, 16)); offset += 16;
d.setCommandTime(getTargetData(src, offset, 6)); offset += 6;
d.setCancelTime(getTargetData(src, offset, 6)); offset += 6;
d.setControllerName(getTargetData(src, offset, 16)); offset += 16;
d.setArrivalTime(getTargetData(src, offset, 6)); offset += 6;
d.setFieldActionName(getTargetData(src, offset, 16)); offset += 16;
d.setActionContent(getTargetData(src, offset, 40)); offset += 40;
d.setFinishTime(getTargetData(src, offset, 6)); offset += 6;
d.setWriter(getTargetData(src, offset, 16)); offset += 16;
d.setCategoryNo(getTargetData(src, offset, 2)); offset += 2;
d.setCategoryName(getTargetData(src, offset, 2)); offset += 2;
d.setPhysicalAddress(getTargetData(src, offset, 8)); offset += 8;
d.setContractNo(getTargetData(src, offset, 8)); offset += 8;
d.setTransferFlag(getTargetData(src, offset, 1)); offset += 1;
d.setIncidentFlag(getTargetData(src, offset, 1)); offset += 1;
d.setReservedField20(parseReserved(src, offset));
return d;
}
/**
* 予備字段0x20
*/
private static String parseReserved(byte[] data, int start) {
byte[] bytes = new byte[21];
System.arraycopy(data, start, bytes, 0, 21);
boolean allSpace = true;
for (byte b : bytes) {
if (b != 0x20) {
allSpace = false;
break;
}
}
if (allSpace) {
return null;
}
return new String(bytes, SHIFT_JIS).trim();
}
public static F10JournalLog parseToEntity(String hexLog) {
byte[] src = hexStringToByteArray(hexLog);

110
src/test/java/com/techsor/datacenter/sender/f10/F10FullParser320.java

@ -0,0 +1,110 @@
package com.techsor.datacenter.sender.f10;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
public class F10FullParser320 {
private static final Charset SHIFT_JIS = Charset.forName("Shift-JIS");
public static void main(String[] args) {
String rawHexLog = "";
try {
rawHexLog = Files.readString(Paths.get("src/test/java/com/techsor/datacenter/sender/f10/data320.txt")).trim();
} catch (IOException e) {
e.printStackTrace();
}
// 自动运行1 的原始 HEX 字符串
// String rawHexLog = "02 30 30 30 31 31 30 30 31 30 30 37 30 30 31 38 32 30 32 36 30 33 31 37 31 35 31 39 31 35 30 30 34 30 30 31 83 75 83 8D 83 62 83 4E 82 50 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 30 33 30 31 30 31 31 30 35 30 20 20 30 30 30 91 D2 8B 40 8F 8A 96 BC 8F CC 20 20 20 20 20 20 20 20 20 20 30 31 30 30 30 33 30 30 8C E3 95 FB 83 56 83 58 83 65 83 80 8E 8E 8C B1 97 70 95 A8 8C 8F 32 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 30 37 32 30 31 20 20 20 20 20 20 20 20 20 20 20 20 32 30 32 36 30 33 31 37 31 35 31 39 31 35 39 39 30 30 30 32 30 30 8F F3 91 D4 82 50 20 20 20 20 20 20 20 20 20 20 20 20 20 20 93 AE 8D EC 92 86 20 20 20 20 20 20 20 20 20 20 20 20 20 20 30 30 30 30 34 36 30 30 30 30 30 38 30 30 30 30 30 30 30 20 20 20 20 20 20 20 20 20 20 03";
String hexLog = rawHexLog.trim();
byte[] src = hexStringToByteArray(hexLog);
// --- 提取并打印正文数据 ---
// 跳过前7字节 (STX:1 + Serial:4 + Mode:2),去掉最后1字节 (ETX:1)
int bodyStart = 7;
int bodyEnd = src.length - 1;
byte[] body = Arrays.copyOfRange(src, bodyStart, bodyEnd);
String rawText = new String(body, SHIFT_JIS);
System.out.println("=== 原始报文分析 ===");
System.out.println("总长度: " + src.length + " 字节");
System.out.println("正文长度: " + body.length + " 字节");
System.out.println("正文 HEX: " + hex(body));
System.out.println("正文 文本: " + rawText);
System.out.println("==================\n");
System.out.println("No 字段名称 | 解析值 | HEX ");
System.out.println("-----------------------------------------------------------------------------------------");
// 数据部从第8字节开始 (STX:1 + Serial:4 + Mode:2 = 7)
int offset = 7;
// 严格按照规格书长度定义
f(1, "信号通番", src, offset, 9); offset += 9;
f(2, "受信日付", src, offset, 8); offset += 8;
f(3, "受信時刻", src, offset, 6); offset += 6;
f(4, "チャンネル番号", src, offset, 3); offset += 3;
f(5, "試験設定", src, offset, 1); offset += 1;
f(6, "ブロック番号", src, offset, 2); offset += 2;
f(7, "ブロック名称", src, offset, 30); offset += 30; // 规格书定义为30字节
f(8, "信号種別1", src, offset, 2); offset += 2;
f(9, "信号種別2", src, offset, 2); offset += 2;
f(10, "信号ラベル", src, offset, 2); offset += 2;
f(11, "信号状態", src, offset, 1); offset += 1;
f(12, "機動コース番号", src, offset, 3); offset += 3;
f(13, "担当地区", src, offset, 2); offset += 2;
f(14, "機動コースコード", src, offset, 3); offset += 3;
f(15, "待機所名", src, offset, 20); offset += 20;
f(16, "物理アドレス", src, offset, 8); offset += 8;
f(17, "契約先名称", src, offset, 30); offset += 30; // 修正:规格书定义为30字节
f(18, "電話番号", src, offset, 20); offset += 20;
f(19, "備考", src, offset, 60); offset += 60;
f(20, "表示色", src, offset, 2); offset += 2; // 正确对应 HEX: 30 37 (07)
f(21, "異常要因", src, offset, 1); offset += 1; // 正确对应 HEX: 32 (2)
f(22, "回線種別", src, offset, 2); offset += 2; // 正确对应 HEX: 30 31 (01)
f(23, "地区名称", src, offset, 12); offset += 12;
f(24, "送信日付", src, offset, 8); offset += 8;
f(25, "送信時刻", src, offset, 6); offset += 6;
f(26, "契約先番号", src, offset, 8); offset += 8;
f(27, "表示データ1", src, offset, 20); offset += 20;
f(28, "表示データ2", src, offset, 20); offset += 20;
f(29, "指令書作成", src, offset, 1); offset += 1;
f(30, "信号コード", src, offset, 4); offset += 4;
f(31, "カード番号", src, offset, 7); offset += 7; // 正确解析为 6000008
f(32, "カード種別", src, offset, 1); offset += 1;
f(33, "マンション棟", src, offset, 2); offset += 2;
f(34, "マンション部屋", src, offset, 4); offset += 4;
f(35, "オプション", src, offset, 10); offset += 10;
}
public static void f(int idx, String name, byte[] src, int start, int len) {
if (start + len > src.length) return;
byte[] raw = Arrays.copyOfRange(src, start, start + len);
String value = new String(raw, SHIFT_JIS).trim();
System.out.printf("%02d %-12s | %-20s | HEX:%s%n", idx, name, value, hex(raw));
}
private static String hex(byte[] raw) {
StringBuilder sb = new StringBuilder();
for (byte b : raw) sb.append(String.format("%02X ", b));
return sb.toString().trim();
}
private static byte[] hexStringToByteArray(String s) {
s = s.replace(" ", "");
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i + 1), 16));
}
return data;
}
}

68
src/test/java/com/techsor/datacenter/sender/f10/SochiData.java

@ -0,0 +1,68 @@
package com.techsor.datacenter.sender.f10;
import lombok.Data;
@Data
public class SochiData {
/** 1 信号通番 */
private String signalSeq;
/** 2 受信日付 yyyyMMdd */
private String receiveDate;
/** 3 受信時刻 HHmmss */
private String receiveTime;
/** 4 電話連絡時刻 */
private String telTime;
/** 5 電話対応者名 */
private String telOperator;
/** 6 指令時刻 */
private String commandTime;
/** 7 指令中止時刻 */
private String cancelTime;
/** 8 管制官名 */
private String controllerName;
/** 9 現着時刻 */
private String arrivalTime;
/** 10 現場対処名 */
private String fieldActionName;
/** 11 措置内容 */
private String actionContent;
/** 12 完了時刻 */
private String finishTime;
/** 13 記入者 */
private String writer;
/** 14 措置分類番号 */
private String categoryNo;
/** 15 措置分類名称 */
private String categoryName;
/** 16 物理アドレス */
private String physicalAddress;
/** 17 契約先番号 */
private String contractNo;
/** 18 転送フラグ */
private String transferFlag;
/** 19 発生事故記録書の有無 */
private String incidentFlag;
/** 20 予備領域(0x20 padding / optional field) */
private String reservedField20;
}

202
src/test/java/com/techsor/datacenter/sender/f10/SochiDataParser.java

@ -0,0 +1,202 @@
package com.techsor.datacenter.sender.f10;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
public class SochiDataParser {
private static final Charset SHIFT_JIS =
Charset.forName("Shift_JIS");
private static final int BASE_OFFSET = 7;
// =========================
// 解析入口
// =========================
public static SochiData parse(byte[] data) {
if (data.length < 200 + BASE_OFFSET) {
throw new IllegalArgumentException(
"数据长度不足: " + data.length);
}
SochiData d = new SochiData();
int bodyStart = 7;
d.setSignalSeq(getTargetData(data, bodyStart, 9)); bodyStart += 9;
d.setReceiveDate(getTargetData(data, bodyStart, 8)); bodyStart += 8;
d.setReceiveTime(getTargetData(data, bodyStart, 6)); bodyStart += 6;
d.setTelTime(getTargetData(data, bodyStart, 6)); bodyStart += 6;
d.setTelOperator(getTargetData(data, bodyStart, 16)); bodyStart += 16;
d.setCommandTime(getTargetData(data, bodyStart, 6)); bodyStart += 6;
d.setCancelTime(getTargetData(data, bodyStart, 6)); bodyStart += 6;
d.setControllerName(getTargetData(data, bodyStart, 16)); bodyStart += 16;
d.setArrivalTime(getTargetData(data, bodyStart, 6)); bodyStart += 6;
d.setFieldActionName(getTargetData(data, bodyStart, 16)); bodyStart += 16;
d.setActionContent(getTargetData(data, bodyStart, 40)); bodyStart += 40;
d.setFinishTime(getTargetData(data, bodyStart, 6)); bodyStart += 6;
d.setWriter(getTargetData(data, bodyStart, 16)); bodyStart += 16;
d.setCategoryNo(getTargetData(data, bodyStart, 2)); bodyStart += 2;
d.setCategoryName(getTargetData(data, bodyStart, 2)); bodyStart += 2;
d.setPhysicalAddress(getTargetData(data, bodyStart, 8)); bodyStart += 8;
d.setContractNo(getTargetData(data, bodyStart, 8)); bodyStart += 8;
d.setTransferFlag(getTargetData(data, bodyStart, 1)); bodyStart += 1;
d.setIncidentFlag(getTargetData(data, bodyStart, 1)); bodyStart += 1;
d.setReservedField20(parseReserved(data, bodyStart));
return d;
}
// =========================
// 普通字段
// =========================
private static String getTargetData(byte[] src, int start, int len) {
return new String(Arrays.copyOfRange(src, start, start + len), SHIFT_JIS).trim();
}
// =========================
// 予備字段(0x20)
// =========================
private static String parseReserved(byte[] data, int start) {
byte[] bytes = new byte[21];
System.arraycopy(data, start, bytes, 0, 21);
boolean allSpace = true;
for (byte b : bytes) {
if (b != 0x20) {
allSpace = false;
break;
}
}
if (allSpace) {
return null;
}
return new String(bytes, SHIFT_JIS).trim();
}
// =========================
// Debug打印(增强版)
// =========================
private static void f(int idx, String name, byte[] src, int start, int len) {
if (start >= src.length) {
System.out.printf("%02d %-18s | %-25s | OUT_OF_RANGE%n",
idx, name, "");
return;
}
int realLen = Math.min(len, src.length - start);
byte[] raw = Arrays.copyOfRange(src, start, start + realLen);
String value = new String(raw, SHIFT_JIS).trim();
System.out.printf(
"%02d %-18s | %-25s | HEX:%s%n",
idx,
name,
value,
hex(raw)
);
}
// =========================
// HEX 输出
// =========================
private static String hex(byte[] raw) {
StringBuilder sb = new StringBuilder();
for (byte b : raw) {
sb.append(String.format("%02X ", b));
}
return sb.toString().trim();
}
// =========================
// HEX转byte[]
// =========================
private static byte[] hexStringToByteArray(String s) {
s = s.replace(" ", "")
.replace("\r", "")
.replace("\n", "");
if (s.length() % 2 != 0) {
throw new IllegalArgumentException("HEX长度非法: " + s.length());
}
byte[] data = new byte[s.length() / 2];
for (int i = 0; i < s.length(); i += 2) {
data[i / 2] = (byte)(
(Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i + 1), 16)
);
}
return data;
}
// =========================
// main 调试入口(保留你原结构)
// =========================
public static void main(String[] args) throws IOException {
String rawHexLog =
Files.readString(
Paths.get("src/test/java/com/techsor/datacenter/sender/f10/data200.txt")
).trim();
byte[] src = hexStringToByteArray(rawHexLog);
System.out.println("=== 措置データ(200byte)解析 ===");
System.out.println("总长度: " + src.length + " byte");
System.out.println("-------------------------------------------------------------");
System.out.println("No 字段名称 | 值 | HEX");
System.out.println("-------------------------------------------------------------");
int o = BASE_OFFSET;
f(1, "信号通番", src, o, 9); o += 9;
f(2, "受信日付", src, o, 8); o += 8;
f(3, "受信時刻", src, o, 6); o += 6;
f(4, "電話連絡時刻", src, o, 6); o += 6;
f(5, "電話対応者名", src, o, 16); o += 16;
f(6, "指令時刻", src, o, 6); o += 6;
f(7, "指令中止時刻", src, o, 6); o += 6;
f(8, "管制官名", src, o, 16); o += 16;
f(9, "現着時刻", src, o, 6); o += 6;
f(10, "現場対処名", src, o, 16); o += 16;
f(11, "措置内容", src, o, 40); o += 40;
f(12, "完了時刻", src, o, 6); o += 6;
f(13, "記入者", src, o, 16); o += 16;
f(14, "措置分類番号", src, o, 2); o += 2;
f(15, "措置分類名称", src, o, 2); o += 2;
f(16, "物理アドレス", src, o, 8); o += 8;
f(17, "契約先番号", src, o, 8); o += 8;
f(18, "転送フラグ", src, o, 1); o += 1;
f(19, "事故記録書有無", src, o, 1); o += 1;
f(20, "予備領域", src, o, 21);
System.out.println("-------------------------------------------------------------");
SochiData data = parse(src);
System.out.println();
System.out.println("=== 对象解析结果 ===");
System.out.println(data);
}
}

1
src/test/java/com/techsor/datacenter/sender/f10/data200-2.txt

@ -0,0 +1 @@
02 30 30 30 31 31 30 30 31 36 35 32 31 37 37 34 32 30 32 36 30 35 31 33 31 30 30 34 34 37 20 20 20 20 20 20 82 AD 82 DC 82 AD 82 E7 20 20 20 20 20 20 20 20 31 30 31 32 30 30 20 20 20 20 20 20 8E 9B 93 63 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 93 5F 8C 9F 92 86 81 40 8C DF 8C E3 82 A9 82 E7 8D EC 82 C8 82 CC 82 C5 82 BB 82 EA 82 DC 82 C5 94 AD 95 F1 82 A0 82 E8 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 30 30 30 30 30 31 30 35 30 32 30 30 31 35 30 31 32 33 30 30 31 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 03

1
src/test/java/com/techsor/datacenter/sender/f10/data200.txt

@ -0,0 +1 @@
02 30 30 30 31 31 30 30 31 36 35 32 31 37 37 34 32 30 32 36 30 35 31 33 31 30 30 34 34 37 20 20 20 20 20 20 82 AD 82 DC 82 AD 82 E7 20 20 20 20 20 20 20 20 31 30 31 32 30 30 20 20 20 20 20 20 8E 9B 93 63 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 93 5F 8C 9F 92 86 81 40 8C DF 8C E3 82 A9 82 E7 8D EC 82 C8 82 CC 82 C5 82 BB 82 EA 82 DC 82 C5 94 AD 95 F1 82 A0 82 E8 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 30 30 30 30 30 31 30 35 30 32 30 30 31 35 30 31 32 33 30 30 31 30 32 30 32 36 30 35 32 32 31 35 33 30 34 35 20 20 20 20 20 20 20 03

1
src/test/java/com/techsor/datacenter/sender/f10/data320.txt

@ -0,0 +1 @@
02 30 30 30 31 31 30 30 31 30 30 37 30 30 31 38 32 30 32 36 30 33 31 37 31 35 31 39 31 35 30 30 34 30 30 31 83 75 83 8D 83 62 83 4E 82 50 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 30 33 30 31 30 31 31 30 35 30 20 20 30 30 30 91 D2 8B 40 8F 8A 96 BC 8F CC 20 20 20 20 20 20 20 20 20 20 30 31 30 30 30 33 30 30 8C E3 95 FB 83 56 83 58 83 65 83 80 8E 8E 8C B1 97 70 95 A8 8C 8F 32 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 30 37 32 30 31 20 20 20 20 20 20 20 20 20 20 20 20 32 30 32 36 30 33 31 37 31 35 31 39 31 35 39 39 30 30 30 32 30 30 8F F3 91 D4 82 50 20 20 20 20 20 20 20 20 20 20 20 20 20 20 93 AE 8D EC 92 86 20 20 20 20 20 20 20 20 20 20 20 20 20 20 30 30 30 30 34 36 30 30 30 30 30 38 30 30 30 30 30 30 30 20 20 20 20 20 20 20 20 20 20 03
Loading…
Cancel
Save