mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
fix code
This commit is contained in:
parent
d8e3c7157d
commit
4e53a9c0b5
@ -195,6 +195,15 @@ public class BeanUtil {
|
|||||||
if (null == bean || StrUtil.isBlank(expression)) {
|
if (null == bean || StrUtil.isBlank(expression)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 先尝试直接获取属性
|
||||||
|
if (bean instanceof Map) {
|
||||||
|
final Map<?, ?> map = (Map<?, ?>) bean;
|
||||||
|
if(map.containsKey(expression)){
|
||||||
|
return (T) map.get(expression);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (T) BeanPath.of(expression).getValue(bean);
|
return (T) BeanPath.of(expression).getValue(bean);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,6 +164,9 @@ public class BeanPath implements Iterator<BeanPath> {
|
|||||||
*/
|
*/
|
||||||
public Object getValue(final Object bean) {
|
public Object getValue(final Object bean) {
|
||||||
final Object value = this.node.getValue(bean);
|
final Object value = this.node.getValue(bean);
|
||||||
|
if(null == value){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if (!hasNext()) {
|
if (!hasNext()) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,9 @@ public class NameNode implements Node {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getValue(final Object bean) {
|
public Object getValue(final Object bean) {
|
||||||
|
if(null == bean){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if ("$".equals(name)) {
|
if ("$".equals(name)) {
|
||||||
return bean;
|
return bean;
|
||||||
}
|
}
|
||||||
|
@ -43,10 +43,7 @@ import java.nio.charset.CharsetDecoder;
|
|||||||
import java.nio.charset.CodingErrorAction;
|
import java.nio.charset.CodingErrorAction;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.text.Normalizer;
|
import java.text.Normalizer;
|
||||||
import java.util.HashSet;
|
import java.util.*;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.function.*;
|
import java.util.function.*;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@ -2485,6 +2482,46 @@ public class CharSequenceUtil extends StrValidator {
|
|||||||
public static String indexedFormat(final CharSequence pattern, final Object... arguments) {
|
public static String indexedFormat(final CharSequence pattern, final Object... arguments) {
|
||||||
return MessageFormat.format(pattern.toString(), arguments);
|
return MessageFormat.format(pattern.toString(), arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化文本,使用 {varName} 占位<br>
|
||||||
|
* map = {a: "aValue", b: "bValue"} format("{a} and {b}", map) ---=》 aValue and bValue
|
||||||
|
*
|
||||||
|
* @param template 文本模板,被替换的部分用 {key} 表示
|
||||||
|
* @param map 参数值对
|
||||||
|
* @return 格式化后的文本
|
||||||
|
*/
|
||||||
|
public static String formatByMap(final CharSequence template, final Map<?, ?> map) {
|
||||||
|
return formatByMap(template, map, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化文本,使用 {varName} 占位<br>
|
||||||
|
* map = {a: "aValue", b: "bValue"} format("{a} and {b}", map) ---=》 aValue and bValue
|
||||||
|
*
|
||||||
|
* @param template 文本模板,被替换的部分用 {key} 表示
|
||||||
|
* @param map 参数值对
|
||||||
|
* @param ignoreNull 是否忽略 {@code null} 值,忽略则 {@code null} 值对应的变量不被替换,否则替换为""
|
||||||
|
* @return 格式化后的文本
|
||||||
|
* @since 5.4.3
|
||||||
|
*/
|
||||||
|
public static String formatByMap(final CharSequence template, final Map<?, ?> map, final boolean ignoreNull) {
|
||||||
|
return StrFormatter.formatByBean(template, map, ignoreNull);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化文本,使用 {varName} 占位<br>
|
||||||
|
* bean = User:{a: "aValue", b: "bValue"} format("{a} and {b}", bean) ---=》 aValue and bValue
|
||||||
|
*
|
||||||
|
* @param template 文本模板,被替换的部分用 {key} 表示
|
||||||
|
* @param bean 参数Bean
|
||||||
|
* @param ignoreNull 是否忽略 {@code null} 值,忽略则 {@code null} 值对应的变量不被替换,否则替换为""
|
||||||
|
* @return 格式化后的文本
|
||||||
|
* @since 5.4.3
|
||||||
|
*/
|
||||||
|
public static String formatByBean(final CharSequence template, final Object bean, final boolean ignoreNull) {
|
||||||
|
return StrFormatter.formatByBean(template, bean, ignoreNull);
|
||||||
|
}
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region ----- wrap
|
// region ----- wrap
|
||||||
|
@ -18,7 +18,6 @@ package org.dromara.hutool.core.text;
|
|||||||
|
|
||||||
import org.dromara.hutool.core.array.ArrayUtil;
|
import org.dromara.hutool.core.array.ArrayUtil;
|
||||||
import org.dromara.hutool.core.func.FunctionPool;
|
import org.dromara.hutool.core.func.FunctionPool;
|
||||||
import org.dromara.hutool.core.text.placeholder.StrFormatter;
|
|
||||||
import org.dromara.hutool.core.text.split.SplitUtil;
|
import org.dromara.hutool.core.text.split.SplitUtil;
|
||||||
import org.dromara.hutool.core.util.CharsetUtil;
|
import org.dromara.hutool.core.util.CharsetUtil;
|
||||||
|
|
||||||
@ -26,7 +25,6 @@ import java.io.StringReader;
|
|||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 字符串工具类<br>
|
* 字符串工具类<br>
|
||||||
@ -36,10 +34,10 @@ import java.util.Map;
|
|||||||
* 字符串分割<strong>split</strong>参考:{@link SplitUtil} <br>
|
* 字符串分割<strong>split</strong>参考:{@link SplitUtil} <br>
|
||||||
* 多字符串判空<strong>hasBlank</strong>参考:{@link ArrayUtil}
|
* 多字符串判空<strong>hasBlank</strong>参考:{@link ArrayUtil}
|
||||||
* </p>
|
* </p>
|
||||||
* @see SplitUtil#split(CharSequence, CharSequence) 对字符串分割
|
|
||||||
* @see ArrayUtil#hasBlank(CharSequence...) 对多个字符串判空
|
|
||||||
*
|
*
|
||||||
* @author Looly
|
* @author Looly
|
||||||
|
* @see SplitUtil#split(CharSequence, CharSequence) 对字符串分割
|
||||||
|
* @see ArrayUtil#hasBlank(CharSequence...) 对多个字符串判空
|
||||||
*/
|
*/
|
||||||
public class StrUtil extends CharSequenceUtil implements StrPool {
|
public class StrUtil extends CharSequenceUtil implements StrPool {
|
||||||
|
|
||||||
@ -130,6 +128,7 @@ public class StrUtil extends CharSequenceUtil implements StrPool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// region ----- str
|
// region ----- str
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将对象转为字符串<br>
|
* 将对象转为字符串<br>
|
||||||
*
|
*
|
||||||
@ -164,9 +163,9 @@ public class StrUtil extends CharSequenceUtil implements StrPool {
|
|||||||
|
|
||||||
if (obj instanceof String) {
|
if (obj instanceof String) {
|
||||||
return (String) obj;
|
return (String) obj;
|
||||||
}else if(obj instanceof char[]){
|
} else if (obj instanceof char[]) {
|
||||||
return new String((char[]) obj);
|
return new String((char[]) obj);
|
||||||
}else if (obj instanceof byte[]) {
|
} else if (obj instanceof byte[]) {
|
||||||
return str((byte[]) obj, charset);
|
return str((byte[]) obj, charset);
|
||||||
} else if (obj instanceof Byte[]) {
|
} else if (obj instanceof Byte[]) {
|
||||||
return str((Byte[]) obj, charset);
|
return str((Byte[]) obj, charset);
|
||||||
@ -240,7 +239,7 @@ public class StrUtil extends CharSequenceUtil implements StrPool {
|
|||||||
* @param value char[]值,注意这个数组不可修改!!
|
* @param value char[]值,注意这个数组不可修改!!
|
||||||
* @return String
|
* @return String
|
||||||
*/
|
*/
|
||||||
public static String strFast(final char[] value){
|
public static String strFast(final char[] value) {
|
||||||
return FunctionPool.createString(value);
|
return FunctionPool.createString(value);
|
||||||
}
|
}
|
||||||
// endregion
|
// endregion
|
||||||
@ -372,30 +371,4 @@ public class StrUtil extends CharSequenceUtil implements StrPool {
|
|||||||
public static String similar(final String str1, final String str2, final int scale) {
|
public static String similar(final String str1, final String str2, final int scale) {
|
||||||
return TextSimilarity.similar(str1, str2, scale);
|
return TextSimilarity.similar(str1, str2, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 格式化文本,使用 {varName} 占位<br>
|
|
||||||
* map = {a: "aValue", b: "bValue"} format("{a} and {b}", map) ---=》 aValue and bValue
|
|
||||||
*
|
|
||||||
* @param template 文本模板,被替换的部分用 {key} 表示
|
|
||||||
* @param map 参数值对
|
|
||||||
* @return 格式化后的文本
|
|
||||||
*/
|
|
||||||
public static String format(final CharSequence template, final Map<?, ?> map) {
|
|
||||||
return format(template, map, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 格式化文本,使用 {varName} 占位<br>
|
|
||||||
* map = {a: "aValue", b: "bValue"} format("{a} and {b}", map) ---=》 aValue and bValue
|
|
||||||
*
|
|
||||||
* @param template 文本模板,被替换的部分用 {key} 表示
|
|
||||||
* @param map 参数值对
|
|
||||||
* @param ignoreNull 是否忽略 {@code null} 值,忽略则 {@code null} 值对应的变量不被替换,否则替换为""
|
|
||||||
* @return 格式化后的文本
|
|
||||||
* @since 5.4.3
|
|
||||||
*/
|
|
||||||
public static String format(final CharSequence template, final Map<?, ?> map, final boolean ignoreNull) {
|
|
||||||
return StrFormatter.format(template, map, ignoreNull);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ package org.dromara.hutool.core.text.placeholder;
|
|||||||
|
|
||||||
import org.dromara.hutool.core.array.ArrayUtil;
|
import org.dromara.hutool.core.array.ArrayUtil;
|
||||||
import org.dromara.hutool.core.lang.mutable.MutableEntry;
|
import org.dromara.hutool.core.lang.mutable.MutableEntry;
|
||||||
|
import org.dromara.hutool.core.map.MapUtil;
|
||||||
import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
|
import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
|
||||||
import org.dromara.hutool.core.text.StrUtil;
|
import org.dromara.hutool.core.text.StrUtil;
|
||||||
import org.dromara.hutool.core.text.placeholder.template.NamedPlaceholderStrTemplate;
|
import org.dromara.hutool.core.text.placeholder.template.NamedPlaceholderStrTemplate;
|
||||||
@ -70,27 +71,31 @@ public class StrFormatter {
|
|||||||
return strPattern;
|
return strPattern;
|
||||||
}
|
}
|
||||||
return ((SinglePlaceholderStrTemplate) CACHE.computeIfAbsent(MutableEntry.of(strPattern, placeHolder), k ->
|
return ((SinglePlaceholderStrTemplate) CACHE.computeIfAbsent(MutableEntry.of(strPattern, placeHolder), k ->
|
||||||
StrTemplate.of(strPattern).placeholder(placeHolder).build()))
|
StrTemplate.of(strPattern).placeholder(placeHolder).build()))
|
||||||
.format(argArray);
|
.format(argArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 格式化文本,使用 {varName} 占位<br>
|
* 格式化文本,使用 {varName} 占位<br>
|
||||||
* map = {a: "aValue", b: "bValue"} format("{a} and {b}", map) ---=》 aValue and bValue
|
* bean = User:{a: "aValue", b: "bValue"} format("{a} and {b}", bean) ---=》 aValue and bValue
|
||||||
*
|
*
|
||||||
* @param template 文本模板,被替换的部分用 {key} 表示
|
* @param template 文本模板,被替换的部分用 {key} 表示
|
||||||
* @param map 参数值对
|
* @param bean 参数Bean
|
||||||
* @param ignoreNull 是否忽略 {@code null} 值,忽略则 {@code null} 值对应的变量不被替换,否则替换为""
|
* @param ignoreNull 是否忽略 {@code null} 值,忽略则 {@code null} 值对应的变量不被替换,否则替换为""
|
||||||
* @return 格式化后的文本
|
* @return 格式化后的文本
|
||||||
* @since 5.7.10
|
* @since 6.0.0
|
||||||
*/
|
*/
|
||||||
public static String format(final CharSequence template, final Map<?, ?> map, final boolean ignoreNull) {
|
public static String formatByBean(final CharSequence template, final Object bean, final boolean ignoreNull) {
|
||||||
if (null == template) {
|
if (null == template) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (null == map || map.isEmpty()) {
|
|
||||||
return template.toString();
|
if (bean instanceof Map) {
|
||||||
|
if (MapUtil.isEmpty((Map<?, ?>) bean)) {
|
||||||
|
return template.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// Bean的空检查需要反射,性能很差,此处不检查
|
||||||
|
|
||||||
return ((NamedPlaceholderStrTemplate) CACHE.computeIfAbsent(MutableEntry.of(template, ignoreNull), k -> {
|
return ((NamedPlaceholderStrTemplate) CACHE.computeIfAbsent(MutableEntry.of(template, ignoreNull), k -> {
|
||||||
final NamedPlaceholderStrTemplate.Builder builder = StrTemplate.ofNamed(template.toString());
|
final NamedPlaceholderStrTemplate.Builder builder = StrTemplate.ofNamed(template.toString());
|
||||||
@ -100,7 +105,7 @@ public class StrFormatter {
|
|||||||
builder.addFeatures(StrTemplate.Feature.FORMAT_NULL_VALUE_TO_EMPTY);
|
builder.addFeatures(StrTemplate.Feature.FORMAT_NULL_VALUE_TO_EMPTY);
|
||||||
}
|
}
|
||||||
return builder.build();
|
return builder.build();
|
||||||
})).format(map);
|
})).format(bean);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -22,6 +22,7 @@ import org.dromara.hutool.core.collection.CollUtil;
|
|||||||
import org.dromara.hutool.core.collection.ListUtil;
|
import org.dromara.hutool.core.collection.ListUtil;
|
||||||
import org.dromara.hutool.core.exception.HutoolException;
|
import org.dromara.hutool.core.exception.HutoolException;
|
||||||
import org.dromara.hutool.core.lang.Assert;
|
import org.dromara.hutool.core.lang.Assert;
|
||||||
|
import org.dromara.hutool.core.map.MapUtil;
|
||||||
import org.dromara.hutool.core.math.NumberUtil;
|
import org.dromara.hutool.core.math.NumberUtil;
|
||||||
import org.dromara.hutool.core.text.StrPool;
|
import org.dromara.hutool.core.text.StrPool;
|
||||||
import org.dromara.hutool.core.text.placeholder.StrTemplate;
|
import org.dromara.hutool.core.text.placeholder.StrTemplate;
|
||||||
@ -353,7 +354,7 @@ public class NamedPlaceholderStrTemplate extends StrTemplate {
|
|||||||
* @return 格式化字符串
|
* @return 格式化字符串
|
||||||
*/
|
*/
|
||||||
public String format(final Map<String, ?> map) {
|
public String format(final Map<String, ?> map) {
|
||||||
if (map == null) {
|
if (MapUtil.isEmpty(map)) {
|
||||||
return getTemplate();
|
return getTemplate();
|
||||||
}
|
}
|
||||||
return format(map::get, map::containsKey);
|
return format(map::get, map::containsKey);
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
package org.dromara.hutool.core.text;
|
package org.dromara.hutool.core.text;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
import org.dromara.hutool.core.text.placeholder.StrFormatter;
|
import org.dromara.hutool.core.text.placeholder.StrFormatter;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -62,4 +64,20 @@ public class StrFormatterTest {
|
|||||||
final String result3 = StrFormatter.formatWith("this is \\\\$$$ for $$$", "$$$", "a", "b");
|
final String result3 = StrFormatter.formatWith("this is \\\\$$$ for $$$", "$$$", "a", "b");
|
||||||
Assertions.assertEquals("this is \\a for b", result3);
|
Assertions.assertEquals("this is \\a for b", result3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void formatByBeanTest() {
|
||||||
|
final User user = new User("张三", 18, true);
|
||||||
|
final String s = StrFormatter.formatByBean("User name: {name}, age: {age}, gender: {gender}", user, true);
|
||||||
|
|
||||||
|
Assertions.assertEquals("User name: 张三, age: 18, gender: true", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
private static class User{
|
||||||
|
private String name;
|
||||||
|
private int age;
|
||||||
|
private boolean gender;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,10 +89,10 @@ public class StrUtilTest {
|
|||||||
@Test
|
@Test
|
||||||
public void formatTest() {
|
public void formatTest() {
|
||||||
final String template = "你好,我是{name},我的电话是:{phone}";
|
final String template = "你好,我是{name},我的电话是:{phone}";
|
||||||
final String result = StrUtil.format(template, Dict.of().set("name", "张三").set("phone", "13888881111"));
|
final String result = StrUtil.formatByMap(template, Dict.of().set("name", "张三").set("phone", "13888881111"));
|
||||||
Assertions.assertEquals("你好,我是张三,我的电话是:13888881111", result);
|
Assertions.assertEquals("你好,我是张三,我的电话是:13888881111", result);
|
||||||
|
|
||||||
final String result2 = StrUtil.format(template, Dict.of().set("name", "张三").set("phone", null));
|
final String result2 = StrUtil.formatByMap(template, Dict.of().set("name", "张三").set("phone", null));
|
||||||
Assertions.assertEquals("你好,我是张三,我的电话是:{phone}", result2);
|
Assertions.assertEquals("你好,我是张三,我的电话是:{phone}", result2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +143,7 @@ public class ConsoleLog extends AbstractLog {
|
|||||||
.set("name", this.name)
|
.set("name", this.name)
|
||||||
.set("msg", StrUtil.format(format, arguments));
|
.set("msg", StrUtil.format(format, arguments));
|
||||||
|
|
||||||
final String logMsg = StrUtil.format(logFormat, dict);
|
final String logMsg = StrUtil.formatByMap(logFormat, dict);
|
||||||
|
|
||||||
//WARN以上级别打印至System.err
|
//WARN以上级别打印至System.err
|
||||||
if (level.ordinal() >= Level.WARN.ordinal()) {
|
if (level.ordinal() >= Level.WARN.ordinal()) {
|
||||||
|
@ -41,6 +41,7 @@ public class VirtualCell extends CellBase {
|
|||||||
private CellType cellType;
|
private CellType cellType;
|
||||||
private Object value;
|
private Object value;
|
||||||
private CellStyle style;
|
private CellStyle style;
|
||||||
|
private Comment comment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造
|
* 构造
|
||||||
@ -57,7 +58,20 @@ public class VirtualCell extends CellBase {
|
|||||||
this.comment = cell.getCellComment();
|
this.comment = cell.getCellComment();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Comment comment;
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param cell 参照单元格
|
||||||
|
* @param x 新的列号,从0开始
|
||||||
|
* @param y 新的行号,从0开始
|
||||||
|
* @param value 新值
|
||||||
|
*/
|
||||||
|
public VirtualCell(final Cell cell, final int x, final int y, final Object value) {
|
||||||
|
this(cell.getRow(), x, y);
|
||||||
|
this.style = cell.getCellStyle();
|
||||||
|
this.comment = cell.getCellComment();
|
||||||
|
CellUtil.setCellValue(this, value);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造
|
* 构造
|
||||||
@ -91,31 +105,37 @@ public class VirtualCell extends CellBase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setCellValueImpl(final double value) {
|
protected void setCellValueImpl(final double value) {
|
||||||
|
this.cellType = CellType.NUMERIC;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setCellValueImpl(final Date value) {
|
protected void setCellValueImpl(final Date value) {
|
||||||
|
this.cellType = CellType.NUMERIC;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setCellValueImpl(final LocalDateTime value) {
|
protected void setCellValueImpl(final LocalDateTime value) {
|
||||||
|
this.cellType = CellType.NUMERIC;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setCellValueImpl(final Calendar value) {
|
protected void setCellValueImpl(final Calendar value) {
|
||||||
|
this.cellType = CellType.NUMERIC;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setCellValueImpl(final String value) {
|
protected void setCellValueImpl(final String value) {
|
||||||
|
this.cellType = CellType.STRING;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setCellValueImpl(final RichTextString value) {
|
protected void setCellValueImpl(final RichTextString value) {
|
||||||
|
this.cellType = CellType.STRING;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,11 +212,13 @@ public class VirtualCell extends CellBase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCellValue(final boolean value) {
|
public void setCellValue(final boolean value) {
|
||||||
|
this.cellType = CellType.BOOLEAN;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCellErrorValue(final byte value) {
|
public void setCellErrorValue(final byte value) {
|
||||||
|
this.cellType = CellType.ERROR;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@ package org.dromara.hutool.poi.excel.writer;
|
|||||||
|
|
||||||
import org.apache.poi.ss.usermodel.Sheet;
|
import org.apache.poi.ss.usermodel.Sheet;
|
||||||
import org.dromara.hutool.core.map.BeanMap;
|
import org.dromara.hutool.core.map.BeanMap;
|
||||||
import org.dromara.hutool.core.text.StrUtil;
|
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -57,31 +56,20 @@ public class SheetTemplateWriter {
|
|||||||
* @return this
|
* @return this
|
||||||
*/
|
*/
|
||||||
public SheetTemplateWriter fillOnce(final Map<?, ?> rowMap) {
|
public SheetTemplateWriter fillOnce(final Map<?, ?> rowMap) {
|
||||||
rowMap.forEach((key, value) -> this.templateContext.fill(StrUtil.toStringOrNull(key), rowMap, false));
|
this.templateContext.fill(rowMap, false);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 填充模板行,用于列表填充
|
* 填充模板行,用于列表填充
|
||||||
*
|
*
|
||||||
* @param rowBean 行的Bean数据
|
* @param rowBean 行的Bean或Map数据
|
||||||
* @return this
|
* @return this
|
||||||
*/
|
*/
|
||||||
public SheetTemplateWriter fillRow(final Object rowBean) {
|
public SheetTemplateWriter fillRow(final Object rowBean) {
|
||||||
// TODO 支持Bean的级联属性获取
|
|
||||||
return fillRow(new BeanMap(rowBean));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 填充模板行,用于列表填充
|
|
||||||
*
|
|
||||||
* @param rowMap 行数据
|
|
||||||
* @return this
|
|
||||||
*/
|
|
||||||
public SheetTemplateWriter fillRow(final Map<?, ?> rowMap) {
|
|
||||||
if (this.config.insertRow) {
|
if (this.config.insertRow) {
|
||||||
// 当前填充行的模板行以下全部下移
|
// 当前填充行的模板行以下全部下移
|
||||||
final int bottomRowIndex = this.templateContext.getBottomRowIndex(rowMap);
|
final int bottomRowIndex = this.templateContext.getBottomRowIndex(rowBean);
|
||||||
if (bottomRowIndex < 0) {
|
if (bottomRowIndex < 0) {
|
||||||
// 无可填充行
|
// 无可填充行
|
||||||
return this;
|
return this;
|
||||||
@ -96,7 +84,7 @@ public class SheetTemplateWriter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rowMap.forEach((key, value) -> this.templateContext.fill(StrUtil.toStringOrNull(key), rowMap, true));
|
this.templateContext.fill(rowBean, true);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -19,11 +19,14 @@ package org.dromara.hutool.poi.excel.writer;
|
|||||||
import org.apache.poi.ss.usermodel.Cell;
|
import org.apache.poi.ss.usermodel.Cell;
|
||||||
import org.apache.poi.ss.usermodel.CellType;
|
import org.apache.poi.ss.usermodel.CellType;
|
||||||
import org.apache.poi.ss.usermodel.Sheet;
|
import org.apache.poi.ss.usermodel.Sheet;
|
||||||
|
import org.dromara.hutool.core.bean.BeanUtil;
|
||||||
import org.dromara.hutool.core.collection.CollUtil;
|
import org.dromara.hutool.core.collection.CollUtil;
|
||||||
import org.dromara.hutool.core.lang.Assert;
|
import org.dromara.hutool.core.lang.Assert;
|
||||||
|
import org.dromara.hutool.core.map.MapUtil;
|
||||||
import org.dromara.hutool.core.regex.ReUtil;
|
import org.dromara.hutool.core.regex.ReUtil;
|
||||||
import org.dromara.hutool.core.text.StrPool;
|
import org.dromara.hutool.core.text.StrPool;
|
||||||
import org.dromara.hutool.core.text.StrUtil;
|
import org.dromara.hutool.core.text.StrUtil;
|
||||||
|
import org.dromara.hutool.core.util.ObjUtil;
|
||||||
import org.dromara.hutool.poi.excel.SheetUtil;
|
import org.dromara.hutool.poi.excel.SheetUtil;
|
||||||
import org.dromara.hutool.poi.excel.cell.CellUtil;
|
import org.dromara.hutool.poi.excel.cell.CellUtil;
|
||||||
import org.dromara.hutool.poi.excel.cell.VirtualCell;
|
import org.dromara.hutool.poi.excel.cell.VirtualCell;
|
||||||
@ -31,6 +34,7 @@ import org.dromara.hutool.poi.excel.cell.VirtualCell;
|
|||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -86,54 +90,71 @@ public class TemplateContext {
|
|||||||
* <li>如果为{@link VirtualCell},返回最底部虚拟单元格各行号</li>
|
* <li>如果为{@link VirtualCell},返回最底部虚拟单元格各行号</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @param rowData 填充数据
|
* @param rowDataBean 填充数据
|
||||||
* @return 最大行索引,-1表示无数据填充,0表示无需下移
|
* @return 最大行索引,-1表示无数据填充,0表示无需下移
|
||||||
*/
|
*/
|
||||||
public int getBottomRowIndex(final Map<?, ?> rowData) {
|
public int getBottomRowIndex(final Object rowDataBean) {
|
||||||
int bottomRowIndex = -1;
|
final AtomicInteger bottomRowIndex = new AtomicInteger(-1);
|
||||||
Cell cell;
|
this.varMap.forEach((name, cell) -> {
|
||||||
for (final Object key : rowData.keySet()) {
|
if(null != BeanUtil.getProperty(rowDataBean, name)){
|
||||||
cell = this.varMap.get(StrUtil.toStringOrNull(key));
|
if (cell instanceof VirtualCell) {
|
||||||
if (null != cell) {
|
bottomRowIndex.set(Math.max(bottomRowIndex.get(), cell.getRowIndex()));
|
||||||
if(cell instanceof VirtualCell){
|
} else if(bottomRowIndex.get() < 0){
|
||||||
bottomRowIndex = Math.max(bottomRowIndex, cell.getRowIndex());
|
|
||||||
} else{
|
|
||||||
// 实体单元格,直接填充,无需下移
|
// 实体单元格,直接填充,无需下移
|
||||||
bottomRowIndex = 0;
|
bottomRowIndex.set(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
return bottomRowIndex;
|
return bottomRowIndex.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 填充变量名name指向的单元格
|
* 填充变量名name指向的单元格
|
||||||
*
|
*
|
||||||
* @param name 变量名
|
* @param rowDataBean 一行数据的键值对
|
||||||
* @param rowData 一行数据的键值对
|
* @param isListVar 是否为列表填充,列表填充会自动指向下一列,否则填充结束后删除变量
|
||||||
* @param isListVar 是否为列表填充,列表填充会自动指向下一列,否则填充结束后删除变量
|
|
||||||
* @since 6.0.0
|
* @since 6.0.0
|
||||||
*/
|
*/
|
||||||
public void fill(final String name, final Map<?, ?> rowData, final boolean isListVar) {
|
public void fill(final Object rowDataBean, final boolean isListVar) {
|
||||||
final Cell cell = varMap.get(name);
|
final Map<String, Cell> varMap = this.varMap;
|
||||||
if (null == cell) {
|
varMap.forEach((name, cell) -> {
|
||||||
// 没有对应变量占位
|
if (null == cell) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String templateStr = cell.getStringCellValue();
|
||||||
|
// 填充单元格
|
||||||
|
if (fill(cell, name, rowDataBean)) {
|
||||||
|
// 指向下一个单元格
|
||||||
|
putNext(name, cell, templateStr, isListVar);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isListVar) {
|
||||||
|
// 清理已经匹配完毕的变量
|
||||||
|
MapUtil.removeNullValue(varMap);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final String templateStr = cell.getStringCellValue();
|
/**
|
||||||
|
* 将变量指向下一行的单元格<br>
|
||||||
|
* 如果为列表,则指向下一行的虚拟单元格(不创建单元格)
|
||||||
|
* 如果非列表,则清空此变量
|
||||||
|
*
|
||||||
|
* @param name 变量名
|
||||||
|
* @param currentCell 当前单元格
|
||||||
|
* @param templateStr 模板字符串
|
||||||
|
* @param isListVar 是否为列表填充
|
||||||
|
*/
|
||||||
|
private void putNext(final String name, final Cell currentCell, final String templateStr, final boolean isListVar) {
|
||||||
if (isListVar) {
|
if (isListVar) {
|
||||||
// 指向下一列的单元格
|
// 指向下一列的单元格
|
||||||
final Cell next = new VirtualCell(cell, cell.getColumnIndex(), cell.getRowIndex() + 1);
|
final Cell next = new VirtualCell(currentCell, currentCell.getColumnIndex(), currentCell.getRowIndex() + 1, templateStr);
|
||||||
next.setCellValue(templateStr);
|
|
||||||
varMap.put(name, next);
|
varMap.put(name, next);
|
||||||
} else {
|
} else {
|
||||||
// 非列表,一次性填充,即变量填充后,和此单元格去掉关联
|
// 非列表,一次性填充,即变量填充后,和此单元格去掉关联
|
||||||
varMap.remove(name);
|
varMap.put(name, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
fill(cell, name, templateStr, rowData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -141,10 +162,11 @@ public class TemplateContext {
|
|||||||
*
|
*
|
||||||
* @param cell 单元格,非模板中变量所在单元格则为{@link VirtualCell}
|
* @param cell 单元格,非模板中变量所在单元格则为{@link VirtualCell}
|
||||||
* @param name 变量名
|
* @param name 变量名
|
||||||
* @param templateStr 模板字符串
|
* @param rowDataBean 填充的数据,可以为Map或Bean
|
||||||
* @param rowData 填充的数据
|
* @return 是否填充成功,{@code false}表示无数据
|
||||||
*/
|
*/
|
||||||
private void fill(Cell cell, final String name, final String templateStr, final Map<?, ?> rowData) {
|
private boolean fill(Cell cell, final String name, final Object rowDataBean) {
|
||||||
|
final String templateStr = cell.getStringCellValue();
|
||||||
if (cell instanceof VirtualCell) {
|
if (cell instanceof VirtualCell) {
|
||||||
// 虚拟单元格,转换为实际单元格
|
// 虚拟单元格,转换为实际单元格
|
||||||
final Cell newCell;
|
final Cell newCell;
|
||||||
@ -159,13 +181,23 @@ public class TemplateContext {
|
|||||||
final Object cellValue;
|
final Object cellValue;
|
||||||
// 模板替换
|
// 模板替换
|
||||||
if (StrUtil.equals(name, StrUtil.unWrap(templateStr, VAR_PREFIX, VAR_SUFFIX))) {
|
if (StrUtil.equals(name, StrUtil.unWrap(templateStr, VAR_PREFIX, VAR_SUFFIX))) {
|
||||||
// 一个单元格只有一个变量
|
// 一个单元格只有一个变量,支持多级表达式
|
||||||
cellValue = rowData.get(name);
|
cellValue = BeanUtil.getProperty(rowDataBean, name);
|
||||||
|
if (null == cellValue) {
|
||||||
|
// 对应表达式无提供的值,跳过填充
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// 模板中存在多个变量或模板填充,直接赋值为String
|
// 模板中存在多个变量或模板填充,直接赋值为String
|
||||||
cellValue = StrUtil.format(templateStr, rowData);
|
// 没有找到值的变量保留原样
|
||||||
|
cellValue = StrUtil.formatByBean(templateStr, rowDataBean, false);
|
||||||
|
if (ObjUtil.equals(cellValue, templateStr)) {
|
||||||
|
// 模板无修改,说明没有变量替换,跳过填充
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
CellUtil.setCellValue(cell, cellValue);
|
CellUtil.setCellValue(cell, cellValue);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package org.dromara.hutool.poi.excel.writer;
|
package org.dromara.hutool.poi.excel.writer;
|
||||||
|
|
||||||
|
import org.dromara.hutool.core.io.file.FileUtil;
|
||||||
import org.dromara.hutool.core.map.MapUtil;
|
import org.dromara.hutool.core.map.MapUtil;
|
||||||
import org.dromara.hutool.poi.excel.ExcelUtil;
|
import org.dromara.hutool.poi.excel.ExcelUtil;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -28,7 +29,7 @@ public class TemplateWriterTest {
|
|||||||
writer.writeRow(createRow(), false);
|
writer.writeRow(createRow(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//writer.flush(FileUtil.file(targetDir + "templateResult.xlsx"), true);
|
writer.flush(FileUtil.file(targetDir + "templateResult.xlsx"), true);
|
||||||
writer.close();
|
writer.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +51,7 @@ public class TemplateWriterTest {
|
|||||||
writer.writeRow(createRow(), false);
|
writer.writeRow(createRow(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//writer.flush(FileUtil.file(targetDir + "templateWithFooterResult.xlsx"), true);
|
writer.flush(FileUtil.file(targetDir + "templateWithFooterResult.xlsx"), true);
|
||||||
writer.close();
|
writer.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user