cn.geektool.http.body.MultipartBody Maven / Gradle / Ivy
The newest version!
package cn.geektool.http.body;
import cn.geektool.http.ContentType;
import cn.geektool.http.HttpUtil;
import cn.geektool.core.io.IORuntimeException;
import cn.geektool.core.io.IoUtil;
import cn.geektool.core.io.resource.MultiResource;
import cn.geektool.core.io.resource.Resource;
import cn.geektool.core.map.MapUtil;
import cn.geektool.core.util.ObjectUtil;
import cn.geektool.core.util.RandomUtil;
import cn.geektool.core.util.StrUtil;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.Map;
/**
* Multipart/form-data数据的请求体封装
*
* @author jd
* @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 form;
/**
* 编码
*/
private final Charset charset;
/**
* 根据已有表单内容,构建MultipartBody
* @param form 表单
* @param charset 编码
* @return MultipartBody
*/
public static MultipartBody create(Map 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 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 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);
}
}