【工具类】常用操作Excel

引言

在公司写代码,常常逃不过数据的统计,但是操作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";
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值