mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-08-18 20:38:02 +08:00
155 lines
4.3 KiB
Java
155 lines
4.3 KiB
Java
package cn.hutool.http.body;
|
||
|
||
import cn.hutool.core.io.IORuntimeException;
|
||
import cn.hutool.core.io.IoUtil;
|
||
import cn.hutool.core.io.resource.MultiResource;
|
||
import cn.hutool.core.io.resource.Resource;
|
||
import cn.hutool.core.map.MapUtil;
|
||
import cn.hutool.core.util.ObjectUtil;
|
||
import cn.hutool.core.util.RandomUtil;
|
||
import cn.hutool.core.util.StrUtil;
|
||
import cn.hutool.http.ContentType;
|
||
import cn.hutool.http.HttpUtil;
|
||
|
||
import java.io.OutputStream;
|
||
import java.nio.charset.Charset;
|
||
import java.util.Map;
|
||
|
||
/**
|
||
* Multipart/form-data数据的请求体封装
|
||
*
|
||
* @author looly
|
||
* @since 5.3.5
|
||
*/
|
||
public class MultipartBody implements RequestBody{
|
||
|
||
private static final String BOUNDARY = "--------------------Hutool_" + RandomUtil.randomString(16);
|
||
private static final String BOUNDARY_END = StrUtil.format("--{}--\r\n", BOUNDARY);
|
||
private static final String CONTENT_DISPOSITION_TEMPLATE = "Content-Disposition: form-data; name=\"{}\"\r\n\r\n";
|
||
private static final String CONTENT_DISPOSITION_FILE_TEMPLATE = "Content-Disposition: form-data; name=\"{}\"; filename=\"{}\"\r\n";
|
||
|
||
private static final String CONTENT_TYPE_MULTIPART_PREFIX = ContentType.MULTIPART.getValue() + "; boundary=";
|
||
private static final String CONTENT_TYPE_FILE_TEMPLATE = "Content-Type: {}\r\n\r\n";
|
||
|
||
/**
|
||
* 存储表单数据
|
||
*/
|
||
private final Map<String, Object> form;
|
||
/**
|
||
* 编码
|
||
*/
|
||
private final Charset charset;
|
||
|
||
/**
|
||
* 根据已有表单内容,构建MultipartBody
|
||
* @param form 表单
|
||
* @param charset 编码
|
||
* @return MultipartBody
|
||
*/
|
||
public static MultipartBody create(Map<String, Object> form, Charset charset){
|
||
return new MultipartBody(form, charset);
|
||
}
|
||
|
||
/**
|
||
* 获取Multipart的Content-Type类型
|
||
*
|
||
* @return Multipart的Content-Type类型
|
||
*/
|
||
public static String getContentType(){
|
||
return CONTENT_TYPE_MULTIPART_PREFIX + BOUNDARY;
|
||
}
|
||
|
||
/**
|
||
* 构造
|
||
*
|
||
* @param form 表单
|
||
* @param charset 编码
|
||
*/
|
||
public MultipartBody(Map<String, Object> form, Charset charset) {
|
||
this.form = form;
|
||
this.charset = charset;
|
||
}
|
||
|
||
/**
|
||
* 写出Multiparty数据,不关闭流
|
||
*
|
||
* @param out out流
|
||
*/
|
||
@Override
|
||
public void write(OutputStream out) {
|
||
writeForm(out);
|
||
formEnd(out);
|
||
}
|
||
|
||
// 普通字符串数据
|
||
|
||
/**
|
||
* 发送文件对象表单
|
||
*
|
||
* @param out 输出流
|
||
*/
|
||
private void writeForm(OutputStream out) {
|
||
if (MapUtil.isNotEmpty(this.form)) {
|
||
for (Map.Entry<String, Object> entry : this.form.entrySet()) {
|
||
appendPart(entry.getKey(), entry.getValue(), out);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 添加Multipart表单的数据项
|
||
*
|
||
* @param formFieldName 表单名
|
||
* @param value 值,可以是普通值、资源(如文件等)
|
||
* @param out Http流
|
||
* @throws IORuntimeException IO异常
|
||
*/
|
||
private void appendPart(String formFieldName, Object value, OutputStream out) throws IORuntimeException {
|
||
// 多资源
|
||
if (value instanceof MultiResource) {
|
||
for (Resource subResource : (MultiResource) value) {
|
||
appendPart(formFieldName, subResource, out);
|
||
}
|
||
return;
|
||
}
|
||
|
||
write(out, "--", BOUNDARY, StrUtil.CRLF);
|
||
|
||
if(value instanceof Resource){
|
||
// 文件资源(二进制资源)
|
||
final Resource resource = (Resource)value;
|
||
final String fileName = resource.getName();
|
||
write(out, StrUtil.format(CONTENT_DISPOSITION_FILE_TEMPLATE, formFieldName, ObjectUtil.defaultIfNull(fileName, formFieldName)));
|
||
// 根据name的扩展名指定互联网媒体类型,默认二进制流数据
|
||
write(out, StrUtil.format(CONTENT_TYPE_FILE_TEMPLATE, HttpUtil.getMimeType(fileName, "application/octet-stream")));
|
||
resource.writeTo(out);
|
||
} else{
|
||
// 普通数据
|
||
write(out, StrUtil.format(CONTENT_DISPOSITION_TEMPLATE, formFieldName));
|
||
write(out, value);
|
||
}
|
||
|
||
write(out, StrUtil.CRLF);
|
||
}
|
||
|
||
/**
|
||
* 上传表单结束
|
||
*
|
||
* @param out 输出流
|
||
* @throws IORuntimeException IO异常
|
||
*/
|
||
private void formEnd(OutputStream out) throws IORuntimeException {
|
||
write(out, BOUNDARY_END);
|
||
}
|
||
|
||
/**
|
||
* 写出对象
|
||
*
|
||
* @param out 输出流
|
||
* @param objs 写出的对象(转换为字符串)
|
||
*/
|
||
private void write(OutputStream out, Object... objs) {
|
||
IoUtil.write(out, this.charset, false, objs);
|
||
}
|
||
}
|