时间:2021-05-20
一.背景
最近业务需求需要导出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, lastColCellRangeAddress 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内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
相信很多童鞋都开发过Execl的导入导出功能,最近产品中无论是后台数据分析的需要,还是前端满足用户管理的方便,都有Execl导入导出的维护需求产生。以前做这个功
DataTable导出Execl代码太简单,我们直接看代码。复制代码代码如下:protectedvoidbtnPrint_Click(objectsender,
在编程中经常需要使用到表格(报表)的处理主要以Excel表格为主。下面给出用java写入数据到excel表格方法: 1.添加jar文件 java导入导出
在编程中经常需要使用到表格(报表)的处理主要以Excel表格为主。下面给出用java读取excel表格方法: 1.添加jar文件 java导入导出Excel
本文实例为大家分享了Java多文件以ZIP压缩包导出的具体代码,供大家参考,具体内容如下1、使用java实现吧服务器的图片打包成一个zip格式的压缩包导出,多个