Files
hutool/hutool-http/src/main/java/cn/hutool/http/body/MultipartBody.java
2020-05-14 01:56:03 +08:00

155 lines
4.3 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
}
}