SpringBoot整合EasyExcel-excel的导入导出

141 阅读6分钟

前情提要:本例子的前端用的是vue、element-ui

1.导入依赖

<!--easyExcel开始-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.3.2</version>
</dependency>
<!--easyExcel结束-->
<!-- mybatis-plus插件开始-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.3.4</version>
</dependency>
<!-- mybatis-plus插件结束-->

2.将实体类与表进行规范

与excel表格的列对应起

实体类,ExcelProperty意思就是将实体类的变量与excel表格的列对应起来,容易理解。

@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("tb_dept")//表的名称
public class Dept implements Serializable {
    @TableId(value = "deptNo",type = IdType.AUTO )
    @ExcelProperty("编号")
    private Integer deptNo;
    @ExcelProperty("部门名称")
    @ColumnWidth(10)
    private String deptName;
    @ExcelProperty("部门位置")
    @ColumnWidth(10)
    private String loc;
    @ExcelProperty("图片")
    @ColumnWidth(20)
    @TableField("picPath")
    private String picPath;
    @ExcelProperty("图片名称")
    @ColumnWidth(10)
    private String picName;
}

3.编写接口和mapper.xml

dao层/mapper层

public interface DeptMapper {
    /**
     * 根据参数查询列表
     * @param dept
     * @return
     */
    List<Dept> queryByParam(Dept dept);
     /**
     * 部门添加
     * @param dept
     * @return
     */
    int  add(Dept dept);
}

service和serviceimpl层

public interface DeptService {
    /**
     * 根据参数查询列表
     * @param dept
     * @return
     */
    List<Dept> queryByParam(Dept dept);
    /**
     * 部门添加
     * @param dept
     * @return
     */
    int  add(Dept dept);
}

mapper.xml写sql语句的

<sql id="select">
    select dept_no deptNo,dname deptName,loc,picpath picPath,picname picName from tb_dept
