热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

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

这篇文章主要介绍了Java导出Execl疑难点处理的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

一.背景

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

二.疑难问题分析

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

三.问题解决

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

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

pom.xml


			org.apache.poi
			poi-ooxml
			3.8
		
		
			org.apache.poi
			poi-scratchpad
			3.8
		

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 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
   */
  private static Map 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 = firstRow && rowIndex <= lastRow) {
        if (columnIndex >= firstColumn && columnIndex <= lastColumn) {
          isPartOfRegion = true;
          break;
        }
      }
    }
    Map 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内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!


推荐阅读
  • 本文目录一览:1、java中几种解析html的工具 ... [详细]
  • spring-session解决session一致性问题,Go语言社区,Golang程序员人脉社 ... [详细]
  • nginx+tomcat session 共享
    *tomcat1192.168.10.153*tomcat2192.168.10.154Tomcat工作模式必须为Nio模式。##添加如下内容,注意更换address ... [详细]
  • mybatis的报错……ORA-00911:无效字符xml里的配置resultTypejava.lang.Stringselectt.sfzhfromt_ldrktandt. ... [详细]
  • 如何理解MyBatis动态SQL
    本篇内容主要讲解“如何理解MyBatis动态SQL”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何理解M ... [详细]
  • Hbase 的伪分布部署、shell基本操作及hbase相关理念
    1,HBase的的的的伪分布式配置-对zookeeper的配置,这个前面配置过,修改zoo.cfg文件,指定zookeeper的主入口-配置的HBase的的:进入optmo ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 微信小程序导航跟随的实现方法
    本文介绍了在微信小程序中实现导航跟随的方法。通过设置导航的position属性和绑定滚动事件,可以实现页面向下滚动到导航位置时,导航固定在页面最上方;页面向上滚动到导航位置时,导航恢复到原始位置;点击导航可以平滑跳转到相应位置。代码示例也给出了具体实现方法。 ... [详细]
  • 浅解XXE与Portswigger Web Sec
    XXE与PortswiggerWebSec​相关链接:​博客园​安全脉搏​FreeBuf​XML的全称为XML外部实体注入,在学习的过程中发现有回显的XXE并不多,而 ... [详细]
  • HTTP请求响应的步骤第一步:第二步:第三步:第四步:第五步第一步:1.客户端连接到Web服务器⼀个HTTP ... [详细]
  • [字符编码]Numeric Character Reference和HTML Entities(一)
    你是否在dreamweaver里编辑网页的时候看到&#x3A3;这样的东西,你曾使用过&nbsp;这样的玩意吧,或者你在调试webservice的时候看到返回xml字符串中现 ... [详细]
  • Adapter相当于C(Controller,控制器),listView相当于V(View,视图)用于显示数据为ListView提供数据的List,数组或数据库相当于MVC模式中的 ... [详细]
  • IntelliJ IDEA 卡成球了?
    在和同事的一次讨论中发现,对IntelliJIDEA内存采用不同的设置方案,会对IDE的速度和响应能力产生不同的影响。Don’tbeaScroogeandgiveyourIDEso ... [详细]
  • 本文介绍了绕过WAF的XSS检测机制的方法,包括确定payload结构、测试和混淆。同时提出了一种构建XSS payload的方法,该payload与安全机制使用的正则表达式不匹配。通过清理用户输入、转义输出、使用文档对象模型(DOM)接收器和源、实施适当的跨域资源共享(CORS)策略和其他安全策略,可以有效阻止XSS漏洞。但是,WAF或自定义过滤器仍然被广泛使用来增加安全性。本文的方法可以绕过这种安全机制,构建与正则表达式不匹配的XSS payload。 ... [详细]
  • 背景应用安全领域,各类攻击长久以来都危害着互联网上的应用,在web应用安全风险中,各类注入、跨站等攻击仍然占据着较前的位置。WAF(Web应用防火墙)正是为防御和阻断这类攻击而存在 ... [详细]
author-avatar
外包小王子
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有