java 导出excel示例(easyExcel)

1.情景展示

在javaweb项目当中,如何将数据导入excel,并将生成的excel文件返回给前端?

2.具体分析

可通过阿里巴巴的easyExcel来实现。

所需jar包

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>2.2.6</version>
</dependency>

如果是maven项目的话,只需要引入这一个easyexcel.jar就可以了,easyExcel所依赖的其它jar包会自动被maven下载;

截至发文,easyExcel的最新版本为:3.1.1;

如果是非maven项目的话,我们还需要下载以下jar包;

注意:jar包版本号不能出错。

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.17</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.17</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml-schemas</artifactId>
    <version>3.17</version>
</dependency>
<dependency>
   <groupId>org.apache.commons</groupId>
   <artifactId>commons-collections4</artifactId>
   <version>4.1</version>
</dependency>
<dependency>
   <groupId>cglib</groupId>
   <artifactId>cglib</artifactId>
   <version>2.2</version>
</dependency>

上述这些jar包,是easyExcel-2.26.jar所依赖的版本号,如果更高版本,需要诸君自行查找对应版本号,否则会jar包冲突,这里我分享一个查找办法:

在idea当中,我们随意打开一个maven项目的pom.xml文件,将easyexcel的依赖引入到项目当中,切换到pom树视图,搜索easyexcel,就能扒到对应的从属jar包,及其版本号。

3.具体实现

说明:只能导出xls格式,不支持*.xlsx格式。

excel工具类

package metadata.web.actions.utils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

import javax.servlet.http.HttpSession;

import com.alibaba.excel.EasyExcel;

/**
 * Excel操作工具类
 * @description
 * @author Marydon
 * @creationTime 2022年6月18日下午3:23:41
 * @version 1.0
 * @since
 * @email marydon20170307@163.com
 */
public class ExcelUtil {
	
    /**
     * 根据模板导出excel
     * <p>
     * 支持简易循环填写excel
     * @param templatePath 模板路径
     * @param temporaryName 临时文件名称
     * @param out 文件输出流
     * @param head easyPoi 表头对象class
     * @param list 填充列表
     * @param col 导出类class
     * @param session session
     */
    public static void exportTemplate(String templatePath, String temporaryName, OutputStream out, Class head, Class col, List<?> list, HttpSession session) {
        String path = null;
        try {
            // 如果模板文件在resources目录下使用这个
            // InputStream resourceAsStream = col.getClassLoader().getResourceAsStream(templatePath);
            // 如果模板文件在WebRoot/WebContent目录下
            InputStream resourceAsStream = session.getServletContext().getResourceAsStream(templatePath);
            path = ExcelUtil.getFilePath(temporaryName, resourceAsStream, session);
            EasyExcel.write(out, head).needHead(false).withTemplate(path).sheet().doWrite(list);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {//删除临时文件
            if (path!=null && !"".equals(path)) {
                File tempFile = new File(path);
                tempFile.delete();
                System.err.println("删除临时文件成功=====path:" + path);
            }
        }
    }

    /**
     * 获取临时文件路径
     * @param inputStream
     * @param session
     * @param fileName
     * @return
     * @throws IOException
     */
    public static String getFilePath(String fileName, InputStream inputStream, HttpSession session) throws IOException {
        // 模板临时目录
        String rootPath = session.getServletContext().getRealPath("templates/");
        // 临时文件路径名
        String filePath = rootPath + "_" + System.currentTimeMillis() + fileName;
        File tempFile = new File(filePath);
        // 保存到临时文件
        saveTempFile(inputStream, tempFile);
        return filePath;
    }

    // 保存到临时目录
    private static void saveTempFile(InputStream inputStream, File tempFile) throws IOException {
        if (!tempFile.getParentFile().exists()) { //如果文件的目录不存在
            tempFile.getParentFile().mkdirs(); //创建目录
        }
        OutputStream os = new FileOutputStream(tempFile);
        byte[] b = new byte[2048];
        int length;
        while ((length = inputStream.read(b)) > 0) {
            os.write(b, 0, length);
        }
        os.flush();
        os.close();
        inputStream.close();
    }

}

模板文件

说明:

我们可以在excel当中不仅可设置每一列对应的的列名称,还可以设置每列的格式。

存放位置:

 

模板对应的实体类

查看代码
/**
 * 资源库数量验证日志实体类
 * @description
 * @author Marydon
 * @creationTime 2022年6月19日下午6:21:25
 * @version 1.0
 * @since
 * @email marydon20170307@163.com
 */
public class DataCheckEntity {
	/**
     * 机构名称
     */
    @ExcelProperty(value = "机构名称",index = 0)
    private String ORGNAME;
    
