Java导出Execl疑难点处理的实现

一.背景

最近业务需求需要导出Execl,最终做出的效果如下,中间牵扯到大量的数据计算。

二.疑难问题分析

问题1:跨单元格处理及边框设置
问题2:自定义背景颜色添加
问题3:单元格中部分文字设置颜色
问题4:高度自适应处理

三.问题解决

在处理整个Excel导出中总结了很多。

整个开发过程使用的是Apache POI

pom.xml

<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>3.8</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-scratchpad</artifactId>
			<version>3.8</version>
		</dependency>

3.1 HSSFworkbook,XSSFworkbook选哪个

最开始我沿用的是之前开发用的,HSSFworkbook最后发现,HSSFworkbook在处理,自定义单元格背景颜色比较复杂,最后换成了XSSFworkbook。

HSSFWorkbook:是操作Excel2003以前(包括2003)的版本,扩展名是.xls;

XSSFWorkbook:是操作Excel2007后的版本,扩展名是.xlsx;

所以在这里我推荐使用XSSFWorkbook

3.2跨单元格及边框设置

//创建第一行,索引是从0开始的
row = sheet.createRow(0);
//创建第一个单元格
XSSFCell cell0 = row.createCell(0);
//设置单元格文字
cell0.setCellValue("姓名");
//设置单元格样式
cell0.setCellStyle(cellStyleHead);
//跨单元格设置
//参数为 firstRow, lastRow, firstCol, lastCol
CellRangeAddress cellRange1 = new CellRangeAddress(0, 1, 0, 0);
sheet.addMergedRegion(cellRange1);
//注意如果直接在下面写设置边框的样式,可能会出现边框覆盖不全的情况,可能是样式覆盖问题
//所以应该在数据渲染完成之后,在代码的最后写跨单元格边框设置,这是非常重要的

调用设置边框

//在数据渲染完成,调用封装的边框设置方法
setRegionStyle(wb, sheet, cellRange1);

设置边框方法

 /**
   * 合并单元格之后设置边框
   *
   * @param wb   XSSFWorkbook对象
   * @param sheet sheet
   * @param region region
   */
  static void setRegionStyle(XSSFWorkbook wb, XSSFSheet sheet, CellRangeAddress region) {
    RegionUtil.setBorderTop(1, region, sheet, wb);
    RegionUtil.setBorderBottom(1, region, sheet, wb);
    RegionUtil.setBorderLeft(1, region, sheet, wb);
    RegionUtil.setBorderRight(1, region, sheet, wb);
  }

3.3自定义背景颜色设置

因为poi自带的颜色索引可能不满足我们开发的需求,需要自定义样色

 //创建单元格样式
 XSSFCellStyle cellStyleContent = wb.createCellStyle();
//创建背景颜色 226, 239, 218 对应的就是RGB颜色 红绿蓝
 cellStyleContent.setFillForegroundColor(new XSSFColor(new java.awt.Color(226, 239, 218)));
//填充m
 cellStyleContent.setFillPattern(CellStyle.SOLID_FOREGROUND);

3.4设置单元格中部分字体颜色

 XSSFRichTextString ts = new XSSFRichTextString("123456\r\n789");
 XSSFFont font2 = wb.createFont();
 //字体高度
font2.setFontHeightInPoints((short) 10);
// 字体
font2.setFontName("宋体");
//字体颜色
font2.setColor(HSSFColor.GREEN.index);
//那些字体要设置颜色,
//int startIndex 开始索引
//int endIndex 结束索引
// Font font 字体
ts.applyFont(5, ts.length(), font2);

3.5高度自适应

封装的工具类如下,需要在数据渲染完的每行,调用如下工具类

//高度自适应
//XSSFRow row;
ExcelUtil.calcAndSetRowHeigt(row);
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;

import java.util.HashMap;
import java.util.Map;

/**
 * @author Created by niugang on 2020/3/13/13:34
 */
public class ExcelUtil {

