Excel工具类

package batchExcel;

import java.io.ByteArrayOutputStream;  
import java.io.File;  
import java.io.FileInputStream;  
import java.io.InputStream;  
import java.io.OutputStream;  
import java.lang.reflect.Array;  
import java.lang.reflect.Field;  
import java.lang.reflect.Method;  
import java.util.ArrayList;  
import java.util.Arrays;  
import java.util.Collections;  
import java.util.Date;  
import java.util.List;  
  
import jxl.BooleanCell;  
import jxl.Cell;  
import jxl.DateCell;  
import jxl.NumberCell;  
import jxl.Sheet;  
import jxl.Workbook;  
import jxl.biff.EmptyCell;  
import jxl.format.Alignment;  
import jxl.format.VerticalAlignment;  
import jxl.write.Blank;  
import jxl.write.DateTime;  
import jxl.write.Label;  
import jxl.write.WritableCellFormat;  
import jxl.write.WritableFont;  
import jxl.write.WritableSheet;  
import jxl.write.WritableWorkbook;  
  
/** 
 * 操作Excel工具类(使用开源项目JXL操作Excel).<br /> 
 * 需要严格按照方法定义来使用, 容错能力不高.<br /> 
 * 实体类应该严格按照JavaBean规范定义, 数据类型仅支持基本类型、java.util.Date、java.lang.String 
 *  
 * 
 */  
public class ExcelUtil {  
      
    /** 
     * getExcelStream(T[], String[], String[], String)的中转方法, 可直接接受List集合数据 
     * @see {@link ExcelUtil#getExcelStream(Object[], String[], String[], String)} 
     */  
    public static <T> OutputStream getExcelStream(List<T> dataList, String [] beanProperties,  
            String [] columnNames, String sheetName) throws Exception {  
        if (null != dataList && dataList.size() > 0) {  
            Class<?> newType = dataList.get(0).getClass();  
            @SuppressWarnings("unchecked")  
            T [] tempArray = (T []) Array.newInstance(newType, dataList.size());  
            dataList.toArray(tempArray);  
              
            return getExcelStream(tempArray, beanProperties, columnNames, sheetName);  
        }  
        return null;  
    }  
      
    /** 
     * getExcelStreamWithPointOutProperties(T[], String[], String[], String)的中转方法,  
     * 可直接接受List集合数据, 方法第二个参数接受指明转换到Excel的JavaBean属性, 顺序任意. 
     * @see {@link ExcelUtil#getExcelStreamWithPointOutProperties(Object[], String[], String[], String)} 
     */  
    public static <T> OutputStream getExcelStreamWithPointOutProperties(List<T> dataList,   
            String [] beanProperties, String [] columnNames, String sheetName)   
            throws Exception {  
        if (null != dataList && dataList.size() > 0) {  
            Class<?> newType = dataList.get(0).getClass();  
            @SuppressWarnings("unchecked")  
            T [] tempArray = (T []) Array.newInstance(newType, dataList.size());  
            dataList.toArray(tempArray);  
              
            return getExcelStreamWithPointOutProperties(tempArray, beanProperties,   
                columnNames, sheetName);  
        }  
        return null;  
    }  
      
