解决导入时报错的问题
This commit is contained in:
@@ -250,9 +250,11 @@ public class LbDailyUserTradeController {
|
|||||||
@Parameter(description = "Excel文件", required = true)
|
@Parameter(description = "Excel文件", required = true)
|
||||||
@RequestParam("file") MultipartFile file,
|
@RequestParam("file") MultipartFile file,
|
||||||
@Parameter(description = "默认报表日期,格式:yyyy-MM-dd;当Excel行里无报表日期时生效")
|
@Parameter(description = "默认报表日期,格式:yyyy-MM-dd;当Excel行里无报表日期时生效")
|
||||||
@RequestParam(required = false) String defaultReportDate) {
|
@RequestParam(required = false) String defaultReportDate,
|
||||||
|
@Parameter(description = "租户ID(必填,导入时写入每行记录)", required = true)
|
||||||
|
@RequestParam String tenantId) {
|
||||||
try {
|
try {
|
||||||
Map<String, Object> result = lbDailyUserTradeService.importFromExcel(file, defaultReportDate);
|
Map<String, Object> result = lbDailyUserTradeService.importFromExcel(file, defaultReportDate, tenantId);
|
||||||
Boolean success = (Boolean) result.get("success");
|
Boolean success = (Boolean) result.get("success");
|
||||||
if (Boolean.TRUE.equals(success)) {
|
if (Boolean.TRUE.equals(success)) {
|
||||||
return ResponseEntity.ok(result);
|
return ResponseEntity.ok(result);
|
||||||
|
|||||||
@@ -13,5 +13,5 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public interface ILbDailyUserTradeService extends IService<LbDailyUserTrade> {
|
public interface ILbDailyUserTradeService extends IService<LbDailyUserTrade> {
|
||||||
|
|
||||||
Map<String, Object> importFromExcel(MultipartFile file, String defaultReportDate);
|
Map<String, Object> importFromExcel(MultipartFile file, String defaultReportDate, String tenantId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|||||||
import com.rj.entity.LbDailyUserTrade;
|
import com.rj.entity.LbDailyUserTrade;
|
||||||
import com.rj.mapper.LbDailyUserTradeMapper;
|
import com.rj.mapper.LbDailyUserTradeMapper;
|
||||||
import com.rj.service.ILbDailyUserTradeService;
|
import com.rj.service.ILbDailyUserTradeService;
|
||||||
|
import org.apache.poi.poifs.filesystem.FileMagic;
|
||||||
import org.apache.poi.ss.usermodel.Cell;
|
import org.apache.poi.ss.usermodel.Cell;
|
||||||
import org.apache.poi.ss.usermodel.CellType;
|
import org.apache.poi.ss.usermodel.CellType;
|
||||||
import org.apache.poi.ss.usermodel.DataFormatter;
|
import org.apache.poi.ss.usermodel.DataFormatter;
|
||||||
@@ -12,12 +13,19 @@ import org.apache.poi.ss.usermodel.DateUtil;
|
|||||||
import org.apache.poi.ss.usermodel.Row;
|
import org.apache.poi.ss.usermodel.Row;
|
||||||
import org.apache.poi.ss.usermodel.Sheet;
|
import org.apache.poi.ss.usermodel.Sheet;
|
||||||
import org.apache.poi.ss.usermodel.Workbook;
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
import org.apache.poi.ss.usermodel.WorkbookFactory;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
@@ -35,19 +43,26 @@ import java.util.UUID;
|
|||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class LbDailyUserTradeServiceImpl extends ServiceImpl<LbDailyUserTradeMapper, LbDailyUserTrade> implements ILbDailyUserTradeService {
|
public class LbDailyUserTradeServiceImpl extends ServiceImpl<LbDailyUserTradeMapper, LbDailyUserTrade> implements ILbDailyUserTradeService {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(LbDailyUserTradeServiceImpl.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Object> importFromExcel(MultipartFile file, String defaultReportDate) {
|
public Map<String, Object> importFromExcel(MultipartFile file, String defaultReportDate, String tenantId) {
|
||||||
Map<String, Object> result = new HashMap<>();
|
Map<String, Object> result = new HashMap<>();
|
||||||
if (file == null || file.isEmpty()) {
|
if (file == null || file.isEmpty()) {
|
||||||
result.put("success", false);
|
result.put("success", false);
|
||||||
result.put("message", "上传文件不能为空");
|
result.put("message", "上传文件不能为空");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
String originalFilename = file.getOriginalFilename();
|
if (StringUtils.isBlank(tenantId)) {
|
||||||
if (originalFilename == null || !originalFilename.toLowerCase().endsWith(".xlsx")) {
|
|
||||||
result.put("success", false);
|
result.put("success", false);
|
||||||
result.put("message", "仅支持 .xlsx 文件");
|
result.put("message", "tenantId不能为空");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
String normalizedTenantId = tenantId.trim();
|
||||||
|
String originalFilename = file.getOriginalFilename();
|
||||||
|
if (originalFilename == null || !isSupportedExcelSuffix(originalFilename)) {
|
||||||
|
result.put("success", false);
|
||||||
|
result.put("message", "仅支持 .xlsx 或 .xls 文件");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +80,9 @@ public class LbDailyUserTradeServiceImpl extends ServiceImpl<LbDailyUserTradeMap
|
|||||||
List<LbDailyUserTrade> importList = new ArrayList<>();
|
List<LbDailyUserTrade> importList = new ArrayList<>();
|
||||||
List<String> skippedRows = new ArrayList<>();
|
List<String> skippedRows = new ArrayList<>();
|
||||||
DataFormatter dataFormatter = new DataFormatter();
|
DataFormatter dataFormatter = new DataFormatter();
|
||||||
try (Workbook workbook = new XSSFWorkbook(file.getInputStream())) {
|
log.info("开始导入Excel,fileName={}, size={} bytes, defaultReportDate={}",
|
||||||
|
originalFilename, file.getSize(), defaultReportDate);
|
||||||
|
try (Workbook workbook = openWorkbook(file)) {
|
||||||
Sheet sheet = workbook.getSheetAt(0);
|
Sheet sheet = workbook.getSheetAt(0);
|
||||||
if (sheet == null) {
|
if (sheet == null) {
|
||||||
result.put("success", false);
|
result.put("success", false);
|
||||||
@@ -76,7 +93,7 @@ public class LbDailyUserTradeServiceImpl extends ServiceImpl<LbDailyUserTradeMap
|
|||||||
int headerRowNum = findHeaderRow(sheet, dataFormatter);
|
int headerRowNum = findHeaderRow(sheet, dataFormatter);
|
||||||
if (headerRowNum < 0) {
|
if (headerRowNum < 0) {
|
||||||
result.put("success", false);
|
result.put("success", false);
|
||||||
result.put("message", "未识别到表头,请确认模板列包含:租户ID、用户ID、单日卖出金额、当日买入金额等字段");
|
result.put("message", "未识别到表头,请确认模板至少包含:用户ID、单日卖出金额、当日买入金额等字段");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,20 +104,38 @@ public class LbDailyUserTradeServiceImpl extends ServiceImpl<LbDailyUserTradeMap
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
LbDailyUserTrade trade = parseTradeRow(row, headerIndexMap, dataFormatter, fallbackReportDate);
|
LbDailyUserTrade trade = parseTradeRow(row, headerIndexMap, dataFormatter, fallbackReportDate, normalizedTenantId);
|
||||||
if (trade == null) {
|
if (trade == null) {
|
||||||
skippedRows.add(String.valueOf(i + 1));
|
skippedRows.add(String.valueOf(i + 1));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
importList.add(trade);
|
importList.add(trade);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
|
log.warn("解析Excel行失败,rowNum={}, message={}", i + 1, ex.getMessage(), ex);
|
||||||
skippedRows.add((i + 1) + "(" + ex.getMessage() + ")");
|
skippedRows.add((i + 1) + "(" + ex.getMessage() + ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
log.info("Excel解析完成,fileName={}, parsedCount={}, skippedCount={}",
|
||||||
|
originalFilename, importList.size(), skippedRows.size());
|
||||||
|
if (importList.isEmpty()) {
|
||||||
|
log.warn("Excel解析后无有效数据,fileName={}, tenantId={}, skippedRows={}",
|
||||||
|
originalFilename, normalizedTenantId, skippedRows);
|
||||||
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
log.error("读取Excel失败,fileName={}, message={}", originalFilename, e.getMessage(), e);
|
||||||
result.put("success", false);
|
result.put("success", false);
|
||||||
result.put("message", "读取Excel失败:" + e.getMessage());
|
result.put("message", "读取Excel失败:" + e.getMessage());
|
||||||
return result;
|
return result;
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
log.error("Excel格式校验失败,fileName={}, message={}", originalFilename, e.getMessage(), e);
|
||||||
|
result.put("success", false);
|
||||||
|
result.put("message", e.getMessage());
|
||||||
|
return result;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("解析Excel异常,fileName={}, message={}", originalFilename, e.getMessage(), e);
|
||||||
|
result.put("success", false);
|
||||||
|
result.put("message", "解析Excel异常:" + e.getMessage());
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (importList.isEmpty()) {
|
if (importList.isEmpty()) {
|
||||||
@@ -112,11 +147,14 @@ public class LbDailyUserTradeServiceImpl extends ServiceImpl<LbDailyUserTradeMap
|
|||||||
|
|
||||||
boolean saved = this.saveBatch(importList);
|
boolean saved = this.saveBatch(importList);
|
||||||
if (!saved) {
|
if (!saved) {
|
||||||
|
log.error("导入数据保存失败,fileName={}, importCount={}", originalFilename, importList.size());
|
||||||
result.put("success", false);
|
result.put("success", false);
|
||||||
result.put("message", "导入失败,数据库保存异常");
|
result.put("message", "导入失败,数据库保存异常");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.info("导入成功,fileName={}, importCount={}, skipCount={}",
|
||||||
|
originalFilename, importList.size(), skippedRows.size());
|
||||||
result.put("success", true);
|
result.put("success", true);
|
||||||
result.put("message", "导入成功");
|
result.put("message", "导入成功");
|
||||||
result.put("importCount", importList.size());
|
result.put("importCount", importList.size());
|
||||||
@@ -133,7 +171,7 @@ public class LbDailyUserTradeServiceImpl extends ServiceImpl<LbDailyUserTradeMap
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Map<String, Integer> headerMap = buildHeaderIndexMap(row, formatter);
|
Map<String, Integer> headerMap = buildHeaderIndexMap(row, formatter);
|
||||||
if (headerMap.containsKey("tenantId") && headerMap.containsKey("userId")) {
|
if (headerMap.containsKey("userId")) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,10 +217,21 @@ public class LbDailyUserTradeServiceImpl extends ServiceImpl<LbDailyUserTradeMap
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private LbDailyUserTrade parseTradeRow(Row row, Map<String, Integer> headerMap, DataFormatter formatter, LocalDate fallbackReportDate) {
|
private LbDailyUserTrade parseTradeRow(Row row,
|
||||||
String tenantId = readString(row, headerMap.get("tenantId"), formatter);
|
Map<String, Integer> headerMap,
|
||||||
|
DataFormatter formatter,
|
||||||
|
LocalDate fallbackReportDate,
|
||||||
|
String defaultTenantId) {
|
||||||
|
String tenantId = defaultTenantId == null ? "" : defaultTenantId;
|
||||||
String userId = readString(row, headerMap.get("userId"), formatter);
|
String userId = readString(row, headerMap.get("userId"), formatter);
|
||||||
if (tenantId.isEmpty() || userId.isEmpty()) {
|
String nickname = readString(row, headerMap.get("nickname"), formatter);
|
||||||
|
if (userId.isEmpty()) {
|
||||||
|
userId = nickname;
|
||||||
|
}
|
||||||
|
if (userId.isEmpty()) {
|
||||||
|
userId = "AUTO_" + UUID.randomUUID().toString().replace("-", "");
|
||||||
|
}
|
||||||
|
if (tenantId.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,7 +239,7 @@ public class LbDailyUserTradeServiceImpl extends ServiceImpl<LbDailyUserTradeMap
|
|||||||
trade.setId(UUID.randomUUID().toString());
|
trade.setId(UUID.randomUUID().toString());
|
||||||
trade.setTenantId(tenantId);
|
trade.setTenantId(tenantId);
|
||||||
trade.setUserId(userId);
|
trade.setUserId(userId);
|
||||||
trade.setNickname(readString(row, headerMap.get("nickname"), formatter));
|
trade.setNickname(nickname);
|
||||||
trade.setDailySellAmt(readDecimal(row, headerMap.get("dailySellAmt"), formatter));
|
trade.setDailySellAmt(readDecimal(row, headerMap.get("dailySellAmt"), formatter));
|
||||||
trade.setDailyBuyAmt(readDecimal(row, headerMap.get("dailyBuyAmt"), formatter));
|
trade.setDailyBuyAmt(readDecimal(row, headerMap.get("dailyBuyAmt"), formatter));
|
||||||
trade.setPromoterId(readString(row, headerMap.get("promoterId"), formatter));
|
trade.setPromoterId(readString(row, headerMap.get("promoterId"), formatter));
|
||||||
@@ -277,4 +326,166 @@ public class LbDailyUserTradeServiceImpl extends ServiceImpl<LbDailyUserTradeMap
|
|||||||
private String normalizeHeader(String header) {
|
private String normalizeHeader(String header) {
|
||||||
return header == null ? "" : header.toLowerCase().replace(" ", "").replace(" ", "").trim();
|
return header == null ? "" : header.toLowerCase().replace(" ", "").replace(" ", "").trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isSupportedExcelSuffix(String fileName) {
|
||||||
|
String lowerCaseName = fileName.toLowerCase();
|
||||||
|
return lowerCaseName.endsWith(".xlsx") || lowerCaseName.endsWith(".xls");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Workbook openWorkbook(MultipartFile file) throws IOException {
|
||||||
|
byte[] fileBytes = file.getBytes();
|
||||||
|
FileMagic fileMagic = detectFileMagic(fileBytes);
|
||||||
|
try {
|
||||||
|
return WorkbookFactory.create(new ByteArrayInputStream(fileBytes));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("标准Excel解析失败,尝试文本格式兜底,fileName={}, fileMagic={}, contentType={}, headHex={}",
|
||||||
|
file.getOriginalFilename(), fileMagic, file.getContentType(), toHexPreview(fileBytes, 16));
|
||||||
|
Workbook textWorkbook = tryCreateWorkbookFromText(fileBytes, file.getOriginalFilename());
|
||||||
|
if (textWorkbook != null) {
|
||||||
|
log.info("文本格式兜底解析成功,fileName={}", file.getOriginalFilename());
|
||||||
|
return textWorkbook;
|
||||||
|
}
|
||||||
|
log.error("文本格式兜底也失败,fileName={}, fileMagic={}, contentType={}",
|
||||||
|
file.getOriginalFilename(), fileMagic, file.getContentType(), e);
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"上传文件内容不是有效的Excel文件,请确认文件未损坏,且不要仅修改后缀名。检测到文件签名:" + fileMagic, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private FileMagic detectFileMagic(byte[] fileBytes) throws IOException {
|
||||||
|
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(fileBytes)) {
|
||||||
|
return FileMagic.valueOf(FileMagic.prepareToCheckMagic(inputStream));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Workbook tryCreateWorkbookFromText(byte[] fileBytes, String fileName) {
|
||||||
|
for (Charset charset : List.of(StandardCharsets.UTF_8, Charset.forName("GBK"))) {
|
||||||
|
try {
|
||||||
|
Workbook workbook = createWorkbookFromDelimitedText(fileBytes, charset);
|
||||||
|
if (workbook != null) {
|
||||||
|
log.info("文本文件按分隔格式解析成功,fileName={}, charset={}", fileName, charset.name());
|
||||||
|
return workbook;
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
log.debug("文本格式兜底解析失败,fileName={}, charset={}, message={}",
|
||||||
|
fileName, charset.name(), ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Workbook createWorkbookFromDelimitedText(byte[] fileBytes, Charset charset) throws IOException {
|
||||||
|
List<String> lines = new ArrayList<>();
|
||||||
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(fileBytes), charset))) {
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
if (!line.trim().isEmpty()) {
|
||||||
|
lines.add(removeUtf8Bom(line));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lines.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
char delimiter = detectDelimiter(lines.get(0));
|
||||||
|
if (delimiter == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<List<String>> parsedRows = new ArrayList<>();
|
||||||
|
int maxColumns = 0;
|
||||||
|
for (String line : lines) {
|
||||||
|
List<String> cells = parseDelimitedLine(line, delimiter);
|
||||||
|
if (cells.size() > 1) {
|
||||||
|
parsedRows.add(cells);
|
||||||
|
maxColumns = Math.max(maxColumns, cells.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (parsedRows.isEmpty() || maxColumns < 2) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Workbook workbook = WorkbookFactory.create(true);
|
||||||
|
Sheet sheet = workbook.createSheet("Sheet1");
|
||||||
|
for (int rowIndex = 0; rowIndex < parsedRows.size(); rowIndex++) {
|
||||||
|
Row row = sheet.createRow(rowIndex);
|
||||||
|
List<String> cells = parsedRows.get(rowIndex);
|
||||||
|
for (int colIndex = 0; colIndex < cells.size(); colIndex++) {
|
||||||
|
row.createCell(colIndex).setCellValue(cells.get(colIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return workbook;
|
||||||
|
}
|
||||||
|
|
||||||
|
private char detectDelimiter(String line) {
|
||||||
|
int tabCount = countChar(line, '\t');
|
||||||
|
int commaCount = countChar(line, ',');
|
||||||
|
int semicolonCount = countChar(line, ';');
|
||||||
|
if (tabCount > 0 && tabCount >= commaCount && tabCount >= semicolonCount) {
|
||||||
|
return '\t';
|
||||||
|
}
|
||||||
|
if (commaCount > 0 && commaCount >= semicolonCount) {
|
||||||
|
return ',';
|
||||||
|
}
|
||||||
|
if (semicolonCount > 0) {
|
||||||
|
return ';';
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int countChar(String text, char ch) {
|
||||||
|
int count = 0;
|
||||||
|
for (int i = 0; i < text.length(); i++) {
|
||||||
|
if (text.charAt(i) == ch) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> parseDelimitedLine(String line, char delimiter) {
|
||||||
|
List<String> cells = new ArrayList<>();
|
||||||
|
StringBuilder current = new StringBuilder();
|
||||||
|
boolean inQuotes = false;
|
||||||
|
for (int i = 0; i < line.length(); i++) {
|
||||||
|
char c = line.charAt(i);
|
||||||
|
if (c == '"') {
|
||||||
|
if (inQuotes && i + 1 < line.length() && line.charAt(i + 1) == '"') {
|
||||||
|
current.append('"');
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
inQuotes = !inQuotes;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c == delimiter && !inQuotes) {
|
||||||
|
cells.add(current.toString().trim());
|
||||||
|
current.setLength(0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
current.append(c);
|
||||||
|
}
|
||||||
|
cells.add(current.toString().trim());
|
||||||
|
return cells;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String removeUtf8Bom(String line) {
|
||||||
|
if (!line.isEmpty() && line.charAt(0) == '\uFEFF') {
|
||||||
|
return line.substring(1);
|
||||||
|
}
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String toHexPreview(byte[] bytes, int len) {
|
||||||
|
int size = Math.min(bytes.length, len);
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
sb.append(String.format("%02X", bytes[i]));
|
||||||
|
if (i < size - 1) {
|
||||||
|
sb.append(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user