java POI导出Excel2007(.xlsx)支持List和List的带下载框的通用类

问题的引入和分析


最近在Struts2+Spring+Mybatis整合的项目的开发工作中呢,遇到一个需要优化数据导出的功能的需求,原来的导出功能是通过jsp模板做的,发现只能导出Excel2003(.xls),并且导出到Excel中的样式也有所改变。因为Excel2003的有行数限制,超过相应行数后数据不显示。所以需要优化下导出功能,我就在寻找通用的导出工具类。但是发现我Dao层查询的数据都是封装在List中的,而网上提供的工具类都是直接接收List的。所以我做了下调整,能够支持两种数据集合的操作,话不多说,以下是实现过程:

  1. 所需POI的jar包导入

    java POI导出Excel2007(.xlsx)支持List和List的带下载框的通用类_第1张图片

  2. 首先创建一个工具类

package cn.voole.util;

import java.awt.Color;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;


public class ExportExcelUtil {

     private Log logger = LogFactory.getLog(ExportExcelUtil.class);
     /** 
         *  
         * @param title 
         *            表格标题名 
         * @param headers 
         *            表格属性列名数组 (第一行标题)
         * @param Col 
         *            需要显示的表格属性列名数组 如果是javabean 必须和字段名字一直 如果为Map 必须为Map的key名字对应
         * @param list 
         *            需要显示的数据集合,集合泛型支持两种,1:符合javabean风格的类的对象 2:Map类型。此方法支持的 
         *            javabean属性的数据类型有基本数据类型及String,Date,byte[](图片数据) 
         * @param pattern 
         *            如果有时间数据,设定输出格式。默认为"yyy-MM-dd" 
         */  
        public XSSFWorkbook exportExcel(String title, String[] headers,String[] Col,List list, String pattern) {
            if(pattern == null || pattern.equals("")) pattern = "yyy-MM-dd";
            XSSFWorkbook workbook = new XSSFWorkbook();
            // 生成一个表格
            XSSFSheet sheet = workbook.createSheet(title);
            // 设置表格默认列宽度为15个字节
            sheet.setDefaultColumnWidth(30);
            // 生成一个样式
            XSSFCellStyle style = workbook.createCellStyle();
            // 设置这些样式
            style.setFillForegroundColor(new XSSFColor(Color.BLUE));
            style.setFillPattern(XSSFCellStyle.SOLID_FOREGROUND);
            style.setBorderBottom(XSSFCellStyle.BORDER_THIN);
            style.setBorderLeft(XSSFCellStyle.BORDER_THIN);
            style.setBorderRight(XSSFCellStyle.BORDER_THIN);
            style.setBorderTop(XSSFCellStyle.BORDER_THIN);
            style.setAlignment(XSSFCellStyle.ALIGN_CENTER);
            // 生成一个字体
            XSSFFont font = workbook.createFont();
            font.setColor(new XSSFColor(Color.YELLOW));
            font.setFontHeightInPoints((short) 12);
            font.setBoldweight(XSSFFont.BOLDWEIGHT_BOLD);
            // 把字体应用到当前的样式
            style.setFont(font);
            // 生成并设置另一个样式
            XSSFCellStyle style2 = workbook.createCellStyle();
            style2.setFillForegroundColor(new XSSFColor(Color.WHITE));
            style2.setFillPattern(XSSFCellStyle.SOLID_FOREGROUND);
            style2.setBorderBottom(XSSFCellStyle.BORDER_THIN);
            style2.setBorderLeft(XSSFCellStyle.BORDER_THIN);
            style2.setBorderRight(XSSFCellStyle.BORDER_THIN);
            style2.setBorderTop(XSSFCellStyle.BORDER_THIN);
            style2.setAlignment(XSSFCellStyle.ALIGN_CENTER);
            style2.setVerticalAlignment(XSSFCellStyle.VERTICAL_CENTER);
            // 生成另一个字体
            XSSFFont font2 = workbook.createFont();
            font2.setBoldweight(XSSFFont.BOLDWEIGHT_NORMAL);
            // 把字体应用到当前的样式
            style2.setFont(font2);
            // 声明一个画图的顶级管理器
            XSSFDrawing patriarch = sheet.createDrawingPatriarch();
            // 产生表格标题行
            XSSFRow row = sheet.createRow(0);
            int Cell = 0;

            for (short i = 0; i < headers.length; i++) {
                XSSFCell cell = row.createCell(Cell);
                cell.setCellStyle(style);
                XSSFRichTextString text = new XSSFRichTextString(headers[i]);
                cell.setCellValue(text);
                Cell ++ ;
            }
            // 遍历集合数据,产生数据行
            Iterator it = (Iterator) list.iterator();
            int index = 0;
            while (it.hasNext()) {
                index++;
                row = sheet.createRow(index);
                T t = (T) it.next();
                String[] fields = Col;
                Cell = 0;
                for (short i = 0; i < fields.length; i++) {
                    String fieldName = fields[i];
                    XSSFCell cell = row.createCell(Cell);
                    cell.setCellStyle(style2);
                    try {
                        Object value = "";
                        Class tCls = null;
                        Map map = null;
                        if(t instanceof Map){
                            map = (Map)t;
                            value = map.get(fieldName);
                        } else {
                            String getMethodName = "get"
                                    + fieldName.substring(0, 1).toUpperCase()
                                    + fieldName.substring(1);
                            tCls = t.getClass();
                            Method getMethod = tCls.getMethod(getMethodName,new Class[] {});
                            value = getMethod.invoke(t, new Object[] {});
                        }
                        if(value == null ) value = "";
                        // 判断值的类型后进行强制类型转换
                        String textValue = null;
                        if (value instanceof Date) {
                            Date date = (Date) value;
                            SimpleDateFormat sdf = new SimpleDateFormat(pattern);
                            textValue = sdf.format(date);
                        } else if (value instanceof byte[]) {
                            // 有图片时,设置行高为60px;
                            row.setHeightInPoints(60);
                            // 设置图片所在列宽度为80px,注意这里单位的一个换算
                            sheet.setColumnWidth(Cell, (short) (35.7 * 80));
                            // sheet.autoSizeColumn(i);
                            byte[] bsValue = (byte[]) value;
                            XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0,
                                    1023, 255, (short) 6, index, (short) 6, index);
                            anchor.setAnchorType(2);
                            patriarch.createPicture(anchor, workbook.addPicture(
                                    bsValue, XSSFWorkbook.PICTURE_TYPE_JPEG));
                        } else {
                            // 其它数据类型都当作字符串简单处理
                            textValue = value.toString();
                        }
                        // 如果不是图片数据,就利用正则表达式判断textValue是否全部由数字组成
                        if (textValue != null) {
                            Pattern p = Pattern.compile("^//d+(//.//d+)?$");
                            Matcher matcher = p.matcher(textValue);
                            if (matcher.matches()) {
                                // 是数字当作double处理
                                cell.setCellValue(Double.parseDouble(textValue));
                            } else {
                                XSSFRichTextString richString = new XSSFRichTextString(
                                        textValue);
                                XSSFFont font3 = workbook.createFont();
                                font3.setColor(new XSSFColor(Color.BLUE));
                                richString.applyFont(font3);
                                cell.setCellValue(richString);
                            }
                        }
                        Cell ++ ;
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            return workbook;
        }
}
  1. 根据所要导出的数据构造工具类所需要的参数

java POI导出Excel2007(.xlsx)支持List和List的带下载框的通用类_第2张图片

页面中表头中的所有列名作为导出Excel没列的列名,从数据库查出封装到List的Map中的key值其实就是数据库中的字段名。当然也可以根据导出的需要自行封装。总之这个key值要传入工具类中,用来通过key值获取map中的数据写入到Excel的每一列中。


        /**
     * 
     * @Title: exportExcel   
     * @Description: 数据字典导出  
     * @param: @return      
     * @return: String      
     * @throws
     */
    public String exportExcel(){
        OutputStream ouputStream = null;
        try {
            HttpServletResponse response = ServletActionContext.getResponse();
            HttpServletRequest request = ServletActionContext.getRequest();

            //导出数据每列的列明
            String[] headers = { "字典数据名称", "字典数据代码", "建档人员", "建档日期", "更新人员", "更新日期","备注"};
            //在List中的key值
            String[] Col = { "VC2ITEMNAME", "VC2ITEMCODE", "CREATEPERSON", "DATCREATE", "UPDATEPERSON", "DATUPDATE" ,"VC2DESC"};

            //获取结果集
            List> resultList =itemListService.exportExcel(itemList);
            ExportExcelUtil> ex = new ExportExcelUtil>();

            XSSFWorkbook workbook = ex.exportExcel("sheet1",headers,Col,resultList,null);

            Date date = new Date();
            SimpleDateFormat sd = new SimpleDateFormat("yyyyMMdd");
            String dt = sd.format(date); 
            //导出的文件名
            String filename = "数据字典导出"+dt+".xlsx";  
            //文件名编码
            filename = encodeFileName(request, filename);
            //设置响应头
            response.setHeader("Content-Disposition", "attachment;filename=" + filename);
            ouputStream = response.getOutputStream();   
            workbook.write(ouputStream);   
            ouputStream.flush();   
            ouputStream.close();  
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 
     * @Title: encodeFileName   
     * @Description: 导出文件名编码设置 
     * @param: @param request
     * @param: @param fileName
     * @param: @return
     * @param: @throws UnsupportedEncodingException      
     * @return: String      
     * @throws
     */
    public static String encodeFileName(HttpServletRequest request, String fileName) throws UnsupportedEncodingException {
        String agent = request.getHeader("USER-AGENT");

        if (null != agent && -1 != agent.indexOf("MSIE")) {
            return URLEncoder.encode(fileName, "UTF-8");
        } else if (null != agent && -1 != agent.indexOf("Mozilla")) {
            return "=?UTF-8?B?"+ (new String(Base64.encodeBase64(fileName.getBytes("UTF-8")))) + "?=";
        } else {
            return fileName;
        }
    }
  1. 编写业务层方法
    /**
     * 
     * 

Title: exportExcel

*

Description: 查询所需要导出的数据并封装到List>中

* @param itemList * @return * @see cn.voole.service.ItemListService#exportExcel(cn.voole.model.ItemList) */
public List> exportExcel(ItemList itemList) { try{ return itemListDao.exportExcel(itemList); }catch(Exception e){ logger.error(e.getMessage()); } return null; }
  1. 定义持久层接口
package cn.voole.dao;
import java.util.HashMap;
import java.util.List;

import org.apache.ibatis.annotations.Param;

import cn.voole.model.ItemList;
public interface ItemListDao {

    /**
     * 
     * @Title: exportExcel   
     * @Description: 查询需要导出的数据
     * @param: @param itemList
     * @param: @return      
     * @return: List>      
     * @throws
     */
    public List> exportExcel(ItemList itemList);
}
  1. 实现mapper配置文件
<select id="exportExcel" parameterType="ItemList" resultType="hashmap">
        select numItemList,
            vc2ItemCode,
            vc2ItemName,
            numCreatePerson,
            to_char(datCreate,'yyyy-MM-dd hh24:mi:ss') datCreate,
            numUpdatePerson,
            to_char(datUpdate,'yyyy-MM-dd hh24:mi:ss') datUpdate,
            vc2Desc
        from T_ITEMLIST
        <if test="vc2Desc==1">
            <where>
                <if test="enterCondition!=null and enterCondition!='' and condition!=null and condition!=''">
                    <if test="enterCondition=='itemName'">
                        and vc2ItemName like '%'||#{condition}||'%'
                    if>
                    <if test="enterCondition=='itemCode'">
                        and vc2ItemCode like '%'||#{condition}||'%'
                    if>
                    <if test="enterCondition=='createPerson'">
                        and numCreatePerson like '%'||#{condition}||'%'
                    if>
                    <if test="enterCondition=='updatePerson'">
                        and numUpdatePerson like '%'||#{condition}||'%'
                    if>
                if>
                <if test="dateCondition!=null and dateCondition!=''">
                    <if test="dateCondition=='createDate'">
                        <if test="beginTime!=null and beginTime!='' and (endTime==null or endTime=='')">
                            
                            = to_date(#{beginTime},'yyyy-MM-dd')]]>
                        if>
                        <if test="(beginTime==null or beginTime=='') and endTime!=null and endTime!=''">
                            
                            
                        if>
                        <if test="beginTime!=null and beginTime!='' and endTime!=null and endTime!=''">
                            
                            and a.datCreate between to_date(#{beginTime},'yyyy-MM-dd') and to_date(#{endTime},'yyyy-MM-dd')
                        if>
                    if>
                    <if test="dateCondition=='updateDate'">
                        <if test="beginTime!=null and beginTime!='' and (endTime==null or endTime=='')">
                            
                            = to_date(#{beginTime},'yyyy-MM-dd')]]>
                        if>
                        <if test="(beginTime==null or beginTime=='') and endTime!=null and endTime!=''">
                            
                            
                        if>
                        <if test="beginTime!=null and beginTime!='' and endTime!=null and endTime!=''">
                            
                            and a.datUpdate between to_date(#{beginTime},'yyyy-MM-dd') and to_date(#{endTime},'yyyy-MM-dd')
                        if>
                    if>
                if>
            where>
        if>
        ORDER BY NLSSORT(vc2ItemName, 'NLS_SORT=SCHINESE_PINYIN_M')
    select>

总结:
以上是我针对我项目中的需求编写的代码,实现了这一个功能,其他的导出只需要根据这个套路进行修改,剩下的就是体力活了,第一次写博客,没有经验,希望大家批评指正。

参考博客:
Java poi Excel 通用导出

你可能感兴趣的:(java)