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();
}
写在最后
哪位大佬如若发现文章存在纰漏之处或需要补充更多内容,欢迎留言!!!