  private ExcelUtil() {
    throw new IllegalStateException("Utility class");
  }

  /**
   * 根据行内容重新计算行高
   *
   * @param sourceRow sourceRow
   */
  public static void calcAndSetRowHeigt(XSSFRow sourceRow) {
    for (int cellIndex = sourceRow.getFirstCellNum(); cellIndex <= sourceRow.getPhysicalNumberOfCells(); cellIndex++) {
      //行高
      double maxHeight = sourceRow.getHeight();
      XSSFCell sourceCell = sourceRow.getCell(cellIndex);
      //单元格的内容
      String cellContent = getCellContentAsString(sourceCell);
      if (null == cellContent || "".equals(cellContent)) {
        continue;
      }
      //单元格的宽高及单元格信息
      Map<String, Object> cellInfoMap = getCellInfo(sourceCell);
      Integer cellWidth = (Integer) cellInfoMap.get("width");
      Integer cellHeight = (Integer) cellInfoMap.get("height");
      if (cellHeight > maxHeight) {
        maxHeight = cellHeight;
      }
      XSSFCellStyle cellStyle = sourceCell.getCellStyle();
      //sourceRow.getSheet().getWorkbook()
      XSSFFont font = cellStyle.getFont();
      //字体的高度
      short fontHeight = font.getFontHeight();

      //cell内容字符串总宽度
      double cellContentWidth = cellContent.getBytes().length * 2 * 256;

      //字符串需要的行数 不做四舍五入之类的操作
      double stringNeedsRows = cellContentWidth / cellWidth;
      //小于一行补足一行
      if (stringNeedsRows < 1.0) {
        stringNeedsRows = 1.0;
      }

      //需要的高度 			(Math.floor(stringNeedsRows) - 1) * 40 为两行之间空白高度
      double stringNeedsHeight = (double) fontHeight * stringNeedsRows;
      //需要重设行高
      if (stringNeedsHeight > maxHeight) {
        maxHeight = stringNeedsHeight;
        //超过原行高三倍 则为5倍 实际应用中可做参数配置
        if (maxHeight / cellHeight > 5) {
          maxHeight = 5 * cellHeight;
        }
        //最后取天花板防止高度不够
        maxHeight = Math.ceil(maxHeight);
        //重新设置行高 同时处理多行合并单元格的情况
        Boolean isPartOfRowsRegion = (Boolean) cellInfoMap.get("isPartOfRowsRegion");
        if (isPartOfRowsRegion.equals(Boolean.TRUE)) {
          Integer firstRow = (Integer) cellInfoMap.get("firstRow");
          Integer lastRow = (Integer) cellInfoMap.get("lastRow");
          //平均每行需要增加的行高
          double addHeight = (maxHeight - cellHeight) / (lastRow - firstRow + 1);
          for (int i = firstRow; i <= lastRow; i++) {
            double rowsRegionHeight = sourceRow.getSheet().getRow(i).getHeight() + addHeight;
            rowsRegionHeight=rowsRegionHeight+10;
            sourceRow.getSheet().getRow(i).setHeight((short) rowsRegionHeight);
          }
        } else {
          maxHeight=maxHeight+10;
          sourceRow.setHeight((short) maxHeight);
        }
      }

    }
  }

  /**
   * 解析一个单元格得到数据
   *
   * @param cell cell
   * @return String
   */
  private static String getCellContentAsString(XSSFCell cell) {
    final String strZero =".0";
    if (null == cell) {
      return "";
    }
    String result = "";
    switch (cell.getCellType()) {
      case Cell.CELL_TYPE_NUMERIC:
        String s = String.valueOf(cell.getNumericCellValue());
        if (s != null) {
          if (s.endsWith(strZero)) {
            s = s.substring(0, s.length() - 2);
          }
        }
        result = s;
        break;
      case Cell.CELL_TYPE_STRING:
        result = String.valueOf(cell.getStringCellValue()).trim();
        break;
      case Cell.CELL_TYPE_BLANK:
        break;
      case Cell.CELL_TYPE_BOOLEAN:
        result = String.valueOf(cell.getBooleanCellValue());
        break;
      case Cell.CELL_TYPE_ERROR:
        break;
      default:
        break;
    }
    return result;
  }

