导入导出通用实现

This commit is contained in:
yuejiajun 2025-10-15 17:02:21 +08:00
parent 091b281544
commit 4f6b03cd53
9 changed files with 226 additions and 8 deletions

View File

@ -3,20 +3,26 @@ package com.example.demo.common.typography;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import cn.zhxu.bs.BeanSearcher; import cn.zhxu.bs.BeanSearcher;
import cn.zhxu.bs.SearchResult; import cn.zhxu.bs.SearchResult;
import cn.zhxu.bs.operator.Contain; import cn.zhxu.bs.operator.Contain;
import cn.zhxu.bs.util.MapUtils; import cn.zhxu.bs.util.MapUtils;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.example.demo.common.constant.GlobalConstants; import com.example.demo.common.constant.GlobalConstants;
import com.example.demo.common.domain.BaseDTO; import com.example.demo.common.domain.BaseDTO;
import com.example.demo.common.domain.BaseEntity; import com.example.demo.common.domain.BaseEntity;
import com.example.demo.common.domain.BaseQueryDTO; import com.example.demo.common.domain.BaseQueryDTO;
import com.example.demo.common.domain.BaseVO; import com.example.demo.common.domain.BaseVO;
import com.example.demo.common.exception.BusinessException;
import com.fhs.trans.service.impl.TransService; import com.fhs.trans.service.impl.TransService;
import com.mybatisflex.core.BaseMapper; import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.spring.service.impl.ServiceImpl; import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy; import jakarta.annotation.PreDestroy;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.DisposableBean;
@ -24,8 +30,12 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -59,6 +69,9 @@ public abstract class BaseServiceImpl<
/** 实际业务实现VO类 */ /** 实际业务实现VO类 */
private final Class<VO> clazzVO; private final Class<VO> clazzVO;
/** 实际业务实现Entity类 */
private final Class<Entity> clazzEntity;
/** 提供Select服务 */ /** 提供Select服务 */
private final BeanSearcher beanSearcher; private final BeanSearcher beanSearcher;
@ -164,12 +177,160 @@ public abstract class BaseServiceImpl<
return wordVO; return wordVO;
} }
@Override
public Object importDetail(String line) {
log.warn("导入细节(暂无实现)");
JSONObject jsonObject = JSON.parseObject(line);
jsonObject.get("ts");
jsonObject.get("");
Entity entity = JSON.parseObject(line, clazzEntity);
Map<String, String> result = new HashMap<>();
// 默认导入失败
result.put("state", "error");
if(ObjectUtil.isNotEmpty(detail(entity.getId()))) {
result.put("id", entity.getId());
if(StrUtil.isNotBlank(entity.getName())) {
result.put("name", entity.getName());
}
return result;
}
// TODO 解密校验完整性
// 设置默认值
if (entity.getIsDeleted() == null) {
entity.setIsDeleted(Integer.valueOf(GlobalConstants.N));
}
// 保存到数据库
boolean flag = save(entity);
if (flag) {
result.put("state", "success");
}
return null;
}
@Override
public Object exportDetail(String id) {
log.warn("导出细节(暂无实现)");
return null;
}
@Override @Override
public void refreshCache() { public void refreshCache() {
// ignore // ignore
log.warn("刷新缓存(暂无实现)"); log.warn("刷新缓存(暂无实现)");
} }
@Override
public Map<String, String> importJSONLData(String content) {
Map<String, String> result = new HashMap<>();
int successCount = 0;
int failCount = 0;
List<String> errors = new ArrayList<>();
try {
// 按行分割JSONL数据
String[] lines = content.split("\n");
for (int i = 0; i < lines.length; i++) {
String line = lines[i].trim();
if (line.isEmpty()) continue;
try {
// 解析每一行JSON为Entity对象
// 使用try-catch块忽略无法转化的数据继续处理下一行
importDetail(line);
successCount++;
} catch (Exception e) {
// 记录失败信息但继续处理下一行数据
failCount++;
errors.add("" + (i + 1) + "行导入失败: " + e.getMessage());
log.warn("忽略无法解析的JSON数据行[{}]: {}", i + 1, line);
// 继续处理下一行不抛出异常中断整体流程
continue;
}
}
result.put("successCount", String.valueOf(successCount));
result.put("failCount", String.valueOf(failCount));
result.put("errors", String.join("\n", errors));
result.put("message", "导入完成,成功 " + successCount + " 条,失败 " + failCount + "");
} catch (Exception e) {
result.put("error", "解析JSONL数据失败: " + e.getMessage());
result.put("successCount", "0");
result.put("failCount", "0");
result.put("message", "导入失败");
}
return result;
}
@Override
public void exportJSONLData(HttpServletResponse response, List<String> ids) {
try {
if (ids == null || ids.isEmpty()) {
throw new BusinessException("导出ID列表不能为空");
}
// 验证并获取所有要导出的数据
List<Object> list = new ArrayList<>();
for (String id : ids) {
try {
// 使用detail方法验证ID是否存在并获取数据
Object templateVO = exportDetail(id);
if (templateVO == null) {
throw new BusinessException("不存在: " + id);
}
// 添加到导出列表
list.add(templateVO);
} catch (Exception e) {
// ignore
}
}
// 准备文件流和文件名列表用于压缩
List<String> fileNameUniqueList = new ArrayList<>();
List<InputStream> inputStreams = new ArrayList<>();
// 创建一个JSONL文件包含所有模板数据每行一个JSON对象
StringBuilder jsonlContent = new StringBuilder();
for (Object object : list) {
String jsonContent = JSON.toJSONString(object);
// TODO 加密
jsonlContent.append(jsonContent).append("\n");
}
// 转换为数组
String[] fileNamesArr = fileNameUniqueList.toArray(new String[0]);
InputStream[] inputStreamsArr = inputStreams.toArray(new InputStream[0]);
// 使用ZipUtil进行压缩下载
try {
ZipUtil.zip(response.getOutputStream(), fileNamesArr, inputStreamsArr);
} catch (IOException e) {
throw new BusinessException("压缩下载失败: " + e.getMessage());
} finally {
// 关闭所有输入流
for (InputStream inputStream : inputStreams) {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
// 忽略关闭流的异常
}
}
}
} catch (BusinessException e) {
// 直接抛出业务异常保留原始错误信息
throw e;
} catch (Exception e) {
throw new BusinessException("导出JSONL数据失败: " + e.getMessage());
}
}
@PostConstruct @PostConstruct
public void init() { public void init() {
// ignore // ignore
@ -270,4 +431,29 @@ public abstract class BaseServiceImpl<
ParameterizedType parameterizedType = (ParameterizedType) superClass; ParameterizedType parameterizedType = (ParameterizedType) superClass;
return (Class<DTO>) parameterizedType.getActualTypeArguments()[2]; return (Class<DTO>) parameterizedType.getActualTypeArguments()[2];
} }
/**
* 确保密钥字节数组为指定长度
* @param key 原始密钥字符串
* @param length 所需长度
* @return 调整后的密钥字节数组
*/
private static byte[] ensureKeyLength(String key, int length) {
byte[] keyBytes = key.getBytes(java.nio.charset.StandardCharsets.UTF_8);
if (keyBytes.length == length) {
return keyBytes;
} else if (keyBytes.length > length) {
// 如果太长则截取
byte[] result = new byte[length];
System.arraycopy(keyBytes, 0, result, 0, length);
return result;
} else {
// 如果太短则填充0或者您可以选择其他填充方式
byte[] result = new byte[length];
System.arraycopy(keyBytes, 0, result, 0, keyBytes.length);
// 剩余部分默认为0
return result;
}
}
} }

