This commit is contained in:
Looly
2022-10-26 21:20:32 +08:00
parent c2262bc40e
commit 0d52562180
54 changed files with 1119 additions and 564 deletions

View File

@@ -1,6 +1,6 @@
package cn.hutool.http.client;
import cn.hutool.core.io.FastByteArrayOutputStream;
import cn.hutool.core.io.stream.FastByteArrayOutputStream;
import cn.hutool.core.io.StreamProgress;
import cn.hutool.core.lang.Assert;
import cn.hutool.http.HttpException;

View File

@@ -0,0 +1,120 @@
package cn.hutool.http.client.body;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.resource.FileResource;
import cn.hutool.core.io.resource.MultiFileResource;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.map.TableMap;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjUtil;
import java.io.File;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.util.Map;
/**
* Form表单形式的消息体
*
* @param <T> this类型用于链式调用
* @author looly
*/
@SuppressWarnings("unchecked")
public abstract class FormBody<T extends FormBody<T>> implements RequestBody {
/**
* 存储表单数据
*/
protected Map<String, Object> form;
/**
* 编码
*/
protected final Charset charset;
/**
* 构造
*
* @param form 表单
* @param charset 编码
*/
protected FormBody(final Map<String, Object> form, final Charset charset) {
this.form = form;
this.charset = charset;
}
/**
* 设置map类型表单数据
*
* @param formMap 表单内容
* @return this
*/
public T form(final Map<String, Object> formMap) {
if (MapUtil.isNotEmpty(formMap)) {
formMap.forEach(this::form);
}
return (T) this;
}
/**
* 设置表单数据<br>
* 如果传入值为{@code null},则移除这个表单项
*
* @param name 名blank则忽略之
* @param value 值为{@code null},则移除这个表单项
* @return this
*/
public T form(final String name, final Object value) {
if (StrUtil.isBlank(name)) {
return (T) this; // 忽略非法的form表单项内容;
}
if(ObjUtil.isNull(value)){
this.form.remove(name);
}
if (value instanceof File) {
return putToForm(name, new FileResource((File) value));
} else if(value instanceof Path){
return putToForm(name, new FileResource((Path) value));
}
// 普通值
final String strValue;
if (value instanceof Iterable) {
// 列表对象
strValue = CollUtil.join((Iterable<?>) value, ",");
} else if (ArrayUtil.isArray(value)) {
final Class<?> componentType = ArrayUtil.getComponentType(value);
// 多文件
if (File.class == componentType) {
return putToForm(name, new MultiFileResource((File[])value));
} else if (Path.class == componentType) {
return putToForm(name, new MultiFileResource((Path[])value));
}
// 数组对象
strValue = ArrayUtil.join(value, ",");
} else {
// 其他对象一律转换为字符串
strValue = Convert.toStr(value, null);
}
return putToForm(name, strValue);
}
/**
* 将参数加入到form中如果form为空新建之。
*
* @param name 表单属性名
* @param value 属性值
* @return this
*/
private T putToForm(final String name, final Object value) {
if (null != name && null != value) {
if (null == this.form) {
this.form = new TableMap<>(16);
}
this.form.put(name, value);
}
return (T) this;
}
}

View File

