mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
fix bug
This commit is contained in:
parent
f99e54d7ae
commit
542120f220
@ -17,6 +17,7 @@ import org.dromara.hutool.core.comparator.CompareUtil;
|
|||||||
import org.dromara.hutool.core.lang.Assert;
|
import org.dromara.hutool.core.lang.Assert;
|
||||||
import org.dromara.hutool.core.text.StrUtil;
|
import org.dromara.hutool.core.text.StrUtil;
|
||||||
import org.dromara.hutool.core.util.CharUtil;
|
import org.dromara.hutool.core.util.CharUtil;
|
||||||
|
import org.dromara.hutool.core.util.ObjUtil;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
@ -1003,47 +1004,6 @@ public class NumberUtil {
|
|||||||
|
|
||||||
// region ----- equals
|
// region ----- equals
|
||||||
|
|
||||||
/**
|
|
||||||
* 比较大小,值相等 返回true<br>
|
|
||||||
* 此方法通过调用{@link Double#doubleToLongBits(double)}方法来判断是否相等<br>
|
|
||||||
* 此方法判断值相等时忽略精度的,即0.00 == 0
|
|
||||||
*
|
|
||||||
* @param num1 数字1
|
|
||||||
* @param num2 数字2
|
|
||||||
* @return 是否相等
|
|
||||||
* @since 5.4.2
|
|
||||||
*/
|
|
||||||
public static boolean equals(final double num1, final double num2) {
|
|
||||||
return Double.doubleToLongBits(num1) == Double.doubleToLongBits(num2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 比较大小,值相等 返回true<br>
|
|
||||||
* 此方法通过调用{@link Float#floatToIntBits(float)}方法来判断是否相等<br>
|
|
||||||
* 此方法判断值相等时忽略精度的,即0.00 == 0
|
|
||||||
*
|
|
||||||
* @param num1 数字1
|
|
||||||
* @param num2 数字2
|
|
||||||
* @return 是否相等
|
|
||||||
* @since 5.4.5
|
|
||||||
*/
|
|
||||||
public static boolean equals(final float num1, final float num2) {
|
|
||||||
return Float.floatToIntBits(num1) == Float.floatToIntBits(num2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 比较大小,值相等 返回true<br>
|
|
||||||
* 此方法修复传入long型数据由于没有本类型重载方法,导致数据精度丢失
|
|
||||||
*
|
|
||||||
* @param num1 数字1
|
|
||||||
* @param num2 数字2
|
|
||||||
* @return 是否相等
|
|
||||||
* @since 5.7.19
|
|
||||||
*/
|
|
||||||
public static boolean equals(final long num1, final long num2) {
|
|
||||||
return num1 == num2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 比较数字值是否相等,相等返回{@code true}<br>
|
* 比较数字值是否相等,相等返回{@code true}<br>
|
||||||
* 需要注意的是{@link BigDecimal}需要特殊处理<br>
|
* 需要注意的是{@link BigDecimal}需要特殊处理<br>
|
||||||
@ -1068,20 +1028,6 @@ public class NumberUtil {
|
|||||||
}
|
}
|
||||||
return Objects.equals(number1, number2);
|
return Objects.equals(number1, number2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 比较两个字符是否相同
|
|
||||||
*
|
|
||||||
* @param c1 字符1
|
|
||||||
* @param c2 字符2
|
|
||||||
* @param ignoreCase 是否忽略大小写
|
|
||||||
* @return 是否相同
|
|
||||||
* @see CharUtil#equals(char, char, boolean)
|
|
||||||
* @since 3.2.1
|
|
||||||
*/
|
|
||||||
public static boolean equals(final char c1, final char c2, final boolean ignoreCase) {
|
|
||||||
return CharUtil.equals(c1, c2, ignoreCase);
|
|
||||||
}
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region ----- toStr
|
// region ----- toStr
|
||||||
@ -1289,7 +1235,7 @@ public class NumberUtil {
|
|||||||
* @since 3.0.9
|
* @since 3.0.9
|
||||||
*/
|
*/
|
||||||
public static BigDecimal null2Zero(final BigDecimal decimal) {
|
public static BigDecimal null2Zero(final BigDecimal decimal) {
|
||||||
return decimal == null ? BigDecimal.ZERO : decimal;
|
return ObjUtil.defaultIfNull(decimal, BigDecimal.ZERO);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,12 +12,11 @@
|
|||||||
|
|
||||||
package org.dromara.hutool.core.net.url;
|
package org.dromara.hutool.core.net.url;
|
||||||
|
|
||||||
import org.dromara.hutool.core.util.ByteUtil;
|
import org.dromara.hutool.core.io.stream.FastByteArrayOutputStream;
|
||||||
|
import org.dromara.hutool.core.text.StrUtil;
|
||||||
import org.dromara.hutool.core.util.CharUtil;
|
import org.dromara.hutool.core.util.CharUtil;
|
||||||
import org.dromara.hutool.core.util.CharsetUtil;
|
import org.dromara.hutool.core.util.CharsetUtil;
|
||||||
import org.dromara.hutool.core.text.StrUtil;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
@ -36,7 +35,7 @@ public class URLDecoder implements Serializable {
|
|||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private static final Charset DEFAULT_CHARSET = CharsetUtil.UTF_8;
|
private static final Charset DEFAULT_CHARSET = CharsetUtil.UTF_8;
|
||||||
private static final byte ESCAPE_CHAR = '%';
|
private static final byte ESCAPE_CHAR = CharUtil.PERCENT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解码,不对+解码
|
* 解码,不对+解码
|
||||||
@ -118,10 +117,41 @@ public class URLDecoder implements Serializable {
|
|||||||
* @return 解码后的字符串
|
* @return 解码后的字符串
|
||||||
*/
|
*/
|
||||||
public static String decode(final String str, final Charset charset, final boolean isPlusToSpace) {
|
public static String decode(final String str, final Charset charset, final boolean isPlusToSpace) {
|
||||||
if (null == charset) {
|
if (null == str) {
|
||||||
return str;
|
return null;
|
||||||
}
|
}
|
||||||
return StrUtil.str(decode(ByteUtil.toBytes(str, charset), isPlusToSpace), charset);
|
final int length = str.length();
|
||||||
|
if(0 == length){
|
||||||
|
return StrUtil.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
final StringBuilder result = new StringBuilder(length / 3);
|
||||||
|
|
||||||
|
int begin = 0;
|
||||||
|
char c;
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
c = str.charAt(i);
|
||||||
|
if(ESCAPE_CHAR == c || CharUtil.isHexChar(c)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遇到非需要处理的字符跳过
|
||||||
|
// 处理之前的hex字符
|
||||||
|
if(i > begin){
|
||||||
|
result.append(decodeSub(str, begin, i, charset, isPlusToSpace));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 非Hex字符,忽略本字符
|
||||||
|
result.append(c);
|
||||||
|
begin = i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理剩余字符
|
||||||
|
if(begin < length){
|
||||||
|
result.append(decodeSub(str, begin, length, charset, isPlusToSpace));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -152,11 +182,12 @@ public class URLDecoder implements Serializable {
|
|||||||
* @return 解码后的bytes
|
* @return 解码后的bytes
|
||||||
* @since 5.6.3
|
* @since 5.6.3
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("resource")
|
||||||
public static byte[] decode(final byte[] bytes, final boolean isPlusToSpace) {
|
public static byte[] decode(final byte[] bytes, final boolean isPlusToSpace) {
|
||||||
if (bytes == null) {
|
if (bytes == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final ByteArrayOutputStream buffer = new ByteArrayOutputStream(bytes.length * 3);
|
final FastByteArrayOutputStream buffer = new FastByteArrayOutputStream(bytes.length / 3);
|
||||||
int b;
|
int b;
|
||||||
for (int i = 0; i < bytes.length; i++) {
|
for (int i = 0; i < bytes.length; i++) {
|
||||||
b = bytes[i];
|
b = bytes[i];
|
||||||
@ -182,4 +213,22 @@ public class URLDecoder implements Serializable {
|
|||||||
}
|
}
|
||||||
return buffer.toByteArray();
|
return buffer.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解码子串
|
||||||
|
*
|
||||||
|
* @param str 字符串
|
||||||
|
* @param begin 开始位置(包含)
|
||||||
|
* @param end 结束位置(不包含)
|
||||||
|
* @param charset 编码
|
||||||
|
* @param isPlusToSpace 是否+转换为空格
|
||||||
|
* @return 解码后的字符串
|
||||||
|
*/
|
||||||
|
private static String decodeSub(final String str, final int begin, final int end,
|
||||||
|
final Charset charset, final boolean isPlusToSpace){
|
||||||
|
return new String(decode(
|
||||||
|
// 截取需要decode的部分
|
||||||
|
str.substring(begin, end).getBytes(CharsetUtil.ISO_8859_1), isPlusToSpace
|
||||||
|
), charset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import org.junit.jupiter.api.Test;
|
|||||||
|
|
||||||
public class URLEncoderTest {
|
public class URLEncoderTest {
|
||||||
@Test
|
@Test
|
||||||
public void encodeTest() {
|
void encodeTest() {
|
||||||
final String body = "366466 - 副本.jpg";
|
final String body = "366466 - 副本.jpg";
|
||||||
final String encode = URLEncoder.encodeAll(body);
|
final String encode = URLEncoder.encodeAll(body);
|
||||||
Assertions.assertEquals("366466%20-%20%E5%89%AF%E6%9C%AC.jpg", encode);
|
Assertions.assertEquals("366466%20-%20%E5%89%AF%E6%9C%AC.jpg", encode);
|
||||||
@ -18,14 +18,14 @@ public class URLEncoderTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void encodeQueryPlusTest() {
|
void encodeQueryPlusTest() {
|
||||||
final String body = "+";
|
final String body = "+";
|
||||||
final String encode2 = URLEncoder.encodeQuery(body);
|
final String encode2 = URLEncoder.encodeQuery(body);
|
||||||
Assertions.assertEquals("+", encode2);
|
Assertions.assertEquals("+", encode2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void encodeEmojiTest(){
|
void encodeEmojiTest(){
|
||||||
final String emoji = "🐶😊😂🤣";
|
final String emoji = "🐶😊😂🤣";
|
||||||
final String encode = URLEncoder.encodeAll(emoji);
|
final String encode = URLEncoder.encodeAll(emoji);
|
||||||
Assertions.assertEquals("%F0%9F%90%B6%F0%9F%98%8A%F0%9F%98%82%F0%9F%A4%A3", encode);
|
Assertions.assertEquals("%F0%9F%90%B6%F0%9F%98%8A%F0%9F%98%82%F0%9F%A4%A3", encode);
|
||||||
|
@ -1,13 +1,44 @@
|
|||||||
package org.dromara.hutool.core.net;
|
package org.dromara.hutool.core.net;
|
||||||
|
|
||||||
import org.dromara.hutool.core.net.url.URLDecoder;
|
import org.dromara.hutool.core.net.url.URLDecoder;
|
||||||
|
import org.dromara.hutool.core.net.url.URLEncoder;
|
||||||
import org.dromara.hutool.core.util.CharsetUtil;
|
import org.dromara.hutool.core.util.CharsetUtil;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
public class UrlDecoderTest {
|
public class UrlDecoderTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void decodeForPathTest(){
|
void decodeForPathTest(){
|
||||||
Assertions.assertEquals("+", URLDecoder.decodeForPath("+", CharsetUtil.UTF_8));
|
Assertions.assertEquals("+", URLDecoder.decodeForPath("+", CharsetUtil.UTF_8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void issue3063Test() throws UnsupportedEncodingException {
|
||||||
|
// https://github.com/dromara/hutool/issues/3063
|
||||||
|
|
||||||
|
final String s = "测试";
|
||||||
|
final String expectedDecode = "%FE%FF%6D%4B%8B%D5";
|
||||||
|
|
||||||
|
final String s1 = URLEncoder.encodeAll(s, StandardCharsets.UTF_16);
|
||||||
|
Assertions.assertEquals(expectedDecode, s1);
|
||||||
|
final String s2 = java.net.URLEncoder.encode(s, "UTF-16");
|
||||||
|
Assertions.assertEquals(expectedDecode, s2);
|
||||||
|
|
||||||
|
final String decode = URLDecoder.decode(s1, StandardCharsets.UTF_16);
|
||||||
|
Assertions.assertEquals(s, decode);
|
||||||
|
|
||||||
|
// 测试编码字符串和非编码字符串混合
|
||||||
|
final String mixDecoded = expectedDecode + "你好";
|
||||||
|
final String decode2 = URLDecoder.decode(mixDecoded, StandardCharsets.UTF_16);
|
||||||
|
Assertions.assertEquals("测试你好", decode2);
|
||||||
|
|
||||||
|
Assertions.assertEquals(
|
||||||
|
java.net.URLDecoder.decode(mixDecoded, "UTF-16"),
|
||||||
|
URLDecoder.decode(mixDecoded, StandardCharsets.UTF_16)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user