add patch support

This commit is contained in:
Looly 2020-02-29 22:25:22 +08:00
parent 1ed2ec9dc4
commit 405a92cfe4
9 changed files with 124 additions and 77 deletions

View File

@ -10,6 +10,7 @@
* 【core 】 增加ReflectUtil.getFieldValue支持Alias注解 * 【core 】 增加ReflectUtil.getFieldValue支持Alias注解
* 【core 】 Bean字段支持Alias注解包括转map,转bean等 * 【core 】 Bean字段支持Alias注解包括转map,转bean等
* 【core 】 增加ValueListHandler优化结果集获取方式 * 【core 】 增加ValueListHandler优化结果集获取方式
* 【http 】 支持patch方法issue#666@Github
### Bug修复 ### Bug修复

View File

@ -1849,7 +1849,9 @@ public class DateUtil {
* @param checkDate 检查时间可以是当前时间 * @param checkDate 检查时间可以是当前时间
* @return 是否过期 * @return 是否过期
* @since 5.1.1 * @since 5.1.1
* @deprecated 使用isIn方法
*/ */
@Deprecated
public static boolean isExpired(Date startDate, Date endDate, Date checkDate) { public static boolean isExpired(Date startDate, Date endDate, Date checkDate) {
return betweenMs(startDate, checkDate) > betweenMs(startDate, endDate); return betweenMs(startDate, checkDate) > betweenMs(startDate, endDate);
} }

View File

@ -294,7 +294,7 @@ public class ReflectUtil {
/** /**
* 设置字段值 * 设置字段值
* *
* @param obj 对象 * @param obj 对象,static字段则此处传Class
* @param fieldName 字段名 * @param fieldName 字段名
* @param value 值类型必须与字段类型匹配不会自动转换对象类型 * @param value 值类型必须与字段类型匹配不会自动转换对象类型
* @throws UtilException 包装IllegalAccessException异常 * @throws UtilException 包装IllegalAccessException异常
@ -303,7 +303,7 @@ public class ReflectUtil {
Assert.notNull(obj); Assert.notNull(obj);
Assert.notBlank(fieldName); 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()); Assert.notNull(field, "Field [{}] is not exist in [{}]", fieldName, obj.getClass().getName());
setFieldValue(obj, field, value); setFieldValue(obj, field, value);
} }
@ -317,9 +317,7 @@ public class ReflectUtil {
* @throws UtilException UtilException 包装IllegalAccessException异常 * @throws UtilException UtilException 包装IllegalAccessException异常
*/ */
public static void setFieldValue(Object obj, Field field, Object value) throws UtilException { public static void setFieldValue(Object obj, Field field, Object value) throws UtilException {
Assert.notNull(field, "Field in [{}] not exist !", obj.getClass().getName()); Assert.notNull(field, "Field in [{}] not exist !", obj);
setAccessible(field);
if (null != value) { if (null != value) {
Class<?> fieldType = field.getType(); Class<?> fieldType = field.getType();
@ -332,10 +330,11 @@ public class ReflectUtil {
} }
} }
setAccessible(field);
try { try {
field.set(obj, value); field.set(obj instanceof Class ? null : obj, value);
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
throw new UtilException(e, "IllegalAccess for {}.{}", obj.getClass(), field.getName()); throw new UtilException(e, "IllegalAccess for {}.{}", obj, field.getName());
} }
} }

View File

@ -82,6 +82,14 @@ public class DateUtilTest {
Assert.assertEquals("2017-03-01 23:59:59", endOfDay.toString()); 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 @Test
public void beginAndWeedTest() { public void beginAndWeedTest() {
String dateStr = "2017-03-01 22:33:23"; String dateStr = "2017-03-01 22:33:23";

View File

@ -2,11 +2,10 @@ package cn.hutool.http;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil; import cn.hutool.core.util.URLUtil;
import cn.hutool.http.ssl.AndroidSupportSSLFactory;
import cn.hutool.http.ssl.DefaultSSLInfo; import cn.hutool.http.ssl.DefaultSSLInfo;
import cn.hutool.http.ssl.SSLSocketFactoryBuilder;
import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.HttpsURLConnection;
@ -14,6 +13,8 @@ import javax.net.ssl.SSLSocketFactory;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.ProtocolException; import java.net.ProtocolException;
import java.net.Proxy; import java.net.Proxy;
@ -21,8 +22,6 @@ import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException; import java.nio.charset.UnsupportedCharsetException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
@ -31,7 +30,6 @@ import java.util.Map.Entry;
* http连接对象对HttpURLConnection的包装 * http连接对象对HttpURLConnection的包装
* *
* @author Looly * @author Looly
*
*/ */
public class HttpConnection { public class HttpConnection {
@ -43,7 +41,7 @@ public class HttpConnection {
* 创建HttpConnection * 创建HttpConnection
* *
* @param urlStr URL * @param urlStr URL
* @param proxy 代理无代理传{@code null} * @param proxy 代理无代理传{@code null}
* @return HttpConnection * @return HttpConnection
*/ */
public static HttpConnection create(String urlStr, Proxy proxy) { public static HttpConnection create(String urlStr, Proxy proxy) {
@ -53,7 +51,7 @@ public class HttpConnection {
/** /**
* 创建HttpConnection * 创建HttpConnection
* *
* @param url URL * @param url URL
* @param proxy 代理无代理传{@code null} * @param proxy 代理无代理传{@code null}
* @return HttpConnection * @return HttpConnection
*/ */
@ -62,10 +60,11 @@ public class HttpConnection {
} }
// --------------------------------------------------------------- Constructor start // --------------------------------------------------------------- Constructor start
/** /**
* 构造HttpConnection * 构造HttpConnection
* *
* @param url URL * @param url URL
* @param proxy 代理 * @param proxy 代理
*/ */
public HttpConnection(URL url, Proxy proxy) { public HttpConnection(URL url, Proxy proxy) {
@ -98,10 +97,11 @@ public class HttpConnection {
} }
// --------------------------------------------------------------- Getters And Setters start // --------------------------------------------------------------- Getters And Setters start
/** /**
* 获取请求方法,GET/POST * 获取请求方法,GET/POST
* *
* @return 请求方法,GET/POST * @return 请求方法, GET/POST
*/ */
public Method getMethod() { public Method getMethod() {
return Method.valueOf(this.conn.getRequestMethod()); return Method.valueOf(this.conn.getRequestMethod());
@ -114,6 +114,18 @@ public class HttpConnection {
* @return 自己 * @return 自己
*/ */
public HttpConnection setMethod(Method method) { 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 // method
try { try {
this.conn.setRequestMethod(method.toString()); this.conn.setRequestMethod(method.toString());
@ -121,12 +133,6 @@ public class HttpConnection {
throw new HttpException(e); 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; return this;
} }
@ -160,12 +166,13 @@ public class HttpConnection {
// --------------------------------------------------------------- Getters And Setters end // --------------------------------------------------------------- Getters And Setters end
// ---------------------------------------------------------------- Headers start // ---------------------------------------------------------------- Headers start
/** /**
* 设置请求头<br> * 设置请求头<br>
* 当请求头存在时覆盖之 * 当请求头存在时覆盖之
* *
* @param header 头名 * @param header 头名
* @param value 头值 * @param value 头值
* @param isOverride 是否覆盖旧值 * @param isOverride 是否覆盖旧值
* @return HttpConnection * @return HttpConnection
*/ */
@ -185,8 +192,8 @@ public class HttpConnection {
* 设置请求头<br> * 设置请求头<br>
* 当请求头存在时覆盖之 * 当请求头存在时覆盖之
* *
* @param header 头名 * @param header 头名
* @param value 头值 * @param value 头值
* @param isOverride 是否覆盖旧值 * @param isOverride 是否覆盖旧值
* @return HttpConnection * @return HttpConnection
*/ */
@ -198,7 +205,7 @@ public class HttpConnection {
* 设置请求头<br> * 设置请求头<br>
* 不覆盖原有请求头 * 不覆盖原有请求头
* *
* @param headerMap 请求头 * @param headerMap 请求头
* @param isOverride 是否覆盖 * @param isOverride 是否覆盖
* @return this * @return this
*/ */
@ -251,7 +258,7 @@ public class HttpConnection {
* 有些时候htts请求会出现com.sun.net.ssl.internal.www.protocol.https.HttpsURLConnectionOldImpl的实现此为sun内部api按照普通http请求处理 * 有些时候htts请求会出现com.sun.net.ssl.internal.www.protocol.https.HttpsURLConnectionOldImpl的实现此为sun内部api按照普通http请求处理
* *
* @param hostnameVerifier 域名验证器非https传入null * @param hostnameVerifier 域名验证器非https传入null
* @param ssf SSLSocketFactory非https传入null * @param ssf SSLSocketFactory非https传入null
* @return this * @return this
* @throws HttpException KeyManagementException和NoSuchAlgorithmException异常包装 * @throws HttpException KeyManagementException和NoSuchAlgorithmException异常包装
*/ */
@ -342,7 +349,7 @@ public class HttpConnection {
* @return this * @return this
*/ */
public HttpConnection setChunkedStreamingMode(int blockSize) { public HttpConnection setChunkedStreamingMode(int blockSize) {
if(blockSize > 0) { if (blockSize > 0) {
conn.setChunkedStreamingMode(blockSize); conn.setChunkedStreamingMode(blockSize);
} }
return this; return this;
@ -501,6 +508,7 @@ public class HttpConnection {
} }
// --------------------------------------------------------------- Private Method start // --------------------------------------------------------------- Private Method start
/** /**
* 初始化http或https请求参数<br> * 初始化http或https请求参数<br>
* 有些时候https请求会出现com.sun.net.ssl.internal.www.protocol.https.HttpsURLConnectionOldImpl的实现此为sun内部api按照普通http请求处理 * 有些时候https请求会出现com.sun.net.ssl.internal.www.protocol.https.HttpsURLConnectionOldImpl的实现此为sun内部api按照普通http请求处理
@ -526,5 +534,23 @@ public class HttpConnection {
private URLConnection openConnection() throws IOException { private URLConnection openConnection() throws IOException {
return (null == this.proxy) ? url.openConnection() : url.openConnection(this.proxy); 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 // --------------------------------------------------------------- Private Method end
} }

View File

@ -338,13 +338,14 @@ public class HttpRequest extends HttpBase<HttpRequest> {
* @return HttpRequest * @return HttpRequest
*/ */
public HttpRequest method(Method method) { public HttpRequest method(Method method) {
if (Method.PATCH == method) { // if (Method.PATCH == method) {
this.method = Method.POST; // this.method = Method.POST;
this.header("X-HTTP-Method-Override", "PATCH"); // this.header("X-HTTP-Method-Override", "PATCH");
} else { // } else {
this.method = method; // this.method = method;
} // }
this.method = method;
return this; return this;
} }

View File

@ -9,14 +9,24 @@ import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.StreamProgress; import cn.hutool.core.io.StreamProgress;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.StrBuilder; 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.File;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.nio.charset.Charset; 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.Map.Entry;
import java.util.regex.Pattern; import java.util.regex.Pattern;

View File

@ -2,8 +2,8 @@ package cn.hutool.http;
/** /**
* Http方法枚举 * Http方法枚举
* @author Looly
* *
* @author Looly
*/ */
public enum Method { public enum Method {
GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE, CONNECT, PATCH GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE, CONNECT, PATCH

View File

@ -220,7 +220,7 @@ public class HttpUtilTest {
@Test @Test
@Ignore @Ignore
public void patchTest() { 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); Console.log(body);
} }