add sortJoin

This commit is contained in:
Looly 2019-10-29 14:45:25 +08:00
parent da39e9e646
commit 3511952a35
5 changed files with 124 additions and 67 deletions

View File

@ -10,6 +10,7 @@
* 【core】 XmlUtil中mapToStr支持namespacepr#599@Github
* 【core】 ZipUtil修改策略:默认关闭输入流issue#604@Github
* 【core】 改进CsvReader支持RowHandler按行处理issue#608@Github
* 【core】 增加MapUtil.sortJoin改进SecureUtil.signParams支持补充字符串issue#606@Github
### Bug修复
* 【core】 解决ConcurrentHashSet不能序列化的问题issue#600@Github

View File

@ -492,11 +492,28 @@ public class MapUtil {
* @param map Map
* @param separator entry之间的连接符
* @param keyValueSeparator kv之间的连接符
* @param otherParams 其它附加参数字符串例如密钥
* @return 连接字符串
* @since 3.1.1
*/
public static <K, V> String join(Map<K, V> map, String separator, String keyValueSeparator) {
return join(map, separator, keyValueSeparator, false);
public static <K, V> String join(Map<K, V> map, String separator, String keyValueSeparator, String... otherParams) {
return join(map, separator, keyValueSeparator, false, otherParams);
}
/**
* 根据参数排序后拼接为字符串常用于签名
*
* @param params 参数
* @param separator entry之间的连接符
* @param keyValueSeparator kv之间的连接符
* @param isIgnoreNull 是否忽略null的键和值
* @param otherParams 其它附加参数字符串例如密钥
* @return 签名字符串
* @since 5.0.4
*/
public static String sortJoin(Map<?, ?> params, String separator, String keyValueSeparator, boolean isIgnoreNull,
String... otherParams) {
return join(sort(params), separator, keyValueSeparator, isIgnoreNull, otherParams);
}
/**
@ -507,11 +524,12 @@ public class MapUtil {
* @param map Map
* @param separator entry之间的连接符
* @param keyValueSeparator kv之间的连接符
* @param otherParams 其它附加参数字符串例如密钥
* @return 连接后的字符串
* @since 3.1.1
*/
public static <K, V> String joinIgnoreNull(Map<K, V> map, String separator, String keyValueSeparator) {
return join(map, separator, keyValueSeparator, true);
public static <K, V> String joinIgnoreNull(Map<K, V> map, String separator, String keyValueSeparator, String... otherParams) {
return join(map, separator, keyValueSeparator, true, otherParams);
}
/**
@ -519,24 +537,33 @@ public class MapUtil {
*
* @param <K> 键类型
* @param <V> 值类型
* @param map Map
* @param map Map为空返回otherParams拼接
* @param separator entry之间的连接符
* @param keyValueSeparator kv之间的连接符
* @param isIgnoreNull 是否忽略null的键和值
* @return 连接后的字符串
* @param otherParams 其它附加参数字符串例如密钥
* @return 连接后的字符串map和otherParams为空返回""
* @since 3.1.1
*/
public static <K, V> String join(Map<K, V> map, String separator, String keyValueSeparator, boolean isIgnoreNull) {
public static <K, V> String join(Map<K, V> map, String separator, String keyValueSeparator, boolean isIgnoreNull, String... otherParams) {
final StringBuilder strBuilder = StrUtil.builder();
boolean isFirst = true;
for (Entry<K, V> entry : map.entrySet()) {
if (false == isIgnoreNull || entry.getKey() != null && entry.getValue() != null) {
if (isFirst) {
isFirst = false;
} else {
strBuilder.append(separator);
if(isNotEmpty(map)){
for (Entry<K, V> entry : map.entrySet()) {
if (false == isIgnoreNull || entry.getKey() != null && entry.getValue() != null) {
if (isFirst) {
isFirst = false;
} else {
strBuilder.append(separator);
}
strBuilder.append(Convert.toStr(entry.getKey())).append(keyValueSeparator).append(Convert.toStr(entry.getValue()));
}
strBuilder.append(Convert.toStr(entry.getKey())).append(keyValueSeparator).append(Convert.toStr(entry.getValue()));
}
}
// 补充其它字符串到末尾默认无分隔符
if (ArrayUtil.isNotEmpty(otherParams)) {
for (String otherParam : otherParams) {
strBuilder.append(otherParam);
}
}
return strBuilder.toString();
@ -687,13 +714,17 @@ public class MapUtil {
*
* @param <K> key的类型
* @param <V> value的类型
* @param map Map
* @param map Map为null返回null
* @param comparator Key比较器
* @return TreeMap
* @return TreeMapmap为null返回null
* @see #newTreeMap(Map, Comparator)
* @since 4.0.1
*/
public static <K, V> TreeMap<K, V> sort(Map<K, V> map, Comparator<? super K> comparator) {
if(null == map){
return null;
}
TreeMap<K, V> result;
if (map instanceof TreeMap) {
// 已经是可排序Map此时只有比较器一致才返回原map

View File

@ -1,14 +1,15 @@
package cn.hutool.core.map;
import java.util.Map;
import java.util.Map.Entry;
import org.junit.Assert;
import org.junit.Test;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Editor;
import cn.hutool.core.lang.Filter;
import cn.hutool.core.util.StrUtil;
import org.junit.Assert;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
public class MapUtilTest {
@ -20,16 +21,7 @@ public class MapUtilTest {
map.put("c", "3");
map.put("d", "4");
Map<String, String> map2 = MapUtil.filter(map, new Filter<Entry<String, String>>() {
@Override
public boolean accept(Entry<String, String> t) {
if (Convert.toInt(t.getValue()) % 2 == 0) {
return true;
}
return false;
}
});
Map<String, String> map2 = MapUtil.filter(map, (Filter<Entry<String, String>>) t -> Convert.toInt(t.getValue()) % 2 == 0);
Assert.assertEquals(2, map2.size());
@ -45,14 +37,10 @@ public class MapUtilTest {
map.put("c", "3");
map.put("d", "4");
Map<String, String> map2 = MapUtil.filter(map, new Editor<Entry<String, String>>() {
@Override
public Entry<String, String> edit(Entry<String, String> t) {
// 修改每个值使之*10
t.setValue(t.getValue() + "0");
return t;
}
Map<String, String> map2 = MapUtil.filter(map, (Editor<Entry<String, String>>) t -> {
// 修改每个值使之*10
t.setValue(t.getValue() + "0");
return t;
});
Assert.assertEquals(4, map2.size());
@ -97,4 +85,21 @@ public class MapUtilTest {
Assert.assertEquals("d", objectArray[3][0]);
Assert.assertEquals("4", objectArray[3][1]);
}
@Test
public void sortJoinTest(){
Map<String, String> build = MapUtil.builder(new HashMap<String, String>())
.put("key1", "value1")
.put("key3", "value3")
.put("key2", "value2").build();
String join1 = MapUtil.sortJoin(build, StrUtil.EMPTY, StrUtil.EMPTY, false);
Assert.assertEquals("key1value1key2value2key3value3", join1);
String join2 = MapUtil.sortJoin(build, StrUtil.EMPTY, StrUtil.EMPTY, false, "123");
Assert.assertEquals("key1value1key2value2key3value3123", join2);
String join3 = MapUtil.sortJoin(build, StrUtil.EMPTY, StrUtil.EMPTY, false, "123", "abc");
Assert.assertEquals("key1value1key2value2key3value3123abc", join3);
}
}

View File

@ -24,6 +24,7 @@ import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
@ -825,13 +826,14 @@ public final class SecureUtil {
* 参数签名为对Map参数按照key的顺序排序后拼接为字符串然后根据提供的签名算法生成签名字符串<br>
* 拼接后的字符串键值对之间无符号键值对之间无符号忽略null值
*
* @param crypto 对称加密算法
* @param params 参数
* @param crypto 对称加密算法
* @param params 参数
* @param otherParams 其它附加参数字符串例如密钥
* @return 签名
* @since 4.0.1
*/
public static String signParams(SymmetricCrypto crypto, Map<?, ?> params) {
return signParams(crypto, params, StrUtil.EMPTY, StrUtil.EMPTY, true);
public static String signParams(SymmetricCrypto crypto, Map<?, ?> params, String... otherParams) {
return signParams(crypto, params, StrUtil.EMPTY, StrUtil.EMPTY, true, otherParams);
}
/**
@ -843,15 +845,13 @@ public final class SecureUtil {
* @param separator entry之间的连接符
* @param keyValueSeparator kv之间的连接符
* @param isIgnoreNull 是否忽略null的键和值
* @param otherParams 其它附加参数字符串例如密钥
* @return 签名
* @since 4.0.1
*/
public static String signParams(SymmetricCrypto crypto, Map<?, ?> params, String separator, String keyValueSeparator, boolean isIgnoreNull) {
if (MapUtil.isEmpty(params)) {
return null;
}
String paramsStr = MapUtil.join(MapUtil.sort(params), separator, keyValueSeparator, isIgnoreNull);
return crypto.encryptHex(paramsStr);
public static String signParams(SymmetricCrypto crypto, Map<?, ?> params, String separator,
String keyValueSeparator, boolean isIgnoreNull, String... otherParams) {
return crypto.encryptHex(MapUtil.sortJoin(params, separator, keyValueSeparator, isIgnoreNull, otherParams));
}
/**
@ -859,12 +859,13 @@ public final class SecureUtil {
* 参数签名为对Map参数按照key的顺序排序后拼接为字符串然后根据提供的签名算法生成签名字符串<br>
* 拼接后的字符串键值对之间无符号键值对之间无符号忽略null值
*
* @param params 参数
* @param params 参数
* @param otherParams 其它附加参数字符串例如密钥
* @return 签名
* @since 4.0.1
*/
public static String signParamsMd5(Map<?, ?> params) {
return signParams(DigestAlgorithm.MD5, params);
public static String signParamsMd5(Map<?, ?> params, String... otherParams) {
return signParams(DigestAlgorithm.MD5, params, otherParams);
}
/**
@ -872,12 +873,13 @@ public final class SecureUtil {
* 参数签名为对Map参数按照key的顺序排序后拼接为字符串然后根据提供的签名算法生成签名字符串<br>
* 拼接后的字符串键值对之间无符号键值对之间无符号忽略null值
*
* @param params 参数
* @param params 参数
* @param otherParams 其它附加参数字符串例如密钥
* @return 签名
* @since 4.0.8
*/
public static String signParamsSha1(Map<?, ?> params) {
return signParams(DigestAlgorithm.SHA1, params);
public static String signParamsSha1(Map<?, ?> params, String... otherParams) {
return signParams(DigestAlgorithm.SHA1, params, otherParams);
}
/**
@ -885,12 +887,13 @@ public final class SecureUtil {
* 参数签名为对Map参数按照key的顺序排序后拼接为字符串然后根据提供的签名算法生成签名字符串<br>
* 拼接后的字符串键值对之间无符号键值对之间无符号忽略null值
*
* @param params 参数
* @param params 参数
* @param otherParams 其它附加参数字符串例如密钥
* @return 签名
* @since 4.0.1
*/
public static String signParamsSha256(Map<?, ?> params) {
return signParams(DigestAlgorithm.SHA256, params);
public static String signParamsSha256(Map<?, ?> params, String... otherParams) {
return signParams(DigestAlgorithm.SHA256, params, otherParams);
}
/**
@ -900,11 +903,12 @@ public final class SecureUtil {
*
* @param digestAlgorithm 摘要算法
* @param params 参数
* @param otherParams 其它附加参数字符串例如密钥
* @return 签名
* @since 4.0.1
*/
public static String signParams(DigestAlgorithm digestAlgorithm, Map<?, ?> params) {
return signParams(digestAlgorithm, params, StrUtil.EMPTY, StrUtil.EMPTY, true);
public static String signParams(DigestAlgorithm digestAlgorithm, Map<?, ?> params, String... otherParams) {
return signParams(digestAlgorithm, params, StrUtil.EMPTY, StrUtil.EMPTY, true, otherParams);
}
/**
@ -916,15 +920,13 @@ public final class SecureUtil {
* @param separator entry之间的连接符
* @param keyValueSeparator kv之间的连接符
* @param isIgnoreNull 是否忽略null的键和值
* @param otherParams 其它附加参数字符串例如密钥
* @return 签名
* @since 4.0.1
*/
public static String signParams(DigestAlgorithm digestAlgorithm, Map<?, ?> params, String separator, String keyValueSeparator, boolean isIgnoreNull) {
if (MapUtil.isEmpty(params)) {
return null;
}
final String paramsStr = MapUtil.join(MapUtil.sort(params), separator, keyValueSeparator, isIgnoreNull);
return new Digester(digestAlgorithm).digestHex(paramsStr);
public static String signParams(DigestAlgorithm digestAlgorithm, Map<?, ?> params, String separator,
String keyValueSeparator, boolean isIgnoreNull, String... otherParams) {
return new Digester(digestAlgorithm).digestHex(MapUtil.sortJoin(params, separator, keyValueSeparator, isIgnoreNull, otherParams));
}
// ------------------------------------------------------------------- UUID

View File

@ -1,5 +1,6 @@
package cn.hutool.crypto.test;
import cn.hutool.core.map.MapUtil;
import org.junit.Assert;
import org.junit.Test;
@ -8,6 +9,9 @@ import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.Sign;
import cn.hutool.crypto.asymmetric.SignAlgorithm;
import java.util.HashMap;
import java.util.Map;
/**
* 签名单元测试
*
@ -88,4 +92,18 @@ public class SignTest {
boolean verify = sign.verify(data, signed);
Assert.assertTrue(verify);
}
@Test
public void signParamsTest(){
Map<String, String> build = MapUtil.builder(new HashMap<String, String>())
.put("key1", "value1")
.put("key2", "value2").build();
String sign1 = SecureUtil.signParamsSha1(build);
Assert.assertEquals("9ed30bfe2efbc7038a824b6c55c24a11bfc0dce5", sign1);
String sign2 = SecureUtil.signParamsSha1(build, "12345678");
Assert.assertEquals("944b68d94c952ec178c4caf16b9416b6661f7720", sign2);
String sign3 = SecureUtil.signParamsSha1(build, "12345678", "abc");
Assert.assertEquals("edee1b477af1b96ebd20fdf08d818f352928d25d", sign3);
}
}