feat(rfid/RfidReadRecord): 优化设备记录条码空格及不可见字符处理

- 在Mapper层统一对barcode字段使用TRIM函数去除前后空格
- 在Service层增加正则表达式清理barcode中所有不可见字符(空格、NULL字符、控制字符)
- 读取记录查询接口调用后,对结果中的barcode调用清理方法确保返回纯业务字符
- 添加barcode清理相关私有方法cleanBarcode和cleanBarcodeList以便复用
- RFID业务逻辑文档中补充分页查询和条码空格符处理说明,明确设备返回条码清理细节
main
zangch@mesnac.com 3 weeks ago
parent 6878770490
commit 88b697e00e

@ -58,8 +58,15 @@
# 业务逻辑 # 业务逻辑
## 设备记录成功率逻辑 ## 设备记录
- ### 分页查询
- 分页查询逻辑参考rfid-middleware\ruoyi-modules\hw-rfid\ShardingQuery.md文档
### 条码信息显示空格符号的空格处理
- 202020202020205357303034 设备返回的这个 20 转成 ascii 是个空格
- 条码信息原始值可能包含空格(0x20) 和 NULL 字符(0x00) 等不可见字符,例如设备返回 `202020202020205357303034`,其中 `20` 转成 ASCII 是空格。
- Mapper 层在 `RfidReadRecordMapper.xml` 中对 `barcode` 使用 `TRIM(t.barcode) as barcode` 去掉前后空格,但对 NULL/控制字符无效SQL 的 `TRIM()` 只能去除标准空格 ASCII 32
- Service 层在 `RfidReadRecordServiceImpl` 中通过 `cleanBarcodeList / cleanBarcode`,使用正则 `Pattern.compile("[\\s\\x00-\\x1F\\x7F]+")` 清理所有不可见字符,只保留业务字符,最终前端看到的条码为无空格的纯业务值(例如 `QNC006`)。
### 设备记录成功率逻辑
- 成功率统计接口:`GET /rfid/dashboard/successRate`按小时023 点)返回折线图数据,用于前端折线图展示. - 成功率统计接口:`GET /rfid/dashboard/successRate`按小时023 点)返回折线图数据,用于前端折线图展示.
- 统计维度:后端自动以当前系统日期作为“今日”,**同时统计昨日同一小时的成功率**,前端无需传任何查询参数. - 统计维度:后端自动以当前系统日期作为“今日”,**同时统计昨日同一小时的成功率**,前端无需传任何查询参数.
- 分表与时间范围:分别通过 `RfidReadRecordTableHelper.getTableName(今日)``RfidReadRecordTableHelper.getTableName(昨日)` 生成当日与昨日分表(如 `rfid_read_record_20251126`),各自只统计 `00:00:00``23:59:59` 之间的读取记录. - 分表与时间范围:分别通过 `RfidReadRecordTableHelper.getTableName(今日)``RfidReadRecordTableHelper.getTableName(昨日)` 生成当日与昨日分表(如 `rfid_read_record_20251126`),各自只统计 `00:00:00``23:59:59` 之间的读取记录.

