:
定制软件大家好久不见!
一、什么是EasyExcel?
EasyExcel定制软件是一个基于Java的简单、定制软件省内存的读写Excel定制软件的开源项目。定制软件在尽可能节约内存的情定制软件况下支持读写百M的Excel。
github地址: https://github.com/alibaba/easyexcel
定制软件官方文档地址:https://www.yuque.com/easyexcel/doc/easyexcel
定制软件当然还有一个POI定制软件也可以实现操作Excel,Apache POI提供API给Java程序对Microsoft Office定制软件格式档案读和写的功能,POI为“Poor Obfuscation Implementation”定制软件的首字母缩写,意为“定制软件简洁版的模糊实现”
EasyExcel和POI的区别:
二、EasyExcel定制软件的实际使用
定制软件首先导入依赖:
<dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.2.4</version></dependency>
- 1
- 2
- 3
- 4
- 5
依赖版本按需使用即可,一些基本的操作大家看官方文档即可,在这里就记录一下自己通过EasyExcel导出的表格及过程
首先看一下需要导出的模板:
区域说明:
A:单个单元格填充
B:列表填充
C:列表填充(但单元格格式与B区域不同)
D:单个单元格填充
一、A区域的填充数据模板的设置:
这个区域填充还是很简单的,只要给每个表格取个参数名,用{}包裹,Java里面用Map来填充即可。Map的键对应{}里面的参数名,对应的值就是填充进去的值:
例如这样,以下数据都是从数据库查出后填入Map即可:
HashMap<String, Object> workOrderFileData = new HashMap<>(); for (ProjectWorkOrderFileData p : WorkOrderFileList) { workOrderFileData.put("projectCode", p.getProjectCode()); workOrderFileData.put("projectName", p.getProjectName()); workOrderFileData.put("inspectedEnt", p.getInspectedEnt()); workOrderFileData.put("customerAddress", p.getCustomerAddress()); workOrderFileData.put("linkMan", p.getLinkMan()); workOrderFileData.put("linkPhone", p.getLinkPhone()); workOrderFileData.put("bizCreateTime", p.getBizCreateTime().substring(0, 10)); workOrderFileData.put("customerName", p.getCustomerName()); workOrderFileData.put("prodCompany", p.getProdCompany()); workOrderFileData.put("testCode", p.getTestCode()); workOrderFileData.put("batchCode", p.getBatchCode()); workOrderFileData.put("region", region); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
二、B和C区域的填充数据模板的设置:
因为B区域是有两个列表,所以我们一定在模板内区分开来,给每个列表取个参数名,然后给每个字段取个参数名,通过列表参数名点(.)字段参数名即可:
即:{} 代表普通变量, {.} 代表是list的变量 {前缀.} 前缀可以区分不同的list
注意: 用{} 来表示你要用的变量 如果本来就有"{“,”}" 特殊字符 用"{“,”}"代替
对于这两组数据,Java里面使用两个列表储存即可,列表内可以存一个对象:
ArrayList<SampleData> SampleDataList = service.selectSampleData(proId);ArrayList<AnalysisMethodData> analysisMethodDataList = service.selectAnalysisMethodData(proId);
- 1
- 2
对象里面的字段名即是该列表所有字段名:
@NoArgsConstructor@AllArgsConstructor@Data@Builderpublic class SampleData { private int number; private String typeName; private String redFolderName; private String redAnalyzeItems; private int spotFrequency; private int frequency; private int day; private int cycleOrder; private int timesOrder; private int sampleOrder; private String remarks;}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
D区域的填充和A区域是一样的,通过Map来填充即可,因为是一对一的关系
三、两个列表之间单元格样式不一样的解决办法
通过模板可以看到BC两个列表之前的单元格样式不一样,如果不做处理,在填充的时候,C区域的样式会根据B区域的样式来填充,也就是C区域合并的单元格会被拆分,所以需要一个工具类:
public class MyHandler extends AbstractMergeStrategy { @Override protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) { if (relativeRowIndex == null || relativeRowIndex == 0) { return; } int rowIndex = cell.getRowIndex(); int colIndex = cell.getColumnIndex(); sheet = cell.getSheet(); Row preRow = sheet.getRow(rowIndex - 1); Cell preCell = preRow.getCell(colIndex);//获取上一行的该格 List<CellRangeAddress> list = sheet.getMergedRegions(); CellStyle cs = cell.getCellStyle(); cell.setCellStyle(cs); for (CellRangeAddress cellRangeAddress : list) { if (cellRangeAddress.containsRow(preCell.getRowIndex()) && cellRangeAddress.containsColumn(preCell.getColumnIndex())) { int lastColIndex = cellRangeAddress.getLastColumn(); int firstColIndex = cellRangeAddress.getFirstColumn(); CellRangeAddress cra = new CellRangeAddress(cell.getRowIndex(), cell.getRowIndex(), firstColIndex, lastColIndex); sheet.addMergedRegion(cra); RegionUtil.setBorderBottom(BorderStyle.THIN, cra, sheet); RegionUtil.setBorderLeft(BorderStyle.THIN, cra, sheet); RegionUtil.setBorderRight(BorderStyle.THIN, cra, sheet); RegionUtil.setBorderTop(BorderStyle.THIN, cra, sheet); return; } } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
直接复制当工具类就完事!
三、完成其他配置,开始填充
我们还要设置两个地址:模板的位置以及导出后文件的储存位置,以下是控制层完整代码
@GetMapping(path = "/generateProjectWorkOrder") public JsonResp<String> generateProjectWorkOrder(@RequestParam("proId") String proId) { //设置模板位置以及导出后储存位置 String templateFile = "D:/WorkProject/ExcelTemplate/模板.xls"; String resultFile = "D:/WorkProject/ExcelTemplate/WorkOrderFile/" +"导出结果.xls"; FillConfig fillConfig = FillConfig.builder().forceNewRow(true).build(); ExcelWriter excelWriter = EasyExcel.write(resultFile).withTemplate(templateFile).build(); //使用让该组单元格格式不受影响的工具类 WriteSheet sheet = EasyExcel.writerSheet(0).registerWriteHandler(new MyHandler()).build(); //获取数据(分别是ABCD四组数据) HashMap<String, Object> workOrderFileData = service.selectWorkOrder(proId); ArrayList<SampleData> SampleDataList = service.selectSampleData(proId); ArrayList<AnalysisMethodData> analysisMethodDataList = service.selectAnalysisMethodData(proId); HashMap<String, String> reviewerData = service.selectReviewerData(proId); //单组填充(A区域) excelWriter.fill(workOrderFileData, sheet); //多个列表填充(B、C区域) // 如果有多个list 模板上必须有{前缀.} 这里的前缀就是 data1,然后多个list必须用 FillWrapper包裹 excelWriter.fill(new FillWrapper("data1", SampleDataList), fillConfig, sheet); excelWriter.fill(new FillWrapper("data2", analysisMethodDataList), fillConfig, sheet); //单组填充(D区域) excelWriter.fill(reviewerData, sheet); //关闭流 excelWriter.finish(); //返回数据 JsonResp<String> objectJsonResp = new JsonResp<>(); //返回路径 resultFile = "lims/downloadGenerateExcel?path=" + resultFile; objectJsonResp.setData(resultFile); return objectJsonResp; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
数据获取的方式按照自己的格式来即可,若完成以上编写,可以实现本地的导出与下载,若需要部署在服务器上,则还需要从服务器下载到本地
三、服务器项目导出后下载到本地
若把项目部署在服务器上,使用该功能首先是下载到服务器上,然后再从服务器上下载到本地电脑。
我们可以使用HttpServletResponse response 来操作:
代码如下:
@GetMapping(path = "/downloadGenerateExcel") public void download(String path, HttpServletResponse response) { try { // path是指想要下载的文件的路径 File file = new File(path); String filename = file.getName(); // 将文件写入输入流 FileInputStream fileInputStream = new FileInputStream(file); InputStream fis = new BufferedInputStream(fileInputStream); byte[] buffer = new byte[fis.available()]; //noinspection ResultOfMethodCallIgnored fis.read(buffer); fis.close(); response.reset(); response.setCharacterEncoding("UTF-8"); response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8")); // 告知浏览器文件的大小 response.addHeader("Content-Length", "" + file.length()); OutputStream outputStream = new BufferedOutputStream(response.getOutputStream()); response.setContentType("application/octet-stream"); outputStream.write(buffer); outputStream.flush(); } catch (IOException ex) { ex.printStackTrace(); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
这个方法的参数就是上述方法最后的代码:
//返回数据JsonResp<String> objectJsonResp = new JsonResp<>();//返回路径resultFile = "lims/downloadGenerateExcel?path=" + resultFile;objectJsonResp.setData(resultFile);return objectJsonResp;
- 1
- 2
- 3
- 4
- 5
- 6
也就是导出完成后返回的参数可以自动调用这个方法,把返回的参数自动传入该方法的Path,即可完成从服务器下载到本地。
四、使用效果
运行对应的接口,即可把数据导出并填充在指定的Excel模板内,并下载到指定位置,使用以上模板导出的结果如下:
以上均为模拟数据,大家根据实际情况来编写即可
在最后附上EasyExcel最新的文档地址:https://easyexcel.opensource.alibaba.com/docs/current/quickstart/fill