이 글은 EasyExcel의 읽기(읽기)만 기록합니다.
1. EasyExcel은 무엇을 합니까?
먼저 EasyExcel에 대한 설명을 살펴보겠습니다:
EasyExcel은 Alibaba에서 오픈 소스로 제공하는 Excel 처리 프레임워크입니다.Java 기반의 Excel을 읽고 쓰기 위한 간단하고 메모리 절약형 오픈 소스 프로젝트입니다. EasyExcel이 메모리 사용량을 크게 줄일 수 있는 주된 이유는 Excel을 파싱할 때 모든 파일 데이터를 한 번에 메모리에 로드하는 것이 아니라 디스크에서 데이터를 한 줄씩 읽어서 하나씩 파싱하기 때문입니다.
오픈소스 주소:
깃허브 주소: https://github.com/alibaba/easyexcel
(코드만 봐도 아직 좀 헷갈리네요. 샤오포역에서 관련 영상 찾아봤는데 크레이지갓 영상에 명쾌하게 설명되어 있네요. . 거의 직접 그가 말한 대로 하십시오. 물론 실제 상황에 따라 적절하게 변경해야 합니다.)
2. 프로젝트 배경
내가 만든 작은 프로젝트는 엑셀 테이블의 데이터를 데이터베이스로 가져와야 하는데 일부 데이터 열에는 [{…},{…},{…},{… 수작업이나 엑셀은 현실적이지 않기 때문에 하나씩 필드로 데이터베이스에 저장해야 합니다. 그래서 이 프레임워크의 사용법을 이해하러 갔습니다.
Excel은 다음과 같습니다.
참고: Excel은 엔터티 클래스에 해당하는 매개 변수 열에서 직접 읽기 시작하므로 헤더가 없습니다.
3. 구체적인 이용절차
1. pom.xml 구성을 추가해야 합니다.
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
2. 코드에는 세 단계가 있습니다.
- Excel에 해당하는 엔티티 개체 Dao 클래스를 만듭니다.
- 쓰기 리스너: 기본적으로 엑셀을 한 줄씩 읽는 것이므로 한 줄씩 엑셀에 대한 콜백 리스너를 만들어야 합니다.리스너는 주로 읽기 및 저장을 실현합니다.
- 리스너 호출: Excel의 위치를 구성하고 리스너를 호출하여 테이블을 읽은 다음 데이터베이스에 저장합니다.
1단계: 엑셀에 해당하는 엔터티 클래스 생성
추신 : @ExcelProperty 주석을 사용하여
해당 Excel 열
"저항 테스트 데이터"에 해당하는 엔터티 클래스 를 설명합니다(여기에서 설명해야 함, 당시 Excel에서 4개의 매개 변수 이름을 모두 해당 영어 이름으로 대체했습니다).
데이터베이스에 저장된 테이블 구조가 Excel에 해당하는 엔터티 클래스와 다릅니다(예를 들어 필드 읽기가 위 그림에서 Excel의 "저항 테스트 데이터"와 같은 배열 개체 구조인 경우 다음이 필요합니다. 처리하여 여러 필드로 분할하여 데이터베이스에 별도로 저장할 수 있음), 모든 데이터를 수신하여 데이터베이스에 저장하려면 데이터베이스의 테이블에 해당하는 추가 클래스를 (약간) 생성해야 합니다.
데이터베이스에서 생성한 테이블:
2단계: 리스너 작성
리스너 구현
/**
* Date:2021/10/20
* Description: excel一行一行的回调监听器
*
* @author ivyhu
*/
@Component
public class DemoDataListener extends AnalysisEventListener<ExcelModel> {
@Resource
ChargingStationMapper charingStationResistanceReportMapper;
@Resource
CharingStationServiceImpl charingStationServiceImpl;
private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class);
/**
* 有参构造
* 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
* @param serviceImpl
*/
public DemoDataListener(CharingStationServiceImpl serviceImpl) {
this.charingStationServiceImpl = serviceImpl;
}
//无参构造
public DemoDataListener() {
}
/**
* 读取数据或执行这个invoke()方法
* @param excelModel 类型
* @param context 分析器
*/
@Override
public void invoke(ExcelModel excelModel, AnalysisContext context) {
LOGGER.info("解析到一条数据:{}", JSON.toJSONString(excelModel));
//最终要保存到数据库的数据
ChargingStationModel reportModelData = new ChargingStationModel();
String productModelNum = "";
String itemNo = "";
Double groundResistance = 0.0;
Double insulationResistance = 0.0;
Byte type = 0;
Integer singlePilePower = 0;
/**
* 获取excel表中充电设施产品信息
*/
String str1 = excelModel.getInfoData();
JSONArray array1 = JSON.parseArray(str1);
//如果不为空,就解析[{},{},{},{}]类型的数组对象并获取值
if (!ObjectUtils.isEmpty(array1)) {
for (Object obj : array1) {
JSONObject jsonObject = (JSONObject) obj;
ChargingStationInfoDataExcelModel infoExcelModel = JSONObject.parseObject(String.valueOf((JSONObject) obj), ChargingStationInfoDataExcelModel.class);
type = infoExcelModel.getType();
singlePilePower = infoExcelModel.getSinglePilePower();
}
}
/**
* 获取excel表中电阻测试数据
*/
String str = excelModel.getResistanceData();
JSONArray array = JSON.parseArray(str);
//电阻测试数据不为空,就解析[{},{},{},{}]类型的数组对象并获取值
if (!ObjectUtils.isEmpty(array)) {
for (Object obj : array) {
JSONObject jsonObject = (JSONObject) obj;
ChargingStationResistanceDataExcelModel reportModel = JSONObject.parseObject(String.valueOf((JSONObject) obj), ChargingStationResistanceDataExcelModel.class);
productModelNum = reportModel.getProductModelNum();
itemNo = reportModel.getItemNo();
groundResistance = reportModel.getGroundResistance();
insulationResistance = reportModel.getInsulationResistance();
//插入数据到数据库
reportModelData = new ChargingStationModel(excelModel.getReportNo(), excelModel.getModelNum(), productModelNum, itemNo, groundResistance, insulationResistance, type, singlePilePower,
excelModel.getOutputVoltageControlErrorOfCharger(), excelModel.getOutputCurrentControlErrorOfCharger(), excelModel.getActiveStopChargeTestOutputCurrentStopRate(), excelModel.getPassiveStopChargeTestOutputCurrentStopRate(),
excelModel.getChargerOutputCurrentAdjustmentTimeAbove20A(), excelModel.getChargerOutputCurrentAdjustmentTimeUnder20A(), excelModel.getImpulseCurrent());
saveData(reportModelData);
}
}
}
/**
* 所有数据解析完成了 都会来调用
*
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
/*saveData();*/
LOGGER.info("所有数据解析完成!");
}
/**
* 加上存储数据库
*/
private void saveData(ChargingStationModel resistanceReportModel) {
//调用mapper插入数据库
charingStationServiceImpl.save(resistanceReportModel);
}
}
3단계: 수신기를 호출하여 데이터 읽기
1. 컨트롤러 계층
@RestController
@Controller
@RequestMapping("/product/charging_station")
public class ChargingStationController {
@Resource
CharingStationService charingStationService;
/**
* 提取excel表格数据的接口
*/
@PostMapping()
public void saveExcel(){
charingStationService.saveData();
}
}
2. 서비스 레이어
@Service
public class CharingStationServiceImpl implements CharingStationService {
@Resource
ChargingStationMapper chargingStationMapper;
@Resource
ExcelUtil excelUtil;
@Resource
ChargingStationAcceptanceValueMapper chargingStationAcceptanceValueMapper;
/**
* 调用读取excel数据的方法
*/
@Override
public void saveData() {
excelUtil.excelRead();
}
3. 리스너 항목
엑셀에 해당하는 파일 주소, 파일명, 엔터티 클래스 설정
@Component
public class ExcelUtil {
@Autowired
private CharingStationServiceImpl charingStationServiceImpl;
/**
* 最简单的读
* 1. 创建excel对应的实体对象 ExcelModel
* 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener}
* 3. 直接读即可
*/
private static final Logger LOGGER = LoggerFactory.getLogger(ExcelUtil.class);
//文件位置
String PATH = "D:\\excelTest\\";
public void excelRead() {
// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
String fileName = PATH + "充电桩验收测试数据.xlsx";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
EasyExcel.read(fileName, ExcelModel.class, new DemoDataListener(charingStationServiceImpl)).sheet().doRead();
}
}
이 문서의 지식 포인트:
- Json을 변환하고 [{},{},{},{}] 유형 배열 객체를 구문 분석하여 내부의 단일 콘텐츠를 가져옵니다.
JSONObject jsonObject = (JSONObject) obj;
ChargingStationResistanceDataExcelModel reportModel = JSONObject.parseObject(String.valueOf((JSONObject) obj);
- @Component 주석을 사용하여 DemoDataListener 및 리스너 항목을 Spring에 전달하여 관리
@Component
public class DemoDataListener extends AnalysisEventListener<ExcelModel> {
...
}
- 읽을 파일 위치 구성
//文件位置
String PATH = "D:\\excelTest\\";
public void excelRead() {
// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
String fileName = PATH + "充电桩验收测试数据.xlsx";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
EasyExcel.read(fileName, ExcelModel.class, new DemoDataListener(charingStationServiceImpl)).sheet().doRead();
}
추신: 작업 시작 시 몇 가지 오류가 보고되었습니다.
- 매퍼가 널 포인터를 보고합니다. 두 가지 가능성 중 하나는 DemoDataListener와 리스너 항목 클래스가 Spring에 주입되지 않았기 때문에 Bean을 찾을 수 없고 @Component를 사용해야 하기 때문이라는 두 가지 가능성을 확인했습니다. 두 번째는 Spring mvc의 모델 호출이 통과되지 않았지만 오픈 소스 프레임워크의 단위 테스트 @Test가 적용되어 실행된다는 것입니다.
- 헤더 열이 삭제되지 않아 파일 읽기에 실패했습니다.
이 글은 꼬마 신인의 작은 기록일 뿐이니, 틀린 부분이 있으면 정정 부탁드립니다!