1. 程式人生 > 其它 >SpringBoot + EasyExcel(Alibaba) 讀操作,將Excel檔案上傳至資料庫

SpringBoot + EasyExcel(Alibaba) 讀操作,將Excel檔案上傳至資料庫

專案中用的需要將原有的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 () {
                //請求異常回調
            }
        });
  );

目前正在學習中的小白,程式碼可能不夠嚴謹,感謝大佬指正!如果可以為你帶來幫助,榮幸之至!