</sql>
<!--   查询所有-->
<select id="queryByParam" resultType="com.aaa.entity.Dept">
    <include refid="select"></include>
    <where>
        <if test="deptName!=null and deptName!=''">
            dname like concat('%',#{deptName},'%')
        </if>
        <if test="loc!=null and loc!=''">
            loc=#{loc}
        </if>
    </where>
</select>
<!--    添加-->
<insert id="add">
    insert into tb_dept(dname, loc,picpath,picname)
    values (#{deptName}, #{loc},#{picPath},#{picName})
</insert>

4.监听器

DeptReadListener是一个关键的地方,这里其实就是导入的对象监听器

@Component//不在三层之内的,将该类交给Spring容器管理,使其成为组件
@Scope("prototype")// 设置该类的实例作用域为原型,每次获取实例都是一个新的对象
public class DeptReadListener extends AnalysisEventListener<Dept> {
    // 依赖注入,将DeptService实例注入到该类中
    @Resource
    private DeptService deptService;
    /**
     * 构造方法,接收一个DeptService实例作为参数,并将其赋值给deptService成员变量
     * @param deptService
     */
    public DeptReadListener(DeptService deptService) {
        this.deptService = deptService;
    }
    /**
     * 重写invoke方法,在分析事件触发时调用该方法
     * @param dept
     * @param analysisContext
     */
    @Override
    public void invoke(Dept dept, AnalysisContext analysisContext) {
        // 打印读取到的dept对象信息
        System.out.println("读取到:"+dept);
        // 调用deptService的add方法,将读取到的dept对象添加到数据库或其他存储中
        deptService.add(dept);
    }
    /**
     *重写doAfterAllAnalysed方法,在所有分析任务完成后调用该方法
     * @param analysisContext
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        // 打印读取完毕的信息
        System.out.println("读取完毕!!!");
    }
}

这段代码定义了一个名为DeptReadListener的类,它继承自AnalysisEventListener<Dept>。该类被交给Spring容器管理,并设置为原型作用域,每次获取实例都是一个新的对象。在构造方法中,将DeptService实例注入到该类中。继承AnalysisEventListener类的2个方法,invoke方法在分析事件触发时调用,用于处理读取到的dept对象,并将其添加到数据库或其他存储中。doAfterAllAnalysed方法在所有分析任务完成后调用,打印读取完毕的信息。

5.接着就是controller层

/**
 * 查询所有
 * @param dept
 * @return
 */
@GetMapping("/queryByParam")
public Result queryByParam(Dept dept){
    return success(deptService.queryByParam(dept));
}
/**
 * 添加数据
 * @param dept
 * @return
 */
@PostMapping("/add")
public Result add(@RequestBody Dept dept){
    return success(deptService.add(dept));
}
/**
 * 导入的excel文件对象是MultipartFile类型的
 * @param file
 * @throws IOException
 */
@PostMapping("/import")
public void ExcelImport(MultipartFile file)throws IOException {
    InputStream is = file.getInputStream();// 获取上传文件的输入流
    DeptReadListener deptReadListener = new DeptReadListener(deptService);// 创建DeptReadListener对象,用于监听读取操作
    EasyExcel.read(is,Dept.class,deptReadListener)//使用EasyExcel库开始读取Excel文件
            .sheet(0)// 指定要读取的工作表索引为0,即第一个工作表
            .headRowNumber(1)// 设置表头行号为1,表示数据从第二行开始读取
            .doRead();// 执行读取操作
}
/**
 * 导出
 * @param response
 * @throws IOException
 */
@GetMapping("/export")
public void ExcelExport(HttpServletResponse response)throws IOException {
    // 查询部门数据
    List<Dept> depts = deptService.queryByParam(null);
    // 设置响应头信息,指定文件类型为Excel(.xlsx)和字符编码为UTF-8
    response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");//.xlsx格式
    response.setCharacterEncoding("utf-8");
    // 对文件名进行URL编码,将空格替换为%20,避免中文乱码问题
    String fileName = URLEncoder.encode("部门数据", "UTF-8").replaceAll("\+", "%20");
    // 设置响应头信息,指定下载文件的文件名和扩展名为.xlsx
    response.setHeader("Content-disposition","attachment;filename="+fileName+".xlsx");
    // 使用EasyExcel库将数据写入响应的输出流中,生成Excel文件
    EasyExcel.write(response.getOutputStream())
            .head(Dept.class)// 设置表头为Dept类的属性
            .excelType(ExcelTypeEnum.XLSX)// 设置文件类型为Excel(.xlsx)
            .sheet("部门数据")// 设置工作表名称为“部门数据”
            .doWrite(depts);// 将查询到的部门数据写入Excel文件中
}

ExcelImport

这个方法接受一个MultipartFile类型的参数file,表示上传的Excel文件。它抛出了IOException异常,以便在发生输入输出错误时进行处理。

方法内部首先通过调用file.getInputStream()方法获取上传文件的输入流,并将其赋值给is变量。

接下来,创建了一个名为deptReadListenerDeptReadListener对象,该对象需要传入一个deptService参数。这个对象用于监听Excel文件的读取操作,并在读取完成后进行相应的处理。

然后,使用EasyExcel库的read方法开始读取Excel文件。read方法接受三个参数:输入流is、目标类Dept.class和监听器deptReadListener。它将Excel文件中的数据映射到Dept类的对象上,并通过调用deptReadListener对象的回调方法来处理读取结果。

read方法之后,调用sheet(0)指定要读取的工作表索引为0,即第一个工作表。

接着,调用headRowNumber(1)设置表头行号为1,表示数据从第二行开始读取。

最后,调用doRead()方法开始执行读取操作。

总结起来,这段代码的作用是将上传的Excel文件的第一张工作表的数据导入到数据库中的Dept类对应的表中。

ExcelExport

这个方法使用了@GetMapping("/export")注解,表示它是一个处理HTTP GET请求的方法,请求路径为"/export"。它接受一个HttpServletResponse对象作为参数,用于设置响应头和响应内容。

在方法内部,首先通过调用deptService.queryByParam(null)方法查询部门数据,并将结果存储在名为depts的列表中。

接下来,通过调用response.setContentType()方法设置响应头信息,指定文件类型为Excel(.xlsx)和字符编码为UTF-8。然后,通过调用response.setCharacterEncoding()方法设置响应的字符编码为UTF-8。

为了确保中文文件名不出现乱码,使用URLEncoder.encode()方法对文件名进行URL编码,将空格替换为%20。然后,通过调用response.setHeader()方法设置响应头信息,指定下载文件的文件名为编码后的文件名,并指定文件扩展名为.xlsx。

最后,使用EasyExcel.write()方法将数据写入响应的输出流中,生成Excel文件。通过调用.head(Dept.class)方法设置表头为Dept类的属性,通过调用.excelType(ExcelTypeEnum.XLSX)方法设置文件类型为Excel(.xlsx),通过调用.sheet(`` "部门数据") 设置工作表名称为“部门数据”,通过调用.doWrite(depts);将查询到的部门数据写入Excel文件中。

6.前端代码编写

写在template里的div里边 image.png 下边的写在方法里边 image.png

7.测试

自行测试 image.png 结束语:参考文章SpringBoot集成EasyExcel实现excel的导入导出_springboot导入excel_Chenbaozeng的博客-CSDN博客

本文如有错误请指正!!!