View File

@ -37,7 +37,11 @@ public class ConditionMapServiceImpl
BeanSearcher beanSearcher, BeanSearcher beanSearcher,
TransService transService TransService transService
) { ) {
super(log, ConditionMapServiceImpl.class.getSimpleName(), ConditionMapVO.class, beanSearcher, transService); super(log,
ConditionMapServiceImpl.class.getSimpleName(),
ConditionMapVO.class,
ConditionMapEntity.class,
beanSearcher, transService);
} }
} }

View File

@ -37,7 +37,11 @@ public class ConfigDocumentServiceImpl
BeanSearcher beanSearcher, BeanSearcher beanSearcher,
TransService transService TransService transService
) { ) {
super(log, ConfigDocumentServiceImpl.class.getSimpleName(), ConfigDocumentVO.class, beanSearcher, transService); super(log,
ConfigDocumentServiceImpl.class.getSimpleName(),
ConfigDocumentVO.class,
ConfigDocumentEntity.class,
beanSearcher, transService);
} }
} }

View File

@ -37,7 +37,11 @@ public class ConfigValueServiceImpl
BeanSearcher beanSearcher, BeanSearcher beanSearcher,
TransService transService TransService transService
) { ) {
super(log, ConfigValueServiceImpl.class.getSimpleName(), ConfigValueVO.class, beanSearcher, transService); super(log,
ConfigValueServiceImpl.class.getSimpleName(),
ConfigValueVO.class,
ConfigValueEntity.class,
beanSearcher, transService);
} }
} }