  /**
   * 获取单元格及合并单元格的宽度
   *
   * @param cell cell
   * @return Map<String  ,    Object>
   */
  private static Map<String, Object> getCellInfo(XSSFCell cell) {
    XSSFSheet sheet = cell.getSheet();
    int rowIndex = cell.getRowIndex();
    int columnIndex = cell.getColumnIndex();

    boolean isPartOfRegion = false;
    int firstColumn = 0;
    int lastColumn = 0;
    int firstRow = 0;
    int lastRow = 0;
    int sheetMergeCount = sheet.getNumMergedRegions();
    for (int i = 0; i < sheetMergeCount; i++) {
      CellRangeAddress ca = sheet.getMergedRegion(i);
      firstColumn = ca.getFirstColumn();
      lastColumn = ca.getLastColumn();
      firstRow = ca.getFirstRow();
      lastRow = ca.getLastRow();
      if (rowIndex >= firstRow && rowIndex <= lastRow) {
        if (columnIndex >= firstColumn && columnIndex <= lastColumn) {
          isPartOfRegion = true;
          break;
        }
      }
    }
    Map<String, Object> map = new HashMap<>(16);
    int width = 0;
    int height = 0;
    boolean isPartOfRowsRegion = false;
    if (isPartOfRegion) {
      for (int i = firstColumn; i <= lastColumn; i++) {
        width += sheet.getColumnWidth(i);
      }
      for (int i = firstRow; i <= lastRow; i++) {
        height += sheet.getRow(i).getHeight();
      }
      if (lastRow > firstRow) {
        isPartOfRowsRegion = true;
      }
    } else {
      width = sheet.getColumnWidth(columnIndex);
      height += cell.getRow().getHeight();
    }
    map.put("isPartOfRowsRegion", isPartOfRowsRegion);
    map.put("firstRow", firstRow);
    map.put("lastRow", lastRow);
    map.put("width", width);
    map.put("height", height);
    return map;
  }
}

