添加ASCII码支持
parent
7b3586d48c
commit
5cb6a5224a
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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类型参数
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in New Issue