    /** 
     * <p>将Java对象组成的集合转换成Excel数据, 以输出流形式返回, 可以实现下载、存储在磁盘等.</p> 
     * <p>Excel文件列按JavaBean属性定义顺序生成, 还需要注意Excel列名数与排除掉的属性数之和必须与 
     *  JavaBean属性总数相等.</p> 
     * @param dataList 需要转换到Excel的Java对象数组 
     * @param columnNames Excel列名(即JavaBean属性对应的列名, 如:name >> '姓名'), 必须按JavaBean 
     *  属性定义顺序给出, 还需要注意跳过excludeProperties指定的排除掉的属性 
     * @param excludeProperties 排除掉的JavaBean属性名 
     * @param sheetName Excel文件表名 
     * @return 生成的Excel文件输出流(ByteArrayOutputStream) 
     * @throws Exception  
     */  
    public static <T> OutputStream getExcelStream(T [] dataList, String [] columnNames,   
            String [] excludeProperties, String sheetName) throws Exception {  
        if (null == columnNames) {  
            throw new Exception("Excel列名必须指定.");  
        }  
        // 取得数组成员的类型Class对象  
        Class<?> clazz = dataList.getClass().getComponentType();  
        Field [] fields = clazz.getDeclaredFields();  
          
        List<String> excludePropertyList = Collections.emptyList();  
        if (excludeProperties != null && excludeProperties.length > 0) {  
            excludePropertyList = Arrays.asList(excludeProperties);  
        }  
          
        if (fields.length != columnNames.length + excludePropertyList.size()) {  
            throw new Exception("给定Excel列名为" + columnNames.length + "个, 排除掉的" +  
                    "属性为" + excludePropertyList.size() + "个, 实体类" +   
                    clazz.getSimpleName() + "共有" + fields.length +   
                    "个属性,个数不匹配.");  
        }  
        // 列名与Bean有效属性一一对应  
        String [] beanProperties = new String [columnNames.length];  
        int i = 0;  
        for(Field field : fields) {  
            String fieldName = field.getName();  
            if (excludePropertyList == null || !excludePropertyList.contains(fieldName)) {  
                // 当给定排除属性数和列名数之和与Bean属性数不等时会有异常  
                beanProperties[i++] = fieldName;  
            }  
        }  
        Method [] getterMethods = parseGetterMethods(beanProperties, clazz);  
        return getExcelStream(dataList, getterMethods, columnNames, sheetName);  
    }  
      
    /** 
     * <p>将Java对象组成的集合转换成Excel数据, 以输出流形式返回, 可以实现下载、存储在磁盘等.</p> 
     * <p>可按任意顺序取任意个数的Bean属性导出到Excel, Excel列顺序将与给定beanProperties顺序保持一致.</p> 
     * @param data 需要生成Excel文件的Java数据, beanProperties即是T中的属性 
     * @param beanProperties 需要转换到Excel中的Bean属性 
     * @param colNames Excel使用的列名, 需要与beanProperties一一对应 
     * @param sheetName Excel表名 
     * @return 生成的Excel输出流(ByteArrayOutputStream) 
     * @throws Exception 
     */  
    public static <T> OutputStream getExcelStreamWithPointOutProperties (T [] data,   
            String [] beanProperties, String [] colNames, String sheetName) throws Exception {  
        if (beanProperties == null || colNames == null) {  
            throw new Exception("必须给出有效的JavaBean属性及相应的Excel列名.");  
        }  
        if (beanProperties.length > colNames.length) {  
            throw new Exception("给出的Excel列名为" + colNames.length +   
            "个, 给出的有效Bean属性为" + beanProperties.length + "个, 个数不匹配.");  
        }  
        Class<?> clazz = data.getClass().getComponentType();  
        Method [] getterMethods = parseGetterMethods(beanProperties, clazz);  
          
        return getExcelStream(data, getterMethods, colNames, sheetName);  
    }  
      
    // 解析JavaBean属性对应的getter方法  
    private static Method [] parseGetterMethods(String [] properties, Class<?> clazz)   
            throws Exception {  
        Method [] getterMethods = new Method [properties.length];  
        int i = 0;  
        for(String property : properties) {  
            String getterName = "get" + property.substring(0, 1).toUpperCase() + property.substring(1);  
            try {  
                getterMethods[i++] = clazz.getMethod(getterName, (Class []) null);  
            } catch (SecurityException e) {  
                throw new Exception("属性" + property + "对应的getter方法可能无法访问.", e);  
            } catch (NoSuchMethodException se) {  
                throw new Exception("属性" + property + "没有对应的getter方法.", se);  
            }  
        }  
        return getterMethods;  
    }  
      
