From 5cb6a5224aab4c667f6aedf35d9e91aaf7061b85 Mon Sep 17 00:00:00 2001 From: luyya Date: Fri, 17 Apr 2026 17:06:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0ASCII=E7=A0=81=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stwzhj-modules/stwzhj-location/pom.xml | 7 + .../controller/LocationController.java | 211 ++++++++++++++++++ 2 files changed, 218 insertions(+) diff --git a/stwzhj-modules/stwzhj-location/pom.xml b/stwzhj-modules/stwzhj-location/pom.xml index f3fcd9db..aa92ce7b 100644 --- a/stwzhj-modules/stwzhj-location/pom.xml +++ b/stwzhj-modules/stwzhj-location/pom.xml @@ -198,6 +198,13 @@ 0.8 + + com.belerweb + pinyin4j + 2.5.1 + + + diff --git a/stwzhj-modules/stwzhj-location/src/main/java/org/dromara/location/controller/LocationController.java b/stwzhj-modules/stwzhj-location/src/main/java/org/dromara/location/controller/LocationController.java index b9241474..b0cb7afe 100644 --- a/stwzhj-modules/stwzhj-location/src/main/java/org/dromara/location/controller/LocationController.java +++ b/stwzhj-modules/stwzhj-location/src/main/java/org/dromara/location/controller/LocationController.java @@ -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>> getAscii(@RequestBody Map 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> list = searchService.getAllLatestLocationFromEs(type, deptId, zzjgdm, online, minLng, minLat, maxLng, maxLat, deviceCode); + list.removeAll(Collections.singleton(null)); + + // 为每个对象添加ASCII字段 + for (Map item : list) { + StringBuilder sb = new StringBuilder(); + sb.append("DEVICE:"); + boolean first = true; + + for (Map.Entry 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类型参数 */