    /**
     * 主题名称
     */
    @ExcelProperty(value = "主题名称",index = 1)
    private String PARENT_THEME_NAME;

    /**
     * 表名
     */
    @ExcelProperty(value = "表名",index = 2)
    private String TABLE_NAME;

    /**
     * 数据量
     */
    @ExcelProperty(value="数据量",index = 3)
    private Long DATA_NUM;

    
    /**
     * 验证日期
     */
    @ExcelProperty(value = "验证日期",index = 4)
    private String CHECK_DATE;
    
    /**
     * 批次号
     */
    @ExcelProperty(value = "批次号",index = 5)
    private String BATCH_CODE;

	public String getORGNAME() {
		return ORGNAME;
	}

	public void setORGNAME(String oRGNAME) {
		ORGNAME = oRGNAME;
	}

	public String getPARENT_THEME_NAME() {
		return PARENT_THEME_NAME;
	}

	public void setPARENT_THEME_NAME(String pARENT_THEME_NAME) {
		PARENT_THEME_NAME = pARENT_THEME_NAME;
	}
	
	public String getTABLE_NAME() {
		return TABLE_NAME;
	}

	public void setTABLE_NAME(String tABLE_NAME) {
		TABLE_NAME = tABLE_NAME;
	}

	public Long getDATA_NUM() {
		return DATA_NUM;
	}

	public void setDATA_NUM(Long dATA_NUM) {
		DATA_NUM = dATA_NUM;
	}

	public String getCHECK_DATE() {
		return CHECK_DATE;
	}

	public void setCHECK_DATE(String cHECK_DATE) {
		CHECK_DATE = cHECK_DATE;
	}
	
	public String getBATCH_CODE() {
		return BATCH_CODE;
	}

	public void setBATCH_CODE(String bATCH_CODE) {
		BATCH_CODE = bATCH_CODE;
	}

	@Override
	public String toString() {
		return "DataCheckEntity [ORGNAME=" + ORGNAME + ", PARENT_THEME_NAME=" + PARENT_THEME_NAME + ", TABLE_NAME="
				+ TABLE_NAME + ", DATA_NUM=" + DATA_NUM + ", CHECK_DATE=" + CHECK_DATE + ", BATCH_CODE=" + BATCH_CODE
				+ "]";
	}

}

如果使用了lombok插件,可以使用@Setter、@Getter和@ToString注解来替代。

注解@ExcelProperty的value属性,可以不要,在插入数据的时候,是按index来决定每列所在位置的;

所以说,即使excel的列名和实体类没有按顺序对照或者完全匹配,并不影响实际数据的插入,只会影响展示效果。

web层调用

/**
 * 导出至excel文件
 * @description 
 * 使用EasyExcel模板导出excel
 * @return 文件流 
 */
public String export(){
    
    try {
        HttpServletResponse response = WebUtils.getResponse();
        HttpSession session = WebUtils.getRequest().getSession();
        
        // 响应参数设置
        response.setContentType("multipart/form-data");
        response.setContentType("application/octet-stream;charset=utf-8");
        
        // excel格式及文件名
        String fileName = URLDecoder.decode("资源库数量验证日志_" + DateUtils.getSysdateStr("yyyyMMddHHmmss"), "UTF-8");
        response.setHeader("Content-Disposition", "attachment; filename=\"" + new String(fileName.getBytes("gb2312"), "ISO8859-1") + ".xls" + "\"");
        OutputStream out = response.getOutputStream();
        
        // 获取请求参数
        //TODO 看中文是否乱码
        Map map = WebUtils.getParameterMap();
        // 查询将要导出的数据
        // 获取数据
        List<Map<String, Object>> data = boZYK_DATE_CHECK.getZYK_DATE_CHECK(map);
        List<DataCheckEntity> data2 = new ArrayList<>(data.size()); 
        // map转实体类
        for (Map<String, Object> map2 : data) {
            data2.add(MapUtil.toJavaBean(DataCheckEntity.class, map2));
        }
        
        // 根据模板导出数excel
        // ExcelUtil.exportTemplate("templates/template.xls", "model.xls", out, DataCheckEntity.class,ExcelUtil.class, data2, session);
        ExcelUtil.exportTemplate("/templates/template.xls", "model.xls", out, DataCheckEntity.class,ExcelUtil.class, data2, session);
        
        return null;
    } catch (Exception e) {
        e.printStackTrace();
        model.put("msg", "excel导出失败");
        model.put("expMsg", e.getMessage());
    }
    
    return getResult();
}

 

写在最后

  哪位大佬如若发现文章存在纰漏之处或需要补充更多内容,欢迎留言!!!

 相关推荐:

posted @ 2022-06-27 10:31  Marydon  阅读(2174)  评论(0编辑  收藏  举报