この記事は EasyExcel の読み取り (read) のみを記録します。
1. EasyExcel は何をしますか?
まず EasyExcel の説明を見てください:
EasyExcel は Alibaba によってオープン ソース化された Excel 処理フレームワークで、Java ベースで Excel を読み書きするためのシンプルで省メモリなオープン ソース プロジェクトです。EasyExcel がメモリ使用量を大幅に削減できる主な理由は、Excel を解析するときに一度にすべてのファイル データをメモリにロードするのではなく、ディスクから 1 行ずつデータを読み取り、1 つずつ解析することです。
オープンソースのアドレス:
githubのアドレス: https://github.com/alibaba/easyexcel
(コードを見ただけでまだ少し混乱しており、Xiaopo Station で関連動画を検索したところ、Crazy God の動画でわかりやすく説明されていました. ほぼ直接彼の言うとおりにします. もちろん、実際の状況に応じて適切な変更を加える必要があります. )
2. プロジェクトの背景
私が作成した小さなプロジェクトでは、Excel テーブルのデータをデータベースにインポートする必要がありますが、一部のデータ列には多数の配列オブジェクト [{…}、{…}、{…}、{…}] も含まれており、内容は次のとおりです。手作業やエクセルでは現実的ではないので、データベースに一つ一つフィールドとして格納する必要があります。それで、このフレームワークの使用法を理解するようになりました。
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. コードには 3 つのステップがあります。
- Excel に対応するエンティティ オブジェクト Dao クラスを作成します。
- 書き込みリスナー: デフォルトでは、Excel を 1 行ずつ読み取るため、Excel の 1 行ごとにコールバック リスナーを作成する必要があります. リスナーは主に読み取りと保存を実現します。
- リスナーを呼び出す: Excel の場所を構成し、リスナーを呼び出してテーブルを読み取り、データベースに保存します。
ステップ 1: Excel に対応するエンティティ クラスを作成する
ps : @ExcelProperty アノテーションを使用して、
対応する Excel 列「耐性試験データ」に対応するエンティティ クラスを
示します (ここで説明する必要があります。当時、4 つのパラメーター名すべてを対応する 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.リスナー入力
Excelに対応するファイルアドレス、ファイル名、エンティティクラスを設定
@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();
}
ps: 操作の開始時にいくつかのエラーが報告されました:
- マッパーは null ポインターを報告します。2 つの可能性があります。確認したところ、1 つは DemoDataListener とリスナー エントリ クラスが Spring に注入されていないため、Bean が見つからず、@Component を使用する必要があるためです。2 つ目は、Spring mvc のモデル呼び出しは通さず、オープンソース フレームワークの単体テスト @Test を適用して実行することです。
- ヘッダー列が削除されていないため、ファイルの読み取りに失敗しました。
この記事は初心者のちょっとした記録です。間違いがあれば訂正してください。