@@ -17,32 +17,48 @@ import java.util.Map;
* @author looly
* @since 5.3.5
*/
public class MultipartBody implements RequestBody {
public class MultipartBody extends FormBody<MultipartBody> {
private static final String CONTENT_TYPE_MULTIPART_PREFIX = ContentType.MULTIPART.getValue() + "; boundary=";
/**
* 存储表单数据
*/
private final Map<String, Object> form;
/**
* 编码
*/
private final Charset charset;
/**
* 边界
*/
private final String boundary = HttpGlobalConfig.getBoundary();
private final String boundary;
/**
* 根据已有表单内容构建MultipartBody
* 根据已有表单内容构建MultipartBody,使用全局默认的边界符{@link HttpGlobalConfig#getBoundary()}
*
* @param form 表单
* @param charset 编码
* @return MultipartBody
*/
public static MultipartBody of(final Map<String, Object> form, final Charset charset) {
return new MultipartBody(form, charset);
return of(form, charset, HttpGlobalConfig.getBoundary());
}
/**
* 根据已有表单内容构建MultipartBody
*
* @param form 表单
* @param charset 编码
* @param boundary Multipart边界符
* @return MultipartBody
*/
public static MultipartBody of(final Map<String, Object> form, final Charset charset, final String boundary) {
return new MultipartBody(form, charset, boundary);
}
/**
* 构造
*
* @param form 表单
* @param charset 编码
* @param boundary Multipart边界符
*/
public MultipartBody(final Map<String, Object> form, final Charset charset, final String boundary) {
super(form, charset);
this.boundary = boundary;
}
/**
@@ -54,17 +70,6 @@ public class MultipartBody implements RequestBody {
return CONTENT_TYPE_MULTIPART_PREFIX + boundary;
}
/**
* 构造
*
* @param form 表单
* @param charset 编码
*/
public MultipartBody(final Map<String, Object> form, final Charset charset) {
this.form = form;
this.charset = charset;
}
/**
* 写出Multiparty数据不关闭流
*

View File

@@ -1,6 +1,6 @@
package cn.hutool.http.client.body;
import cn.hutool.core.io.FastByteArrayOutputStream;
import cn.hutool.core.io.stream.FastByteArrayOutputStream;
import cn.hutool.core.io.IoUtil;
import java.io.InputStream;

View File

@@ -1,8 +1,10 @@
package cn.hutool.http.client.body;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.net.url.UrlQuery;
import cn.hutool.core.text.StrUtil;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.Map;
@@ -12,7 +14,7 @@ import java.util.Map;
* @author looly
* @since 5.7.17
*/
public class FormUrlEncodedBody extends BytesBody {
public class UrlEncodedFormBody extends FormBody<UrlEncodedFormBody> {
/**
* 创建 Http request body
@@ -21,8 +23,8 @@ public class FormUrlEncodedBody extends BytesBody {
* @param charset 编码
* @return FormUrlEncodedBody
*/
public static FormUrlEncodedBody of(final Map<String, Object> form, final Charset charset) {
return new FormUrlEncodedBody(form, charset);
public static UrlEncodedFormBody of(final Map<String, Object> form, final Charset charset) {
return new UrlEncodedFormBody(form, charset);
}
/**
@@ -31,8 +33,13 @@ public class FormUrlEncodedBody extends BytesBody {
* @param form 表单
* @param charset 编码
*/
public FormUrlEncodedBody(final Map<String, Object> form, final Charset charset) {
super(StrUtil.bytes(UrlQuery.of(form, true).build(charset), charset));
public UrlEncodedFormBody(final Map<String, Object> form, final Charset charset) {
super(form, charset);
}
@Override
public void write(final OutputStream out) {
final byte[] bytes = StrUtil.bytes(UrlQuery.of(form, true).build(charset), charset);
IoUtil.write(out, false, bytes);
}
}

View File

@@ -26,7 +26,7 @@ import cn.hutool.http.meta.HttpStatus;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.meta.Method;
import cn.hutool.http.client.body.BytesBody;
import cn.hutool.http.client.body.FormUrlEncodedBody;
import cn.hutool.http.client.body.UrlEncodedFormBody;
import cn.hutool.http.client.body.MultipartBody;
import cn.hutool.http.client.body.RequestBody;
import cn.hutool.http.client.cookie.GlobalCookieManager;
@@ -1311,7 +1311,7 @@ public class HttpRequest extends HttpBase<HttpRequest> {
if (ArrayUtil.isNotEmpty(this.bodyBytes)) {
body = BytesBody.of(this.bodyBytes);
} else {
body = FormUrlEncodedBody.of(this.form, this.charset);
body = UrlEncodedFormBody.of(this.form, this.charset);
}
body.writeClose(this.httpConnection.getOutputStream());
}

View File

@@ -1,7 +1,7 @@
package cn.hutool.http.client.engine.jdk;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.FastByteArrayOutputStream;
import cn.hutool.core.io.stream.FastByteArrayOutputStream;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;

View File

@@ -1,6 +1,6 @@
package cn.hutool.http.client.engine.okhttp;
import cn.hutool.core.io.EmptyInputStream;
import cn.hutool.core.io.stream.EmptyInputStream;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.http.HttpUtil;