    /** 
     * 具体执行方法, 公开的方法getExcelStreamWithPointOutProperties和getExcelStream都是为调用此方法作相应准备.  
     * 方法中调用getters并将值填进相应的单元格中, 最后将Excel文件以输出流的形式返回. 
     * @param data Java集合数据, 公开方法中的List形式也会转为数组形式. 
     * @param getterMethods 需要转换成Excel列的JavaBean属性对应的getters方法 
     * @param colNames Excel列名, 与JavaBean属性对应 
     * @param sheetName Excel表名 
     * @return Excel文件对应的输出流 
     * @throws Exception 
     */  
    private static <T> OutputStream getExcelStream(T [] data, Method [] getterMethods,   
            String [] colNames, String sheetName) throws Exception {  
        if (null == sheetName) {  
            sheetName = "Sheet_1";  
        }  
        ByteArrayOutputStream os = new ByteArrayOutputStream();  
        WritableWorkbook workbook = Workbook.createWorkbook(os);  
        WritableSheet sheet = workbook.createSheet(sheetName, 0);  
          
        WritableCellFormat cellFormat = new WritableCellFormat();  
        cellFormat.setAlignment(Alignment.CENTRE);  
        cellFormat.setVerticalAlignment(VerticalAlignment.CENTRE);  
        cellFormat.setFont(new WritableFont(WritableFont.ARIAL, 12, WritableFont.BOLD));  
          
       
      
        sheet.addCell(new Label(0, 0, "汽车品牌参数批量倒入清单", cellFormat));
        int col = 0;  
        for(Method method : getterMethods) {  
            int row = 1;
           
            // 第一行(列名)采用粗体、15号字, 并居中对齐  
            sheet.addCell(new Label(col, row++, colNames[col], cellFormat));      
            for(T t : data) {  
                // 调用getter方法, 并将返回值添加到Excel的单元格中  
                invokeGetterMethod(method, t, sheet, row++, col);     
            }  
            col++;  
        }  
        sheet.mergeCells(0 , 0 , 3 , 0 );
        workbook.write();  
        workbook.close();  
        return os;  
    }  
      
    /** 
     * 调用JavaBean中的取值方法, 并将返回值按照JavaBean属性的数据类型填充到Excel指定的单元格. 
     * @param getterMethod JavaBean中的取值方法Method 
     * @param o 调用Getter方法的JavaBean实例 
     * @param sheet Excel表 
     * @param rowIndex Excel表中的行索引 
     * @param colIndex Excel表中的列索引 
     * @throws Exception 
     */  
    private static void invokeGetterMethod(Method getterMethod, Object o, WritableSheet sheet,  
            int rowIndex, int colIndex) throws Exception {  
        Class<?> type = getterMethod.getReturnType();  
        Object returnVal = getterMethod.invoke(o, (Object []) null);  
        if (null == returnVal) {    // getter方法返回值为null  
            sheet.addCell(new Blank(colIndex, rowIndex));  
        }else if (String.class.isAssignableFrom(type) || char.class.isAssignableFrom(type)  
                || Character.class.isAssignableFrom(type)) {  
            // getter方法返回值为String或char  
            sheet.addCell(new Label(colIndex, rowIndex, returnVal.toString()));  
        } else if (Number.class.isAssignableFrom(type) || double.class.isAssignableFrom(type)  
                || int.class.isAssignableFrom(type) || long.class.isAssignableFrom(type)  
                || short.class.isAssignableFrom(type) || float.class.isAssignableFrom(type)) {  
            // getter方法返回值为数字类型  
            sheet.addCell(new jxl.write.Number(colIndex, rowIndex, ((Number)returnVal).doubleValue()));  
        } else if (Date.class.isAssignableFrom(type)) {     // getter方法返回值为java.util.Date类型  
            sheet.addCell(new DateTime(colIndex, rowIndex, (Date) returnVal));  
        } else if (Boolean.class.isAssignableFrom(type) || boolean.class.isAssignableFrom(type)) {  
            // getter方法返回值为布尔类型  
            sheet.addCell(new jxl.write.Boolean(colIndex, rowIndex, (Boolean) returnVal));  
        } else {    // 不支持其它的返回值类型  
            throw new Exception("getter方法: " + getterMethod.getName() +   
                "的返回值类型不被支持.");  
        }  
    }  
      
