SpringBoot + EasyExcel(Alibaba) 讀操作,將Excel檔案上傳至資料庫
阿新 • • 發佈:2021-05-11
專案中用的需要將原有的Excel表格中的資料上傳到資料庫中,參考了一些文章部落格,目前主要採用的就是poi和阿里的easyexcel,這裡對它們的好壞不做評價,根據個人習慣,這裡我選擇的是阿里的easyExcel。
官方文件給的內容已經非常詳細了,這裡我將整個開發的流程都展現一下,提供給大家參考。
點選跳轉至官方文件
引入依賴
<!--生成Excel-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId> easyexcel</artifactId>
<version>2.2.6</version>
</dependency>
Excel例項
配置實體類
主要就是為欄位新增一個@ExcelProperty(index = 0, value = "xx")
註解 value 對應的是excel表格中的列名,這裡index可用可不用,使用index是強制去匹配index所對應的列(和陣列一樣 index從0開始)不建議 index 和 name 同時用。
常用的註解,解釋
@ExcelProperty @ColumnWith 列寬 @ContentFontStyle 文字字型樣式 @ContentLoopMerge 文字合併 @ContentRowHeight 文字行高度 @ContentStyle 文字樣式 @HeadFontStyle 標題字型樣式 @HeadRowHeight 標題高度 @HeadStyle 標題樣式 @ExcelIgnore 忽略項 @ExcelIgnoreUnannotated 忽略未註解
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = false)
@TableName("tb_role")
@ApiModel(value = "住戶資訊", description = "")
public class ResidentDto implements Serializable {
@ExcelProperty(index = 0, value = "住戶編號")
@TableId(value = "res_id", type = IdType.AUTO)
private Integer resId;
@ExcelProperty(index = 1, value = "住戶名")
private String resName;
@ExcelProperty(index = 2, value = "性別")
private Integer resSex;
@ExcelProperty(index = 3, value = "手機號")
private String resPhone;
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@ExcelProperty(index = 4, value = "入住小區時間")
private String resIntotime;
@ExcelProperty(index = 5, value = "狀態")
@ApiModelProperty("0表示正常,1表示低風險,2表示高風險")
private Integer resStatus;
@ExcelProperty(index = 6, value = "備註")
private String resRemark;
}
監聽器的配置(重點)
public class ExcelListener extends AnalysisEventListener<ResidentDto> {
private static final Logger LOGGER = LoggerFactory.getLogger(ExcelListener.class);
/**
* 每隔5條儲存資料庫,實際使用中可以3000條,然後清理list ,方便記憶體回收
*/
private static final int BATCH_COUNT = 5;
/**
* 實現業務邏輯的service
*/
private final ResidentService residentService;
/**
* 儲存資料的集合
*/
List<ResidentDto> list = new ArrayList<ResidentDto>();
/**
* 如果使用了spring,請使用這個構造方法。每次建立Listener的時候需要把spring管理的類傳進來
*
* @param residentService
*/
public ExcelListener(ResidentService residentService) {
this.residentService = residentService;
}
@Override
public void invoke(ResidentDto data, AnalysisContext context) {
list.add(data);
// 達到BATCH_COUNT了,需要去儲存一次資料庫,防止資料幾萬條資料在記憶體,容易OOM
if (list.size() >= BATCH_COUNT) {
saveData();
// 儲存完成清理 list
list.clear();
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 這裡也要儲存資料,確保最後遺留的資料也儲存到資料庫
saveData();
LOGGER.info("所有資料解析完成!");
}
/**
* 加上儲存資料庫
*/
private void saveData() {
//這裡才是資料繼續資料庫儲存的重點
int batchResident = residentService.insertBatchResident(list);
if (batchResident < 1) {
LOGGER.info("資料儲存異常,未知錯誤");
}
}
}
編寫Controller
@Api(value = "檔案上傳", tags = "檔案上傳相關介面")
@RestController
@RequestMapping("/api/excel")
public class ExcelController {
public static Logger logger = LoggerFactory.getLogger(ExcelController.class);
@Resource
private ResidentService residentService;
@PostMapping("/uploadRes")
public Result upload(@RequestParam MultipartFile file) {
InputStream fileInputStream = null;
try {
fileInputStream = file.getInputStream();
} catch (IOException e) {
e.printStackTrace();
return Result.fail("上傳檔案異常");
}
try {
//呼叫EasyExcel.read然後去呼叫你寫的監聽器,隨後去執行你寫的Service
EasyExcel.read(fileInputStream, ResidentDto.class, new ExcelListener(residentService)).sheet().doRead();
return Result.ok("上傳檔案成功");
} catch (Exception e) {
e.printStackTrace();
}
return Result.fail("未知錯誤");
}
}
編寫Service、ServiceImpl 和 Mapper
Service
/**
* 批量新增資料
*/
int insertBatchResident(List<ResidentDto> residentDtos);
ServiceImpl
/**
* 批量新增資料
*
* @param residentDtos
* @return
*/
@Override
public int insertBatchResident(List<ResidentDto> residentDtos) {
int batchResident = residentMapper.insertBatchResident(residentDtos);
return batchResident;
}
Mapper
int insertBatchResident(@Param("residentDtos") List<ResidentDto> residentDtos);
Mapper.Xml
<!-- 批量新增資料-->
<insert id="insertBatchResident">
insert into tb_resident(res_id, res_name, res_sex, res_phone, res_intotime,res_status, res_remark, res_photo)
values
<foreach collection="residentDtos" item="resident" index="index" separator=",">
(#{resident.resId}, #{resident.resName}, #{resident.resSex}, #{resident.resPhone}, #{resident.resIntotime},
#{resident.resStatus},#{resident.resRemark}, null)
</foreach>
</insert>
前端部分展示
這裡專案我採用的是LayUI的框架,直接引用了它本身的檔案上傳元件
<div class="layui-btn-container">
<button type="submit" class="layui-btn layui-btn-sm" lay-submit lay-filter="data-all"><i
class="layui-icon layui-icon-home"></i>全部住戶
</button>
<button class="layui-btn layui-btn-normal layui-btn-sm data-add-btn" lay-event="add"> 新增</button>
<button class="layui-btn layui-btn-sm layui-btn-danger data-delete-btn" lay-event="delete"> 刪除</button>
<button class="layui-btn layui-btn-sm " id="upload">上傳檔案
</button>
</div>
//元件引用
layui.use(['form', 'table', 'miniPage', 'element', 'laydate', 'upload'], function () {
var $ = layui.jquery,
form = layui.form,
table = layui.table,
laydate = layui.laydate,
miniPage = layui.miniPage,
upload = layui.upload;
//檔案上傳操作
upload.render({
elem: '#upload' //繫結元素
, url: '/api/excel/uploadRes' //上傳介面
, accept: 'file'
, size: 10240 // 最大上傳限制,最大為10M
, done: function (res) {
//上傳完畢回撥
if (res.code == 200) {
layer.msg(res.msg, {icon: 6, time: 1000});
//頁面重新整理
parent.window.location.reload();
} else {
layer.msg(res.msg, {icon: 5, time: 1000});
}
}, error: function () {
//請求異常回調
}
});
);
目前正在學習中的小白,程式碼可能不夠嚴謹,感謝大佬指正!如果可以為你帶來幫助,榮幸之至!