【POI框架实战】——POI导出Excel时设置单元格类型为数值类型

简介:   最近做的一个ITFIN的项目中,后台需要用POI实现导出功能,导出的数据中有文本格式,也有货币格式,所以为了方便在将来导出的表格中做计算,存放货币的单元格需要设置为数值类型。

背 景


  最近做的一个ITFIN的项目中,后台需要用POI实现导出功能,导出的数据中有文本格式,也有货币格式,所以为了方便在将来导出的表格中做计算,存放货币的单元格需要设置为数值类型。

  导出的Excel的单元格都是文本格式(单元格左上角有个小三角):


28.png

 费了不少功夫,终于把“小三角”去掉了,这里总结并分享一下问题的解决方法。



 通过poi导出excel的过程大致是这样的:


    规定单元格的格式

       ↓

     创建单元格

       ↓

    设置单元格的格式

       ↓

    设置数据的格式

       ↓

   把数据存放到单元格中

       ↓

     通过IO流输出


背景POI导出Excel时设置单元格类型为数值类型


  要想存放数值的单元格以数值类型导出,其中最关键的步骤就是上面加粗的两步,设置单元格的格式和向单元格中存放数据。


  核心代码如下:


  /**
   * 导出Excel-2015年11月11日
   * 
   *@param outPutParam Excel数据实体,包括要导出的excel标头、列标题、数据等
   * */
  private void createContentRows(ExcelParam outPutParam) {
    HSSFWorkbook workbook=new HSSFWorkbook(); //创建一个Excel文件
    // 遍历集合数据,产生数据行
    for (int i = 0; i < outPutParam.getContent().size(); i++) {
      int rowIndex = i + 2;
      HSSFRow contentRow = sheet.createRow(rowIndex);
      Map<String, Object> rowDate = outPutParam.getContent().get(i);
      //遍历列
      for (int j = 0; j < outPutParam.getTitleList().size(); j++) {   
        Title headTitle = outPutParam.getTitleList().get(j);//获取第i行第j列列标题
        String headerName = headTitle.getName();//获取第j列列标识
        Object data = rowDate.get(headerName);//获取第i行第j列所放数据
        HSSFCellStyle contextstyle =workbook.createCellStyle();
        HSSFCell contentCell = contentRow.createCell(j);        
        Boolean isNum = false;//data是否为数值型
        Boolean isInteger=false;//data是否为整数
        Boolean isPercent=false;//data是否为百分数
        if (data != null || "".equals(data)) {
          //判断data是否为数值型
          isNum = data.toString().matches("^(-?\\d+)(\\.\\d+)?$");
          //判断data是否为整数(小数部分是否为0)
          isInteger=data.toString().matches("^[-\\+]?[\\d]*$");
          //判断data是否为百分数(是否包含“%”)
          isPercent=data.toString().contains("%");
        }
        //如果单元格内容是数值类型,涉及到金钱(金额、本、利),则设置cell的类型为数值型,设置data的类型为数值类型
        if (isNum && !isPercent) {
          HSSFDataFormat df = workbook.createDataFormat(); // 此处设置数据格式
          if (isInteger) {
            contextstyle.setDataFormat(df.getBuiltinFormat("#,#0"));//数据格式只显示整数
          }else{
            contextstyle.setDataFormat(df.getBuiltinFormat("#,##0.00"));//保留两位小数点
          }         
          // 设置单元格格式
          contentCell.setCellStyle(contextstyle);
          // 设置单元格内容为double类型
          contentCell.setCellValue(Double.parseDouble(data.toString()));
        } else {
          contentCell.setCellStyle(contextstyle);
          // 设置单元格内容为字符型
          contentCell.setCellValue(data.toString());
        }
      }
    }
  }


 如上,有两个比较重要的点:

 1、先用正则表达式判断数据是否为数值型,如果为数值型,则设置单元格格式为整数或者小数;

 2、然后往单元格中存放数据的时候要设置数据的格式为double类型,如果查看poi的源码HSSFCell.java会发现设置数据的方法如下,所以用setCellValue(double)方法即可。


29.png


