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 () {
                //请求异常回调
            }
        });
  );

目前正在学习中的小白,代码可能不够严谨,感谢大佬指正!如果可以为你带来帮助,荣幸之至!

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值