diff --git a/CHANGELOG.md b/CHANGELOG.md index ce920e7b2..4182165dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ * 【core 】 增加ReflectUtil.getFieldValue支持Alias注解 * 【core 】 Bean字段支持Alias注解(包括转map,转bean等) * 【core 】 增加ValueListHandler,优化结果集获取方式 +* 【http 】 支持patch方法(issue#666@Github) ### Bug修复 diff --git a/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java b/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java index 3da787edb..f4d559fc4 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java @@ -1849,7 +1849,9 @@ public class DateUtil { * @param checkDate 检查时间,可以是当前时间,既 * @return 是否过期 * @since 5.1.1 + * @deprecated 使用isIn方法 */ + @Deprecated public static boolean isExpired(Date startDate, Date endDate, Date checkDate) { return betweenMs(startDate, checkDate) > betweenMs(startDate, endDate); } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java index 8ea51107b..46cb279fd 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java @@ -294,7 +294,7 @@ public class ReflectUtil { /** * 设置字段值 * - * @param obj 对象 + * @param obj 对象,static字段则此处传Class * @param fieldName 字段名 * @param value 值,值类型必须与字段类型匹配,不会自动转换对象类型 * @throws UtilException 包装IllegalAccessException异常 @@ -303,7 +303,7 @@ public class ReflectUtil { Assert.notNull(obj); Assert.notBlank(fieldName); - final Field field = getField(obj.getClass(), fieldName); + final Field field = getField((obj instanceof Class) ? (Class)obj : obj.getClass(), fieldName); Assert.notNull(field, "Field [{}] is not exist in [{}]", fieldName, obj.getClass().getName()); setFieldValue(obj, field, value); } @@ -317,9 +317,7 @@ public class ReflectUtil { * @throws UtilException UtilException 包装IllegalAccessException异常 */ public static void setFieldValue(Object obj, Field field, Object value) throws UtilException { - Assert.notNull(field, "Field in [{}] not exist !", obj.getClass().getName()); - - setAccessible(field); + Assert.notNull(field, "Field in [{}] not exist !", obj); if (null != value) { Class fieldType = field.getType(); @@ -332,10 +330,11 @@ public class ReflectUtil { } } + setAccessible(field); try { - field.set(obj, value); + field.set(obj instanceof Class ? null : obj, value); } catch (IllegalAccessException e) { - throw new UtilException(e, "IllegalAccess for {}.{}", obj.getClass(), field.getName()); + throw new UtilException(e, "IllegalAccess for {}.{}", obj, field.getName()); } } diff --git a/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java index 8655953b7..1d1fab4a4 100644 --- a/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java @@ -82,6 +82,14 @@ public class DateUtilTest { Assert.assertEquals("2017-03-01 23:59:59", endOfDay.toString()); } + @Test + public void truncateTest(){ + String dateStr2 = "2020-02-29 12:59:34"; + Date date2 = DateUtil.parse(dateStr2); + final DateTime dateTime = DateUtil.truncate(date2, DateField.MINUTE); + Assert.assertEquals("2020-02-29 12:59:00", dateTime.toString()); + } + @Test public void beginAndWeedTest() { String dateStr = "2017-03-01 22:33:23"; diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpConnection.java b/hutool-http/src/main/java/cn/hutool/http/HttpConnection.java index 1a954063f..bd73c99b2 100644 --- a/hutool-http/src/main/java/cn/hutool/http/HttpConnection.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpConnection.java @@ -2,11 +2,10 @@ package cn.hutool.http; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.URLUtil; -import cn.hutool.http.ssl.AndroidSupportSSLFactory; import cn.hutool.http.ssl.DefaultSSLInfo; -import cn.hutool.http.ssl.SSLSocketFactoryBuilder; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; @@ -14,6 +13,8 @@ import javax.net.ssl.SSLSocketFactory; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.net.HttpURLConnection; import java.net.ProtocolException; import java.net.Proxy; @@ -21,17 +22,14 @@ import java.net.URL; import java.net.URLConnection; import java.nio.charset.Charset; import java.nio.charset.UnsupportedCharsetException; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; import java.util.List; import java.util.Map; import java.util.Map.Entry; /** * http连接对象,对HttpURLConnection的包装 - * - * @author Looly * + * @author Looly */ public class HttpConnection { @@ -41,9 +39,9 @@ public class HttpConnection { /** * 创建HttpConnection - * + * * @param urlStr URL - * @param proxy 代理,无代理传{@code null} + * @param proxy 代理,无代理传{@code null} * @return HttpConnection */ public static HttpConnection create(String urlStr, Proxy proxy) { @@ -52,8 +50,8 @@ public class HttpConnection { /** * 创建HttpConnection - * - * @param url URL + * + * @param url URL * @param proxy 代理,无代理传{@code null} * @return HttpConnection */ @@ -62,10 +60,11 @@ public class HttpConnection { } // --------------------------------------------------------------- Constructor start + /** * 构造HttpConnection - * - * @param url URL + * + * @param url URL * @param proxy 代理 */ public HttpConnection(URL url, Proxy proxy) { @@ -80,7 +79,7 @@ public class HttpConnection { /** * 初始化连接相关信息 - * + * * @return HttpConnection * @since 4.4.1 */ @@ -98,10 +97,11 @@ public class HttpConnection { } // --------------------------------------------------------------- Getters And Setters start + /** * 获取请求方法,GET/POST - * - * @return 请求方法,GET/POST + * + * @return 请求方法, GET/POST */ public Method getMethod() { return Method.valueOf(this.conn.getRequestMethod()); @@ -109,11 +109,23 @@ public class HttpConnection { /** * 设置请求方法 - * + * * @param method 请求方法 * @return 自己 */ public HttpConnection setMethod(Method method) { + if (Method.POST.equals(method) // + || Method.PUT.equals(method)// + || Method.PATCH.equals(method)// + || Method.DELETE.equals(method)) { + this.conn.setUseCaches(false); + + // 增加PATCH方法支持 + if (Method.PATCH.equals(method)) { + allowPatch(); + } + } + // method try { this.conn.setRequestMethod(method.toString()); @@ -121,18 +133,12 @@ public class HttpConnection { throw new HttpException(e); } - if (Method.POST.equals(method) // - || Method.PUT.equals(method)// - || Method.PATCH.equals(method)// - || Method.DELETE.equals(method)) { - this.conn.setUseCaches(false); - } return this; } /** * 获取请求URL - * + * * @return 请求URL */ public URL getUrl() { @@ -141,7 +147,7 @@ public class HttpConnection { /** * 获得代理 - * + * * @return {@link Proxy} */ public Proxy getProxy() { @@ -150,7 +156,7 @@ public class HttpConnection { /** * 获取HttpURLConnection对象 - * + * * @return HttpURLConnection */ public HttpURLConnection getHttpURLConnection() { @@ -160,12 +166,13 @@ public class HttpConnection { // --------------------------------------------------------------- Getters And Setters end // ---------------------------------------------------------------- Headers start + /** * 设置请求头
* 当请求头存在时,覆盖之 - * - * @param header 头名 - * @param value 头值 + * + * @param header 头名 + * @param value 头值 * @param isOverride 是否覆盖旧值 * @return HttpConnection */ @@ -184,9 +191,9 @@ public class HttpConnection { /** * 设置请求头
* 当请求头存在时,覆盖之 - * - * @param header 头名 - * @param value 头值 + * + * @param header 头名 + * @param value 头值 * @param isOverride 是否覆盖旧值 * @return HttpConnection */ @@ -197,8 +204,8 @@ public class HttpConnection { /** * 设置请求头
* 不覆盖原有请求头 - * - * @param headerMap 请求头 + * + * @param headerMap 请求头 * @param isOverride 是否覆盖 * @return this */ @@ -217,7 +224,7 @@ public class HttpConnection { /** * 获取Http请求头 - * + * * @param name Header名 * @return Http请求头值 */ @@ -227,7 +234,7 @@ public class HttpConnection { /** * 获取Http请求头 - * + * * @param name Header名 * @return Http请求头值 */ @@ -237,7 +244,7 @@ public class HttpConnection { /** * 获取所有Http请求头 - * + * * @return Http请求头Map */ public Map> headers() { @@ -249,9 +256,9 @@ public class HttpConnection { /** * 设置https请求参数
* 有些时候htts请求会出现com.sun.net.ssl.internal.www.protocol.https.HttpsURLConnectionOldImpl的实现,此为sun内部api,按照普通http请求处理 - * + * * @param hostnameVerifier 域名验证器,非https传入null - * @param ssf SSLSocketFactory,非https传入null + * @param ssf SSLSocketFactory,非https传入null * @return this * @throws HttpException KeyManagementException和NoSuchAlgorithmException异常包装 */ @@ -271,9 +278,9 @@ public class HttpConnection { /** * 关闭缓存 - * + * * @return this - * @see HttpURLConnection#setUseCaches(boolean) + * @see HttpURLConnection#setUseCaches(boolean) */ public HttpConnection disableCache() { this.conn.setUseCaches(false); @@ -282,7 +289,7 @@ public class HttpConnection { /** * 设置连接超时 - * + * * @param timeout 超时 * @return this */ @@ -296,7 +303,7 @@ public class HttpConnection { /** * 设置读取超时 - * + * * @param timeout 超时 * @return this */ @@ -310,7 +317,7 @@ public class HttpConnection { /** * 设置连接和读取的超时时间 - * + * * @param timeout 超时时间 * @return this */ @@ -323,7 +330,7 @@ public class HttpConnection { /** * 设置Cookie - * + * * @param cookie Cookie * @return this */ @@ -337,12 +344,12 @@ public class HttpConnection { /** * 采用流方式上传数据,无需本地缓存数据。
* HttpUrlConnection默认是将所有数据读到本地缓存,然后再发送给服务器,这样上传大文件时就会导致内存溢出。 - * + * * @param blockSize 块大小(bytes数),0或小于0表示不设置Chuncked模式 * @return this */ public HttpConnection setChunkedStreamingMode(int blockSize) { - if(blockSize > 0) { + if (blockSize > 0) { conn.setChunkedStreamingMode(blockSize); } return this; @@ -350,7 +357,7 @@ public class HttpConnection { /** * 设置自动HTTP 30X跳转 - * + * * @param isInstanceFollowRedirects 是否自定跳转 * @return this */ @@ -361,7 +368,7 @@ public class HttpConnection { /** * 连接 - * + * * @return this * @throws IOException IO异常 */ @@ -371,10 +378,10 @@ public class HttpConnection { } return this; } - + /** * 静默断开连接。不抛出异常 - * + * * @return this * @since 4.6.0 */ @@ -384,13 +391,13 @@ public class HttpConnection { } catch (Throwable e) { // ignore } - + return this; } /** * 断开连接 - * + * * @return this */ public HttpConnection disconnect() { @@ -403,7 +410,7 @@ public class HttpConnection { /** * 获得输入流对象
* 输入流对象用于读取数据 - * + * * @return 输入流对象 * @throws IOException IO异常 */ @@ -416,7 +423,7 @@ public class HttpConnection { /** * 当返回错误代码时,获得错误内容流 - * + * * @return 错误内容 */ public InputStream getErrorStream() { @@ -428,7 +435,7 @@ public class HttpConnection { /** * 获取输出流对象 输出流对象用于发送数据 - * + * * @return OutputStream * @throws IOException IO异常 */ @@ -444,7 +451,7 @@ public class HttpConnection { /** * 获取响应码 - * + * * @return 响应码 * @throws IOException IO异常 */ @@ -459,7 +466,7 @@ public class HttpConnection { * 获得字符集编码
* 从Http连接的头信息中获得字符集
* 从ContentType中获取 - * + * * @return 字符集编码 */ public String getCharsetName() { @@ -470,7 +477,7 @@ public class HttpConnection { * 获取字符集编码
* 从Http连接的头信息中获得字符集
* 从ContentType中获取 - * + * * @return {@link Charset}编码 * @since 3.0.9 */ @@ -501,10 +508,11 @@ public class HttpConnection { } // --------------------------------------------------------------- Private Method start + /** * 初始化http或https请求参数
* 有些时候https请求会出现com.sun.net.ssl.internal.www.protocol.https.HttpsURLConnectionOldImpl的实现,此为sun内部api,按照普通http请求处理 - * + * * @return {@link HttpURLConnection},https返回{@link HttpsURLConnection} */ private HttpURLConnection openHttp() throws IOException { @@ -519,12 +527,30 @@ public class HttpConnection { /** * 建立连接 - * + * * @return {@link URLConnection} * @throws IOException IO异常 */ private URLConnection openConnection() throws IOException { return (null == this.proxy) ? url.openConnection() : url.openConnection(this.proxy); } + + /** + * 增加支持的METHOD方法 + * see: https://stackoverflow.com/questions/25163131/httpurlconnection-invalid-http-method-patch + * + * @since 5.1.6 + */ + private static void allowPatch() { + final Field methodsField = ReflectUtil.getField(HttpURLConnection.class, "methods"); + if (null != methodsField) { + // 去除final修饰 + ReflectUtil.setFieldValue(methodsField, "modifiers", methodsField.getModifiers() & ~Modifier.FINAL); + final String[] methods = { + "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE", "PATCH" + }; + ReflectUtil.setFieldValue(null, methodsField, methods); + } + } // --------------------------------------------------------------- Private Method end } \ No newline at end of file diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java b/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java index cfcae98fe..a4d2ddd4d 100644 --- a/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java @@ -338,13 +338,14 @@ public class HttpRequest extends HttpBase { * @return HttpRequest */ public HttpRequest method(Method method) { - if (Method.PATCH == method) { - this.method = Method.POST; - this.header("X-HTTP-Method-Override", "PATCH"); - } else { - this.method = method; - } +// if (Method.PATCH == method) { +// this.method = Method.POST; +// this.header("X-HTTP-Method-Override", "PATCH"); +// } else { +// this.method = method; +// } + this.method = method; return this; } diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java b/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java index 61730c507..bd0068c99 100644 --- a/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java @@ -9,14 +9,24 @@ import cn.hutool.core.io.IoUtil; import cn.hutool.core.io.StreamProgress; import cn.hutool.core.map.MapUtil; import cn.hutool.core.text.StrBuilder; -import cn.hutool.core.util.*; +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.ReUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.URLUtil; import java.io.File; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.nio.charset.Charset; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import java.util.Map.Entry; import java.util.regex.Pattern; diff --git a/hutool-http/src/main/java/cn/hutool/http/Method.java b/hutool-http/src/main/java/cn/hutool/http/Method.java index ec2d7ee92..8f3ae2e13 100644 --- a/hutool-http/src/main/java/cn/hutool/http/Method.java +++ b/hutool-http/src/main/java/cn/hutool/http/Method.java @@ -2,8 +2,8 @@ package cn.hutool.http; /** * Http方法枚举 - * @author Looly * + * @author Looly */ public enum Method { GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE, CONNECT, PATCH diff --git a/hutool-http/src/test/java/cn/hutool/http/test/HttpUtilTest.java b/hutool-http/src/test/java/cn/hutool/http/test/HttpUtilTest.java index 28c0f030f..58ea75870 100644 --- a/hutool-http/src/test/java/cn/hutool/http/test/HttpUtilTest.java +++ b/hutool-http/src/test/java/cn/hutool/http/test/HttpUtilTest.java @@ -220,7 +220,7 @@ public class HttpUtilTest { @Test @Ignore public void patchTest() { - String body = HttpRequest.post("https://www.baidu.com").execute().body(); + String body = HttpRequest.patch("https://www.baidu.com").execute().body(); Console.log(body); }