@ -24,6 +24,7 @@ import org.dromara.rfid.service.IRfidReadRecordService;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Collection; import java.util.Collection;
import java.util.regex.Pattern;
/** /**
* Service * Service
@ -41,6 +42,12 @@ public class RfidReadRecordServiceImpl implements IRfidReadRecordService {
private final RfidReadRecordMapper baseMapper; private final RfidReadRecordMapper baseMapper;
/**
* NULL
* NULL(\x00)
*/
private static final Pattern BARCODE_CLEAN_PATTERN = Pattern.compile("[\\s\\x00-\\x1F\\x7F]+");
/** /**
* *
* *
@ -51,7 +58,10 @@ public class RfidReadRecordServiceImpl implements IRfidReadRecordService {
@Override @Override
public RfidReadRecordVo queryById(Long id, Date queryDate) { public RfidReadRecordVo queryById(Long id, Date queryDate) {
String tableName = RfidReadRecordTableHelper.getTableName(queryDate); String tableName = RfidReadRecordTableHelper.getTableName(queryDate);
return baseMapper.selectCustomRfidReadRecordVoById(tableName, id); RfidReadRecordVo record = baseMapper.selectCustomRfidReadRecordVoById(tableName, id);
// 清理条码中的不可见字符
cleanBarcode(record);
return record;
} }
/** /**
@ -81,6 +91,9 @@ public class RfidReadRecordServiceImpl implements IRfidReadRecordService {
? baseMapper.selectCustomRfidReadRecordVoPage(tableNames.get(0), pageQuery.build(), lqw) ? baseMapper.selectCustomRfidReadRecordVoPage(tableNames.get(0), pageQuery.build(), lqw)
: baseMapper.selectCustomRfidReadRecordVoPageMultiTable(tableNames, pageQuery.build(), lqw); : baseMapper.selectCustomRfidReadRecordVoPageMultiTable(tableNames, pageQuery.build(), lqw);
// 清理条码中的不可见字符
cleanBarcodeList(result.getRecords());
return TableDataInfo.build(result); return TableDataInfo.build(result);
} }
@ -112,15 +125,22 @@ public class RfidReadRecordServiceImpl implements IRfidReadRecordService {
// 采样查询:每 N 分钟取一条代表数据 // 采样查询:每 N 分钟取一条代表数据
// tableNames.size() == 1 表示只涉及一张分表直接调用单表采样SQL // tableNames.size() == 1 表示只涉及一张分表直接调用单表采样SQL
// 否则说明跨多天/多张分表调用多表采样SQL进行 UNION ALL 聚合。 // 否则说明跨多天/多张分表调用多表采样SQL进行 UNION ALL 聚合。
return tableNames.size() == 1 List<RfidReadRecordVo> sampledRecords = tableNames.size() == 1
? baseMapper.selectWithSampling(tableNames.get(0), samplingInterval, lqw) ? baseMapper.selectWithSampling(tableNames.get(0), samplingInterval, lqw)
: baseMapper.selectWithSamplingMultiTable(tableNames, samplingInterval, lqw); : baseMapper.selectWithSamplingMultiTable(tableNames, samplingInterval, lqw);
// 清理条码中的不可见字符
cleanBarcodeList(sampledRecords);
return sampledRecords;
} }
// 普通查询 // 普通查询
return tableNames.size() == 1 List<RfidReadRecordVo> records = tableNames.size() == 1
? baseMapper.selectCustomRfidReadRecordVoList(tableNames.get(0), lqw) ? baseMapper.selectCustomRfidReadRecordVoList(tableNames.get(0), lqw)
: baseMapper.selectCustomRfidReadRecordVoListMultiTable(tableNames, lqw); : baseMapper.selectCustomRfidReadRecordVoListMultiTable(tableNames, lqw);
// 清理条码中的不可见字符
cleanBarcodeList(records);
return records;
} }
/** /**
@ -151,6 +171,53 @@ public class RfidReadRecordServiceImpl implements IRfidReadRecordService {
return lqw; return lqw;
} }
/**
*
*
* @param records
*/
private void cleanBarcodeList(List<RfidReadRecordVo> records) {
if (CollUtil.isEmpty(records)) {
return;
}
for (RfidReadRecordVo record : records) {
cleanBarcode(record);
}
}
/**
*
* <p>
* (0x20)NULL(0x00)
*
* </p>
*
* @param record
*/
private void cleanBarcode(RfidReadRecordVo record) {
if (record == null || record.getBarcode() == null) {
return;
}
String originalBarcode = record.getBarcode();
// 使用正则替换所有不可见字符,仅保留可见业务字符
String cleanedBarcode = BARCODE_CLEAN_PATTERN.matcher(originalBarcode).replaceAll("");
record.setBarcode(cleanedBarcode);
}
/**
*
*/
private String toHexString(String str) {
if (str == null) {
return "null";
}
StringBuilder sb = new StringBuilder();
for (char c : str.toCharArray()) {
sb.append(String.format("%02X ", (int) c));
}
return sb.toString().trim();
}
/** /**
* *
* <p> * <p>

@ -14,7 +14,7 @@
d.device_code as deviceCode, d.device_code as deviceCode,
d.device_name as deviceName, d.device_name as deviceName,
t.read_status, t.read_status,
t.barcode, TRIM(t.barcode) as barcode,
t.record_time, t.record_time,
t.alarm_flag, t.alarm_flag,
t.alarm_level, t.alarm_level,
@ -36,7 +36,7 @@
d.device_code as deviceCode, d.device_code as deviceCode,
d.device_name as deviceName, d.device_name as deviceName,
combined.read_status, combined.read_status,
combined.barcode, TRIM(combined.barcode) as barcode,
combined.record_time, combined.record_time,
combined.alarm_flag, combined.alarm_flag,
combined.alarm_level, combined.alarm_level,
@ -47,7 +47,7 @@
select t.id, select t.id,
t.device_id, t.device_id,
t.read_status, t.read_status,
t.barcode, TRIM(t.barcode) as barcode,
t.record_time, t.record_time,
t.alarm_flag, t.alarm_flag,
t.alarm_level, t.alarm_level,
@ -70,7 +70,7 @@
d.device_code as deviceCode, d.device_code as deviceCode,
d.device_name as deviceName, d.device_name as deviceName,
t.read_status, t.read_status,
t.barcode, TRIM(t.barcode) as barcode,
t.record_time, t.record_time,
t.alarm_flag, t.alarm_flag,
t.alarm_level, t.alarm_level,
@ -88,7 +88,7 @@
d.device_code as deviceCode, d.device_code as deviceCode,
d.device_name as deviceName, d.device_name as deviceName,
t.read_status, t.read_status,
t.barcode, TRIM(t.barcode) as barcode,
t.record_time, t.record_time,
t.alarm_flag, t.alarm_flag,
t.alarm_level, t.alarm_level,
@ -131,7 +131,7 @@
d.device_code as deviceCode, d.device_code as deviceCode,
d.device_name as deviceName, d.device_name as deviceName,
t.read_status, t.read_status,
t.barcode, TRIM(t.barcode) as barcode,
t.record_time, t.record_time,
t.alarm_flag, t.alarm_flag,
t.alarm_level, t.alarm_level,
@ -153,7 +153,7 @@
d.device_code as deviceCode, d.device_code as deviceCode,
d.device_name as deviceName, d.device_name as deviceName,
combined.read_status, combined.read_status,
combined.barcode, TRIM(combined.barcode) as barcode,
combined.record_time, combined.record_time,
combined.alarm_flag, combined.alarm_flag,
combined.alarm_level, combined.alarm_level,
@ -164,7 +164,7 @@
select t.id, select t.id,
t.device_id, t.device_id,
t.read_status, t.read_status,
t.barcode, TRIM(t.barcode) as barcode,
t.record_time, t.record_time,
t.alarm_flag, t.alarm_flag,
t.alarm_level, t.alarm_level,
@ -355,7 +355,7 @@
d.device_code as deviceCode, d.device_code as deviceCode,
d.device_name as deviceName, d.device_name as deviceName,
t.read_status, t.read_status,
t.barcode, TRIM(t.barcode) as barcode,
t.record_time, t.record_time,
t.alarm_flag, t.alarm_flag,
t.alarm_level, t.alarm_level,
@ -400,7 +400,7 @@
d.device_name as deviceName, d.device_name as deviceName,
l.location_alias as locationAlias, l.location_alias as locationAlias,
t.read_status, t.read_status,
t.barcode, TRIM(t.barcode) as barcode,
t.record_time, t.record_time,
t.alarm_flag, t.alarm_flag,
t.alarm_level, t.alarm_level,
@ -425,7 +425,7 @@
d.device_code as deviceCode, d.device_code as deviceCode,
d.device_name as deviceName, d.device_name as deviceName,
t1.read_status, t1.read_status,
t1.barcode, TRIM(t1.barcode) as barcode,
t1.record_time, t1.record_time,
t1.alarm_flag, t1.alarm_flag,
t1.alarm_level, t1.alarm_level,
@ -456,7 +456,7 @@
d.device_code as deviceCode, d.device_code as deviceCode,
d.device_name as deviceName, d.device_name as deviceName,
sampled.read_status, sampled.read_status,
sampled.barcode, TRIM(sampled.barcode) as barcode,
sampled.record_time, sampled.record_time,
sampled.alarm_flag, sampled.alarm_flag,
sampled.alarm_level, sampled.alarm_level,
@ -467,7 +467,7 @@
select t1.id, select t1.id,
t1.device_id, t1.device_id,
t1.read_status, t1.read_status,
t1.barcode, TRIM(t1.barcode) as barcode,
t1.record_time, t1.record_time,
t1.alarm_flag, t1.alarm_flag,
t1.alarm_level, t1.alarm_level,

Loading…
Cancel
Save