文件下载、excel导出、支持中文
导出excel、下载文件
流程:导出都是从服务器下载文件,数据库中的数据查询出来 生成文件放到服务器上,再下载。下载之后可以根据需要自行删除或保留。
一、数据库查询出的数据导出excel
1.List<Map> 形式的数据
1.1生成excel的工具类
import java.util.List; import java.util.Map; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFCellStyle; import org.apache.poi.hssf.util.HSSFColor; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.DataFormat; import org.apache.poi.ss.usermodel.Font; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.xssf.streaming.SXSSFWorkbook; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /**** * List<Map<String, Object>> 形式的数据 生成excel * CellStyle 为设置每个类型数据的样式 * 内容设置里面的value 为得到数据类型,可根据需要补充 * else 里面为excel的类型数据。可根据需要补充 * 建议:避免输入输出格式有误,建议全部用String格式走 * * @author tablemiao * */ public class CreateMapExcel { private static Logger logger = LoggerFactory.getLogger(CreateMapExcel.class); /** * @param * datas 数据 * @param * props 参数设置 * @param * sheetName 单元格名称 * * */ public static SXSSFWorkbook create(List<Map<String, Object>> datas, List<PropSetter> props, String sheetName) { long startTime = System.currentTimeMillis(); SXSSFWorkbook workbook = new SXSSFWorkbook(); Sheet sheet = workbook.createSheet(); workbook.setSheetName(0, sheetName); Font titleFont = workbook.createFont(); titleFont.setFontName("微软雅黑"); titleFont.setFontHeightInPoints((short) 10); // 字体大小 titleFont.setBoldweight(Font.BOLDWEIGHT_BOLD);// 加粗 Font contentFont = workbook.createFont(); contentFont.setFontName("微软雅黑"); contentFont.setFontHeightInPoints((short) 9); DataFormat format = workbook.createDataFormat(); CellStyle titleStyle = workbook.createCellStyle(); titleStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);// 垂直 titleStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);// 水平 titleStyle.setBorderBottom(CellStyle.BORDER_THIN); titleStyle.setBorderLeft(CellStyle.BORDER_THIN); titleStyle.setBorderRight(CellStyle.BORDER_THIN); titleStyle.setBorderTop(CellStyle.BORDER_THIN); titleStyle.setFillForegroundColor(HSSFColor.LIGHT_GREEN.index);// 填暗红色 titleStyle.setFillPattern(CellStyle.SOLID_FOREGROUND); titleStyle.setFont(titleFont); titleStyle.setWrapText(true); CellStyle stringStyle = workbook.createCellStyle(); stringStyle.setAlignment(CellStyle.ALIGN_LEFT); stringStyle.setBorderBottom(CellStyle.BORDER_THIN); stringStyle.setBorderLeft(CellStyle.BORDER_THIN); stringStyle.setBorderRight(CellStyle.BORDER_THIN); stringStyle.setBorderTop(CellStyle.BORDER_THIN); stringStyle.setFont(contentFont); stringStyle.setWrapText(true); CellStyle longStyle = workbook.createCellStyle(); longStyle.setAlignment(CellStyle.ALIGN_LEFT); longStyle.setBorderBottom(CellStyle.BORDER_THIN); longStyle.setBorderLeft(CellStyle.BORDER_THIN); longStyle.setBorderRight(CellStyle.BORDER_THIN); longStyle.setBorderTop(CellStyle.BORDER_THIN); longStyle.setFont(contentFont); longStyle.setDataFormat(format.getFormat("0")); longStyle.setWrapText(true); CellStyle doubleStyle = workbook.createCellStyle(); doubleStyle.setAlignment(CellStyle.ALIGN_LEFT); doubleStyle.setBorderBottom(CellStyle.BORDER_THIN); doubleStyle.setBorderLeft(CellStyle.BORDER_THIN); doubleStyle.setBorderRight(CellStyle.BORDER_THIN); doubleStyle.setBorderTop(CellStyle.BORDER_THIN); doubleStyle.setFont(contentFont); doubleStyle.setDataFormat(format.getFormat("0.00")); doubleStyle.setWrapText(true); Row rowOne = sheet.createRow(0); rowOne.setHeight((short) 350); Cell cell; for (int i = 0; i < props.size(); i++) {// 标题的设置 cell = rowOne.createCell(i); sheet.setColumnWidth(i, props.get(i).getWidth()); // 宽度 cell.setCellStyle(titleStyle); cell.setCellValue(props.get(i).getrOne()); // 标题 } // 内容设置 Row row; if (datas.size() != 0) { for (int m = 0; m < datas.size(); m++) { row = sheet.createRow(m + 1); row.setHeight((short) 310); for (int i = 0; i < props.size(); i++) { Cell cont = row.createCell(i); Object value = datas.get(m).get(props.get(i).getProp()); if (value == null) { cont.setCellValue(""); cont.setCellStyle(stringStyle); }else{ try{ cont.setCellType(HSSFCell.CELL_TYPE_STRING); cont.setCellValue(Long.valueOf(String.valueOf(value))); cont.setCellStyle(longStyle); }catch(Exception e){ try{ cont.setCellType(HSSFCell.CELL_TYPE_STRING); cont.setCellValue((Double.valueOf(String.valueOf(value)))); cont.setCellStyle(doubleStyle); }catch(Exception e1){ cont.setCellType(HSSFCell.CELL_TYPE_STRING); cont.setCellValue(String.valueOf(value)); cont.setCellStyle(stringStyle); } } } } } } logger.info("导出总计耗时: {}", System.currentTimeMillis() - startTime + "毫秒!"); return workbook; } }
1.2 组成excel数据的实体
/*** * 组成list数据的实体 * * @author tablemiao * */ public class PropSetter { private String rOne; private String rTwo; private String prop; private String type; private int width; private boolean color; /**** get、set 方法省略 ******/ public PropSetter(String rOne, String rTwo, String prop, int width) { super(); this.rOne = rOne; this.rTwo = rTwo; this.prop = prop; this.width = width; } public PropSetter(String rOne, String rTwo, String prop, int width, boolean color) { super(); this.rOne = rOne; this.rTwo = rTwo; this.prop = prop; this.width = width; this.color = color; } public PropSetter(String rOne, String rTwo, String prop, String type, int width) { super(); this.rOne = rOne; this.rTwo = rTwo; this.prop = prop; this.type = type; this.width = width; } public PropSetter() { super(); } }
1.3 数据库的数据填充的excel里
/*** * map数据 直接 导出 * @param param dao层参数,这里直接测试 不通过dao * @param realFile 导出的生成文件名,用来下载 * @throws IOException */ public void exportToMap(Map<String, String> param, String realFile) throws IOException{ // param 为dao成过来的参数,可利用dao层查询数据库 得到一个需要导出的List<Map>数据 //此处自定义这样的数据 导出测试,根据实际查询数据库即可 List<Map<String, Object>> datas = new ArrayList<Map<String,Object>>(); Map<String, Object> map = null; map = new HashMap<String, Object>(); map.put("customersNum", "2101087118"); map.put("customersName", "上海习正金融信息服务有限公司"); map.put("logo", "CL-BQ-A-NULL-218840-ZB"); datas.add(map); map = new HashMap<String, Object>(); map.put("customersNum", "2100309828"); map.put("customersName", "苏州银行股份有限公司"); map.put("logo", "CL-XB-A-NULL-1211-0072"); datas.add(map); map = new HashMap<String, Object>(); map.put("customersNum", "2100311056"); map.put("customersName", "中国移动国际有限公司"); map.put("logo", "CL-JK-I-NULL-218446-XB"); datas.add(map); //构造一个excel,每一行即为一个PropSetter //第一列为导出的excel的列名、第三列为map数据的key,大小写必须一致,第五列为excel每一格的宽度,具体可以在1.2的类里面自定义 List<PropSetter> props = new ArrayList<PropSetter>(); props.add(new PropSetter("集团编号qqqqq", null, "customersNum", null, 4000)); props.add(new PropSetter("集团名称", null, "customersName", null, 6000)); props.add(new PropSetter("专线编号", null, "logo", null, 6000)); //调用1.1中的生成方法 生成excel OutputStream outputStream = new FileOutputStream(realFile); SXSSFWorkbook workbook = CreateMapExcel.create(datas, props,"ExcelToMap测试"); workbook.write(outputStream); logger.info("ExcelToMap 测试 导出成功"); outputStream.flush(); outputStream.close(); }
1.4 servlet导出生成1.3生成的excel,下载文件也是如此
组装下载地址
private final FastDateFormat dayFormat = FastDateFormat.getInstance("yyyyMMdd^yyyyMMddHHmmss^"); public String exportToMap() throws Exception { String fileName = "export" + File.separator + "Map数据直接导出测试_" + dayFormat.format(System.currentTimeMillis()) + ".xlsx"; //获取服务器地址加文件名字,即文件存放的位置 String realFile = webPath + File.separator + fileName; fileOperate(realFile);//上传方法里的判断文件是否存在,根据需要删除 exportExcel.exportToMap(new HashMap<String, String>(),realFile); return fileName; } private void fileOperate(String realFile) { File file = new File(realFile); if(file.exists()) { logger.info("文件已经存在, 执行文件删除操作"); file.delete(); logger.info("删除已经存在的文件, 文件名称: {}", realFile); } }
1.5 暴露接口,通过一串地址在浏览器地址栏中输入下载服务器相应文件
@GET @Path("/export") @Produces("text/plain;charset=UTF-8") public String exportExcel() throws Exception { String fileName = servletUpload.exportToMap(); logger.info("ExcelToMap导出 成功 FileName : {} ", fileName); String tmp = getUrlCode(fileName); logger.info("组装后的文件名称: {}", tmp); return tmp; } protected String getUrlCode(String fileName) throws UnsupportedEncodingException { String tmp = fileName.replace("export/", ""); String[] fs = tmp.split("\\^"); tmp = fs[0] + fs[2]; tmp = "servletExportUtil/" + URLEncoder.encode(tmp, "utf-8") + "?timeId=" + fs[1]; return tmp; }
1.6 servlet 拦截地址下载文件
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URLDecoder; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ServletExportUtil extends HttpServlet { protected final Logger logger = LoggerFactory.getLogger(this.getClass()); private static final long serialVersionUID = 1L; @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String url = request.getRequestURI(); String timeId = request.getParameter("timeId"); String fileNameDecode = url.substring(url.lastIndexOf('/') + 1); logger.info("timeId: {}", timeId); fileNameDecode = URLDecoder.decode(fileNameDecode, "utf-8"); String[] fs = fileNameDecode.split("\\."); String realFileName = fs[0] + "^" + timeId + "^." + fs[1]; // fileNameDecode = fs[0] + fs[2]; logger.info("转义后的文件名称: {}, {}", fileNameDecode); String savepath = getInitParameter("FilePath"); logger.info("文件保存的路径: {}", savepath); logger.info("文件绝对路径: {}", savepath + File.separator + realFileName); File file = new File(savepath + File.separator + realFileName); if (!file.exists()) { throw new RuntimeException("文件不存在"); } else { InputStream in = new FileInputStream(file); // 设置响应类型 response.setContentType("application/force-download"); response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileNameDecode.getBytes("utf-8"), "ISO-8859-1")); // 把本地文件发送给客户端 OutputStream out = response.getOutputStream(); int len = 0; byte[] bs = new byte[in.available()]; while ((len = in.read(bs)) != -1) { out.write(bs, 0, len); } in.close(); out.flush(); out.close(); } } }
1.7 web.xml 配置servlet 即 webpath的 服务器路径(这个路径亦可以写死在代码里)
<servlet> <servlet-name>ServletExportUtil</servlet-name> <servlet-class>com.eastcom.linksight.ws.webservices.ext.ServletExportUtil</servlet-class> <init-param> <param-name>FilePath</param-name> <param-value>/home/table/tomcat-res1/webapps/shjkws/export</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>ServletExportUtil</servlet-name> <url-pattern>/servletExportUtil/*</url-pattern> </servlet-mapping> <!-- class 对应相应webpath定义的类,value 就是初始化给的值,即服务器路径 --> <bean class="com.eastcom.linksight.ws.elapse.service.impl.ElapseNoticeServiceImpl"> <property value="/home/table/tomcat-res1/webapps/shjkws" name="webPath"/> </bean>
总结流程:
1.客户端调用导出接口拿到一个地址放在服务器请求
eg:http://10.221.xx.xx:8080/table/servletExportUtil/%E7%BB%9F%E8%AE%A1%E5%88%86%E6%9E%90.xlsx?timeId=20150430165132 以servletExportUtil为分割 前面一节为服务器地址,后面一节为export接口生成的地址,详见1.4和1.5
拿到1.4中的filename通过1.5中getUriCode方法转码拼接之后就得到了。
2.该请求地址被servlet拦截(web.xml有配置),进入1.6解析,找到服务器中对应的文件 通过流方式 生成文件到客户端
二 List<bean> 方式的数据处理,下载方式完全,生成文件到服务器有点差异。
2.1生成excel的模板
package com.eastcom.linksight.ws.elapse.export; import java.beans.PropertyDescriptor; import java.lang.reflect.Method; import java.util.Date; import java.util.List; import org.apache.poi.hssf.util.HSSFColor; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.DataFormat; import org.apache.poi.ss.usermodel.Font; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.xssf.streaming.SXSSFWorkbook; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.CollectionUtils; public class CreateExcel<Record> { private Logger logger = LoggerFactory.getLogger(getClass()); public SXSSFWorkbook create(List<CellSetter> cellSetters, List<Record> records, String sheetName) { long xl = System.currentTimeMillis(); CellSetter cellSetter; Cell cell; SXSSFWorkbook workbook = new SXSSFWorkbook(); DataFormat format = workbook.createDataFormat(); Method getMethod = null; try { int cols = cellSetters.size(); int rows = records.size(); Font titleFont = workbook.createFont(); titleFont.setFontName("微软雅黑"); titleFont.setFontHeightInPoints((short) 10); // 字体大小 titleFont.setBoldweight(Font.BOLDWEIGHT_BOLD);// 加粗 Font contentFont = workbook.createFont(); contentFont.setFontName("微软雅黑"); contentFont.setFontHeightInPoints((short) 8); CellStyle titleStyle = workbook.createCellStyle(); CellStyle longStyle = workbook.createCellStyle(); CellStyle stringStyle = workbook.createCellStyle(); CellStyle dateStyle = workbook.createCellStyle(); CellStyle booleanStyle = workbook.createCellStyle(); CellStyle doubleStyle = workbook.createCellStyle(); titleStyle.setAlignment(CellStyle.ALIGN_CENTER); titleStyle.setBorderBottom(CellStyle.BORDER_THIN); titleStyle.setBorderLeft(CellStyle.BORDER_THIN); titleStyle.setBorderRight(CellStyle.BORDER_THIN); titleStyle.setBorderTop(CellStyle.BORDER_THIN); titleStyle.setFillForegroundColor(HSSFColor.LIGHT_GREEN.index);// 填暗红色 titleStyle.setFillPattern(CellStyle.SOLID_FOREGROUND); titleStyle.setFont(titleFont); titleStyle.setWrapText(true); longStyle.setAlignment(CellStyle.ALIGN_LEFT); longStyle.setBorderBottom(CellStyle.BORDER_THIN); longStyle.setBorderLeft(CellStyle.BORDER_THIN); longStyle.setBorderRight(CellStyle.BORDER_THIN); longStyle.setBorderTop(CellStyle.BORDER_THIN); longStyle.setFont(contentFont); longStyle.setWrapText(true); doubleStyle.setAlignment(CellStyle.ALIGN_LEFT); doubleStyle.setBorderBottom(CellStyle.BORDER_THIN); doubleStyle.setBorderLeft(CellStyle.BORDER_THIN); doubleStyle.setBorderRight(CellStyle.BORDER_THIN); doubleStyle.setBorderTop(CellStyle.BORDER_THIN); doubleStyle.setFont(contentFont); doubleStyle.setWrapText(true); stringStyle.setAlignment(CellStyle.ALIGN_LEFT); stringStyle.setBorderBottom(CellStyle.BORDER_THIN); stringStyle.setBorderLeft(CellStyle.BORDER_THIN); stringStyle.setBorderRight(CellStyle.BORDER_THIN); stringStyle.setBorderTop(CellStyle.BORDER_THIN); stringStyle.setFont(contentFont); stringStyle.setWrapText(true); dateStyle.setAlignment(CellStyle.ALIGN_LEFT); dateStyle.setBorderBottom(CellStyle.BORDER_THIN); dateStyle.setBorderLeft(CellStyle.BORDER_THIN); dateStyle.setBorderRight(CellStyle.BORDER_THIN); dateStyle.setBorderTop(CellStyle.BORDER_THIN); dateStyle.setFont(contentFont); dateStyle.setWrapText(true); booleanStyle.setAlignment(CellStyle.ALIGN_LEFT); booleanStyle.setBorderBottom(CellStyle.BORDER_THIN); booleanStyle.setBorderLeft(CellStyle.BORDER_THIN); booleanStyle.setBorderRight(CellStyle.BORDER_THIN); booleanStyle.setBorderTop(CellStyle.BORDER_THIN); booleanStyle.setFont(contentFont); booleanStyle.setWrapText(true); Sheet sheet = workbook.createSheet(); workbook.setSheetName(0, sheetName); Row row = sheet.createRow(0); // Drawing draw = sheet.createDrawingPatriarch(); Class<Record> clz = null; Method[] methods = new Method[cols]; if (!CollectionUtils.isEmpty(records)) { clz = (Class<Record>) records.get(0).getClass(); } // 设置标题 for (int i = 0; i < cols; i++) { cell = row.createCell(i); cellSetter = cellSetters.get(i); cell.setCellValue(cellSetter.getTitle().trim()); cell.setCellStyle(titleStyle); // if (cellSetters.get(i) != null) { // Comment comment = draw // .createCellComment(new XSSFClientAnchor(0, 0, 0, 0, // cell.getColumnIndex(), row.getRowNum(), // cell.getColumnIndex() + 1, // row.getRowNum() + 2)); // comment.setString(new XSSFRichTextString(cellSetter // .getTitle())); // cell.setCellComment(comment); // } if (clz != null) { PropertyDescriptor pd = new PropertyDescriptor( cellSetter.getProperty(), clz); methods[i] = pd.getReadMethod(); } } // 这是内容 for (int i = 0; i < rows; i++) { row = sheet.createRow(i + 1); row.setHeight((short) 300); if ((i + 1) % 10000 == 0) logger.info("存了一万条记录 {}"); for (int j = 0; j < cols; j++) { cellSetter = cellSetters.get(j); cell = row.createCell(j); Record record = records.get(i); getMethod = methods[j]; if (getMethod.invoke(record) == null) { cell.setCellStyle(stringStyle); continue; } if (cellSetter.getRender() != null) { cell.setCellType(Cell.CELL_TYPE_STRING); cell.setCellStyle(stringStyle); cell.setCellValue(cellSetter.getRender().view( getMethod.invoke(record))); // Comment comment = draw // .createCellComment(new XSSFClientAnchor(0, 0, // 0, 0, cell.getColumnIndex(), row // .getRowNum(), cell // .getColumnIndex() + 1, row // .getRowNum() + 2)); // comment.setString(new XSSFRichTextString(cellSetter // .getRender().view(getMethod.invoke(record)))); // cell.setCellComment(comment); continue; } if (cellSetter.getType().trim().toLowerCase() .equals("long") || cellSetter.getType().trim().toLowerCase() .equals("int") || cellSetter.getType().trim().toLowerCase() .equals("byte") || cellSetter.getType().trim().toLowerCase() .equals("short")) { cell.setCellType(Cell.CELL_TYPE_NUMERIC); longStyle.setDataFormat(format.getFormat(cellSetter .getFormat())); cell.setCellValue(Long.parseLong(getMethod.invoke( record).toString())); // Comment comment = draw // .createCellComment(new XSSFClientAnchor(0, 0, // 0, 0, cell.getColumnIndex(), row // .getRowNum(), cell // .getColumnIndex() + 1, row // .getRowNum() + 2)); // comment.setString(new XSSFRichTextString(getMethod // .invoke(record).toString())); // cell.setCellComment(comment); cell.setCellStyle(longStyle); continue; } if (cellSetter.getType().trim().toLowerCase() .equals("double") || cellSetter.getType().trim().toLowerCase() .equals("float")) { cell.setCellType(Cell.CELL_TYPE_NUMERIC); doubleStyle.setDataFormat(format.getFormat(cellSetter .getFormat())); cell.setCellValue(Double.parseDouble(getMethod.invoke( record).toString())); // Comment comment = draw // .createCellComment(new XSSFClientAnchor(0, 0, // 0, 0, cell.getColumnIndex(), row // .getRowNum(), cell // .getColumnIndex() + 1, row // .getRowNum() + 2)); // comment.setString(new XSSFRichTextString(getMethod // .invoke(record).toString())); // cell.setCellComment(comment); cell.setCellStyle(doubleStyle); continue; } if (cellSetter.getType().trim().toLowerCase() .equals("date")) { cell.setCellType(Cell.CELL_TYPE_NUMERIC); dateStyle.setDataFormat(format.getFormat(cellSetter .getFormat())); cell.setCellValue((Date) getMethod.invoke(record)); cell.setCellStyle(dateStyle); // Comment comment = draw // .createCellComment(new XSSFClientAnchor(0, 0, // 0, 0, cell.getColumnIndex(), row // .getRowNum(), cell // .getColumnIndex() + 1, row // .getRowNum() + 2)); // comment.setString(new XSSFRichTextString(getMethod // .invoke(record).toString())); // cell.setCellComment(comment); continue; } if (cellSetter.getType().trim().toLowerCase() .equals("string") || cellSetter.getType().trim().toLowerCase() .equals("char")) { cell.setCellType(Cell.CELL_TYPE_STRING); try { cell.setCellValue(Integer.parseInt(getMethod .invoke(record).toString())); cell.setCellStyle(longStyle); } catch (Exception e) { try { cell.setCellValue(Double.parseDouble(getMethod .invoke(record).toString())); cell.setCellStyle(doubleStyle); } catch (Exception e1) { cell.setCellStyle(stringStyle); cell.setCellValue(getMethod.invoke(record) .toString()); } } // Comment comment = draw // .createCellComment(new XSSFClientAnchor(0, 0, // 0, 0, cell.getColumnIndex(), row // .getRowNum(), cell // .getColumnIndex() + 1, row // .getRowNum() + 2)); // comment.setString(new XSSFRichTextString(getMethod // .invoke(record).toString())); // cell.setCellComment(comment); continue; } if (cellSetter.getType().trim().toLowerCase() .equals("boolean")) { cell.setCellType(Cell.CELL_TYPE_BOOLEAN); booleanStyle.setDataFormat(format.getFormat(cellSetter .getFormat())); cell.setCellStyle(booleanStyle); cell.setCellValue((Boolean) getMethod.invoke(record)); // Comment comment = draw // .createCellComment(new XSSFClientAnchor(0, 0, // 0, 0, cell.getColumnIndex(), row // .getRowNum(), cell // .getColumnIndex() + 1, row // .getRowNum() + 2)); // comment.setString(new XSSFRichTextString(getMethod // .invoke(record).toString())); // cell.setCellComment(comment); continue; } } } // 给每行设置单元格长度 for (int i = 0; i < cellSetters.size(); i++) { cellSetter = cellSetters.get(i); sheet.setColumnWidth(i, cellSetter.getCellColumnWidth()); } logger.info("总耗时 {} ", System.currentTimeMillis() - xl); return workbook; } catch (Exception e) { e.printStackTrace(); } return null; } }
2.2构造组成excel数据的实体
/*** * 该类 可根据具体需求设定 * **/ public class CellSetter { private String title; private String property; private String type; private String format; private int cellColumnWidth; private ExeclColRnderer render; /**** 省略 get、set *****/ public CellSetter(String title, String property, String type, String format, int cellColumnWidth) { super(); this.title = title; this.property = property; this.type = type; this.format = format; this.cellColumnWidth = cellColumnWidth; } public CellSetter(String title, String property, String type, String format, int cellColumnWidth, ExeclColRnderer render) { super(); this.title = title; this.property = property; this.type = type; this.format = format; this.cellColumnWidth = cellColumnWidth; this.render = render; } public CellSetter() { } } interface ExeclColRnderer{ String view(Object o); }
2.3 数据库的数据填充的excel里
/*** * 统计分析_kpi指标_售中kpi指标_售中kpi维护 * * @param data ws层直接传过来的数据 * @throws Exception */ public void createKpiIndexSZ(List<KpiIndexSZ> data,String realFile) throws Exception{ CreateExcel<KpiIndexSZ> createExcel = new CreateExcel<KpiIndexSZ>(); logger.info("开始导出 统计分析_kpi指标_售中kpi指标_售中kpi维护 数据"); // CellSetter 第一列为 excel中的头、第二列为实体对应的字段、第三列为数据的类型、第4列为excel的类型、5列为宽度 List<CellSetter> cellSetter = new ArrayList<CellSetter>(); cellSetter.add(new CellSetter("月份", "saveDate", "String", "G/通用格式", 6000)); cellSetter.add(new CellSetter("属地分公司", "dependency", "String", "G/通用格式", 6000)); cellSetter.add(new CellSetter("售中开通及时率(%)", "ratio", "String", "G/通用格式", 6000)); OutputStream outputStream = new FileOutputStream(realFile); SXSSFWorkbook workbook = createExcel.create(cellSetter, data,"售中kpi维护"); workbook.write(outputStream); logger.info("统计分析_kpi指标_售中kpi指标 数据导出成功"); outputStream.flush(); outputStream.close(); }
其余下载为List<Map> 一致
三、复杂表头的数据导出
下载方式与上述一致,只是构造excel的模板不同,跨列和跨行其实就算坐标。合并坐标。
比如:要导出这样的格式(客户信息跨两列,专线编号跨两行)
import java.util.List; import java.util.Map; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFCellStyle; import org.apache.poi.hssf.util.HSSFColor; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.Font; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.xssf.streaming.SXSSFWorkbook; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CreateTwoMapExcel { private static Logger logger = LoggerFactory.getLogger(CreateMapExcel.class); /** * @param * datas 数据 * @param * props 参数设置 * @param * fps 合并单元格坐标值 * @param * sheetName 单元格名称 * * */ public static SXSSFWorkbook create(List<Map<String, Object>> datas, List<PropSetter> props, List<FourPoint> fps, String sheetName) { long startTime = System.currentTimeMillis(); SXSSFWorkbook workbook = new SXSSFWorkbook(); Sheet sheet = workbook.createSheet(); workbook.setSheetName(0, sheetName); Font titleFont = workbook.createFont(); titleFont.setFontName("微软雅黑"); titleFont.setFontHeightInPoints((short) 10); // 字体大小 titleFont.setBoldweight(Font.BOLDWEIGHT_BOLD);// 加粗 Font contentFont = workbook.createFont(); contentFont.setFontName("微软雅黑"); contentFont.setFontHeightInPoints((short) 9); CellStyle titleStyle = workbook.createCellStyle(); titleStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);// 垂直 titleStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);// 水平 titleStyle.setBorderBottom(CellStyle.BORDER_THIN); titleStyle.setBorderLeft(CellStyle.BORDER_THIN); titleStyle.setBorderRight(CellStyle.BORDER_THIN); titleStyle.setBorderTop(CellStyle.BORDER_THIN); titleStyle.setFillForegroundColor(HSSFColor.LIGHT_GREEN.index);// 填暗红色 titleStyle.setFillPattern(CellStyle.SOLID_FOREGROUND); titleStyle.setFont(titleFont); titleStyle.setWrapText(true); CellStyle stringStyle = workbook.createCellStyle(); stringStyle.setAlignment(CellStyle.ALIGN_LEFT); stringStyle.setBorderBottom(CellStyle.BORDER_THIN); stringStyle.setBorderLeft(CellStyle.BORDER_THIN); stringStyle.setBorderRight(CellStyle.BORDER_THIN); stringStyle.setBorderTop(CellStyle.BORDER_THIN); stringStyle.setFont(contentFont); stringStyle.setWrapText(true); Row rowOne = sheet.createRow(0); rowOne.setHeight((short) 350); Row rowTwo = sheet.createRow(1); Cell cell; for(int i=0; i<props.size(); i++) { cell = rowOne.createCell(i);// 一级标题的设置 cell.setCellStyle(titleStyle); cell.setCellValue(props.get(i).getrOne()); cell = rowTwo.createCell(i);// 二级标题的设置 cell.setCellStyle(titleStyle); cell.setCellValue(props.get(i).getrTwo()); sheet.setColumnWidth(i, props.get(i).getWidth()); // 宽度 } for(FourPoint fp : fps) {// 合并单元格 sheet.addMergedRegion(new CellRangeAddress(fp.getRowStart(), fp.getRowEnd(), fp.getColStart(), fp.getColEnd())); } // 内容设置 Row row; if (datas.size() != 0) { for (int m = 0; m < datas.size(); m++) { row = sheet.createRow(m + 2); row.setHeight((short) 310); for (int i = 0; i < props.size(); i++) { Cell cont = row.createCell(i); Object value = datas.get(m).get(props.get(i).getProp()); if (value == null) { cont.setCellValue(""); // cont.setCellType(HSSFCell.CELL_TYPE_STRING); cont.setCellStyle(stringStyle); } else { cont.setCellType(HSSFCell.CELL_TYPE_STRING); cont.setCellValue(String.valueOf(value)); cont.setCellStyle(stringStyle); } } } } logger.info("导出总计耗时: {}", System.currentTimeMillis() - startTime + "毫秒!"); return workbook; } }
3.2构造导出实体
package com.tm.util; /*** * 组成list数据的实体 * * @author tablemiao * */ public class PropSetter { private String rOne; //第一行标题 private String rTwo; //第二行标题 private String prop;//对应的导出数据的字段名 private String type;//数据类型 private int width;//表格宽度 private boolean color;//颜色 /****** Getter Setter 省略*****/ public PropSetter(String rOne, String rTwo, String prop, int width) { super(); this.rOne = rOne; this.rTwo = rTwo; this.prop = prop; this.width = width; } public PropSetter(String rOne, String rTwo, String prop, int width, boolean color) { super(); this.rOne = rOne; this.rTwo = rTwo; this.prop = prop; this.width = width; this.color = color; } public PropSetter(String rOne, String rTwo, String prop, String type, int width) { super(); this.rOne = rOne; this.rTwo = rTwo; this.prop = prop; this.type = type; this.width = width; } public PropSetter() { super(); } }
3.3 填充数据并导出(此处简单起见,就直接导出测试,以单元测试的方式呈现,也可向上诉一样封装接口)
@Test public void testMapExport1() throws Exception { List<Map<String, Object>> datas = new ArrayList<Map<String,Object>>(); Map<String, Object> map = null; map = new HashMap<String, Object>(); map.put("customersNum", "2101087118"); map.put("customersName", "上海习正金融信息服务有限公司"); map.put("logo", "CL-BQ-A-NULL-218840-ZB"); datas.add(map); map = new HashMap<String, Object>(); map.put("customersNum", "2100309828"); map.put("customersName", "苏州银行股份有限公司"); map.put("logo", "CL-XB-A-NULL-1211-0072"); datas.add(map); map = new HashMap<String, Object>(); map.put("customersNum", "2100311056"); map.put("customersName", "中国移动国际有限公司"); map.put("logo", "CL-JK-I-NULL-218446-XB"); datas.add(map); List<PropSetter> props = new ArrayList<PropSetter>(); props.add(new PropSetter("客户信息", "客户名称", "customersName", 4000)); props.add(new PropSetter("", "客户编号", "customersNum", 4000)); props.add(new PropSetter("专线编号", "", "logo", 4000)); List<FourPoint> fps = new ArrayList<FourPoint>(); //合并A,B列,坐标从0开始(客户信息这一栏为第一行所以是(0,0)纵左边跨AB所以是(0,1)) fps.add(new FourPoint(0, 0, 0, 1)); //合并1,2行,坐标从0开始(专线编号这一栏为1,2行所以是(0,1)纵左边为C列所以是(2,2)) fps.add(new FourPoint(0, 1, 2, 2)); OutputStream outputStream = new FileOutputStream("Z:/复杂表头导出.xlsx"); SXSSFWorkbook workbook = CreateTwoMapExcel.create(datas, props, fps, "跨行跨列导出测试"); workbook.write(outputStream); outputStream.flush(); outputStream.close(); }