最近业务提了一个导出excle报表的功能需求,而之前我记忆中的导出功能,都是直接使用代码画表格的方式,往往是一大坨代码,看着就让人头大。于是我就想着有没有基于excle模板直接替换变量的方式呢,于是就找到jxls,的确很简单,数行代码就解决了我的导出需求,甚是欢喜。特此根据网上查询的资料和自己的实践,整理一下笔记,以便后期学习回顾,也期望能帮助到其他人。
直接上代码,代码有注释,注释很详细,注意看注释
添加pom依赖或Jar依赖
<!-- https://mvnrepository.com/artifact/net.sf.jxls/jxls-core --> <dependency> <groupId>net.sf.jxls</groupId> <artifactId>jxls-core</artifactId> <version>1.0.3</version> </dependency>
导出功能在和我原来旧的项目融合时,是只添加了jxls-core即可。但在我搭建的单独测试工程中,还另外依赖了如下的依赖包。
网络异常,图片无法展示
|
工程依赖jar包列表
1. 使用jxls基于模板导出单个sheet的excle
1.1 单sheet模板样式
网络异常,图片无法展示
|
单个sheet模板样式
一般数据直接绑定跟 jstl比较像,直接${name},循环就是
<jx:forEach items="${data}" var="item" ></jx:forEach>
,上图中红色框框住的区间就是列表遍历的位置。
1.2 单sheet代码演示
代码具体含义,详见注释:
import net.sf.jxls.transformer.XLSTransformer; import org.apache.poi.ss.usermodel.Workbook; import org.junit.Test; import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class JxlsDemo { @Test public void method1() throws Exception { // 循环数据 List<Object> list = new ArrayList<>(); for (int i = 0; i < 5; i++) { Map<String,Object> map = new HashMap<>(); map.put("A1", (int)(Math.random()*100)); map.put("A2", (int)(Math.random()*100)+""); map.put("A3", (int)(Math.random()*100)+""); map.put("A4", (int)(Math.random()*100)+""); map.put("A5", (int)(Math.random()*100)+""); map.put("A6", (int)(Math.random()*100)+""); list.add(map); } // 表格使用的数据 Map map = new HashMap(); map.put("data",list); map.put("title","java基于excle模板导出excle"); map.put("val","演示合并单元格"); // 获取模板文件 InputStream is = this.getClass().getClassLoader().getResourceAsStream("temp02.xls"); // 实例化 XLSTransformer 对象 XLSTransformer xlsTransformer = new XLSTransformer(); // 获取 Workbook ,传入 模板 和 数据 Workbook workbook = xlsTransformer.transformXLS(is,map); // 写出文件 OutputStream os = new BufferedOutputStream(new FileOutputStream("D://file2020.xls")); // 输出 workbook.write(os); // 关闭和刷新管道,不然可能会出现表格数据不齐,打不开之类的问题 is.close(); os.flush(); os.close(); } }
1.3 单sheet导出效果
网络异常,图片无法展示
|
导出效果
2. 使用jxls基于模板导出带有多个sheet的excle
2.1 多sheet模板样式
代码具体含义,详见注释:
网络异常,图片无法展示
|
多sheet模板
2.2 多sheet模板导出代码
@Test public void method2() throws Exception { // 循环数据 List<Object> list = new ArrayList<>(); for (int i = 0; i < 10; i++) { Map<String,Object> map = new HashMap<>(); map.put("A1", (int)(Math.random()*100)); map.put("A2", (int)(Math.random()*100)+""); map.put("A3", (int)(Math.random()*100)+""); map.put("A4", (int)(Math.random()*100)+""); map.put("A5", (int)(Math.random()*100)+""); map.put("A6", (int)(Math.random()*100)+""); list.add(map); } // 表格使用的数据 Map map = new HashMap(); map.put("data",list); map.put("title","java基于excle模板导出多sheet的Excle"); map.put("val","演示合并单元格"); List<Object> list1 = new ArrayList<>(); for (int i = 0; i < 10; i++) { Map<String,Object> map3 = new HashMap<>(); map3.put("A1", (int)(Math.random()*100)+""); map3.put("A2", (int)(Math.random()*100)+""); map3.put("A3", (int)(Math.random()*100)+""); map3.put("A4", (int)(Math.random()*100)+""); map3.put("A5", (int)(Math.random()*100)+""); map3.put("A6", (int)(Math.random()*100)+""); list1.add(map3); } // 表格使用的数据 Map map2 = new HashMap(); map2.put("data",list1); map2.put("title","标题title"); map2.put("val","合并测试2"); // 获取模板文件 InputStream is = this.getClass().getClassLoader().getResourceAsStream("tempmultisheet01.xls"); // 实例化 XLSTransformer 对象 XLSTransformer xlsTransformer = new XLSTransformer(); //模板文件对应的sheet名称列表 List templateSheetNameList = new ArrayList<String>(); templateSheetNameList.add("Template1"); templateSheetNameList.add("Template2"); //生成文件对应的sheet名称列表 List sheetNameList = new ArrayList<String>(); sheetNameList.add("表单1"); sheetNameList.add("表单2"); //模板文件不同sheet对应的不同数据,注意保持顺序一致 List beanParamsList = new ArrayList<Map<String,Object>>(); beanParamsList.add(map); beanParamsList.add(map2); // 获取 Workbook ,传入 模板 和 数据 Workbook workbook =xlsTransformer.transformXLS(is,templateSheetNameList,sheetNameList,beanParamsList); // 写出文件 OutputStream os = new BufferedOutputStream(new FileOutputStream("D://multisheetExcleFile2020.xls")); // 输出 workbook.write(os); // 关闭和刷新管道,不然可能会出现表格数据不齐,打不开之类的问题 is.close(); os.flush(); os.close(); }
2.3 多sheet导出效果
网络异常,图片无法展示
|
多sheet导出效果
3 使用jxls基于模板导出复杂sheet的excle
3.1 模板和导出结果样例
网络异常,图片无法展示
|
3.2 复杂sheet模板导出代码
@Test public void genComplexExcle() throws Exception { // 循环数据 List<Object> list = new ArrayList<>(); for (int i = 0; i < 5; i++) { Company company = new Company(); company.setName("名称" + Math.random() * 100); company.setAddress("地址" + Math.random() * 100); company.setAge((int) (Math.random() * 100)); list.add(company); } List<Object> list2 = new ArrayList<>(); for (int i = 0; i < 3; i++) { Company company = new Company(); company.setName("名称2" + Math.random() * 100); company.setAddress("地址2" + Math.random() * 100); company.setAge((int) (Math.random() * 100)); list2.add(company); } // 表格使用的数据 Map map = new HashMap(); map.put("data", list); map.put("data2", list2); map.put("title", "这个是标题"); map.put("val", "这是演示合并单元格的填值情况"); map.put("adminName", "戴晓年"); map.put("adminClass", "2021-100班"); // 获取模板文件 InputStream is = this.getClass().getClassLoader().getResourceAsStream("temp03.xls"); // 实例化 XLSTransformer 对象 XLSTransformer xlsTransformer = new XLSTransformer(); // 获取 Workbook ,传入 模板 和 数据 Workbook workbook = xlsTransformer.transformXLS(is, map); // 写出文件 OutputStream os = new BufferedOutputStream(new FileOutputStream("D://companys2021complex.xls")); // 输出 workbook.write(os); // 关闭和刷新管道,不然可能会出现表格数据不齐,打不开之类的问题 is.close(); os.flush(); os.close(); }
4. web环境下运行
web环境下跑和上面的代码基本上一样,不一样的就是 OutputStream 的地方换成了 response.getOutputStream(),然后 response 设置一下文件名,
response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode("报表.xls" ,"UTF-8"));
代码如下:
@RestController @RequestMapping(value = "/report") public class ReportController { private final static Logger LOGGER = LoggerFactory.getLogger(ReportController.class); @RequestMapping(value = "/downLoadDataFile/{createdMonth}", method = RequestMethod.GET) public String downLoadDataFile(HttpServletResponse response,@PathVariable String createdMonth) throws Exception { InputStream is = null; OutputStream os = null; LOGGER.info("downLoadDataFile createdMonth : -> [{}]", createdMonth); try { // 循环数据 List<Object> list = new ArrayList<>(); for (int i = 0; i < 10; i++) { Student student = new Student(); student.setAge1((int) (Math.random() * 100)+"字符串"); student.setAge2((int) (Math.random() * 100)); student.setAge3((int) (Math.random() * 100)); student.setAge4((int) (Math.random() * 100)); student.setAge5((int) (Math.random() * 100)); student.setAge6((int) (Math.random() * 100)); list.add(student); } // 表格使用的数据 Map map = new HashMap(); map.put("data", list); map.put("title", "java基于模板导出"); map.put("val", "演示合并单元格"); // 获取模板文件 is = this.getClass().getClassLoader().getResourceAsStream("temp02.xls"); // 实例化 XLSTransformer 对象 XLSTransformer xlsTransformer = new XLSTransformer(); // 获取Workbook,传入 模板 和 数据 Workbook workbook = xlsTransformer.transformXLS(is, map); // 写出文件 // 设置文件名 response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode("报表224.xls" ,"UTF-8")); // 写出文件 os = new BufferedOutputStream( response.getOutputStream() ); // 输出 workbook.write(os); return "Downloading..."; } catch (Exception e) { LOGGER.error("DOWNLOAD data FILE THROW EXCEPTION:" + e.getMessage(), e); return "Error"; } finally { if (os != null) { os.flush(); os.close(); } if (is != null) { is.close(); } } } }
5.参考文档
https://blog.csdn.net/yali_aini/article/details/85804466