添加ASCII码支持

stwzhj
luyya 2026-04-17 17:06:52 +08:00
parent 7b3586d48c
commit 5cb6a5224a
2 changed files with 218 additions and 0 deletions

View File

@ -198,6 +198,13 @@
<version>0.8</version>
</dependency>
<dependency>
<groupId>com.belerweb</groupId>
<artifactId>pinyin4j</artifactId>
<version>2.5.1</version>
</dependency>
</dependencies>
<build>

View File

@ -5,6 +5,11 @@ import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONObject;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
import org.apache.dubbo.config.annotation.DubboReference;
import org.dromara.common.core.domain.R;
import org.dromara.common.redis.utils.RedisUtils;
@ -28,6 +33,7 @@ import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.*;
@Configuration
@ -417,6 +423,118 @@ public class LocationController {
return R.ok(list);
}
@PostMapping(value = "/getAscii")
public R<List<Map<String, Object>>> getAscii(@RequestBody Map<String, Object> params) {
// 解析JSON中的ASCII字段使用数组包装以支持lambda赋值
String[] typeHolder = new String[1];
String[] deptIdHolder = new String[1];
String[] zzjgdmHolder = new String[1];
Integer[] onlineHolder = new Integer[1];
Double[] minLngHolder = new Double[1];
Double[] minLatHolder = new Double[1];
Double[] maxLngHolder = new Double[1];
Double[] maxLatHolder = new Double[1];
String[] deviceCodeHolder = new String[1];
logger.info("接收到的原始参数: {}", params);
// 支持 ASCII 和 ascii 两种key
// 支持 ASCII 和 ascii 两种key
Object asciiObj = params.get("ASCII");
if (asciiObj == null) {
asciiObj = params.get("ascii");
}
String asciiBody = asciiObj != null ? asciiObj.toString() : null;
logger.info("接收到的原始ASCII内容: [{}]", asciiBody);
String parsedAsciiBody = null; // 用于实际解析的明文字符串
if (asciiBody != null && !asciiBody.isEmpty()) {
// 【新增】智能判断:如果字符串只包含 0-9, a-f, A-F且长度为偶数则认为是十六进制ASCII码
if (asciiBody.matches("^[0-9A-Fa-f]+$") && asciiBody.length() % 2 == 0) {
parsedAsciiBody = fromAsciiHex(asciiBody);
logger.info("检测到入参为纯十六进制ASCII码解码后的明文内容: [{}]", parsedAsciiBody);
} else {
// 否则认为是普通明文(兼容老版本调用)
parsedAsciiBody = asciiBody;
logger.info("检测到入参为普通明文格式,直接使用: [{}]", parsedAsciiBody);
}
// 使用解码后的明文 parsedAsciiBody 进行解析
parseAndSet(parsedAsciiBody, "type", v -> typeHolder[0] = v);
parseAndSet(parsedAsciiBody, "deptId", v -> deptIdHolder[0] = v);
parseAndSet(parsedAsciiBody, "zzjgdm", v -> zzjgdmHolder[0] = v);
parseAndSetInt(parsedAsciiBody, "online", v -> onlineHolder[0] = v);
parseAndSetDouble(parsedAsciiBody, "minLng", v -> minLngHolder[0] = v);
parseAndSetDouble(parsedAsciiBody, "minLat", v -> minLatHolder[0] = v);
parseAndSetDouble(parsedAsciiBody, "maxLng", v -> maxLngHolder[0] = v);
parseAndSetDouble(parsedAsciiBody, "maxLat", v -> maxLatHolder[0] = v);
parseAndSet(parsedAsciiBody, "deviceCode", v -> deviceCodeHolder[0] = v);
}
String type = typeHolder[0];
String deptId = deptIdHolder[0];
String zzjgdm = zzjgdmHolder[0];
Integer online = onlineHolder[0];
Double minLng = minLngHolder[0];
Double minLat = minLatHolder[0];
Double maxLng = maxLngHolder[0];
Double maxLat = maxLatHolder[0];
String deviceCode = deviceCodeHolder[0];
logger.info("ASCII协议POST获取设备位置 - type={}, deptId={}, zzjgdm={}, online={}, deviceCode={}", type, deptId, zzjgdm, online, deviceCode);
List<Map<String, Object>> list = searchService.getAllLatestLocationFromEs(type, deptId, zzjgdm, online, minLng, minLat, maxLng, maxLat, deviceCode);
list.removeAll(Collections.singleton(null));
// 为每个对象添加ASCII字段
for (Map<String, Object> item : list) {
StringBuilder sb = new StringBuilder();
sb.append("DEVICE:");
boolean first = true;
for (Map.Entry<String, Object> entry : item.entrySet()) {
if (!first) sb.append(",");
first = false;
String key = entry.getKey();
Object val = entry.getValue();
String valStr = val != null ? val.toString() : "";
// 【步骤1中文转英文处理】
// 情况A如果你加了拼音库用这行
String cleanKey = chineseToEnglish(key);
String cleanVal = chineseToEnglish(valStr);
// 【步骤2转成ASCII码】
// 方式1转成16进制ASCII码 (硬件协议最常用,无空格)
sb.append(toAsciiHex(cleanKey));
sb.append("=");
sb.append(toAsciiHex(cleanVal));
// 方式2转成10进制ASCII码 (如果有特殊要求可以用这个,带空格)
// sb.append(toAsciiDec(cleanKey));
// sb.append("=");
// sb.append(toAsciiDec(cleanVal));
}
// 最后把拼好的整个字符串也转一遍ASCII码确保连 "DEVICE:" 和 "," 也是纯码
// 如果你想连结构符都变成码,用下面这行:
item.put("ASCII", toAsciiHex(sb.toString()));
// 如果你只想把值变成码,保留可读性结构(如 DEVICE:id=313233用上面循环里的代码并把这行改为
// item.put("ASCII", sb.toString());
}
logger.info("ASCII协议POST返回设备数量: {}", list.size());
return R.ok(list);
}
/**
* ASCII
* ASCII
@ -459,6 +577,72 @@ public class LocationController {
}
}
/**
* ASCII (: "A" -> "41", "123" -> "313233")
*/
private String toAsciiHex(String str) {
if (str == null || str.isEmpty()) return "";
// 强制使用ASCII编码遇到非ASCII字符(如中文)会变成问号'?'
byte[] bytes = str.getBytes(StandardCharsets.US_ASCII);
StringBuilder hex = new StringBuilder();
for (byte b : bytes) {
hex.append(String.format("%02X", b & 0xFF));
}
return hex.toString();
}
/**
* ASCII (: "A" -> "65", "123" -> "49 50 51")
*/
private String toAsciiDec(String str) {
if (str == null || str.isEmpty()) return "";
byte[] bytes = str.getBytes(StandardCharsets.US_ASCII);
StringBuilder dec = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
if (i > 0) dec.append(" ");
dec.append(bytes[i] & 0xFF);
}
return dec.toString();
}
/**
* ASCII()
* /
*/
private String removeNonAscii(String str) {
if (str == null) return "";
// 替换掉所有不在 ASCII 0-127 范围内的字符
return str.replaceAll("[^\\x00-\\x7F]", "");
}
/**
* ASCII (: "74797065" -> "type")
* ASCII(0-255)UTF-8
*/
private String fromAsciiHex(String hex) {
if (hex == null || hex.isEmpty()) return "";
// 去除可能存在的空格
hex = hex.replaceAll("\\s+", "");
if (hex.length() % 2 != 0) {
logger.warn("十六进制ASCII码长度不是偶数可能存在损坏: {}", hex);
return "";
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hex.length(); i += 2) {
String str = hex.substring(i, i + 2);
try {
// 将两个十六进制字符转为一个十进制数字再强转为char
sb.append((char) Integer.parseInt(str, 16));
} catch (NumberFormatException e) {
logger.warn("解析十六进制字符失败: {}", str);
sb.append("?"); // 非法字符替换为问号
}
}
return sb.toString();
}
/**
* Integer
*/
@ -482,6 +666,33 @@ public class LocationController {
}
}
/*
*
* */
private String chineseToEnglish(String str) {
if (str == null) return "";
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
StringBuilder py = new StringBuilder();
for (char c : str.toCharArray()) {
if (c > 127) { // 非ASCII字符大概率是中文
try {
String[] pinyinArr = PinyinHelper.toHanyuPinyinStringArray(c, format);
if (pinyinArr != null && pinyinArr.length > 0) {
py.append(pinyinArr[0]);
}
} catch (BadHanyuPinyinOutputFormatCombination e) {
py.append("?");
}
} else {
py.append(c); // 英文、数字、符号直接保留
}
}
return py.toString();
}
/**
* Double
*/