浏览代码

fix cell style

Looly 6 年之前
父节点
当前提交
def6b802f3

+ 3 - 0
CHANGELOG.md

@@ -11,10 +11,13 @@
 * 【core】        MapUtil、CollUtil增加emptyIfNull(issue#502@Github)
 * 【core】        增加emptyIfNull等(issue#503@Github)
 * 【setting】     Props增加toBean方法(issue#499@Github)
+* 【poi】          CellUtil增加getMergedRegionValue方法,ExcelWriter增加getDisposition方法
+* 【http】         HttpBase增加headerMap方法
 
 ### Bug修复
 * 【http】         修复HttpRquest中body方法长度计算问题(issue#I10UPG@Gitee)
 * 【system】     修复获取本地IP问题(pr#65@Gitee)
+* 【poi】          修复设置单元格样式无效问题
 
 -------------------------------------------------------------------------------------------------------------
 

+ 20 - 2
hutool-http/src/main/java/cn/hutool/http/HttpBase.java

@@ -135,6 +135,25 @@ public abstract class HttpBase<T> {
 	}
 	
 	/**
+	 * 设置请求头
+	 * 
+	 * @param headers 请求头
+	 * @param isOverride 是否覆盖已有头信息
+	 * @return this
+	 * @since 4.6.3
+	 */
+	public T headerMap(Map<String, String> headers, boolean isOverride) {
+		if(CollectionUtil.isEmpty(headers)) {
+			return (T)this;
+		}
+		
+		for (Entry<String, String> entry : headers.entrySet()) {
+			this.header(entry.getKey(), StrUtil.nullToEmpty(entry.getValue()), isOverride);
+		}
+		return (T)this;
+	}
+	
+	/**
 	 * 设置请求头<br>
 	 * 不覆盖原有请求头
 	 * 
@@ -146,8 +165,7 @@ public abstract class HttpBase<T> {
 	}
 	
 	/**
-	 * 设置请求头<br>
-	 * 不覆盖原有请求头
+	 * 设置请求头
 	 * 
 	 * @param headers 请求头
 	 * @param isOverride 是否覆盖已有头信息

+ 48 - 18
hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelBase.java

@@ -14,6 +14,7 @@ import org.apache.poi.xssf.usermodel.XSSFSheet;
 import cn.hutool.core.io.IoUtil;
 import cn.hutool.core.lang.Assert;
 import cn.hutool.poi.excel.cell.CellUtil;
+import cn.hutool.poi.excel.style.StyleUtil;
 
 /**
  * Excel基础类,用于抽象ExcelWriter和ExcelReader中共用部分的对象和方法
@@ -198,45 +199,74 @@ public class ExcelBase<T extends ExcelBase<T>> implements Closeable {
 	 * @since 4.1.4
 	 */
 	public CellStyle getOrCreateCellStyle(int x, int y) {
+		final CellStyle cellStyle = getOrCreateCell(x, y).getCellStyle();
+		return StyleUtil.isNullOrDefaultStyle(this.workbook, cellStyle) ? createCellStyle(x, y) : cellStyle;
+	}
+	
+	/**
+	 * 为指定单元格创建样式,返回样式后可以设置样式内容
+	 * 
+	 * @param x X坐标,从0计数,既列号
+	 * @param y Y坐标,从0计数,既行号
+	 * @return {@link CellStyle}
+	 * @since 4.6.3
+	 */
+	public CellStyle createCellStyle(int x, int y) {
 		final Cell cell = getOrCreateCell(x, y);
-		CellStyle cellStyle = cell.getCellStyle();
-		if (null == cellStyle) {
-			cellStyle = this.workbook.createCellStyle();
-			cell.setCellStyle(cellStyle);
-		}
+		final CellStyle cellStyle = this.workbook.createCellStyle();
+		cell.setCellStyle(cellStyle);
 		return cellStyle;
 	}
 
 	/**
-	 * 获取或创建某一行的样式,返回样式后可以设置样式内容
+	 * 获取或创建某一行的样式,返回样式后可以设置样式内容<br>
+	 * 需要注意,此方法返回行样式,设置背景色在单元格设置值后会被覆盖,需要单独设置其单元格的样式。
 	 * 
 	 * @param y Y坐标,从0计数,既行号
 	 * @return {@link CellStyle}
 	 * @since 4.1.4
 	 */
 	public CellStyle getOrCreateRowStyle(int y) {
-		final Row row = getOrCreateRow(y);
-		CellStyle rowStyle = row.getRowStyle();
-		if (null == rowStyle) {
-			rowStyle = this.workbook.createCellStyle();
-			row.setRowStyle(rowStyle);
-		}
+		CellStyle rowStyle = getOrCreateRow(y).getRowStyle();
+		return StyleUtil.isNullOrDefaultStyle(this.workbook, rowStyle) ? createRowStyle(y) : rowStyle;
+	}
+	
+	/**
+	 * 创建某一行的样式,返回样式后可以设置样式内容
+	 * 
+	 * @param y Y坐标,从0计数,既行号
+	 * @return {@link CellStyle}
+	 * @since 4.6.3
+	 */
+	public CellStyle createRowStyle(int y) {
+		final CellStyle rowStyle = this.workbook.createCellStyle();
+		getOrCreateRow(y).setRowStyle(rowStyle);
 		return rowStyle;
 	}
 
 	/**
-	 * 获取或创建某一行的样式,返回样式后可以设置样式内容
+	 * 获取或创建某一行的样式,返回样式后可以设置样式内容<br>
+	 * 需要注意,此方法返回行样式,设置背景色在单元格设置值后会被覆盖,需要单独设置其单元格的样式。
 	 * 
 	 * @param x X坐标,从0计数,既列号
 	 * @return {@link CellStyle}
 	 * @since 4.1.4
 	 */
 	public CellStyle getOrCreateColumnStyle(int x) {
-		CellStyle columnStyle = this.sheet.getColumnStyle(x);
-		if (null == columnStyle) {
-			columnStyle = this.workbook.createCellStyle();
-			this.sheet.setDefaultColumnStyle(x, columnStyle);
-		}
+		final CellStyle columnStyle = this.sheet.getColumnStyle(x);
+		return StyleUtil.isNullOrDefaultStyle(this.workbook, columnStyle) ? createColumnStyle(x) : columnStyle;
+	}
+	
+	/**
+	 * 创建某一行的样式,返回样式后可以设置样式内容
+	 * 
+	 * @param x X坐标,从0计数,既列号
+	 * @return {@link CellStyle}
+	 * @since 4.6.3
+	 */
+	public CellStyle createColumnStyle(int x) {
+		final CellStyle columnStyle = this.workbook.createCellStyle();
+		this.sheet.setDefaultColumnStyle(x, columnStyle);
 		return columnStyle;
 	}
 

+ 61 - 1
hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelWriter.java

@@ -3,6 +3,7 @@ package cn.hutool.poi.excel;
 import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.nio.charset.Charset;
 import java.util.Comparator;
 import java.util.LinkedHashMap;
 import java.util.Map;
@@ -34,6 +35,10 @@ import cn.hutool.core.io.IORuntimeException;
 import cn.hutool.core.io.IoUtil;
 import cn.hutool.core.lang.Assert;
 import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.CharsetUtil;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.core.util.URLUtil;
 import cn.hutool.poi.excel.cell.CellUtil;
 import cn.hutool.poi.excel.style.Align;
 
@@ -263,6 +268,17 @@ public class ExcelWriter extends ExcelBase<ExcelWriter> {
 		this.sheet.autoSizeColumn(columnIndex, useMergedCells);
 		return this;
 	}
+	
+	/**
+	 * 禁用默认样式
+	 * 
+	 * @return this
+	 * @see #setStyleSet(StyleSet)
+	 * @since 4.6.3
+	 */
+	public ExcelWriter disableDefaultStyle() {
+		return setStyleSet(null);
+	}
 
 	/**
 	 * 设置样式集,如果不使用样式,传入{@code null}
@@ -319,6 +335,31 @@ public class ExcelWriter extends ExcelBase<ExcelWriter> {
 	public int getCurrentRow() {
 		return this.currentRow.get();
 	}
+	
+	/**
+	 * 获取Content-Disposition头对应的值,可以通过调用以下方法快速设置下载Excel的头信息:
+	 * 
+	 * <pre>
+	 * response.setHeader("Content-Disposition", excelWriter.getDisposition("test.xlsx", CharsetUtil.CHARSET_UTF_8));
+	 * </pre>
+	 * 
+	 * @param fileName 文件名,如果文件名没有扩展名,会自动按照生成Excel类型补齐扩展名,如果提供空,使用随机UUID
+	 * @param charset 编码,null则使用默认UTF-8编码
+	 * @return Content-Disposition值
+	 */
+	public String getDisposition(String fileName, Charset charset) {
+		if(null == charset) {
+			charset = CharsetUtil.CHARSET_UTF_8;
+		}
+		
+		if(StrUtil.isBlank(fileName)) {
+			// 未提供文件名使用随机UUID作为文件名
+			fileName = IdUtil.fastSimpleUUID();
+		}
+		
+		fileName = StrUtil.addSuffixIfNot(URLUtil.encodeAll(fileName, charset), isXlsx() ? ".xlsx" : ".xls");
+		return StrUtil.format("attachment; filename=\"{}\"; filename*={}''{}", fileName, charset.name(), fileName);
+	}
 
 	/**
 	 * 设置当前所在行
@@ -824,7 +865,7 @@ public class ExcelWriter extends ExcelBase<ExcelWriter> {
 	 * @param y Y坐标,从0计数,既行号
 	 * @return {@link CellStyle}
 	 * @since 4.0.9
-	 * @deprecated 请使用{@link #getOrCreateCellStyle(int, int)}
+	 * @deprecated 请使用{@link #createCellStyle(int, int)}
 	 */
 	@Deprecated
 	public CellStyle createStyleForCell(int x, int y) {
@@ -833,6 +874,25 @@ public class ExcelWriter extends ExcelBase<ExcelWriter> {
 		cell.setCellStyle(cellStyle);
 		return cellStyle;
 	}
+	
+	/**
+	 * 设置某个单元格的样式<br>
+	 * 此方法用于多个单元格共享样式的情况<br>
+	 * 可以调用{@link #getOrCreateCellStyle(int, int)} 方法创建或取得一个样式对象。
+	 * 
+	 * <p>
+	 * 需要注意的是,共享样式会共享同一个{@link CellStyle},一个单元格样式改变,全部改变。
+	 * 
+	 * @param x X坐标,从0计数,既列号
+	 * @param y Y坐标,从0计数,既行号
+	 * @return this
+	 * @since 4.6.3
+	 */
+	public ExcelWriter setStyle(CellStyle style, int x, int y) {
+		final Cell cell = getOrCreateCell(x, y);
+		cell.setCellStyle(style);
+		return this;
+	}
 
 	/**
 	 * 创建字体

+ 54 - 3
hutool-poi/src/main/java/cn/hutool/poi/excel/cell/CellUtil.java

@@ -3,6 +3,7 @@ package cn.hutool.poi.excel.cell;
 import java.math.BigDecimal;
 import java.util.Calendar;
 import java.util.Date;
+import java.util.List;
 
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.CellStyle;
@@ -13,6 +14,7 @@ import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.usermodel.Sheet;
 import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.ss.util.RegionUtil;
+import org.apache.poi.ss.util.SheetUtil;
 
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.StrUtil;
@@ -26,7 +28,18 @@ import cn.hutool.poi.excel.editors.TrimEditor;
  * @since 4.0.7
  */
 public class CellUtil {
-	
+
+	/**
+	 * 获取单元格值
+	 * 
+	 * @param cell {@link Cell}单元格
+	 * @return 值,类型可能为:Date、Double、Boolean、String
+	 * @since 4.6.3
+	 */
+	public static Object getCellValue(Cell cell) {
+		return getCellValue(cell, false);
+	}
+
 	/**
 	 * 获取单元格值
 	 * 
@@ -121,7 +134,11 @@ public class CellUtil {
 	 * @param isHeader 是否为标题单元格
 	 */
 	public static void setCellValue(Cell cell, Object value, StyleSet styleSet, boolean isHeader) {
-		if(null != styleSet) {
+		if(null == cell) {
+			return;
+		}
+		
+		if (null != styleSet) {
 			final CellStyle headCellStyle = styleSet.getHeadCellStyle();
 			final CellStyle cellStyle = styleSet.getCellStyle();
 			if (isHeader && null != headCellStyle) {
@@ -148,7 +165,7 @@ public class CellUtil {
 		} else if (value instanceof RichTextString) {
 			cell.setCellValue((RichTextString) value);
 		} else if (value instanceof Number) {
-			if ((value instanceof Double || value instanceof Float  || value instanceof BigDecimal) && null != styleSet && null != styleSet.getCellStyleForNumber()) {
+			if ((value instanceof Double || value instanceof Float || value instanceof BigDecimal) && null != styleSet && null != styleSet.getCellStyleForNumber()) {
 				cell.setCellStyle(styleSet.getCellStyleForNumber());
 			}
 			cell.setCellValue(((Number) value).doubleValue());
@@ -221,6 +238,40 @@ public class CellUtil {
 		return sheet.addMergedRegion(cellRangeAddress);
 	}
 
+	/**
+	 * 获取合并单元格的值<br>
+	 * 传入的x,y坐标(列行数)可以是合并单元格范围内的任意一个单元格
+	 * 
+	 *
+	 * @param sheet {@link Sheet}
+	 * @param y 行号,从0开始,可以是合并单元格范围中的任意一行
+	 * @param x 列号,从0开始,可以是合并单元格范围中的任意一列
+	 * @return 合并单元格的值
+	 * @since 4.6.3
+	 */
+	public static Object getMergedRegionValue(Sheet sheet, int x, int y) {
+		final List<CellRangeAddress> addrs = sheet.getMergedRegions();
+
+		int firstColumn;
+		int lastColumn;
+		int firstRow;
+		int lastRow;
+		for (CellRangeAddress ca : addrs) {
+			firstColumn = ca.getFirstColumn();
+			lastColumn = ca.getLastColumn();
+			firstRow = ca.getFirstRow();
+			lastRow = ca.getLastRow();
+
+			if (y >= firstRow && y <= lastRow) {
+				if (x >= firstColumn && x <= lastColumn) {
+					return getCellValue(SheetUtil.getCell(sheet, firstRow, firstColumn));
+				}
+			}
+		}
+
+		return null;
+	}
+
 	// -------------------------------------------------------------------------------------------------------------- Private method start
 	/**
 	 * 获取数字类型的单元格值

+ 14 - 0
hutool-poi/src/main/java/cn/hutool/poi/excel/style/StyleUtil.java

@@ -175,4 +175,18 @@ public class StyleUtil {
 		setColor(cellStyle, IndexedColors.GREY_25_PERCENT, FillPatternType.SOLID_FOREGROUND);
 		return cellStyle;
 	}
+	
+	/**
+	 * 给定样式是否为null(无样式)或默认样式,默认样式为<code>workbook.getCellStyleAt(0)</code>
+	 * @param workbook 工作簿
+	 * @param style 被检查的样式
+	 * @return 是否为null(无样式)或默认样式
+	 * @since 4.6.3
+	 */
+	public static boolean isNullOrDefaultStyle(Workbook workbook, CellStyle style) {
+		if(null == style || style.equals(workbook.getCellStyleAt(0))) {
+			return true;
+		}
+		return false;
+	}
 }

+ 28 - 1
hutool-poi/src/test/java/cn/hutool/poi/excel/test/ExcelWriteTest.java

@@ -208,6 +208,33 @@ public class ExcelWriteTest {
 		// 关闭writer,释放内存
 		writer.close();
 	}
+	
+	@Test
+	@Ignore
+	public void writeMapWithStyleTest() {
+		Map<String, Object> row1 = MapUtil.newHashMap(true);
+		row1.put("姓名", "张三");
+		row1.put("年龄", 23);
+		row1.put("成绩", 88.32);
+		row1.put("是否合格", true);
+		row1.put("考试日期", DateUtil.date());
+
+		// 通过工具类创建writer
+		String path = "f:/test/writeMapWithStyleTest.xlsx";
+		FileUtil.del(path);
+		ExcelWriter writer = ExcelUtil.getWriter(path);
+		writer.setStyleSet(null);
+		
+		// 一次性写出内容,使用默认样式
+		writer.writeRow(row1, true);
+		
+		// 设置某个单元格样式
+		CellStyle orCreateRowStyle = writer.getOrCreateCellStyle(0, 1);
+		StyleUtil.setColor(orCreateRowStyle,IndexedColors.RED.getIndex(),FillPatternType.SOLID_FOREGROUND );
+		
+		// 关闭writer,释放内存
+		writer.close();
+	}
 
 	@Test
 	@Ignore
@@ -278,7 +305,7 @@ public class ExcelWriteTest {
 	}
 	
 	@Test
-//	@Ignore
+	@Ignore
 	public void writeMapOnlyAliasTest2() {
 		Map<Object, Object> row1 = new LinkedHashMap<>();
 		row1.put("name", "张三");