2018-01-22 09:29:41 huangchunxia_1 阅读数 4143
  • 基于SSM的POI导入导出Excel实战

    本课程将给大家分享如何基于SSM实现POI导入导出Excel,并讲解目前企业级JavaWeb应用mvc三层模式的开发流程,可让初学者或者职场萌新掌握如何基于SSM整合第三方框架并采用mvc三层开发模式实现自己的业务模块!

    1273 人正在学习 去看看 钟林森

转载自:http://bbs.chinaunix.net/thread-3620272-1-1.html

说明:我的电脑 2.0CPU 2G内存 能够十秒钟导出 20W 条数据 ,12.8M的excel内容压缩后2.68M
我们知道在POI导出Excel时,数据量大了,很容易导致内存溢出。由于Excel 一个sheet允许的最大行数是65536这时我们想到分sheet进行导出;但是这种情况也不能解决内存溢出的问题。毕竟数据还是一次性在内存中进行保存的。这时我们想是不是可以导出多个excel呢?下面我就尝试着按照导出多个excel
首先:我们要确定数据量有多大,然后确定一个excel导出多少条数据,这样就可以确定导出的Excel的数量,于是我们就可以循环的导出excel并保存在任意的临时目录中。去这样如果内存不够的话虚拟机就会去进行回收已经保存的excel在内存中的空间。
假设我们我们已经成功的生成了多个excel,这时我们怎么把这N个excel文档传到客户端呢?其实一个一个的传也未尝不可,但是考虑那样对用户来说体验不够好,再次多个文件在网络上传输也比较慢。我们可以考虑对生成的几个文件进行压缩,然后传到客户端。
总结一下第一、分批次生成excel第二、压缩后到客户端

下面我把我的一个小实例贴上供大家参考

第一、Person.java 普通javabean

Javabean代码

  1. package bean;  
  2. /**  
  3. *   
  4. * @author QQ:三二8二4七6七六  
  5. *  
  6. */  
  7. public class Person {  
  8.   
  9.     private Integer id;  
  10.     private String name;  
  11.     private String address;  
  12.     private String tel;  
  13.     private Double money=0.0;  
  14.     public Double getMoney() {  
  15.         return money;  
  16.     }  
  17.     public void setMoney(Double money) {  
  18.         this.money = money;  
  19.     }  
  20.     public Person(Integer id, String name, String address, String tel,Double money) {  
  21.         super();  
  22.         this.id = id;  
  23.         this.name = name;  
  24.         this.address = address;  
  25.         this.tel = tel;  
  26.         this.money=money;  
  27.     }  
  28.     public Integer getId() {  
  29.         return id;  
  30.     }  
  31.     public void setId(Integer id) {  
  32.         this.id = id;  
  33.     }  
  34.     public String getName() {  
  35.         return name;  
  36.     }  
  37.     public void setName(String name) {  
  38.         this.name = name;  
  39.     }  
  40.     public String getAddress() {  
  41.         return address;  
  42.     }  
  43.     public void setAddress(String address) {  
  44.         this.address = address;  
  45.     }  
  46.     public String getTel() {  
  47.         return tel;  
  48.     }  
  49.     public void setTel(String tel) {  
  50.         this.tel = tel;  
  51.     }  
  52. }  
复制代码
第二、PersonService模拟业务逻辑循环生成100023个Person对象

模拟业务逻辑代码
  1. package service;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import bean.Person;  
  7. /**  
  8. *   
  9. * @author QQ:三二8二4七6七六  
  10. *  
  11. */  
  12. public class PersonService {  
  13.     public static List getPerson(){  
  14.         List<Person> list =new ArrayList<Person>();  
  15.         for(int i=0;i<100320;i++){  
  16.             list.add(new Person(i,"zhangsan"+i,"北京"+i,"13214587632",123123.12+i));   
  17.         }  
  18.         return list;  
  19.     }  
  20.   
  21. }  
复制代码
第三、业务处理Servlet