View File

@ -37,6 +37,10 @@ public class FileRecordServiceImpl
BeanSearcher beanSearcher, BeanSearcher beanSearcher,
TransService transService TransService transService
) { ) {
super(log, FileRecordServiceImpl.class.getSimpleName(), FileRecordVO.class, beanSearcher, transService); super(log,
FileRecordServiceImpl.class.getSimpleName(),
FileRecordVO.class,
FileRecordEntity.class,
beanSearcher, transService);
} }
} }

View File

@ -37,7 +37,11 @@ public class LevelConfigServiceImpl
BeanSearcher beanSearcher, BeanSearcher beanSearcher,
TransService transService TransService transService
) { ) {
super(log, LevelConfigServiceImpl.class.getSimpleName(), LevelConfigVO.class, beanSearcher, transService); super(log,
LevelConfigServiceImpl.class.getSimpleName(),
LevelConfigVO.class,
LevelConfigEntity.class,
beanSearcher, transService);
} }
} }

View File

@ -38,7 +38,11 @@ public class MapperRuleServiceImpl
BeanSearcher beanSearcher, BeanSearcher beanSearcher,
TransService transService TransService transService
) { ) {
super(log, MapperRuleServiceImpl.class.getSimpleName(), MapperRuleVO.class, beanSearcher, transService); super(log,
MapperRuleServiceImpl.class.getSimpleName(),
MapperRuleVO.class,
MapperRuleEntity.class,
beanSearcher, transService);
} }
} }

View File

@ -38,7 +38,11 @@ public class ParseRuleServiceImpl
BeanSearcher beanSearcher, BeanSearcher beanSearcher,
TransService transService TransService transService
) { ) {
super(log, ParseRuleServiceImpl.class.getSimpleName(), ParseRuleVO.class, beanSearcher, transService); super(log,
ParseRuleServiceImpl.class.getSimpleName(),
ParseRuleVO.class,
ParseRuleEntity.class,
beanSearcher, transService);
} }
} }

View File

@ -37,7 +37,11 @@ public class ValueConfigServiceImpl
BeanSearcher beanSearcher, BeanSearcher beanSearcher,
TransService transService TransService transService
) { ) {
super(log, ValueConfigServiceImpl.class.getSimpleName(), ValueConfigVO.class, beanSearcher, transService); super(log,
ValueConfigServiceImpl.class.getSimpleName(),
ValueConfigVO.class,
ValueConfigEntity.class,
beanSearcher, transService);
} }
} }