    /** 
     * <p>解析Excel, 将Excel扁平数据解析封装为Java对象, 以Java集合形式返回.</p> 
     * <p>由于封装并不完善, 需要严格按照方法指定调用方式使用才可. 解析顺序必须按照Excel文件中列顺序</p> 
     * @param excel 需要解析的Excel文件 
     * @param beanProperties JavaBean的属性名, 以数组方式给出; 必须依照Excel文件所定义列顺序给出. 
     * @param columnTypes JavaBean属性的数据类型, 必需与columns数组数据一一对应 
     * @param clazz JavaBean的Class对象, 必须指定, 否则无法使用反射 
     * @return Excel解析所得JavaBean组成的List 
     * @throws Exception 
     */  
    public static <T> List<T> parseExcel(File excel, String [] beanProperties,   
            Class<?> [] propertyTypes, Class<T> clazz) throws Exception {  
        return parseExcel(new FileInputStream(excel), beanProperties, propertyTypes, clazz);  
    }  
      
    /** 
     * 解析Excel, 将Excel扁平数据解析封装为Java对象. 
     * @param inputStream Excel文件对应的输入流. 
     * @param columns JavaBean的属性名 
     * @param columnTypes JavaBean属性的数据类型 
     * @param clazz JavaBean类的Class对象 
     * @return Excel解析所得JavaBean组成的List 
     * @throws Exception 
     * @see {@link ExcelUtil#parseExcel(File, String[], Class[], Class)} 
     */  
    public static <T> List<T> parseExcel(InputStream inputStream, String [] beanProperties,  
            Class<?> [] propertyTypes, Class<T> clazz) throws Exception {  
        if (beanProperties == null || propertyTypes == null) {  
            throw new Exception("必须指定Excel列映射的JavaBean属性及相应的数据类型.");  
        }  
        if (beanProperties.length > propertyTypes.length) {  
            throw new Exception("给定的JavaBean属性为" + beanProperties.length +   
                "个, 数据类型为" + propertyTypes.length + "个, 个数不匹配.");  
        }  
        Method [] setMethods = new Method [beanProperties.length];  
        int i = 0;  
        for(String property : beanProperties) {  
            String setMethodName = "set" + property.substring(0, 1).toUpperCase() +   
                property.substring(1);  
            try {  
                setMethods[i] = clazz.getDeclaredMethod(setMethodName, propertyTypes[i++]);  
            } catch (SecurityException se) {  
                throw new Exception("属性" + property + "对应的setter方法可能无法访问.", se);  
            } catch (NoSuchMethodException e) {  
                String paramType = propertyTypes[--i].getName();  
                throw new Exception("属性" + property + "没有参数类型为" + paramType +   
                    "的setter方法.", e);  
            }  
        }  
        return parseExcel(inputStream, setMethods, propertyTypes, clazz);  
    }  
      