操作servlet代码
  1. package servlet;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileInputStream;  
  5. import java.io.FileOutputStream;  
  6. import java.io.IOException;  
  7. import java.io.OutputStream;  
  8. import java.text.SimpleDateFormat;  
  9. import java.util.ArrayList;  
  10. import java.util.Date;  
  11. import java.util.List;  
  12.   
  13. import javax.servlet.ServletException;  
  14. import javax.servlet.http.HttpServlet;  
  15. import javax.servlet.http.HttpServletRequest;  
  16. import javax.servlet.http.HttpServletResponse;  
  17.   
  18. import org.apache.poi.hssf.usermodel.HSSFWorkbook;  
  19. import org.apache.poi.hssf.util.CellRangeAddress;  
  20. import org.apache.poi.ss.usermodel.Cell;  
  21. import org.apache.poi.ss.usermodel.CellStyle;  
  22. import org.apache.poi.ss.usermodel.Row;  
  23. import org.apache.poi.ss.usermodel.Sheet;  
  24. import org.apache.poi.ss.usermodel.Workbook;  
  25.   
  26. import bean.Person;  
  27.   
  28. import service.PersonService;  
  29.   
  30. /**  
  31. *   
  32. * @author QQ:三二8二4七6七六  
  33. *   
  34. */  
  35. public class PersonServlet extends HttpServlet {  
  36.     private String fileName;  
  37.   
  38.     public PersonServlet() {  
  39.         super();  
  40.     }  
  41.   
  42.     public void destroy() {  
  43.         super.destroy(); // Just puts "destroy" string in log  
  44.         // Put your code here  
  45.     }  
  46.   
  47.     public void doGet(HttpServletRequest request, HttpServletResponse response)  
  48.             throws ServletException, IOException {  
  49.         // 文件名获取  
  50.         Date date = new Date();  
  51.         SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");  
  52.         String f = "Person-" + format.format(date);  
  53.         this.fileName = f;  
  54.         setResponseHeader(response);  
  55.         OutputStream out = null;  
  56.         try {  
  57.             out = response.getOutputStream();  
  58.             List<Person> list = PersonService.getPerson();  
  59.             toExcel(list,request,10000,f,out);  
  60.         } catch (IOException e1) {  
  61.             e1.printStackTrace();  
  62.         } finally {  
  63.             try {  
  64.                 out.flush();  
  65.                 out.close();  
  66.             } catch (IOException e) {  
  67.                 e.printStackTrace();  
  68.             }  
  69.         }  
  70.     }  
  71.   
  72.     /** 设置响应头 */  
  73.     public void setResponseHeader(HttpServletResponse response) {  
  74.         try {  
  75.             response.setContentType("application/octet-stream;charset=UTF-8");  
  76.             response.setHeader("Content-Disposition", "attachment;filename="  
  77.                     + java.net.URLEncoder.encode(this.fileName, "UTF-8")  
  78.                     + ".zip");  
  79.             response.addHeader("Pargam", "no-cache");  
  80.             response.addHeader("Cache-Control", "no-cache");  
  81.         } catch (Exception ex) {  
  82.             ex.printStackTrace();  
  83.         }  
  84.     }  
  85.     public void doPost(HttpServletRequest request, HttpServletResponse response)  
  86.             throws ServletException, IOException {  
  87.   
  88.         doGet(request, response);  
  89.     }  
  90.     public void init() throws ServletException {  
  91.         // Put your code here  
  92.     }  
  93.   
  94.     public void toExcel(List<Person> list, HttpServletRequest request,  
  95.             int length, String f, OutputStream out) throws IOException {  
  96.         List<String> fileNames = new ArrayList();// 用于存放生成的文件名称s  
  97.         File zip = new File(request.getRealPath("/files") + "/" + f + ".zip");// 压缩文件  
  98.         // 生成excel  
  99.         for (int j = 0, n = list.size() / length + 1; j < n; j++) {  
  100.             Workbook book = new HSSFWorkbook();  
  101.             Sheet sheet = book.createSheet("person");  
  102.   
  103.             double d = 0;// 用来统计  
  104.             String file = request.getRealPath("/files") + "/" + f + "-" + j  
  105.                     + ".xls";  
  106.   
  107.             fileNames.add(file);  
  108.             FileOutputStream o = null;  
  109.             try {  
  110.                 o = new FileOutputStream(file);  
  111.   
  112.                 // sheet.addMergedRegion(new  
  113.                 // CellRangeAddress(list.size()+1,0,list.size()+5,6));  
  114.                 Row row = sheet.createRow(0);  
  115.                 row.createCell(0).setCellValue("ID");  
  116.                 row.createCell(1).setCellValue("NAME");  
  117.                 row.createCell(2).setCellValue("ADDRESS");  
  118.                 row.createCell(3).setCellValue("TEL");  
  119.                 row.createCell(4).setCellValue("Money");  
  120.   
  121.                 int m = 1;  
  122.   
  123.                 for (int i = 1, min = (list.size() - j * length + 1) > (length + 1) ? (length + 1)  
  124.                         : (list.size() - j * length + 1); i < min; i++) {  
  125.                     m++;  
  126.                     Person user = list.get(length * (j) + i - 1);  
  127.                     Double dd = user.getMoney();  
  128.                     if (dd == null) {  
  129.                         dd = 0.0;  
  130.                     }  
  131.                     d += dd;  
  132.                     row = sheet.createRow(i);  
  133.                     row.createCell(0).setCellValue(user.getId());  
  134.                     row.createCell(1).setCellValue(user.getName());  
  135.                     row.createCell(2).setCellValue(user.getAddress());  
  136.                     row.createCell(3).setCellValue(user.getTel());  
  137.                     row.createCell(4).setCellValue(dd);  
  138.   
  139.                 }  
  140.                 CellStyle cellStyle2 = book.createCellStyle();  
  141.                 cellStyle2.setAlignment(CellStyle.ALIGN_CENTER);  
  142.                 row = sheet.createRow(m);  
  143.                 Cell cell0 = row.createCell(0);  
  144.                 cell0.setCellValue("Total");  
  145.                 cell0.setCellStyle(cellStyle2);  
  146.                 Cell cell4 = row.createCell(4);  
  147.                 cell4.setCellValue(d);  
  148.                 cell4.setCellStyle(cellStyle2);  
  149.                 sheet.addMergedRegion(new CellRangeAddress(m, m, 0, 3));  
  150.             } catch (Exception e) {  
  151.                 e.printStackTrace();  
  152.             }  
  153.             try {  
  154.                 book.write(o);  
  155.             } catch (Exception ex) {  
  156.                 ex.printStackTrace();  
  157.             } finally {  
  158.                 o.flush();  
  159.                 o.close();  
  160.             }  
  161.         }  
  162.         File srcfile[] = new File[fileNames.size()];  
  163.         for (int i = 0, n = fileNames.size(); i < n; i++) {  
  164.             srcfile[i] = new File(fileNames.get(i));  
  165.         }  
  166.         util.FileZip.ZipFiles(srcfile, zip);  
  167.         FileInputStream inStream = new FileInputStream(zip);  
  168.         byte[] buf = new byte[4096];  
  169.         int readLength;  
  170.         while (((readLength = inStream.read(buf)) != -1)) {  
  171.             out.write(buf, 0, readLength);  
  172.         }  
  173.         inStream.close();  
  174.     }  
  175. }  
  176. 最后还有个工具类package util;
  177. 压缩工具类代码  
  178. import java.io.FileInputStream;  
  179. import java.io.FileOutputStream;  
  180. import java.io.IOException;  
  181. import java.util.zip.ZipEntry;  
  182. import java.util.zip.ZipOutputStream;  
  183. /**  
  184. *   
  185. * @author QQ:三二8二4七6七六  
  186. *  
  187. */  
  188. public class FileZip {  
  189.     /**  
  190.      *   
  191.      * @param srcfile 文件名数组  
  192.      * @param zipfile 压缩后文件  
  193.      */  
  194.     public static void ZipFiles(java.io.File[] srcfile, java.io.File zipfile) {  
  195.         byte[] buf = new byte[1024];  
  196.         try {  
  197.             ZipOutputStream out = new ZipOutputStream(new FileOutputStream(  
  198.                     zipfile));  
  199.             for (int i = 0; i < srcfile.length; i++) {  
  200.                 FileInputStream in = new FileInputStream(srcfile[i]);  
  201.                 out.putNextEntry(new ZipEntry(srcfile[i].getName()));  
  202.                 int len;  
  203.                 while ((len = in.read(buf)) > 0) {  
  204.                     out.write(buf, 0, len);  
  205.                 }  
  206.                 out.closeEntry();  
  207.                 in.close();  
  208.             }  
  209.             out.close();  
  210.         } catch (IOException e) {  
  211.             e.printStackTrace();  
  212.         }  
  213.     }  
  214. }  

