最近根据公司需求,写一个导出Excel的功能,我使用的是POI,没有选择easyPOI,这里根据POI的基本功能,自己写了一个工具类,可以大大减少工作量,分享到这里,希望能帮到有需要的小伙伴。
说明:这里是根据时间段来查询数据的。
@Override public void Settlement(Map<String, Object> map, HttpServletResponse response) { ReportBaseReq req; req = new ReportBaseReq(); req.setEndTime(map.get("endTime").toString()); req.setStartTime(map.get("startTime").toString()); List<SybxCntTimeSettlementResp> obj = rfAccountService.sybxCntTimeSettlement(req.getStartTime(), req.getEndTime()); if (obj==null){ return; } String filePath = "excelTemplate/reportformaccount/sybx_cntTimeSettlementD.xls"; //添加表格数据 HSSFWorkbook workbook = ExportUtils.structureExcel(obj, filePath, 4); //合并单元格 ExportUtils.mergeCells(obj,workbook,4,0,1); //下载表格 ExportUtils.downLoadTable(workbook,response); }
2.1 请求参数:
map是接收startTime和endTime这两个参数的
2.2 添加表格数据
obj:是查询出来的数据对象
filePath:这里我使用的是模板,只使用了表头的部分,filePath为加载模板的路径
rowBegin:是开始添加数据的行数,4:为从第4行开始添加数据
2.3 合并单元格
obj:查询数据的对象
workbook:工作薄对象
mergeRowBegin:和之前的rowBegin值时一样的,但这里的意思是:开始合并的行数
columns:是需要合并的列数,0,1:合并第0 列和第1列
2.4 下载表格,固定写法
package com.mbf.tianjin.common.utils; import com.mbf.tianjin.common.enums.*; import com.mbf.tianjin.common.po.bigDataAnalysis.InsuPopKpiCntD; import lombok.extern.slf4j.Slf4j; import org.apache.poi.hssf.usermodel.*; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.ss.util.CellRangeAddress; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.net.URLEncoder; import java.time.LocalDate; import java.util.List; import java.util.Map; import java.util.Set; /** * @Author: sniper * @Date: 2021/06/18 * @Description: 导出表格工具类 */ @Slf4j public class ExportUtils { /** * 构造Excel表 * @param obj * @param filePath * @param rowBegin * @param <T> * @return */ public static <T> HSSFWorkbook structureExcel(List<T> obj,String filePath,int rowBegin){ Resource resource = new ClassPathResource(filePath); HSSFWorkbook workbook = null; try { InputStream inputStream = resource.getInputStream(); POIFSFileSystem fspoi=new POIFSFileSystem(inputStream); //创建工作薄对象 workbook=new HSSFWorkbook(fspoi); //获取工作表对象 HSSFSheet sheet=workbook.getSheet("sheet1"); //定义单元格格式 HSSFCellStyle cellStyle = CellStyleUtils.createCellStyle(workbook,sheet, (short) 9,false,true,false,false,12,false,true); //填写报表数据 int r = rowBegin; for(T resp :obj){ Field[] field = resp.getClass().getDeclaredFields(); HSSFRow row = sheet.createRow(r);//行 for (int i = 0; i < resp.getClass().getDeclaredFields().length; i++) { field[i].setAccessible(true);//设置字段可访问, 否则无法访问private修饰的变量值 HSSFCell cell = row.createCell(i);//列 cell.setCellValue(field[i].get(resp)+"");//如果使用.toString可能会报空指针异常 cell.setCellStyle(cellStyle); } r++; } //修改报表日期 LocalDate now = LocalDate.now(); HSSFRow row = sheet.createRow(r); HSSFCell cell = row.createCell(0); cell.setCellValue("下载日期:"+now); CellRangeAddress cellAddresses = new CellRangeAddress(r , r, 0, 2); sheet.addMergedRegion(cellAddresses); } catch (IOException e) { e.printStackTrace(); }catch (Exception e) { log.info("获取属性值失败:"+e); } return workbook; } /** * 合并单元格 * @param workbook * @param mergeRowBegin 开始合并的行 * @param columns 需要合并的列 */ public static <T> void mergeCells(List<T> obj,HSSFWorkbook workbook,int mergeRowBegin,Integer... columns){ HSSFSheet sheet = workbook.getSheet("sheet1"); String[] str = new String[obj.size()]; for (Integer column : columns) { int rowBegin = mergeRowBegin; //获取指定列,不同行的单元格值 try { for (int i = 0; i < obj.size(); i++) { //遍历行 HSSFRow row = sheet.getRow(rowBegin); HSSFCell cell = row.getCell(column); String value = cell.getStringCellValue(); str[i] = value; rowBegin++; } } catch (Exception e) { log.info("获取单元格值失败:" + e); } //合并 try { int index = 0;//计数器 for (int i = 0; i < str.length - 1; i++) { index++;//1 2 3 //判断单元格值是否相同 if (!str[i].equals(str[i + 1])) { if (1 - index != 0) { //如果只有一个单元格,不合并 CellRangeAddress cellAddresses = new CellRangeAddress(i + 1 - index + mergeRowBegin, i + mergeRowBegin, column, column); sheet.addMergedRegion(cellAddresses); index = 0; } } //判断是否循环到最后一行 if (i + 1 == str.length - 1) { if ( index != 0) {//如果只有一个单元格,不合并 CellRangeAddress cellAddresses = new CellRangeAddress(i + 1 - index + mergeRowBegin, i + 1 + mergeRowBegin, column, column); sheet.addMergedRegion(cellAddresses); } } } } catch (Exception e) { log.info("合并单元格失败:" + e); } } } /** * 添加维度值 * @param obj * @param workbook * @param rowBegin 行 * @param map key:维度类型 value:需要合并的列 * @param <T> * @return */ public static <T> HSSFWorkbook replaceValue(List<T> obj, HSSFWorkbook workbook, int rowBegin, Map<String,Integer> map){ HSSFSheet sheet = workbook.getSheet("sheet1"); Set<Map.Entry<String, Integer>> entries = map.entrySet(); for (Map.Entry<String, Integer> entry : entries) { int r = rowBegin; //医疗类别('0':住院,'1':门诊,'2':门特) MED_TYPE if (AllDimension.MedType.getName().equals(entry.getKey())){ for (int i = 0; i < obj.size(); i++) { HSSFRow row = sheet.getRow(r); HSSFCell cell = row.getCell(entry.getValue()); String value = cell.getStringCellValue(); cell.setCellValue("0".equals(value)? MedType.MedType0.getName(): "1".equals(value)?MedType.MedType1.getName():MedType.MedType2.getName()); r++; } } } /** * 下载 * @param workbook * @param response */ public static void downLoadTable(HSSFWorkbook workbook, HttpServletResponse response){ try { workbook.write(response.getOutputStream()); response.setCharacterEncoding("UTF-8"); response.setHeader("content-Type", "application/vnd.ms-excel"); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode( "test.xls", "UTF-8")); }catch (Exception e){ log.info("下载失败:"+e); } } }
工具类里的方法,如何调用上面已经说过了,里面有一个方法:添加维度值,后面再说
看一下此时的效果:
已经实现了合并,但是和第一张图的结果不一样呢?这里是因为,纬度值没有添加进去
这里用到了枚举类,放一个枚举类
@Getter @AllArgsConstructor @NoArgsConstructor public enum AllDimension { InsuType("insuType"),//险种类型(0:城镇职工,1:城乡居民) INSU_TYPE private String name; }
参数介绍:
AllDimension.MedType.getName():险种的name
0:需要替换纬度值的第0列,
obj:查询的数据对象
workbook:工作薄对象
rowBegin:开始替换纬度值的行数
m:map对象
吧这个方法加上就可以替换维度了。
纯属原创分享,希望各路大神指点。