到此这篇关于Java导出Execl疑难点处理的实现的文章就介绍到这了,更多相关Java导出Execl内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • java导出Excel通用方法的实例详解

    java导出Excel通用方法的实例详解 Java导出Excel通用方法,只需要一个list 集合.通用方法改进之处踊跃提出 package oa.common.utils; import java.io.OutputStream; import java.util.List; import javax.servlet.http.HttpServletResponse; import org.apache.struts2.ServletActionContext; import java.lan

  • JavaWeb动态导出Excel可弹出下载

    由于项目需求,需要将数据导出成Excel表格,并且可选择导出项,可下载.项目使用的Spring+Mybatis+SpringMVC框架,利用Apache POI导出Excel.POI具体使用请自行百度.话不多说,上代码. ExportExcelUtil代码 package com.rixin.common.util; import java.io.OutputStream; import java.lang.reflect.Method; import java.net.URLEncoder;

  • java实现合并单元格的同时并导出excel示例

    介绍 POI提供API给Java程序对Microsoft Office格式档案读和写的功能.POI可以操作的文档格式有excel,word,powerpoint等,POI进行跨行需要用到对象HSSFSheet对象,现在就当我们程序已经定义了一个HSSFSheet对象sheet. 跨第1行第1个到第2个单元格的操作为 sheet.addMergedRegion(new Region(0,(short)0,0,(short)1)); 跨第1行第1个到第2行第1个单元格的操作为 sheet.addMe

  • java导出Excel通用方法实例

    数据导出到Excel几乎是所有客户都会提出的一个需求.下面我就分享一下我的代码. 首先需要引入的jar包: 然后就是正式代码了. package lcy._41_50; import java.io.FileOutputStream; import java.io.OutputStream; import java.net.URLEncoder; import javax.servlet.http.HttpServletResponse; import org.apache.poi.hssf.u

  • java实现导出Excel的功能

    导出excel是咱Java开发的必备技能啦,之前项目有这个功能,现在将其独立出来,分享一下. 所用技术就是SpringBoot,然后是MVC架构模式. 废话不多说,直接上代码了,源码点末尾链接就可以下载. (1)新建一个SpringBoot项目(可以官网https://start.spring.io/直接生成下载,然后导入eclipse),项目结构如下: (2)修改pom文件,添加依赖: <dependency> <groupId>org.springframework.boot&

  • Java利用POI实现导入导出Excel表格示例代码

    介绍 Jakarta POI 是一套用于访问微软格式文档的Java API.Jakarta POI有很多组件组成,其中有用于操作Excel格式文件的HSSF和用于操作Word的HWPF,在各种组件中目前只有用于操作Excel的HSSF相对成熟.官方主页http://poi.apache.org/index.html,API文档http://poi.apache.org/apidocs/index.html 实现 已经在代码中加入了完整的注释. import java.io.FileInputSt

  • java导出Excel文件的步骤全纪录

    一.背景 当前B/S模式已成为应用开发的主流,而在企业办公系统中,常常有客户这样子要求:你要把我们的报表直接用Excel打开(电信系统.银行系统).或者是:我们已经习惯用Excel打印.这样在我们实际的开发中,很多时候需要实现导入.导出Excel的应用. 最近在java上做了一个EXCEL的导出功能,写了一个通用类,在这里分享分享,该类支持多sheet,且无需手动进行复杂的类型转换,只需提供三个参数即可: 1.fileName excel文件名 2.HasMap<String,List<?&g

  • java导出数据库的全部表到excel

    本文实例为大家分享了java将某个数据库的表全部导出到excel中的方法,供大家参考,具体内容如下 第一步:如何用POI操作Excel @Test public void createXls() throws Exception{ //声明一个工作薄 HSSFWorkbook wb = new HSSFWorkbook(); //声明表 HSSFSheet sheet = wb.createSheet("第一个表"); //声明行 HSSFRow row = sheet.createR

  • Java实现Excel导入导出数据库的方法示例

    本文实例讲述了Java实现Excel导入导出数据库的方法.分享给大家供大家参考,具体如下: 由于公司需求,想通过Excel导入数据添加到数据库中,而导入的Excel的字段是不固定的,使用得通过动态创建数据表,每个Excel对应一张数据表,怎么动态创建数据表,可以参考前面一篇<java使用JDBC动态创建数据表及SQL预处理的方法>. 下面主要讲讲怎么将Excel导入到数据库中,直接上代码:干货走起~~ ExcellToObjectUtil 类 主要功能是讲Excel中的数据导入到数据库中,有几

  • java实现Excel的导入、导出

    一.Excel的导入 导入可采用两种方式,一种是JXL,另一种是POI,但前者不能读取高版本的Excel(07以上),后者更具兼容性.由于对两种方式都进行了尝试,就都贴出来分享(若有错误,请给予指正) 方式一.JXL导入  所需jar包 JXL.jar publicstaticList<PutStorageInfo> readExcelByJXL(String filePath){ List<PutStorageInfo> infoList =newArrayList<Put

  • Java数据导出功能之导出Excel文件实例

    在编程中经常需要使用到表格(报表)的处理主要以Excel表格为主.下面给出用java写入数据到excel表格方法: 1.添加jar文件 java导入导出Excel文件要引入jxl.jar包,最关键的是这套API是纯Java的,并不依赖Windows系统,即使运行在Linux下,它同样能够正确的处理Excel文件.下载地址:http://www.andykhan.com/jexcelapi/ 2.jxl对Excel表格的认识 可以参见:http://www.jb51.net/article/686

随机推荐