2017-07-20 10:14:12 Topxixi 阅读数 240
  • 基于SSM的POI导入导出Excel实战

    本课程将给大家分享如何基于SSM实现POI导入导出Excel,并讲解目前企业级JavaWeb应用mvc三层模式的开发流程,可让初学者或者职场萌新掌握如何基于SSM整合第三方框架并采用mvc三层开发模式实现自己的业务模块!

    1273 人正在学习 去看看 钟林森

gradle 导入 org.apache.poi:poi-ooxml:3.14


POI对excel的导出操作,一般只使用HSSFWorkbook以及SXSSFWorkbook:
HSSFWorkbook用来处理较少的数据量,

SXSSFWorkbook用来处理超大数据量的导出,20w数据没什么问题。


注意导出文件后缀 (.xlsx)


public class ExcelUtils {
    public static void exportExcel(HttpServletResponse response,List<String> sheetList, List<List<String>> rowList, String fileName) {
        OutputStream output = null;
        try {
            SXSSFWorkbook workbook = new SXSSFWorkbook();
            SXSSFSheet sheet = workbook.createSheet();
            SXSSFRow firstRow = sheet.createRow(0);
            for(int i = 0; i < sheetList.size(); i++){
                firstRow.createCell(i).setCellValue(sheetList.get(i));
            }
            int rowNum = 1;
            for(int i = 0; i < rowList.size(); i++){
                SXSSFRow row = sheet.createRow(rowNum);
                List<String> detailRowList = rowList.get(i);
                for (int j = 0; j < detailRowList.size(); j++) {
                    row.createCell(j).setCellValue(detailRowList.get(j));
                }
                rowNum++;
            }
            output = response.getOutputStream();
            response.reset();
            response.setContentType("application/x-download");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-Disposition", "attachment;filename="
                    + new String(fileName.getBytes("gbk"), "iso8859-1")+".xlsx");
            workbook.write(output);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (output != null) {
                    output.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}




2011-11-17 14:42:05 hopestar2008 阅读数 650
  • 基于SSM的POI导入导出Excel实战

    本课程将给大家分享如何基于SSM实现POI导入导出Excel,并讲解目前企业级JavaWeb应用mvc三层模式的开发流程,可让初学者或者职场萌新掌握如何基于SSM整合第三方框架并采用mvc三层开发模式实现自己的业务模块!

    1273 人正在学习 去看看 钟林森

说明:我的电脑 2.0CPU 2G内存 能够十秒钟导出 20W 条数据 ,12.8M的excel内容压缩后2.68M

我们知道在POI导出Excel时,数据量大了,很容易导致内存溢出。由于Excel 一个sheet允许的最大行数是65536这时我们想到分sheet进行导出;但是这种情况也不能解决内存溢出的问题。毕竟数据还是一次性在内存中进行保存的。这时我们想是不是可以导出多个excel呢?下面我就尝试着按照导出多个excel

首先:我们要确定数据量有多大,然后确定一个excel导出多少条数据,这样就可以确定导出的Excel的数量,于是我们就可以循环的导出excel并保存在任意的临时目录中。去这样如果内存不够的话虚拟机就会去进行回收已经保存的excel在内存中的空间。

假设我们我们已经成功的生成了多个excel,这时我们怎么把这N个excel文档传到客户端呢?其实一个一个的传也未尝不可,但是考虑那样对用户来说体验不够好,再次多个文件在网络上传输也比较慢。我们可以考虑对生成的几个文件进行压缩,然后传到客户端。

总结一下第一、分批次生成excel第二、压缩后到客户端

 

下面我把我的一个小实例贴上供大家参考

 

第一、Person.java 普通javabean

 

package bean;
/**
 * 
 * @author http://javaflex.iteye.com/
 *
 */
public class Person {

	private Integer id;
	private String name;
	private String address;
	private String tel;
	private Double money=0.0;
	public Double getMoney() {
		return money;
	}
	public void setMoney(Double money) {
		this.money = money;
	}
	public Person(Integer id, String name, String address, String tel,Double money) {
		super();
		this.id = id;
		this.name = name;
		this.address = address;
		this.tel = tel;
		this.money=money;
	}
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public String getTel() {
		return tel;
	}
	public void setTel(String tel) {
		this.tel = tel;
	}
}

 

第二、PersonService模拟业务逻辑循环生成100023个Person对象

 

package service;

import java.util.ArrayList;
import java.util.List;

import bean.Person;
/**
 * 
 * @author http://javaflex.iteye.com/
 *
 */
public class PersonService {
	public static List getPerson(){
		List<Person> list =new ArrayList<Person>();
		for(int i=0;i<100320;i++){
			list.add(new Person(i,"zhangsan"+i,"北京"+i,"13214587632",123123.12+i));	
		}
		return list;
	}

}

 

 第三、业务处理Servlet

 

package servlet;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.CellRangeAddress;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;

import bean.Person;

import service.PersonService;

/**
 * 
 * @author http://javaflex.iteye.com/
 *
 */
public class PersonServlet extends HttpServlet {
	private String fileName;

	public PersonServlet() {
		super();
	}

	public void destroy() {
		super.destroy(); // Just puts "destroy" string in log
		// Put your code here
	}

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 文件名获取
		Date date = new Date();
		SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
		String f = "Person-" + format.format(date);
		this.fileName = f;
		setResponseHeader(response);
		OutputStream out = null;
		try {
			out = response.getOutputStream();
			List<Person> list = PersonService.getPerson();
			toExcel(list,request,10000,f,out);
		} catch (IOException e1) {
			e1.printStackTrace();
		} finally {
			try {
				out.flush();
				out.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/** 设置响应头 */
	public void setResponseHeader(HttpServletResponse response) {
		try {
			response.setContentType("application/octet-stream;charset=UTF-8");
			response.setHeader("Content-Disposition", "attachment;filename="
					+ java.net.URLEncoder.encode(this.fileName, "UTF-8")
					+ ".zip");
			response.addHeader("Pargam", "no-cache");
			response.addHeader("Cache-Control", "no-cache");
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doGet(request, response);
	}
	public void init() throws ServletException {
		// Put your code here
	}

	public void toExcel(List<Person> list, HttpServletRequest request,
			int length, String f, OutputStream out) throws IOException {
		List<String> fileNames = new ArrayList();// 用于存放生成的文件名称s
		File zip = new File(request.getRealPath("/files") + "/" + f + ".zip");// 压缩文件
		// 生成excel
		for (int j = 0, n = list.size() / length + 1; j < n; j++) {
			Workbook book = new HSSFWorkbook();
			Sheet sheet = book.createSheet("person");

			double d = 0;// 用来统计
			String file = request.getRealPath("/files") + "/" + f + "-" + j
					+ ".xls";

			fileNames.add(file);
			FileOutputStream o = null;
			try {
				o = new FileOutputStream(file);

				// sheet.addMergedRegion(new
				// CellRangeAddress(list.size()+1,0,list.size()+5,6));
				Row row = sheet.createRow(0);
				row.createCell(0).setCellValue("ID");
				row.createCell(1).setCellValue("NAME");
				row.createCell(2).setCellValue("ADDRESS");
				row.createCell(3).setCellValue("TEL");
				row.createCell(4).setCellValue("Money");

				int m = 1;

				for (int i = 1, min = (list.size() - j * length + 1) > (length + 1) ? (length + 1)
						: (list.size() - j * length + 1); i < min; i++) {
					m++;
					Person user = list.get(length * (j) + i - 1);
					Double dd = user.getMoney();
					if (dd == null) {
						dd = 0.0;
					}
					d += dd;
					row = sheet.createRow(i);
					row.createCell(0).setCellValue(user.getId());
					row.createCell(1).setCellValue(user.getName());
					row.createCell(2).setCellValue(user.getAddress());
					row.createCell(3).setCellValue(user.getTel());
					row.createCell(4).setCellValue(dd);

				}
				CellStyle cellStyle2 = book.createCellStyle();
				cellStyle2.setAlignment(CellStyle.ALIGN_CENTER);
				row = sheet.createRow(m);
				Cell cell0 = row.createCell(0);
				cell0.setCellValue("Total");
				cell0.setCellStyle(cellStyle2);
				Cell cell4 = row.createCell(4);
				cell4.setCellValue(d);
				cell4.setCellStyle(cellStyle2);
				sheet.addMergedRegion(new CellRangeAddress(m, m, 0, 3));
			} catch (Exception e) {
				e.printStackTrace();
			}
			try {
				book.write(o);
			} catch (Exception ex) {
				ex.printStackTrace();
			} finally {
				o.flush();
				o.close();
			}
		}
		File srcfile[] = new File[fileNames.size()];
		for (int i = 0, n = fileNames.size(); i < n; i++) {
			srcfile[i] = new File(fileNames.get(i));
		}
		util.FileZip.ZipFiles(srcfile, zip);
		FileInputStream inStream = new FileInputStream(zip);
		byte[] buf = new byte[4096];
		int readLength;
		while (((readLength = inStream.read(buf)) != -1)) {
			out.write(buf, 0, readLength);
		}
		inStream.close();
	}
}

最后还有个工具类package util;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
 * 
 * @author http://javaflex.iteye.com/
 *
 */
public class FileZip {
	/**
	 * 
	 * @param srcfile 文件名数组
	 * @param zipfile 压缩后文件
	 */
	public static void ZipFiles(java.io.File[] srcfile, java.io.File zipfile) {
		byte[] buf = new byte[1024];
		try {
			ZipOutputStream out = new ZipOutputStream(new FileOutputStream(
					zipfile));
			for (int i = 0; i < srcfile.length; i++) {
				FileInputStream in = new FileInputStream(srcfile[i]);
				out.putNextEntry(new ZipEntry(srcfile[i].getName()));
				int len;
				while ((len = in.read(buf)) > 0) {
					out.write(buf, 0, len);
				}
				out.closeEntry();
				in.close();
			}
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

OK全部内容完成



 

12.8M的excel内容压缩后2.68M,给力吧

以后记得代码加注释

 

亲,记得给个评论哦

2018-10-11 01:23:52 justry_deng 阅读数 9500
  • 基于SSM的POI导入导出Excel实战

    本课程将给大家分享如何基于SSM实现POI导入导出Excel,并讲解目前企业级JavaWeb应用mvc三层模式的开发流程,可让初学者或者职场萌新掌握如何基于SSM整合第三方框架并采用mvc三层开发模式实现自己的业务模块!

    1273 人正在学习 去看看 钟林森

说明:
        前面我们介绍了使用xls或xlsx模板导出excel数据。但是当数据量比较大时,这样的方式就会特别慢。导出2万条(每条数据占11列)数据时,使用模板的方式,会大约耗时20几分钟。那要导出百万千万甚至更多条数据呢?这时我们可以使用poi的SXSSFWorkbook来导出。

      POI3.8之前的版本不支持大数据量处理,如果数据过多则经常报OOM错误,有时候调整JVM大小效果也不是太好。POI3.8版本新出来了SXSSFWorkbook,可以支持大数据量的操作。

     3.8版本的POI对excel的导出操作,一般只使用HSSFWorkbook以及SXSSFWorkbook,HSSFWorkbook用来处理较少的数据量,SXSSFWorkbook用来处理大数据量以及超大数据量的导出。

 

HSSFWorkbook、XSSFWorkbook、SXSSFWorkbook的区别:

     ◎HSSFWorkbook一般用于Excel2003版及更早版本(扩展名为.xls)的导出。

     ◎XSSFWorkbook一般用于Excel2007版(扩展名为.xlsx)的导出。

     ◎SXSSFWorkbook一般用于大数据量的导出。

注:HSSFWorkbook和XSSFWorkbook的Excel Sheet导出条数上限(<=2003版)是65535行、256列,(>=2007版)是
       1048576行,16384列,如果数据量超过了此上限,那么可以使用SXSSFWorkbook来导出。实际上上万条数据,
       甚至上千条数据就可以考虑使用SXSSFWorkbook了。

 

本人测试时软硬件环境:Windows10、idea、jdk1.8

准备工作:在pom.xml中引入依赖

<!--poi-ooxml-->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.9</version>
</dependency>

注:因为本人还需要连库查询,所以本人还引入了MySQL的相关依赖,并在application.properties中进行了相关的数据库连接
     配置;这里就不再一一给出了。

SXSSFWorkbook导出excel示例

import com.mapper.DemoMapper;
import com.model.ExcelExportModel;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFDataFormat;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class SxxfWorkbookApplicationTests {
    private final static Logger logger = LoggerFactory.getLogger(SxxfWorkbookApplicationTests.class);

    @Autowired
    private DemoMapper mapper;

    @Test
    public void contextLoads() {

    // 导出的excel,全文件名
    final String excelExportDestfilepath = "C:/Users/JustryDeng/Desktop/abc.xlsx";

        FileOutputStream fos = null;
        SXSSFWorkbook sxssfWorkbook = null;
        try {
            /// -> 从数据库中查询出要进行excel导出的数据
            String timeLeft = "2018-10-10 00:00:00";
            String timeRight = "2018-10-11 00:00:00";
            long startTime0 = System.currentTimeMillis();
            List<ExcelExportModel> list = mapper.queryData(timeLeft, timeRight);
            long endTime0 = System.currentTimeMillis();
            logger.info("查询数据总耗时:{} 毫秒; list数量为 {}", endTime0 - startTime0, list.size());

            /// -> excel到处逻辑
            long startTime = System.currentTimeMillis();
            // 获取SXSSFWorkbook实例
            sxssfWorkbook = new SXSSFWorkbook();
            Sheet sheet = sxssfWorkbook.createSheet("我是Sheet");
            // 冻结最左边的两列、冻结最上面的一行
            // 即:滚动横向滚动条时,左边的第一、二列固定不动;滚动纵向滚动条时,上面的第一行固定不动。
            sheet.createFreezePane(2, 1);
            // 设置并获取到需要的样式
            XSSFCellStyle xssfCellStyleHeader = getAndSetXSSFCellStyleHeader(sxssfWorkbook);
            XSSFCellStyle xssfCellStyleOne = getAndSetXSSFCellStyleOne(sxssfWorkbook);
            XSSFCellStyle xssfCellStyleTwo = getAndSetXSSFCellStyleTwo(sxssfWorkbook);
            // 创建第一行,作为header表头
            Row header = sheet.createRow(0);
            // 循环创建header单元格(根据实际情况灵活创建即可)
            for (int cellnum = 0; cellnum < 11; cellnum++) {
                Cell cell = header.createCell(cellnum);
                cell.setCellStyle(xssfCellStyleHeader);
                // 判断单元格
                if (cellnum == 0) {
                    cell.setCellValue("通话ID");
                } else if (cellnum == 1) {
                    cell.setCellValue("绑定关系ID");
                } else if (cellnum == 2) {
                    cell.setCellValue("主叫号码");
                } else if (cellnum == 3) {
                    cell.setCellValue("被叫号码");
                } else if (cellnum == 4) {
                    cell.setCellValue("中间号码");
                } else if (cellnum == 5) {
                    cell.setCellValue("通话发生时间");
                } else if (cellnum == 6) {
                    cell.setCellValue("通话开始时间");
                } else if (cellnum == 7) {
                    cell.setCellValue("通话结束时间");
                } else if (cellnum == 8) {
                    cell.setCellValue("通话时长(秒)");
                } else if (cellnum == 9) {
                    cell.setCellValue("结束发起方");
                } else {
                    cell.setCellValue("结束状态(即挂断原因)");
                }
            }

            // 遍历创建行,导出数据
            for (int rownum = 1; rownum <= list.size(); rownum++) {
                Row row = sheet.createRow(rownum);
                // 循环创建单元格
                for (int cellnum = 0; cellnum < 11; cellnum++) {
                    Cell cell = row.createCell(cellnum);
                    // 根据行数,设置该行内的单元格样式
                    if (rownum % 2 == 1) { // 奇数
                        cell.setCellStyle(xssfCellStyleOne);
                    } else { // 偶数
                        cell.setCellStyle(xssfCellStyleTwo);
                    }
                    // 根据单元格所属,录入相应内容
                    // 将部分数字类型的字符串,转换为Long;以免导出excel后,单元格左上角有三
                    //    角形(这是excel检查到该单元格内的内容均为数字,但是单元格类型却不是
                    //    数字,给出的提示),转不转看自己需求灵活处理
                    if (cellnum == 0) {
                        cell.setCellValue((list.get(rownum - 1).getCallId()));
                    } else if (cellnum == 1) {
                        cell.setCellValue(list.get(rownum - 1).getBindId());
                    } else if (cellnum == 2) {
                        cell.setCellType(Cell.CELL_TYPE_NUMERIC);
                        cell.setCellValue(Long.parseLong(list.get(rownum - 1).getCallNo()));
                    } else if (cellnum == 3) {
                        cell.setCellType(Cell.CELL_TYPE_NUMERIC);
                        cell.setCellValue(Long.parseLong(list.get(rownum - 1).getPeerNo()));
                    } else if (cellnum == 4) {
                        cell.setCellType(Cell.CELL_TYPE_NUMERIC);
                        cell.setCellValue(Long.parseLong(list.get(rownum - 1).getTelX()));
                    } else if (cellnum == 5) {
                        cell.setCellType(Cell.CELL_TYPE_NUMERIC);
                        cell.setCellValue(Long.parseLong(list.get(rownum - 1).getCallTime()));
                    } else if (cellnum == 6) {
                        cell.setCellType(Cell.CELL_TYPE_NUMERIC);
                        cell.setCellValue(Long.parseLong(list.get(rownum - 1).getStartTime()));
                    } else if (cellnum == 7) {
                        cell.setCellType(Cell.CELL_TYPE_NUMERIC);
                        cell.setCellValue(Long.parseLong(list.get(rownum - 1).getFinishTime()));
                    } else if (cellnum == 8) {
                        cell.setCellValue(list.get(rownum - 1).getCallDuration());
                    } else if (cellnum == 9) {
                        cell.setCellType(Cell.CELL_TYPE_NUMERIC);
                        cell.setCellValue(Long.parseLong(list.get(rownum - 1).getFinishType()));
                    } else {
                        cell.setCellType(Cell.CELL_TYPE_NUMERIC);
                        cell.setCellValue(Long.parseLong(list.get(rownum - 1).getFinishState()));

                    }
                }
            }
            // 在后面设置sheet
            setSheet(sheet);
            fos = new FileOutputStream(excelExportDestfilepath);
            sxssfWorkbook.write(fos);
            long endTime = System.currentTimeMillis();
            logger.info("数据全部导出至excel总耗时:{} 毫秒!", endTime - startTime, list.size());
        } catch (Exception e) {
            logger.error("发生异常咯!", e);
        } finally {
            try {
                if(sxssfWorkbook != null) {
                    // dispose of temporary files backing this workbook on disk -> 处
                    //     理SXSSFWorkbook导出excel时,产生的临时文件
                    sxssfWorkbook.dispose();
                }
                if(fos != null) {
                    fos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }



    /**
     * 设置sheet
     */
    private void setSheet(Sheet sheet) {
        // 设置各列宽度(单位为:字符宽度的1/256)
        sheet.setColumnWidth(0, 32 * 256);
        sheet.setColumnWidth(1, 32 * 256);
        sheet.setColumnWidth(2, 20 * 256);
        sheet.setColumnWidth(3, 20 * 256);
        sheet.setColumnWidth(4, 20 * 256);
        sheet.setColumnWidth(5, 20 * 256);
        sheet.setColumnWidth(6, 20 * 256);
        sheet.setColumnWidth(7, 20 * 256);
        sheet.setColumnWidth(8, 20 * 256);
        sheet.setColumnWidth(9, 20 * 256);
        sheet.setColumnWidth(10, 32 * 256);
    }

    /**
     * 获取并设置header样式
     */
    private XSSFCellStyle getAndSetXSSFCellStyleHeader(SXSSFWorkbook sxssfWorkbook) {
        XSSFCellStyle xssfCellStyle = (XSSFCellStyle) sxssfWorkbook.createCellStyle();
        Font font = sxssfWorkbook.createFont();
        // 字体大小
        font.setFontHeightInPoints((short) 14);
        // 字体粗细
        font.setBoldweight((short) 20);
        // 将字体应用到样式上面
        xssfCellStyle.setFont(font);
        // 是否自动换行
        xssfCellStyle.setWrapText(false);
        // 水平居中
        xssfCellStyle.setAlignment(HorizontalAlignment.CENTER);
        // 垂直居中
        xssfCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        return xssfCellStyle;
    }

    /**
     * 获取并设置样式一
     */
    private XSSFCellStyle getAndSetXSSFCellStyleOne(SXSSFWorkbook sxssfWorkbook) {
        XSSFCellStyle xssfCellStyle = (XSSFCellStyle) sxssfWorkbook.createCellStyle();
        XSSFDataFormat format = (XSSFDataFormat)sxssfWorkbook.createDataFormat();
        // 是否自动换行
        xssfCellStyle.setWrapText(false);
        // 水平居中
        xssfCellStyle.setAlignment(HorizontalAlignment.CENTER);
        // 垂直居中
        xssfCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        // 前景颜色
        xssfCellStyle.setFillPattern(XSSFCellStyle.SOLID_FOREGROUND);
        xssfCellStyle.setFillForegroundColor(IndexedColors.AQUA.getIndex());
        // 边框
        xssfCellStyle.setBorderBottom(BorderStyle.THIN);
        xssfCellStyle.setBorderRight(BorderStyle.THIN);
        xssfCellStyle.setBorderTop(BorderStyle.THIN);
        xssfCellStyle.setBorderLeft(BorderStyle.THIN);
        xssfCellStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
        xssfCellStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
        xssfCellStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
        xssfCellStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
        // 防止数字过长,excel导出后,显示为科学计数法,如:防止8615192053888被显示为8.61519E+12
        xssfCellStyle.setDataFormat(format.getFormat("0"));
        return xssfCellStyle;
    }

    /**
     * 获取并设置样式二
     */
    private XSSFCellStyle getAndSetXSSFCellStyleTwo(SXSSFWorkbook sxssfWorkbook) {
        XSSFCellStyle xssfCellStyle = (XSSFCellStyle) sxssfWorkbook.createCellStyle();
        XSSFDataFormat format = (XSSFDataFormat)sxssfWorkbook.createDataFormat();
        // 是否自动换行
        xssfCellStyle.setWrapText(false);
        // 水平居中
        xssfCellStyle.setAlignment(HorizontalAlignment.CENTER);
        // 边框
        xssfCellStyle.setBorderBottom(BorderStyle.THIN);
        xssfCellStyle.setBorderRight(BorderStyle.THIN);
        xssfCellStyle.setBorderTop(BorderStyle.THIN);
        xssfCellStyle.setBorderLeft(BorderStyle.THIN);
        xssfCellStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
        xssfCellStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
        xssfCellStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
        xssfCellStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
        // 垂直居中
        xssfCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        // 防止数字过长,excel导出后,显示为科学计数法,如:防止8615192053888被显示为8.61519E+12
        xssfCellStyle.setDataFormat(format.getFormat("0"));
        return xssfCellStyle;
    }

}

小知识:列宽自适应的设置(示例)

注:当设置宽度自适应时,设置时机需要放在设置完cell样式后面进行,如果放在开头设置,那么可能不起作用;
       设置宽度自适应时不能同时设置自动换行,否者也可能导致宽度自适应失效。

注:autoSizeColumn方法对中文支不不是很好,必要的话可自己写部分逻辑来实现宽度自适应,可参照着源码进行编写。

测试一下:运行测试方法,控制台输出一下信息

再去C:/Users/JustryDeng/Desktop/下,看见abc.xlsx文件确实生成了,打开该excel文件,比对数据,发现数据准确无误。

由此可见->成功!

 

注:如果目标位置已存在同名(含后缀名)文件,那么会覆盖原来的那个文件

注:导出同样数量的数据,使用poi的SXSSFWorkbook最快,其次是使用poi的HSSFWorkbook(或XSSFWorkbook),使用
       其他(对poi进行了封装的)框架,效率会比较低,如使用模板导出excel

 

^_^ 参考链接
            https://blog.csdn.net/qq_34869143/article/details/76512289
            https://zhidao.baidu.com/question/508958518.html

            http://happyqing.iteye.com/blog/2190225

^_^ 如有不当之处,欢迎指正

^_^ 本文已经被收录进《程序员成长笔记(三)》,笔者JustryDeng

2019-11-18 11:38:47 qq_38263083 阅读数 84
  • 基于SSM的POI导入导出Excel实战

    本课程将给大家分享如何基于SSM实现POI导入导出Excel,并讲解目前企业级JavaWeb应用mvc三层模式的开发流程,可让初学者或者职场萌新掌握如何基于SSM整合第三方框架并采用mvc三层开发模式实现自己的业务模块!

    1273 人正在学习 去看看 钟林森

思路

因为每一个sheet都是有大小限制的,所以如果导出的数据过大,而全部放在一个sheet中,那么就会报错,所以我们应该分sheet保存,主要的工具就是使用apache提供的poi中的HSSFWorkbook、
项目结构
在这里插入图片描述

jar包依赖

 <!-- poi -->
        <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>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-csv</artifactId>
            <version>1.4</version>
        </dependency>

主要类

DesExport 注解类,加在需要下载的pojo的属性上

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author GKJ
 * @date 2019/11/8
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DesExport {
    /**
     * 对应的 每一列的表头
     * @return
     */
    String value() default "";

    /**
     * 是否需要导出
     * @return
     */
    boolean isExport() default false;

    /**
     * 排在第几列
     * @return
     */
    int sort() default 0;
}

ExcelUtil 为excel工具类,例如设置可以下载的格式,表头的格式样式等等

import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.xssf.usermodel.XSSFCell;

import javax.servlet.http.HttpServletRequest;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 * @author GKJ
 * @date 2019/11/8
 */
public class ExcelUtil {
    public static final String OFFICE_EXCEL_2003_POSTFIX = "xls";
    public static final String OFFICE_EXCEL_2010_POSTFIX = "xlsx";
    public static final String OFFICE_EXCEL_CSV_POSTFIX = "csv";
    public static final String EMPTY = "";
    public static final String POINT = ".";
    public static SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");

    /**
     * 获得path的后缀名
     *
     * @param path
     * @return
     */
    public static String getPostfix(String path) {
        if (path == null || EMPTY.equals(path.trim())) {
            return EMPTY;
        }
        if (path.contains(POINT)) {
            return path.substring(path.lastIndexOf(POINT) + 1, path.length());
        }
        return EMPTY;
    }

    /**
     * 判断是否是指定的文件类型(.xls,.xlsx)
     *
     * @param fileName
     * @return
     */
    public static boolean checkFile(String fileName) {
        // 设置允许上传文件类型
        String suffixList = ".xls,.xlsx";
        // 获取文件后缀
        String suffix = fileName.substring(fileName.lastIndexOf("."), fileName.length());
        if (suffixList.contains(suffix.trim().toLowerCase())) {
            return true;
        }
        return false;
    }

    /**
     * 处理excel中的单元格格式
     *
     * @param hssfCell
     * @return
     */
    public static String getHValue(HSSFCell hssfCell) {
        // boolean
        if (hssfCell.getCellType() == HSSFCell.CELL_TYPE_BOOLEAN) {
            return String.valueOf(hssfCell.getBooleanCellValue());
        } else if (hssfCell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) {
            // 数值
            String cellValue = "";
            if (HSSFDateUtil.isCellDateFormatted(hssfCell)) {
                // 日期
                Date date = HSSFDateUtil.getJavaDate(hssfCell.getNumericCellValue());
                cellValue = sdf.format(date);
            } else {
                DecimalFormat df = new DecimalFormat("#.##");
                cellValue = df.format(hssfCell.getNumericCellValue());
                String strArr = cellValue.substring(cellValue.lastIndexOf(POINT) + 1, cellValue.length());
                if (strArr.equals("00")) {
                    cellValue = cellValue.substring(0, cellValue.lastIndexOf(POINT));
                }
            }
            return cellValue;
        } else if (hssfCell.getCellType() == HSSFCell.CELL_TYPE_FORMULA) {
            String cellValue = "";
            try {
                cellValue = String.valueOf(hssfCell.getNumericCellValue());
            } catch (IllegalStateException e) {
                cellValue = String.valueOf(hssfCell.getRichStringCellValue());
            }
            return cellValue;
        } else {
            return String.valueOf(hssfCell.getStringCellValue());
        }
    }

    /**
     * 单元格格式
     *
     * @param xssfCell
     * @return
     */
    public static String getXValue(XSSFCell xssfCell) {
        if (xssfCell.getCellType() == Cell.CELL_TYPE_BOOLEAN) {
            return String.valueOf(xssfCell.getBooleanCellValue());
        } else if (xssfCell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
            String cellValue = "";
            if (XSSFDateUtil.isCellDateFormatted(xssfCell)) {
                Date date = XSSFDateUtil.getJavaDate(xssfCell.getNumericCellValue());
                cellValue = sdf.format(date);
            } else {
                DecimalFormat df = new DecimalFormat("#.##");
                cellValue = df.format(xssfCell.getNumericCellValue());
                String strArr = cellValue.substring(cellValue.lastIndexOf(POINT) + 1, cellValue.length());
                if (strArr.equals("00")) {
                    cellValue = cellValue.substring(0, cellValue.lastIndexOf(POINT));
                }
            }
            return cellValue;
        } else {
            return String.valueOf(xssfCell.getStringCellValue());
        }
    }

    /**
     * 设置单元格格式
     *
     * @param workbook
     * @return
     */
    public static HSSFCellStyle getCellStyle(HSSFWorkbook workbook) {
        HSSFCellStyle style = workbook.createCellStyle();
        style.setFillForegroundColor(HSSFColor.GREY_25_PERCENT.index);
        style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
        style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        style.setBorderTop(HSSFCellStyle.BORDER_THIN);
        style.setLeftBorderColor(HSSFCellStyle.BORDER_THIN);
        style.setRightBorderColor(HSSFCellStyle.BORDER_THIN);
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        return style;
    }

    /**
     * 设置字体样式
     *
     * @param workbook
     * @return
     */
    public static HSSFFont getFont(HSSFWorkbook workbook) {
        HSSFFont font = workbook.createFont();
        font.setColor(HSSFColor.WHITE.index);
        font.setFontHeightInPoints((short) 12);
        font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        return font;
    }

    /**
     * 判断是否IE浏览器
     *
     * @param request
     * @return
     */
    public static boolean isIE(HttpServletRequest request) {
        return request.getHeader("USER-AGENT").toLowerCase().indexOf("msie") > 0 ? true : false;
    }
}

/**
 * 自定义xssf日期工具类
 */
class XSSFDateUtil extends DateUtil {
    protected static int absoluteDay(Calendar cal, boolean use1904windowing) {
        return DateUtil.absoluteDay(cal, use1904windowing);
    }
}

ExcelWrite 为向excel中导入数据的核心类,会将数根据自定义的每个sheet的大小决定sheet的个数,进行导出保存

import cn.gxm.test.annotation.DesExport;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author GKJ
 * @date 2019/11/8
 */
public class ExcelWrite {
    private static final Logger LOGGER = LoggerFactory.getLogger(ExcelWrite.class);

    /**
     * 添加内容到EXCEL文件
     *
     * @param list
     * @param headers
     * @param methodNames
     * @param title  每一个 Sheet的标题
     * @param os
     */
    public static <T> void write2Excel(List<T> list, String[] headers, String[] methodNames, String title, int pageSize,
                                       OutputStream os) {
        try {
            HSSFWorkbook workbook = new HSSFWorkbook();
            if (null != list && list.size() > 0) {
                int total = list.size();
                // 根据total大小按pageSize分成多个sheet来生成excel
                int totalSheet = total % pageSize == 0 ? (total / pageSize) : ((total / pageSize) + 1);
                for (int a = 1; a <= totalSheet; a++) {
                    int startIdx = (a - 1) * pageSize;
                    int endIdx = (a * pageSize) - 1;
                    if (endIdx > total) {
                        endIdx = total - 1;
                    }
                    // 分页生成sheet
                    HSSFSheet sheet = workbook.createSheet(title + "" + (startIdx + 1) + "到" + (endIdx + 1));
                    writeHeader(workbook, sheet, headers);
                    writeSheet(list, sheet, startIdx, endIdx, methodNames);
                }
            } else {
                HSSFSheet sheet = workbook.createSheet(title);
                writeHeader(workbook, sheet, headers);
            }
            workbook.write(os);
        } catch (Exception e) {
            LOGGER.error("workbook write error:", e);
        } finally {
            try {
                os.flush();
                os.close();
            } catch (IOException e) {
                LOGGER.error("write2Excel flush error:", e);
            }
        }
    }

    private static void writeHeader(HSSFWorkbook workbook, HSSFSheet sheet, String[] headers) {
        // 设置表格默认列宽15个字节
        sheet.setDefaultColumnWidth(15);
        // 生成一个样式
        HSSFCellStyle style = ExcelUtil.getCellStyle(workbook);
        // 生成一个字体
        HSSFFont font = ExcelUtil.getFont(workbook);
        // 把字体应用到当前样式
        style.setFont(font);

        // 生成表格标题
        HSSFRow row = sheet.createRow(0);
        row.setHeight((short) 300);

        for (int i = 0; i < headers.length; i++) {
            HSSFCell cell = row.createCell(i);
            cell.setCellStyle(style);
            HSSFRichTextString text = new HSSFRichTextString(headers[i]);
            cell.setCellValue(text);
        }
    }

    /**
     * @param list
     * @param sheet
     * @param startIdx
     * @param endIdx
     * @param methodNames
     * @param <T>
     */
    private static <T> void writeSheet(List<T> list, HSSFSheet sheet, int startIdx, int endIdx, String[] methodNames) {
        writeSheet(list, sheet, startIdx, endIdx, methodNames, "yyyy-MM-dd");
    }

    /**
     * 如果有日期则指定写入excel中的日期格式
     * @param list
     * @param sheet
     * @param startIdx
     * @param endIdx
     * @param methodNames
     * @param patter
     * @param <T>
     */
    private static <T> void writeSheet(List<T> list, HSSFSheet sheet, int startIdx, int endIdx, String[] methodNames,
                                       String patter) {
        // 将数据放入sheet中
        if (null != list && list.size() > 0) {
            int num = 0;
            for (int i = startIdx; i <= endIdx; i++) {
                HSSFRow row = sheet.createRow(num + 1);
                T t = list.get(i);
                try {
                    for (int j = 0; j < methodNames.length; j++) {
                        HSSFCell cell = row.createCell(j);
                        // 利用反射,根据JavaBean属性,动态调用get方法得到属性的值
                        Method getMethod = t.getClass().getMethod(methodNames[j], new Class[]{});
                        Object value = getMethod.invoke(t, new Object[]{});
                        if (null != value && value instanceof Date) {
                            SimpleDateFormat sdf = new SimpleDateFormat(patter);
                            cell.setCellValue(sdf.format((Date) value));
                        } else {
                            cell.setCellValue(null == value ? "" : value.toString());
                        }
                    }
                } catch (Exception e) {
                    LOGGER.error("java reflect get value error:", e);
                }
                num += 1;
            }
        }
    }

    public static <T> void getHeadersAndMothedNames(Class<T> targetClass, List<ExportDto> list) throws Exception {
        List<Field> fields = FieldUtils.getAllFieldsList(targetClass);
        for (Field field : fields) {
            String propName = field.getName();
            DesExport desExport = field.getAnnotation(DesExport.class);
            // 加了注解的才会导出 并且 isExport = true 的才导出( isExport 默认为 false )
            if (desExport != null && desExport.isExport()) {
                ExportDto dto = new ExportDto();
                dto.setHeader(desExport.value());
                dto.setMothed("get" + propName.substring(0, 1).toUpperCase() + propName.substring(1));
                dto.setSort(desExport.sort());
                list.add(dto);
            }
        }

        list.sort((a, b) -> a.getSort() - b.getSort());
    }
}

ExportDto 为根据注解而生成的pojo

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author GKJ
 * @date 2019/11/8
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ExportDto {
    private String header;
    private String mothed;
    private int sort;
}

BaseConfig需要导出的数据集合列表的pojo,并设置需要导出的自定义注解

@Data
@AllArgsConstructor
@NoArgsConstructor
public class BaseConfig {
    private Integer id;
    @DesExport(value = "类型", sort = -1, isExport = true)
    private String configType;
    @DesExport(value = "类型名称", sort = 0, isExport = true)
    private String configName;
    private String configValue;
    private String remark;
    @DesExport(value = "创建时间", sort = 1, isExport = true)
    private String createBy;
    private Date createDT;
    private String updateBy;
    private Date updateDT;
    @DesExport(value = "图片路径", sort = 2, isExport = true)
    private String imgUrl;
    @DesExport(value = "排序字段", sort = 3, isExport = true)
    private Integer seq;
    private Integer contentType;
    private Integer prodId;
}

测试

@GetMapping("/export")
    public void export(HttpServletResponse response) throws Exception {

        List<ExportDto> eList = new ArrayList<>();


        ExcelWrite.getHeadersAndMothedNames(BaseConfig.class, eList);

        setResponseHeader(response, "基础配置报表.xls");

        ExcelWrite.write2Excel(baseConfigMapper.selectAll(),
                eList.stream().map(p -> p.getHeader()).collect(Collectors.toList()).toArray(new String[eList.size()]),
                eList.stream().map(p -> p.getMothed()).collect(Collectors.toList()).toArray(new String[eList.size()]),
                "sheet基础配置报表", 65535, response.getOutputStream());
    }


    /**
     *
     * @param response
     * @param fileName  导出的文件名
     * @throws Exception
     */
    private void setResponseHeader(HttpServletResponse response, String fileName) throws Exception {
        fileName = new String(fileName.getBytes(), "ISO8859-1");
        response.setContentType("application/octet-stream;charset=UTF-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
        response.addHeader("Pargam", "no-cache");
        response.addHeader("Cache-Control", "no-cache");
    }

导出结果如图
在这里插入图片描述

POI大数据量导出

阅读数 15

没有更多推荐了,返回首页