一、 第一种方式
1.首先从中央仓库中导入架包Poi3.14以及Poi-ooxml3.14.
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.17</version> </dependency>
2.编写工具类
编写用于导出Excel的工具类ExportExcelUtils,工具类可以直接使用,不需要更改。
package com.roncoo.education.web.common; import org.apache.poi.hssf.usermodel.*; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; /** * @author ZhangRF */ public class ExcelUtil { /** * Excel表格导出 * * @param response HttpServletResponse对象 * @param excelData Excel表格的数据,封装为List<List<String>> * @param sheetName sheet的名字 * @param fileName 导出Excel的文件名 * @param columnWidth Excel表格的宽度,建议为15 * @throws IOException 抛IO异常 */ public static void exportExcel(HttpServletResponse response, List<List<String>> excelData, String sheetName, String fileName, int columnWidth) throws IOException { //声明一个工作簿 HSSFWorkbook workbook = new HSSFWorkbook(); //生成一个表格,设置表格名称 HSSFSheet sheet = workbook.createSheet(sheetName); //设置表格列宽度 sheet.setDefaultColumnWidth(columnWidth); //写入List<List<String>>中的数据 int rowIndex = 0; for (List<String> data : excelData) { //创建一个row行,然后自增1 HSSFRow row = sheet.createRow(rowIndex++); //遍历添加本行数据 for (int i = 0; i < data.size(); i++) { //创建一个单元格 HSSFCell cell = row.createCell(i); //创建一个内容对象 HSSFRichTextString text = new HSSFRichTextString(data.get(i)); //将内容对象的文字内容写入到单元格中 cell.setCellValue(text); } } //准备将Excel的输出流通过response输出到页面下载 //八进制输出流 response.setContentType("application/octet-stream"); //设置导出Excel的名称 response.setHeader("Content-disposition", "attachment;filename=" + java.net.URLEncoder.encode(fileName, "UTF-8")); //刷新缓冲 response.flushBuffer(); //workbook将Excel写入到response的输出流中,供页面下载该Excel文件 workbook.write(response.getOutputStream()); //关闭workbook workbook.close(); } }
3.service导出实现
public void orderExport(OrderInfoQO orderInfoQO, HttpServletResponse response) { orderInfoQO.setPageCurrent(1); orderInfoQO.setPageSize(1000); Integer courseFlag = orderInfoQO.getCourseFlag(); CourseFlagEnum courseFlagEnum = CourseFlagEnum.values(courseFlag); boolean isGet = true; List<List<String>> excelData = new ArrayList<>(); List<String> head = new ArrayList<>(); head.add("订单编号"); head.add("讲师信息"); head.add("用户手机号"); head.add("用户姓名"); if (courseFlagEnum == CourseFlagEnum.YUNXIAOHUI) { head.add("机构名称"); } head.add("课程顾问"); head.add("课程名称"); head.add("课程原价"); head.add("课程实付"); head.add("齿币"); head.add("交易类型"); head.add("支付方式"); head.add("购买渠道"); head.add("支付时间"); head.add("客户备注"); excelData.add(head); do { Page<OrderInfoVO> page = feignOrderInfo.listForPage(orderInfoQO); if (page.getPageCurrent() == page.getTotalPage()) { isGet = false; } else { orderInfoQO.setPageCurrent(page.getPageCurrent() + 1); } page.getList().stream().map(m -> { UserExtVO userExtVO = feignUserExt.getByUserNo(m.getUserNo()); List<String> data = new ArrayList<>(); data.add(String.valueOf(m.getOrderNo())); data.add(m.getLecturerName()); data.add(m.getMobile()); if (userExtVO != null && userExtVO.getId() != null) { data.add(userExtVO.getRealName()); if (courseFlagEnum == CourseFlagEnum.YUNXIAOHUI) { data.add(userExtVO.getOrgName()); } data.add(userExtVO.getKefuName()); } else { data.add(""); if (courseFlagEnum == CourseFlagEnum.YUNXIAOHUI) { data.add(""); } data.add(""); } data.add(m.getCourseName()); data.add(String.valueOf(m.getPricePayable())); data.add(String.valueOf(m.getPricePaid())); data.add(String.valueOf(m.getUsePoint())); TradeTypeEnum tradeTypeEnum = TradeTypeEnum.values(m.getTradeType()); if (tradeTypeEnum == null) { data.add(""); } else { data.add(tradeTypeEnum.getDesc()); } PayTypeEnum payTypeEnum = PayTypeEnum.values(m.getPayType()); if (payTypeEnum == null) { data.add(""); } else { data.add(payTypeEnum.getDesc()); } ChannelTypeEnum channelTypeEnum = ChannelTypeEnum.values(m.getChannelType()); if (channelTypeEnum == null) { data.add(""); } else { data.add(channelTypeEnum.getDesc()); } data.add(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(m.getPayTime())); data.add(m.getRemarkCus()); excelData.add(data); return m; }).collect(Collectors.toList()); } while (isGet); String sheetName = "课程订单"; String fileName = "订单报表-"; if (courseFlagEnum == CourseFlagEnum.YUNXIAOHUI) { fileName = "云校汇订单报表"; } fileName = fileName + new SimpleDateFormat("yyyy-MM-dd").format(new Date()) + ".xls"; try { ExcelUtil.exportExcel(response, excelData, sheetName, fileName, 15); } catch (IOException e) { e.printStackTrace(); } }
4.接口调用
/** * 报表导出 * * @param response * @throws IOException */ @RequestMapping(value = "/export", method = RequestMethod.GET) public void orderExport(@ModelAttribute OrderInfoQO orderInfoQO, HttpServletResponse response) throws IOException { biz.orderExport(orderInfoQO, response); }
二、第二种方式
1.首先从中央仓库中导入架包Poi3.14以及Poi-ooxml3.14.
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.14</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.14</version> </dependency>
2.编写工具类
编写用于导出Excel的工具类ExportExcelUtils,工具类可以直接使用,不需要更改。
package org.emall.website.util; import org.apache.poi.hssf.usermodel.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.http.HttpServletResponse; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.lang.reflect.Field; import java.util.Date; import java.text.SimpleDateFormat; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * @version v.0.1 * @Description TODO * @date 2020/6/1 * @备注 **/ public class ExportExcelUtils { private static final Logger logger = LoggerFactory.getLogger(ExportExcelUtils.class); /** * 导出Excel * * @param excelName 要导出的excel名称 * @param list 要导出的数据集合 * @param fieldMap 中英文字段对应Map,即要导出的excel表头 * @param response 使用response可以导出到浏览器 * @param <T> */ public static <T> void export(String excelName, List<T> list, LinkedHashMap<String, String> fieldMap, HttpServletResponse response) { // 设置默认文件名为当前时间:年月日时分秒 if (excelName == null || excelName == "") { excelName = new SimpleDateFormat("yyyyMMddhhmmss").format( new Date()).toString(); } // 设置response头信息 response.reset(); response.setContentType("application/vnd.ms-excel"); // 改成输出excel文件 try { response.setHeader("Content-disposition", "attachment; filename=" + new String(excelName.getBytes("gb2312"), "ISO-8859-1") + ".xls"); } catch (UnsupportedEncodingException e1) { logger.info(e1.getMessage()); } try { //创建一个WorkBook,对应一个Excel文件 HSSFWorkbook wb = new HSSFWorkbook(); //在Workbook中,创建一个sheet,对应Excel中的工作薄(sheet) HSSFSheet sheet = wb.createSheet(excelName); //创建单元格,并设置值表头 设置表头居中 HSSFCellStyle style = wb.createCellStyle(); //创建一个居中格式 style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 填充工作表 fillSheet(sheet, list, fieldMap, style); //将文件输出 OutputStream ouputStream = response.getOutputStream(); wb.write(ouputStream); ouputStream.flush(); ouputStream.close(); } catch (Exception e) { logger.info("导出Excel失败!"); logger.error(e.getMessage()); } } /** * 根据字段名获取字段对象 * * @param fieldName 字段名 * @param clazz 包含该字段的类 * @return 字段 */ public static Field getFieldByName(String fieldName, Class<?> clazz) { logger.info("根据字段名获取字段对象:getFieldByName()"); // 拿到本类的所有字段 Field[] selfFields = clazz.getDeclaredFields(); // 如果本类中存在该字段,则返回 for (Field field : selfFields) { //如果本类中存在该字段,则返回 if (field.getName().equals(fieldName)) { return field; } } // 否则,查看父类中是否存在此字段,如果有则返回 Class<?> superClazz = clazz.getSuperclass(); if (superClazz != null && superClazz != Object.class) { //递归 return getFieldByName(fieldName, superClazz); } // 如果本类和父类都没有,则返回空 return null; } /** * 根据字段名获取字段值 * * @param fieldName 字段名 * @param o 对象 * @return 字段值 * @throws Exception 异常 */ public static Object getFieldValueByName(String fieldName, Object o) throws Exception { logger.info("根据字段名获取字段值:getFieldValueByName()"); Object value = null; //根据字段名得到字段对象 Field field = getFieldByName(fieldName, o.getClass()); //如果该字段存在,则取出该字段的值 if (field != null) { field.setAccessible(true);//类中的成员变量为private,在类外边使用属性值,故必须进行此操作 value = field.get(o);//获取当前对象中当前Field的value } else { throw new Exception(o.getClass().getSimpleName() + "类不存在字段名 " + fieldName); } return value; } /** * 根据带路径或不带路径的属性名获取属性值,即接受简单属性名, * 如userName等,又接受带路径的属性名,如student.department.name等 * * @param fieldNameSequence 带路径的属性名或简单属性名 * @param o 对象 * @return 属性值 * @throws Exception 异常 */ public static Object getFieldValueByNameSequence(String fieldNameSequence, Object o) throws Exception { logger.info("根据带路径或不带路径的属性名获取属性值,即接受简单属性名:getFieldValueByNameSequence()"); Object value = null; // 将fieldNameSequence进行拆分 String[] attributes = fieldNameSequence.split("\."); if (attributes.length == 1) { value = getFieldValueByName(fieldNameSequence, o); } else { // 根据数组中第一个连接属性名获取连接属性对象,如student.department.name Object fieldObj = getFieldValueByName(attributes[0], o); //截取除第一个属性名之后的路径 String subFieldNameSequence = fieldNameSequence .substring(fieldNameSequence.indexOf(".") + 1); //递归得到最终的属性对象的值 value = getFieldValueByNameSequence(subFieldNameSequence, fieldObj); } return value; } /** * 向工作表中填充数据 * * @param sheet excel的工作表名称 * @param list 数据源 * @param fieldMap 中英文字段对应关系的Map * @param style 表格中的格式 * @throws Exception 异常 */ public static <T> void fillSheet(HSSFSheet sheet, List<T> list, LinkedHashMap<String, String> fieldMap, HSSFCellStyle style) throws Exception { logger.info("向工作表中填充数据:fillSheet()"); // 定义存放英文字段名和中文字段名的数组 String[] enFields = new String[fieldMap.size()]; String[] cnFields = new String[fieldMap.size()]; // 填充数组 int count = 0; for (Map.Entry<String, String> entry : fieldMap.entrySet()) { enFields[count] = entry.getKey(); cnFields[count] = entry.getValue(); count++; } //在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制short HSSFRow row = sheet.createRow((int) 0); // 填充表头 for (int i = 0; i < cnFields.length; i++) { HSSFCell cell = row.createCell(i); cell.setCellValue(cnFields[i]); cell.setCellStyle(style); sheet.autoSizeColumn(i); } // 填充内容 for (int index = 0; index < list.size(); index++) { row = sheet.createRow(index + 1); // 获取单个对象 T item = list.get(index); for (int i = 0; i < enFields.length; i++) { Object objValue = getFieldValueByNameSequence(enFields[i], item); String fieldValue = objValue == null ? "" : objValue.toString(); row.createCell(i).setCellValue(fieldValue); } } } }
3.编写实体类
需要输出到Excel的实体表。
package org.emall.website.entity; import java.math.BigInteger; /** * @version v.0.1 * @Description TODO * @date 2020/6/1 * @备注 **/ public class Excel { private BigInteger id; private String order_number; private String amount_real; private String date_add; private String status_str; private String link_man; private String mobie; private String address; private String detailValue; public Excel() { } public Excel(BigInteger id, String order_number, String amount_real, String date_add, String status_str, String link_man, String mobie, String address, String detailValue) { this.id = id; this.order_number = order_number; this.amount_real = amount_real; this.date_add = date_add; this.status_str = status_str; this.link_man = link_man; this.mobie = mobie; this.address = address; this.detailValue = detailValue; } public BigInteger getId() { return id; } public void setId(BigInteger id) { this.id = id; } public String getOrder_number() { return order_number; } public void setOrder_number(String order_number) { this.order_number = order_number; } public String getAmount_real() { return amount_real; } public void setAmount_real(String amount_real) { this.amount_real = amount_real; } public String getDate_add() { return date_add; } public void setDate_add(String date_add) { this.date_add = date_add; } public String getStatus_str() { return status_str; } public void setStatus_str(String status_str) { this.status_str = status_str; } public String getLink_man() { return link_man; } public void setLink_man(String link_man) { this.link_man = link_man; } public String getMobie() { return mobie; } public void setMobie(String mobie) { this.mobie = mobie; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getDetailValue() { return detailValue; } public void setDetailValue(String detailValue) { this.detailValue = detailValue; } }
4.编写控制层即得到Json数据
编写控制层ExcelController,注意fieldMap.put(“实体类属性名”,“Excel中显示的属性名”); 设置实体属性名和数据库中对应。如果得不到数据对应不上,请采用ResultMap设置或者用Select XX(数据库名)As 实体属性名。
package org.emall.website.controller; import org.emall.website.entity.Excel; import org.emall.website.entity.Order; import org.emall.website.service.OrderService; import org.emall.website.util.ExportExcelUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.LinkedHashMap; import java.util.List; /** * @version v.0.1 * @Description TODO * @date 2020/6/1 * @备注 **/ @Controller public class ExcelController { @Autowired private HttpServletRequest request; @Autowired private OrderService orderService; @RequestMapping(value = "/excel/exportBankCheckInfo",method = RequestMethod.GET) public void ExportBankCkeckInfo(HttpServletResponse response, HttpServletRequest request){ //这里是笔者实际业务需求中需要得到时间间隔。可忽略 String start=request.getParameter("start"); String end=request.getParameter("end"); System.out.println("打印的起始日期为:"+start+",打印的结束日期为:"+end); //得到所有要导出的数据 List<Excel> orderlist =orderService.listexcel(start,end); //定义导出的excel名字 String excelName = "订单详情表"; //获取需要转出的excel表头的map字段 LinkedHashMap<String, String> fieldMap = new LinkedHashMap<>(); fieldMap.put("id","编号"); fieldMap.put("link_man","姓名"); fieldMap.put("amount_real","价格"); fieldMap.put("date_add","日期"); fieldMap.put("status_str","订单状态"); fieldMap.put("mobie","收货电话"); fieldMap.put("address","地址"); fieldMap.put("detailValue","订单详情"); //导出用户相关信息 new ExportExcelUtils().export(excelName,orderlist,fieldMap,response); } }
5.验证
在导出工具类中,通过HttpServletResponse response设置输出为Excel。所以通过Controller层的Url可以直接得到URL。保存位置是保存在浏览器的默认保存位置,因为是下载请求。