    /** 
     * 具体解析方法, 由公共方法准备好数据后调用, 因此不公开. 
     * @param inputStream 准备解析的Excel文件对应的输入流 
     * @param setMethods setter方法数组, 与给定列顺序一样 
     * @param propertyTypes JavaBean属性类型数组 
     * @param cls JavaBean类的Class对象 
     * @return 解析成功后JavaBean集合 
     * @throws Exception 
     */  
    private static <T> List<T> parseExcel(InputStream inputStream, Method [] setterMethods,   
            Class<?> [] propertyTypes, Class<T> beanType) throws Exception {  
        Workbook workbook = Workbook.getWorkbook(inputStream);  
        Sheet sheet = workbook.getSheet(0);  
  
        List<T> parseResultList = new ArrayList<T>(sheet.getRows() - 1);  
        for(int row = 1; row < sheet.getRows(); row++) { // 跳过第0行, 一般第0行是列名  
            T instance = beanType.newInstance();    // 创建实例  
            Cell [] cells = sheet.getRow(row);  
            for(Cell cell : cells) {  
                if (cell.getColumn() >= setterMethods.length) break;  
                Method setMethod = setterMethods[cell.getColumn()];  
                Class<?> type = propertyTypes[cell.getColumn()];  
                if (null != setMethod) {  
                    // 调用新创建实例的setter  
                    invokeSetterMethod(setMethod, instance, cell, type);  
                }  
            }  
            parseResultList.add(instance);  
        }  
        workbook.close();  
        return parseResultList;  
    }  
      
    /** 
     * 取出Excel单元格中的数据并作相应转换, 然后调用实例的设置属性值方法(setters), 给实例设置指定值 
     * @param setterMethod setter方法 
     * @param o setterMethod调用所针对的实例 
     * @param cell Excel单元格 
     * @param paramType setter方法所需参数的类型 
     * @throws Exception 
     */  
    private static void invokeSetterMethod(Method setterMethod, Object o, Cell cell,  
            Class<?> paramType) throws Exception  {  
        try {  
            if (cell instanceof EmptyCell) {    // 单元格没有内容, 将实体类相应属性设置为null  
                setterMethod.invoke(o, new Object [] { null });  
            } else if (String.class.isAssignableFrom(paramType) || char.class.isAssignableFrom(paramType)  
                    || Character.class.isAssignableFrom(paramType)) {  
                // String|char|Character设置为String  
                setterMethod.invoke(o, cell.getContents());  
            } else if (Double.class.isAssignableFrom(paramType) || double.class.isAssignableFrom(paramType)) {  // Double|double  
                Double number = ((NumberCell) cell).getValue();  
                setterMethod.invoke(o, number);  
            } else if (Integer.class.isAssignableFrom(paramType) || int.class.isAssignableFrom(paramType)) {        // Integer|int  
                Double number = ((NumberCell) cell).getValue();  
                setterMethod.invoke(o, number.intValue());  
            } else if (Long.class.isAssignableFrom(paramType) || long.class.isAssignableFrom(paramType)) {      // Long|long  
                Double number = ((NumberCell) cell).getValue();  
                setterMethod.invoke(o, number.longValue());  
            } else if (Float.class.isAssignableFrom(paramType) || float.class.isAssignableFrom(paramType)) {        // Float|float  
                Double number = ((NumberCell) cell).getValue();  
                setterMethod.invoke(o, number.floatValue());  
            } else if (Short.class.isAssignableFrom(paramType) || short.class.isAssignableFrom(paramType)) {        // Short|short  
                Double number = ((NumberCell) cell).getValue();  
                setterMethod.invoke(o, number.shortValue());  
            } else if (Boolean.class.isAssignableFrom(paramType) || boolean.class.isAssignableFrom(paramType)) {    // Boolean|boolean  
                setterMethod.invoke(o, ((BooleanCell)cell).getValue());  
            } else if (Date.class.isAssignableFrom(paramType)) {    // java.util.Date  
                setterMethod.invoke(o, ((DateCell)cell).getDate());  
            } else {  
                throw new Exception("方法" + setterMethod.getName() +   
                    "所需要的参数类型不被支持.");  
            }  
        } catch (IllegalArgumentException e) {  
            throw new Exception("setter方法" + setterMethod.getName() + "需要参数的类型为" +   
                    setterMethod.getParameterTypes()[0].getName() +   
                    ", 传入的类型为" + paramType.getName(), e);  
        }  
    }  
}  

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值