优化


 到了这里,您可能以为万事大吉啊了,其实上面的代码有个陷阱,如果不经过大数据量的测试是发觉不出来的哦~~


 如果数据量大的话,系统可能会报错“The maximum number of cell styles was exceeded. You can define up to 4000 styles in a .xls workbook”,原因是style创建的次数太多了,解决这个问题的方法很简单,在循环体外面创建单元格格式contextstyle(即把它当成一个“全局”变量),不要在循环内部创建。


 正确的代码如下:

  /**
   * 导出Excel-2015年11月11日
   * 
   *@param outPutParam Excel数据实体,包括要导出的excel标头、列标题、数据等
   * */
  private void createContentRows(ExcelParam outPutParam) {
    HSSFWorkbook workbook=new HSSFWorkbook(); //创建一个Excel文件
    HSSFCellStyle contextstyle =workbook.createCellStyle();
    // 遍历集合数据,产生数据行
    for (int i = 0; i < outPutParam.getContent().size(); i++) {
      int rowIndex = i + 2;
      HSSFRow contentRow = sheet.createRow(rowIndex);
      Map<String, Object> rowDate = outPutParam.getContent().get(i);
      //遍历列
      for (int j = 0; j < outPutParam.getTitleList().size(); j++) {   
        Title headTitle = outPutParam.getTitleList().get(j);//获取第i行第j列列标题
        String headerName = headTitle.getName();//获取第j列列标识
        Object data = rowDate.get(headerName);//获取第i行第j列所放数据
        HSSFCell contentCell = contentRow.createCell(j);        
        Boolean isNum = false;//data是否为数值型
        Boolean isInteger=false;//data是否为整数
        Boolean isPercent=false;//data是否为百分数
        if (data != null || "".equals(data)) {
          //判断data是否为数值型
          isNum = data.toString().matches("^(-?\\d+)(\\.\\d+)?$");
          //判断data是否为整数(小数部分是否为0)
          isInteger=data.toString().matches("^[-\\+]?[\\d]*$");
          //判断data是否为百分数(是否包含“%”)
          isPercent=data.toString().contains("%");
        }
        //如果单元格内容是数值类型,涉及到金钱(金额、本、利),则设置cell的类型为数值型,设置data的类型为数值类型
        if (isNum && !isPercent) {
          HSSFDataFormat df = workbook.createDataFormat(); // 此处设置数据格式
          if (isInteger) {
            contextstyle.setDataFormat(df.getBuiltinFormat("#,#0"));//数据格式只显示整数
          }else{
            contextstyle.setDataFormat(df.getBuiltinFormat("#,##0.00"));//保留两位小数点
          }         
          // 设置单元格格式
          contentCell.setCellStyle(contextstyle);
          // 设置单元格内容为double类型
          contentCell.setCellValue(Double.parseDouble(data.toString()));
        } else {
          contentCell.setCellStyle(contextstyle);
          // 设置单元格内容为字符型
          contentCell.setCellValue(data.toString());
        }
      }
    }
  }


  最后导出的正确格式:

30.png


相关文章
Excel如何使用VBA操作引用其它工作簿中的单元格
Excel引用其它工作簿中的单元格的值及使用VBA操作
|
10天前
|
easyexcel Java API
SpringBoot集成EasyExcel 3.x:高效实现Excel数据的优雅导入与导出
SpringBoot集成EasyExcel 3.x:高效实现Excel数据的优雅导入与导出
34 1
|
11天前
|
JSON 资源调度 JavaScript
蓝易云 - vue实现导出excel的多种方式
以上两种方式都可以实现在Vue中导出Excel的功能,你可以根据你的需求选择合适的方式。
17 1
|
4天前
如何使用Navicat导出Excel
如何使用Navicat导出Excel
6 0
|
1月前
|
前端开发 Java
基于Java爬取微博数据(二) 正文长文本+导出数据Excel
【5月更文挑战第12天】基于Java爬取微博数据,正文长文本+导出数据Excel
|
1月前
|
Java
java导出复杂excel
java导出复杂excel
|
1月前
|
文字识别
分享:如何ocr识别身份证复印件并导出至excel表格 ? 图片批量识别导出excel表格应用,图片批量识别转excel表格的方法
该软件是一款OCR身份证识别工具,能批量处理图片,自动提取身份证信息并导出为Excel。支持百度网盘和腾讯云盘下载。用户界面直观,操作简单,适合新手。识别过程包括:打开图片、一键识别、导出结果。特别注意,此程序仅适用于身份证识别,不适用于其他类型的图片识别。
分享:如何ocr识别身份证复印件并导出至excel表格 ? 图片批量识别导出excel表格应用,图片批量识别转excel表格的方法
|
15天前
|
JavaScript 前端开发
JS导出excel功能
JS导出excel功能
|
23天前
|
前端开发
react框架对Excel文件进行上传和导出
react框架对Excel文件进行上传和导出
分享:2秒快速查询40万手机号码归属地,批量手机号码归属地查询可以导出excel表格,WPS表格查询手机号码归属地怎么操作,批量手机号码归属地批量查询软件,批量号码查询按省份和城市分类,按运移动号码电信号码联通号码分类整理
本文介绍了如何批量快速查询手机号码归属地并进行分类。首先,通过提供的百度网盘或腾讯云盘链接下载免费查询软件。其次,开启软件,启用复制粘贴功能,直接粘贴号码列表并选择高速查询。软件能在极短时间内(如1.76秒内)完成40多万个号码的查询,结果包括归属地、运营商、邮箱和区号,且数据准确。之后,可直接导出数据至表格,若数据超过100万,可按省份、城市及运营商分类导出。文章还附带了操作动画演示,展示全程流畅的处理大量手机号码归属地查询的过程。
分享:2秒快速查询40万手机号码归属地,批量手机号码归属地查询可以导出excel表格,WPS表格查询手机号码归属地怎么操作,批量手机号码归属地批量查询软件,批量号码查询按省份和城市分类,按运移动号码电信号码联通号码分类整理