【工具类】常用操作Excel

来源:互联网 发布:erp开源软件 编辑:程序博客网 时间:2024/05/12 12:09

引言

在公司写代码,常常逃不过数据的统计,但是操作Excel又很烦恼,于是就手写了一个操作便捷的工具类。

有几个功能亮点

方法详细参数请参考下面源代码。

1. createExcel()

  • 直接通过传入类型内容数据List<List<String>>和标题String []title 就能生成一张简介的excel表格。

2. objectListProToStrList()

  • 但是上面的内容数据又不好封装,常常会从实体类中提取,于是就有了FieldUtils这个工具类,专门通过反射操作对象属性用的。

3. getCellValue()

  • 传入Cell,直接自动判断类型返回字符串,时间格式还可以自定义。

下面放出临时代码,以后的excel工具代码都在github中更新,github地址。下面的代码已经不是最新的了,需要最新的代码去github的utils里面Copy,都有注释的 Joy。

ExcelUtils.java

/** * Create by MoonFollow (or named FireLang) * Only For You , Joy * Date: 2017/10/17 * Time: 12:45 * Excel工具类:所有方法都经过深思熟虑实现,扩展强,功能实现具体,BUG 少,结构堪称完美!!! * * 都是为了让你写出优雅的代码,不!是少加班! */public class ExcelUtils {    private static SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd");    /**     *     * @param bathPath 要类似于这样的路径:c:/base/path/     * @param fileName 随意     * @param insertData 字符串List     * @param sheetName 要创建的sheetName     * @param titleName 标题名数组     * @param startX 整个表的起始位置X     * @param startY 整个表的起始位置Y     * @throws Exception 异常     */    public static void createExcel(String bathPath, String fileName, List<List<String>> insertData, String sheetName, String titleName[], int startX, int startY) throws Exception {        XSSFWorkbook wb = new XSSFWorkbook();        XSSFSheet sheet = wb.createSheet(sheetName);//创建表        CellStyle cellStyle = wb.createCellStyle();        cellStyle.setBorderTop(BorderStyle.THIN);//设置标题细黑色边框        cellStyle.setBorderBottom(BorderStyle.THIN);        cellStyle.setBorderLeft(BorderStyle.THIN);        cellStyle.setBorderRight(BorderStyle.THIN);        cellStyle.setAlignment(HorizontalAlignment.CENTER);//让文本居中        Row titleRow = sheet.createRow(startY);//创建标题行        //设置标题行内容        for (int i = 0; i < titleName.length; i++) {            String tempTitle = titleName[i];            if(tempTitle == null){                continue;            }            int startIndexColumn = i+startX;//计算开始插入列            Cell tempCell = titleRow.createCell(startIndexColumn);            tempCell.setCellValue(tempTitle);            tempCell.setCellStyle(cellStyle);            //计算列宽并且设置列宽,按照最大值设置            int maxStrLen = getMaxLengthInColumn(insertData,i);            maxStrLen = maxStrLen < tempTitle.length() ? tempTitle.length() : maxStrLen;            System.out.println(maxStrLen);            sheet.setColumnWidth(startIndexColumn,520*maxStrLen);        }        int allCellCount = titleName.length;//一共有多少列,列按照标题来        int startRowIndex = startY+1;//内容的起始行        int allRow = insertData.size();//内容一共有多少行        CellStyle tempCellStyle = wb.createCellStyle();        tempCellStyle.setAlignment(HorizontalAlignment.CENTER);//让文本居中        for (int row = 0; row < allRow; row++) {//遍历所有的内容            Row tempRow = sheet.createRow(row+startRowIndex);            List<String> tempData = insertData.get(row);            int nowCellCount = tempData.size();//实际的列数            for (int cell = 0; cell < allCellCount; cell++) {                if(nowCellCount<=cell){//如果当前遍历的列数大于实际的列数就退出当前行,设置下一行!                    break;                }                Cell targetCell = tempRow.createCell(cell+startX);//创建列,设置列。                targetCell.setCellStyle(tempCellStyle);//让文本居中                targetCell.setCellValue(tempData.get(cell));            }        }        try {            OutputStream outputStream = new FileOutputStream(bathPath+fileName);            wb.write(outputStream);            outputStream.close();            wb.close();        } catch (Exception e) {            throw new BaseException(StaticString.WARNING_TYPE,"生成的excel写入文件失败!");        }    }    /**     * 在excel内容数据中找到当前列的最长字符串长度     * @param data excel内容数据     * @param column 指定列     * @return 当前列最长字符串长度     */    public static int getMaxLengthInColumn(List<List<String>> data ,int column){        int max = 0;        for (List<String> tempData : data) {            if(tempData.size() <= column){                continue;            }            String tempStr = tempData.get(column);            if(tempStr == null){                continue;            }            int tempLen = tempStr.length();            max = max < tempLen ? tempLen : max;        }        return max;    }    /**     * 如果Cell为时间时,就通过默认的时间格式获取值     * @param cell 目标Cell     * @return 返回目标Cell字符串     */    public static String getCellValue(Cell cell){        return getCellValue(cell,format);    }    /**     * 获取Cell的值,自动判断类型     * @param cell 目标Cell     * @return 返回字符串     */    public static String getCellValue(Cell cell,SimpleDateFormat format) {        if(cell == null){//如果为空就返回Null            return null;        }        String o = null;        int cellType = cell.getCellType();//获取当前Cell的类型        switch (cellType) {            //这里有个技巧,就是只判断特殊的几种类型,其它的类型就直接通过default处理。            case Cell.CELL_TYPE_ERROR:// 5 当该单元格数据 ERROR 的时候,(故障)                break;            case Cell.CELL_TYPE_BLANK:// 3 当该单元格没有数据的时候                o = "";                break;            case Cell.CELL_TYPE_NUMERIC:// 0 当该单元格数据为数字的时候                o = getValueOfNumericCell(cell,format);                break;            case Cell.CELL_TYPE_FORMULA:// 2 当该单元格数据为公式的时候                try {                    o = getValueOfNumericCell(cell,format);                } catch (IllegalStateException e) {                    o = cell.getRichStringCellValue().toString();                } catch (Exception e) {                    e.printStackTrace();                }                break;            default:                o = cell.getRichStringCellValue().toString();        }        return o;    }    /**     * 获取日期类型Cell的字符串值,通过默认的日期Pattern     * @param cell 目标Cell     * @return 返回目标Cell字符串     */    private static String getValueOfNumericCell(Cell cell) {        return getValueOfNumericCell(cell,format);    }    /**     * 获取日期类型Cell的字符串值     * @param cell 目标Cell     * @param format 日期Pattern     * @return 返回目标Cell字符串     */    private static String getValueOfNumericCell(Cell cell, SimpleDateFormat format) {        Boolean isDate = DateUtil.isCellDateFormatted(cell);        String o = null;        if (isDate) {            o = format.format(cell.getDateCellValue());        } else {            o = String.valueOf(cell.getNumericCellValue());        }        return o;    }}

FieldUtils.java

/** * Create by MoonFollow (or named FireLang) * Only For You , Joy * Date: 2017/10/17 * Time: 12:57 * 属性工具类,所有方法都经过深思熟虑实现,扩展强,功能实现具体,BUG 少,结构堪称完美!!! * * 都是为了让你写出优雅的代码,不!是少加班! */public class FieldUtils {    /**     * 在指定Class对象里面获取指定的属性     * @param fieldName 属性名     * @param targetClazz Class对象     * @return     */    public static Field getTargetField(String fieldName, Class targetClazz){        Field result = null;        while (targetClazz != null){            try {                result = targetClazz.getDeclaredField(fieldName);                return result;            } catch (NoSuchFieldException e) {                targetClazz = targetClazz.getSuperclass();            }        }        return result;    }    /**     * 将 List<Object> 中的属性按照属性数组顺序提取城 List<List<String>>,注意:使用该方法的前提是,你要提取的属性值都是字符串!     * @param insertData 被转换的数据源     * @param objectProName 数据属性     * @return     */    public static List<List<String>> objectListProToStrList(List<?> insertData, String [] objectProName){        List<List<String>> result = new LinkedList<>();        for (Object tempInsert : insertData) {            List<String> tempDate = objectProToStrList(tempInsert,objectProName);            result.add(tempDate);        }        return result;    }    /**     * 提取指定对象里面的指定属性,并且按照指定属相数组的顺序提取。注意:使用该方法的前提是,你要提取的属性值都是字符串!     * @param data 指定对象     * @param objectProName 指定属性字符串数组     * @return 指定提取的属性List     */    public static List<String> objectProToStrList(Object data , String []objectProName){        List<String> tempItem = new LinkedList<>();//创建装指定属性值的容器        Class tempClazz = data.getClass();//获得该对象的Class对象        for (String tempPro : objectProName) {            try {                Field tempField = FieldUtils.getTargetField(tempPro,tempClazz);                tempField.setAccessible(true);//设置当前属性可访问                String tempProValue = (String) tempField.get(data);                if(tempProValue == null){//如果当前属性为 Null 那么就输出空字符串。                    tempProValue = "";                }                tempItem.add(tempProValue);            } catch (IllegalAccessException e) {                e.printStackTrace();            }        }        return tempItem;    }}

BaseException.java

public class BaseException extends Exception{    private String errorType;//这是错误类型,一般是前端会用的一个东西,它标志着 key 。    private String errorMessage;//这是错误信息,代表具体错误解释。    public BaseException(String errorType, String errorMessage) {        this.errorType = errorType;        this.errorMessage = errorMessage;    }    public BaseException() {    }    public BaseException(String message) {        super(message);    }    public BaseException(String message, Throwable cause) {        super(message, cause);    }    public BaseException(Throwable cause) {        super(cause);    }}

StaticString.java

public class StaticString {    public static final String DEFAULTPATH = "K:\\文件上传\\POI学习测试数据\\";    //错误级别。以后自定义错误的时候,建议通过错误级别分类。这是血的教训!!!    public static final String WARNING_TYPE = "WARNING";    public static final String DANGER_TYPE = "DANGER";}