java poi对于excel的读写与反射的结合使用

java poi对于excel的读写与反射的结合使用

本人目前还在学习阶段,部分代码写的不够完善,也有参考网上的代码片段,只是结合自己的想法,希望对poi导入导出做个适合于自己使用的封装,尽量把常用的工具能封装成自己的jar,便于以后工作学习中的使用。

工作学习中难免需要将数据导入导出到excel表中,java 也有许多jar包支持这部分操作,我使用的就是poi包进行excel的导入导出。新建项目就就免了,我用的是mvn构建的,主要的poi依赖:

        <!-- poi依赖  -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.10-FINAL</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.10-FINAL</version>
        </dependency>

前期工作准备完成,开始代码部分:

/**
     * 通过传入对象list集合写入excel表
     * @param contentList 需写入的list集合对象
     * @param outpath  excel输出路径,包含excel文件名
     * @param <T>
     * @throws IOException
     */
    public static <T>  void writeExcel(List<T> contentList , String outpath) throws IOException{

        if(contentList !=null && outpath !=null){
            //创建工作簿,若包含".xlsx"则认为是10版本,否则用03版
            Workbook wb=new HSSFWorkbook();
            if(outpath.contains(".xlsx")){
                wb=new XSSFWorkbook();
            }
            CreationHelper helper=wb.getCreationHelper();
            //
            Sheet sheet=wb.createSheet("sheet1");
            //利用反射获取传入对象第一个元素的所有属性
            Field[] fields=contentList.get(0).getClass().getDeclaredFields();
            Row row;
            Cell cell;
            //遍历内容list,每行
            for (int i=0;i<contentList.size();++i){
                //创建第一行
                row =sheet.createRow(i);
                //设置行高
                row.setHeightInPoints(20.0F);
                //遍历元素属性,每列
                for (int j=0;j<fields.length;j++){
                    //创建单元格样式
                    CellStyle cellStyle=createStyleCell(wb);
                    cell = row.createCell(j);
                    //设置居中对齐
                    cellStyle=setCellStyleAlignment(cellStyle);
                    cellStyle=setCellFormat(helper,cellStyle);
                    //设置单元格样式
                    cell.setCellStyle(cellStyle);
                    //获取当前行内容对象
                    Object o = contentList.get(i);
                    try {
                        String fi = fields[j].getName();
                        String mname = "get" + fi.substring(0, 1).toUpperCase() + fi.substring(1);
                        Method mt = o.getClass().getMethod(mname);
                        //反射方法过去值
                        String val = mt.invoke(o) != null ? PramTypeJudgeUtil.obj2Str(mt.invoke(o)) : "";
                        //将值写入单元格
                        cell.setCellValue(val);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }

            for (int j=0;j<fields.length;j++){
                //设置列宽自动调整
                sheet.autoSizeColumn(j);
            }
            //输出文件
            OutputStream os = new FileOutputStream(new File(outpath));
            wb.write(os);
            os.close();

        }else{
            System.err.println("传入参数存在空:contentList:"+contentList+"\t outpath:"+outpath);
            logger.error("传入参数存在空:contentList:"+contentList+"\t outpath:"+outpath);
        }

    }

其实注释也都写有,水平有限,写的基本都是只能实现自己想要的功能,想必都能看懂。代码中为了提高通用性,使用了泛型,也就是<T>。其中涉及到单元格样式设置的也只是简单设置了下,可以根据自己需要自行设置或者屏蔽。这种封装方式适用于有时候从数据库读取数据,并且有对应的实体类,那么使用这个封装方法会方便点,当然,这只是简单的一个模版,许多都可以再调整,比如样式,比如还可以再加参数第一行的标题变成可自定义的,这个看自己需要可以调整,完整代码下面提供。在部分场合如果每次都要对应的实体类想必很麻烦,所以我在工具类中还封装有另一个不需要实体类的方法,但是传入参数需要两层list集合,代码如下:

/***
     *  通用写入excel表,将需写入内容放入list集合
     * @param list
     * @param outpath
     * @throws IOException
     */
    public static void writeExcelUniversal(List<List<Object>> list, String outpath) throws IOException {
        if(list !=null && outpath !=null) {
            //创建工作簿,若包含".xlsx"则认为是10版本,否则用03版
            Workbook wb = new HSSFWorkbook();
            if (outpath.contains(".xlsx")) {
                wb = new XSSFWorkbook();
            }
            CreationHelper helper = wb.getCreationHelper();
            Sheet sheet1 = wb.createSheet("sheet1");
            Row row;
            Cell cell;
            int maxCol=0;
            //循环第一层list,每行
            for(int i = 0; i < list.size(); ++i) {
                List rowList = list.get(i);
                row = sheet1.createRow(i);
                row.setHeightInPoints(20.0F);
                //获取最大列数
                if(rowList.size()>maxCol){
                    maxCol=rowList.size();
                }

                //循环第二层list,每列
                for(int j = 0; j < rowList.size(); ++j) {
                    CellStyle cellStyle = createStyleCell(wb);
                    cell = row.createCell(j);
                    cellStyle = setCellStyleAlignment(cellStyle);
                    cellStyle = setCellFormat(helper, cellStyle);
                    //设置单元格样式
                    cell.setCellStyle(cellStyle);
                    //设置单元格值
                    cell.setCellValue(PramTypeJudgeUtil.obj2Str(rowList.get(j)));
                }
            }
            for (int j=0;j< maxCol;j++){
                //设置列宽自动调整
                sheet1.autoSizeColumn(j);
            }
            OutputStream os = new FileOutputStream(new File(outpath));
            wb.write(os);
            os.close();
        }else {
            System.err.println("传入参数存在空:contentList:"+list+"\t outpath:"+outpath);
            logger.error("传入参数存在空:contentList:"+list+"\t outpath:"+outpath);
        }

    }

这个代码就相对简单了,大体思路和上面类似,只是第一种封装采用了泛型和反射,用于获取对象中的属性数据,第二种是单纯的放入object对象值,然后转换为string类型放入单元格。excel读取跟写是大同小异,只是因为excel数据类型和java不一样,同样是需要转换的,转换函数我也封装了,也是部分,可根据自身需要或者以后接触再扩展。先看第一种封装的读取:

/**
     * 读取excel,返回传入对象的list集合
     * @param excelpath
     * @param t
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> List<T> readExcel(String excelpath, T t) throws Exception {
        InputStream is = new FileInputStream(new File(excelpath));
        Workbook wb = WorkbookFactory.create(is);
        List<T> list = new ArrayList<>();
        Sheet ts = wb.getSheetAt(0);
        //获取对象的所有属性
        Field[] fields = t.getClass().getDeclaredFields();

        if (ts != null) {
            //读取每行内容
            for(int rowN = 0; rowN <= ts.getLastRowNum(); ++rowN) {
                Row row = ts.getRow(rowN);
                if (row != null) {
                    Object obj = t.getClass().newInstance();

                    //循环次数小于对象的元素个数且小于表格列数
                    for(int i = 0; i < fields.length && i<row.getLastCellNum(); ++i) {
                        Cell cell = row.getCell(i);
                        String fi = fields[i].getName();
                        String sname = "set" + fi.substring(0, 1).toUpperCase() + fi.substring(1);
                        //利用反射注入读取的值
                        //获取属性的set方法
                        Method mt = obj.getClass().getMethod(sname, fields[i].getType());
                        //获取单元格的string类型的值
                        String strCellVal=PramTypeJudgeUtil.getCellStringValue(cell);
                        //注入数据
                        mt.invoke(obj, newInstance(fields[i].getType(),strCellVal) );

                    }
                    list.add((T) obj);
                }
            }
        }

        return list;
    }

    /**
     * 得到带构造的类的实例
     * 实现类的有参实例
     * */
    private static Object newInstance(Class clazz, Object... args){

        try {
            if(clazz.getName().contains("util.Date")){
                java.util.Date date=DateConvertHelper.str2LongDate(args[0].toString());
                return  date;
            }
            Class[] argsClass = new Class[args.length];
            for (int i = 0, j = args.length; i < j; i++) {
                argsClass[i] = args[i].getClass();
            }
            Constructor cons = clazz.getConstructor(argsClass);

            return cons.newInstance(args);
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }

    }

同样是通过反射进行数据注入对象的,有个思路就是先把读取的单元格的数据先转为string类型,然后构建带参数的对象实例化用于注入的匹配对应类型数据。同样的还有一种就是不注入到对象中,直接返回两层list集合的:

/**
     * 通用方法读取excel返回list集合
     * @param excelpath
     * @return
     * @throws Exception
     */
    public static List<List<String>> readExcelUniversal(String excelpath) throws Exception {
        InputStream is = new FileInputStream(new File(excelpath));
        Workbook wb = WorkbookFactory.create(is);
        Sheet ts = wb.getSheetAt(0);
        List<List<String>> lastlL = new ArrayList<>();
        if (ts != null) {
            //读取每行内容
            for(int rowN = 0; rowN <= ts.getLastRowNum(); ++rowN) {
                //获取行对象
                Row row = ts.getRow(rowN);
                if (row != null) {
                    List<String> rowList = new ArrayList<>();
                    //读取每列
                    for(int i = 0; i < row.getLastCellNum(); ++i) {
                        //获取单元格对象
                        Cell cell = row.getCell(i);
                        //将获取的值放入行内容list集合
                        rowList.add(PramTypeJudgeUtil.getCellStringValue(cell));
                    }
                    //将行内容list集合放入总list集合
                    lastlL.add(rowList);
                }
            }
        }

        return lastlL;
    }

放下使用到的部分关键函数:

/**
     * 获取单元格String类型的值
     * @param cell
     * @return
     */
    public static String getCellStringValue(Cell cell)
    {
        String cellvalue = "";
        if(cell != null)
            switch(cell.getCellType())
            {
                case Cell.CELL_TYPE_NUMERIC:
                    short format = cell.getCellStyle().getDataFormat();
                    if(format == 14 || format == 31 || format == 57 || format == 58)
                    {
                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                        double value = cell.getNumericCellValue();
                        Date date = DateUtil.getJavaDate(value);
                        cellvalue = sdf.format(date);
                    } else
                    if(DateUtil.isCellDateFormatted(cell))
                    {
                        Date date = cell.getDateCellValue();
                        DateFormat formater = new SimpleDateFormat("yyyy-MM-dd");
                        cellvalue = formater.format(date);
                    } else
                    {
                        cellvalue = NumberToTextConverter.toText(cell.getNumericCellValue());
                    }
                    break;

                case Cell.CELL_TYPE_STRING:
                    cellvalue = cell.getStringCellValue().replaceAll("'", "''");
                    break;

                case Cell.CELL_TYPE_BLANK:
                    cellvalue = null;
                    break;

                case Cell.CELL_TYPE_FORMULA:
                default:
                    cellvalue = "";
                    break;
            }
        else
            cellvalue = "";
        return cellvalue;
    }

/**
     * 对象转String
     * @param param
     * @return
     */
    public static String obj2Str(Object param)
    {
        String res = null;
        if(param == null)
            res = null;
        else if(param instanceof Integer)
            res = ((Integer)param).toString();
        else
        if(param instanceof String)
            res = param.toString();
        else
        if(param instanceof Double)
            res = ((Double)param).toString();
        else
        if(param instanceof Float)
            res = ((Float)param).toString();
        else
        if(param instanceof Long)
            res = ((Long)param).toString();
        else
        if(param instanceof Boolean)
            res = ((Boolean)param).booleanValue() ? "true" : "false";
        else
        if(param instanceof Date)
        {
            Date d = (Date)param;
            DateFormat dt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            res = dt.format(d);
        } else
        {
            res = param.toString();
        }
        return res;
    }

测试部分:
对象集合excel读写测试
list集合excel读写测试

git源码链接:https://github.com/luoFrom/appinterface/tree/master/src/main/java/com/ryx/springboot/appinterface/util
新手进入,容我赚点积分,各位见谅:http://download.csdn.net/download/suiyilp/10231520

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值