Zhiqim Kernel即知启蒙内核,是Zhiqim Framework的核心,负责工程的生命周期管理:包括工程开发和发布的目录结构管理、统一的配置规约、单多例服务接口定义、服务启动运行更新和销毁管理。并提供基础开发工具:包括工具类、日志类、线程池、JSON/XML编解析、HTTP客户端、时钟任务定时器等。
HttpClient.java31KB
/*
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
*
* https://zhiqim.org/project/zhiqim_framework/zhiqim_kernel.htm
*
* Zhiqim Kernel is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.zhiqim.kernel.httpclient;
import java.io.IOException;
import java.io.InputStream;
import java.net.BindException;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLConnection;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.TrustManager;
import org.zhiqim.kernel.constants.HttpConstants;
import org.zhiqim.kernel.logging.Log;
import org.zhiqim.kernel.logging.LogFactory;
import org.zhiqim.kernel.model.codes.SSL;
import org.zhiqim.kernel.model.codes.SSL.DefaultHostnameVerifier;
import org.zhiqim.kernel.model.codes.URI;
import org.zhiqim.kernel.model.lists.ArrayListS;
import org.zhiqim.kernel.model.lists.ListS;
import org.zhiqim.kernel.model.maps.HashMapSO;
import org.zhiqim.kernel.model.objects.Int;
import org.zhiqim.kernel.util.Arrays;
import org.zhiqim.kernel.util.Ints;
import org.zhiqim.kernel.util.Streams;
import org.zhiqim.kernel.util.Strings;
import org.zhiqim.kernel.util.Stringx;
import org.zhiqim.kernel.util.Validates;
/**
* Http客户端基类,实现子类实现execute功能
*
* @see HttpGet GET方法调用,只需URL,无需传入参数
* @see HttpPost POST方法调用,传入Form参数
* @see HttpDownload GET方法调用,得到内容是大文件,保存到本地
* @see HttpUpload POST方法调用,传入Form-data,包括文件和参数
*
* @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
*/
public abstract class HttpClient implements HttpConstants
{
public static final String _USER_AGENT_VALUE_ = "ZhiqimHttpClient/V8.0.5";
public static final Pattern _REGEX_FILE_NAME_ = Pattern.compile("attachment;\\s*filename=\"([\\w\\-\\._]+)\"");
/**************************************************************************/
//以下为HTTP参数
/**************************************************************************/
protected static final Log log = LogFactory.getLog(HttpClient.class);
private boolean keepAlive = false; //是否长连接
private HttpURLConnection conn; //HTTP连接
private int connectTimeout = 10; //连接超时时间,单位秒,默认10秒,实现传入毫秒,=0表示一直等待直到成功,!=0时时间达到则抛出java.net.SocketTimeoutException
private int readTimeout = 30; //读资源超时时间,单位秒,默认30秒,实现传入毫秒,=0表示一直等待直到成功,!=0时时间达到则抛出java.net.SocketTimeoutException
private boolean doInput = true; //是否输入,默认=true
private boolean doOutput = false; //是否输出,默认=false
private boolean instanceFollowRedirects = false; //当3XX重定向时,是否访问重定向的地址,HTTP默认是true,我们改为默认false,即返回location
private boolean useCaches = false; //设置当前是否使用缓存,我们默认=false,系统默认取defaultUseCaches=true,也可以实际设置
private long ifModifiedSince = 0; //设置资源比较时间
private int chunkLength = -1; //指定资源块大小,系统默认-1,提供了一个缺省值4096参考,如果未设置,则缓存本地再发送,否则流逐步发送,
private int fixedContentLength = -1; //指定读取资源内容大小,默认是未开启,按服务端ContentLength读内容大小,只有设置了才有效,默认-1
private boolean allowUserInteraction = false; //允许用户交互,默认=false
private boolean hasUserAgent = false; //是否有客户端代理
private boolean hasHost = false; //是否有主机
private final HashMapSO requestPropertyMap; //请求属性参数表
private final HashMapSO responsePropertyMap; //响应属性参数表
private String responseStatusLine; //响应状态行
protected final String url; //请求连接URL
protected final URI uri; //请求连接URI
private final String method; //HTTP方法 [GET,POST,HEAD,OPTIONS,PUT,DELETE,TRACE]
private String sslProtocol = "TLSv1.2"; //SSL协议
private KeyManager[] sslKeyManagers; //SSL密钥管理器
private TrustManager[] sslTrustManagers; //SSL信任管理器
protected int responseStatus; //响应状态码
protected String responseText; //响应状态信息
protected boolean responseClose; //响应是否关闭
protected Throwable exception; //调用异常
public HttpClient(String url, String method)
{
this.url = url;
this.uri = new URI();
this.uri.parse(url);
this.method = method;
this.requestPropertyMap = new HashMapSO();
this.responsePropertyMap = new HashMapSO();
}
/** 设置请求属性完成后保持活跃 */
public void setConnectionKeepAlive()
{
this.keepAlive = true;
this.requestPropertyMap.put(_CONNECTION_, _KEEP_ALIVE_);
}
/** 设置请求属性完成后关闭 */
public void setConnectionClose()
{
this.keepAlive = false;
this.requestPropertyMap.put(_CONNECTION_, _CLOSE_);
}
/***********************************************************/
//通用的执行方法,子类不可重写,子类重写以下三个方法
/***********************************************************/
public final void execute()
{
this.responseStatus = 0;
this.responseText = null;
this.responseClose = false;
this.exception = null;
if (!isValidUrl())
return;
try
{
//1.预置请求连接属性和消息头信息,如果返回false表示不可执行
if (!doPreRequestProperty())
return;
if (conn == null)
{//2.新建连接并连接
conn = newHttpConnection();
conn.connect();
}
//3.子类可重写该方法设置连接内容
doWriteRequestContent(conn);
//4.获取响应状态和响应属性
responseStatus = conn.getResponseCode();
doReadResponseProperty(conn);
//5.子类可重写该方法获取连接内容
doReadResponseContent(conn);
}
catch (SocketTimeoutException e)
{
responseStatus = _73_SOCKET_TIMEOUT_;
responseText = "调用服务端超时";
exception = e;
}
catch (ConnectException e)
{
responseStatus = _91_CONNECT_EXCEPTION_;
responseText = "连接服务器失败";
exception = e;
}
catch (BindException e)
{
responseStatus = _92_BIND_EXCEPTION_;
responseText = "绑定本地地址和端口失败";
exception = e;
}
catch (SocketException e)
{
responseStatus = _90_SOCKET_EXCEPTION_;
responseText = "调用服务端失败:"+e.getMessage();
exception = e;
}
catch (IOException e)
{
responseStatus = _98_IO_EXCEPTION_;
responseText = "调用服务端失败:"+e.getMessage();
exception = e;
}
catch(Exception e)
{
responseStatus = _99_EXCEPTION_;
responseText = "调用服务端异常:"+e.getMessage();
exception = e;
}
finally
{
if (!keepAlive || exception != null || responseClose)
{//指定短连接或者异常或者响应关闭
if (conn != null)
{//有连接的,断开
conn.disconnect();
conn = null;
}
}
}
}
/***********************************************************/
//子类可重写的方法,包括预置请求属性、写请求内容,读响应内容
/***********************************************************/
/**
* 预处理请求属性,并检查是否可执行,默认可执行,子类重写
*
* @return =true表示正常可执行,=false表示异常不向下执行
*/
protected boolean doPreRequestProperty()
{
return true;
}
/**
* 写请求内容,子类可重写
*
* @param conn HTTP/HTTPS连接
* @throws IOException 可能的异常
*/
protected void doWriteRequestContent(HttpURLConnection conn) throws IOException
{
}
/**
* 读响应内容,子类可重写
*
* @param conn HTTP/HTTPS连接
* @throws IOException 可能的异常
*/
protected void doReadResponseContent(HttpURLConnection conn) throws IOException
{
if (responseStatus == _302_FOUND_)
{//重定向
responseText = conn.getHeaderField("Location");
return;
}
responseText = getResponseAsString(conn);
}
/*****************************************************************************/
//以下为创建连接,并设置基本属性
/*****************************************************************************/
private boolean isValidUrl()
{
if (Validates.isUrl(url) && uri.isParsed())
return true;
responseStatus = _70_MALFORMED_URL_;
responseText = "请求的URL不正确";
return false;
}
/** 创建连接 */
private HttpURLConnection newHttpConnection() throws NoSuchAlgorithmException, KeyManagementException, IOException
{
if (Validates.isUrlHttp(url))
{//HTTP连接
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
setConnectionProperty(conn);
return conn;
}
else
{//HTTPS连接
HttpsURLConnection conn = (HttpsURLConnection)new URL(url).openConnection();
conn.setSSLSocketFactory(SSL.getSocketFactory(sslProtocol, sslKeyManagers, sslTrustManagers));
conn.setHostnameVerifier(new DefaultHostnameVerifier());
setConnectionProperty(conn);
return conn;
}
}
/** 设置连接属性 */
private void setConnectionProperty(HttpURLConnection conn)
{
//设置方法
try{conn.setRequestMethod(method);}catch (ProtocolException e){}
if (!doInput)
{//有设置输入打开,输入默认打开
conn.setDoInput(doInput);
}
if (doOutput)
{//有设置输出打开,输出默认关闭
conn.setDoOutput(doOutput);
}
//当3XX重定向时,当前实例是否访问重定向的地址
conn.setInstanceFollowRedirects(instanceFollowRedirects);
if (connectTimeout > 0)
{//有设置连接超时秒数,大于0时有效
conn.setConnectTimeout(connectTimeout * 1000);
}
if (readTimeout > 0)
{//有设置读超时秒数,大于0时有效
conn.setReadTimeout(readTimeout * 1000);
}
if (!useCaches)
{//是否启用缓存,默认开启
conn.setUseCaches(useCaches);
}
if (ifModifiedSince > 0)
{//有设置比较资源时间
conn.setIfModifiedSince(ifModifiedSince);
}
if (fixedContentLength != -1)
{//有设置固定读资源内容大小,和设置资源块大小互斥,默认优先取固定读资源内容大小
conn.setFixedLengthStreamingMode(fixedContentLength);
}
if (fixedContentLength == -1 && chunkLength != -1)
{//有设置资源块大小,和设置固定资源大小互斥
conn.setChunkedStreamingMode(chunkLength);
}
if (allowUserInteraction)
{//有设置允许人工交互
conn.setAllowUserInteraction(allowUserInteraction);
}
if (requestPropertyMap != null && !requestPropertyMap.isEmpty())
{//请求自定义属性表
for (Map.Entry<String, Object> entry : requestPropertyMap.entrySet())
{
String key = entry.getKey();
Object value = entry.getValue();
if (value instanceof String)
conn.setRequestProperty(key, (String)value);
else
{
ListS list = (ListS)value;
for (String val : list)
{
conn.addRequestProperty(key, val);
}
}
}
}
if (!hasUserAgent)
{//未设置代理的,使用zhiqim默认值
conn.addRequestProperty(_USER_AGENT_, _USER_AGENT_VALUE_);
}
if (!hasHost)
{//未设置HOST的,从url中获取
conn.addRequestProperty(_HOST_, uri.getHost());
}
}
/***********************************************************/
//增加请求属性信息,包括信任管理器,属性,是否输入输出流等
/***********************************************************/
/** 设置请求,由请求处理 */
public void setRequest(HttpClientRequest request)
{
request.buildRequest(this);
}
/** 设置SSL协议 */
public void setSSLProtocol(String protocol)
{
this.sslProtocol = protocol;
}
/** 设置SSL密钥管理器 */
public void setSSLKeyManagers(KeyManager[] keyManagers)
{
this.sslKeyManagers = keyManagers;
}
/** 设置SSL信任管理器 */
public void setSSLTrustManagers(TrustManager[] trustManagers)
{
this.sslTrustManagers = trustManagers;
}
/** 设置请求属性 */
public void setRequestProperty(String key, int value)
{
setRequestProperty(key, String.valueOf(value));
}
/** 设置请求属性 */
public void setRequestProperty(String key, String value)
{
if (_USER_AGENT_.equalsIgnoreCase(key))
hasUserAgent = true;
else if (_HOST_.equalsIgnoreCase(key))
hasHost = true;
requestPropertyMap.put(key, value);
}
/** 增加请求属性 */
public void addRequestProperty(String key, int value)
{
addRequestProperty(key, String.valueOf(value));
}
/** 增加请求属性 */
public void addRequestProperty(String key, String value)
{
if (_USER_AGENT_.equalsIgnoreCase(key))
hasUserAgent = true;
else if (_HOST_.equalsIgnoreCase(key))
hasHost = true;
Object val = requestPropertyMap.get(key);
if (val == null)
requestPropertyMap.put(key, value);
else if (val instanceof ListS)
((ListS)val).add(value);
else
{
ListS list = new ArrayListS();
list.add((String)val);
list.add(value);
requestPropertyMap.put(key, list);
}
}
/** 获取请求属性表,值为(String/ListS两种可能) */
public HashMapSO getRequestPropertyMap()
{
return requestPropertyMap;
}
/** 获取请求属性对象(null/String/ListS三种可能) */
public Object getRequestPropertyObj(String key)
{
return requestPropertyMap.get(key);
}
/** 获取请求属性 */
public String getRequestProperty(String key)
{
Object value = requestPropertyMap.get(key);
if (value == null)
return null;
else if (value instanceof String)
return (String)value;
else
return ((ListS)value).get(0);
}
/** 是否有请求属性 */
public boolean hasRequestProperty(String key)
{
return requestPropertyMap.containsKey(key);
}
/** 获取配置的URL */
public String getUrl()
{
return url;
}
/** 获取配置的URL转URI */
public URI getUri()
{
return uri;
}
/** 获取方法 */
public String getMethod()
{
return method;
}
/** 判断是否打开了输入流 */
public boolean isDoInput()
{
return doInput;
}
/** 设置是是否有输入流 */
public void setDoInput(boolean doInput)
{
this.doInput = doInput;
}
/** 判断是否打开了输出流 */
public boolean isDoOutput()
{
return doOutput;
}
/** 设置是是否有输出流 */
public void setDoOutput(boolean doOutput)
{
this.doOutput = doOutput;
}
/** 设置连接超时时长,单位:秒 */
public void setConnectTimeout(int connectTimeout)
{
this.connectTimeout = connectTimeout;
}
/** 获取连接超时时长,单位:秒 */
public int getConnectTimeout()
{
return connectTimeout;
}
/** 设置数据获取超时时长,单位:秒 */
public void setReadTimeout(int readTimeout)
{
this.readTimeout = readTimeout;
}
/** 获取读流超时时长 */
public int getReadTimeout()
{
return readTimeout;
}
/** 设置协议是否使用缓存,默认是有条件即使用,我们修改成不使用 */
public boolean isUseCaches()
{
return useCaches;
}
/** 设置协议是否使用缓存 */
public void setUseCaches(boolean useCaches)
{
this.useCaches = useCaches;
}
/** 获取资源本地缓存上次最后修改时间 */
public long getIfModifiedSince()
{
return ifModifiedSince;
}
/** 设置资源本地缓存上次最后修改时间 */
public void setIfModifiedSince(long ifModifiedSince)
{
this.ifModifiedSince = ifModifiedSince;
}
/** 获取配置的块大小,-1表示未配置,操作时默认4096 */
public int getChunkLength()
{
return chunkLength;
}
/** 设置块大小,-1表示不生效,取默认4096 */
public void setChunkLength(int chunkLength)
{
this.chunkLength = chunkLength;
}
/** 获取配置的读取固定内容长度,-1表示不生效,取响应的Content-Length */
public int getFixedContentLength()
{
return fixedContentLength;
}
/** 设置配置的读取固定内容长度,-1表示不生效,取响应的Content-Length */
public void setFixedContentLength(int fixedContentLength)
{
this.fixedContentLength = fixedContentLength;
}
/** 判断是否允许用户交互,用于访问服务端时等待管理操作验证 */
public boolean isAllowUserInteraction()
{
return allowUserInteraction;
}
/** 设置是否允许用户交互,默认是不允许 */
public void setAllowUserInteraction(boolean allowUserInteraction)
{
this.allowUserInteraction = allowUserInteraction;
}
/** 判断当3XX重定向时,是否访问重定向的地址 */
public boolean isInstanceFollowRedirects()
{
return instanceFollowRedirects;
}
/** 设置当3XX重定向时,是否访问重定向的地址 */
public void setInstanceFollowRedirects(boolean instanceFollowRedirects)
{
this.instanceFollowRedirects = instanceFollowRedirects;
}
/***********************************************************/
//获取结果信息,包括状态、内容和字节流
/***********************************************************/
/** 增加响应属性 */
protected void doReadResponseProperty(URLConnection conn)
{
responseStatusLine = conn.getHeaderField(0);
Map<String, List<String>> map = conn.getHeaderFields();
for (String key : map.keySet())
{
if (Validates.isEmpty(key))
continue;
List<String> list = map.get(key);
if (list == null || list.isEmpty())
continue;
if (list.size() == 1)
responsePropertyMap.put(key.toLowerCase(), list.get(0));
else
responsePropertyMap.put(key.toLowerCase(), new ArrayListS(list));
}
if (keepAlive)
{//检查服务端是否强制关闭
Object connectionValue = responsePropertyMap.get(_CONNECTION_);
if (connectionValue == null || !(connectionValue instanceof String))
{//服务端未指定或指定多项的,认为服务端关闭
responseClose = true;
}
else
{//有keepAlive标志
responseClose = !_KEEP_ALIVE_.equalsIgnoreCase((String)connectionValue);
}
}
}
/** 获取响应状态 */
public int getResponseStatus()
{
return responseStatus;
}
/** 判断响应是否成功 */
public boolean isResponseSuccess()
{
return responseStatus == 200;
}
/** 获取响应内容(正确内容或错误内容) */
public String getResponseText()
{
return responseText;
}
/** 返回指定的Http调用结果 */
public HttpResult getResult()
{
return new HttpResult(responseStatus, responseText);
}
/** 返回指定的Int类型的调用结果 */
public Int getResultInt()
{
return new Int(responseStatus==200?0:responseStatus, responseText);
}
/** 获取调用前异常(responseStatus < 100) */
public Throwable getException()
{
return exception;
}
/** 获取响应状态行 */
public String getResponseStatusLine()
{
return responseStatusLine;
}
/** 获取响应属性表 */
public HashMapSO getResponsePropertyMap()
{
return responsePropertyMap;
}
/** 获取响应属性(String/ListS两种可能) */
public Object getResponsePropertyObj(String key)
{
return responsePropertyMap.get(key.toLowerCase());
}
/** 获取响应属性,列表取第一个 */
public String getResponseProperty(String key)
{
Object value = responsePropertyMap.get(key.toLowerCase());
if (value == null)
return null;
else if (value instanceof String)
return (String)value;
else
return ((ListS)value).get(0);
}
/** 是否有响应属性 */
public boolean hasResponseProperty(String key)
{
return responsePropertyMap.containsKey(key.toLowerCase());
}
/** 获取响应内容长度 */
public int getResponseContentLength()
{
String value = getResponseProperty(_CONTENT_LENGTH_);
if (Validates.isEmptyBlank(value))
return 0;
value = Strings.trim(value);
if (!Validates.isIntegerPositive(value))
return 0;
return Ints.toInt(value);
}
/** 获取响应内容类型 */
public String getResponseContentType()
{
return getResponseProperty(_CONTENT_TYPE_);
}
/** 获取响应内容字符集,默认UTF-8 */
public String getResponseCharset()
{
return getResponseCharset(getResponseContentType());
}
/** 获取响应内容编码 */
public String getResponseContentEncoding()
{
return getResponseProperty(_CONTENT_ENCODING_);
}
/** 判断响应内容编码是否是Gzip */
public boolean isResponseGzip()
{
return _ENCODING_GZIP_.equals(getResponseContentEncoding());
}
/*****************************************************************************/
//以下为静态方法
/*****************************************************************************/
/**
* 判断是否响应使用GZIP压缩
*
* @param conn HTTP连接
* @return =true表示启用,=false表示未启用
*/
public static boolean isResponseGzip(HttpURLConnection conn)
{
return "gzip".equals(conn.getContentEncoding());
}
/**
* 从响应中获取内容字符集
*
* @param contentType 内容类型
* @return String, 默认UTF-8
*/
public static String getResponseCharset(String contentType)
{
if (Validates.isEmptyBlank(contentType))
return _UTF_8_;
String[] params = Arrays.toStringArray(contentType.trim(), ";");
for (String param : params)
{
if (!param.startsWith(_CHARSET_))
continue;
String[] pair = Arrays.toStringArray(param, "=");
if (pair.length != 2 || Validates.isEmpty(pair[1]))
continue;
return pair[1];
}
return _UTF_8_;
}
/**
* 从响应中获取字符串,包括成功和失败的内容
*
* @param conn HTTP连接
* @return 成功或失败的内容
* @throws IOException 可能的异常
*/
public static String getResponseAsString(HttpURLConnection conn) throws IOException
{
boolean isGzip = isResponseGzip(conn);
String charset = getResponseCharset(conn.getContentType());
if (conn.getErrorStream() != null)
{//有出错返回
String message = null;
if (isGzip)
message = Streams.getStringGzip(conn.getErrorStream(), charset);
else
message = Streams.getString(conn.getErrorStream(), charset);
if (Validates.isEmptyBlank(message))
message = "调用服务端接口失败,错误码:"+conn.getResponseCode();
return message;
}
else if (conn.getInputStream() != null)
{//正常返回
if (isGzip)
return Streams.getStringGzip(conn.getInputStream(), charset);
else
return Streams.getString(conn.getInputStream(), charset);
}
else
{//无出错内容返回
return "调用服务端接口失败,错误码:"+conn.getResponseCode();
}
}
/**
* 读取错误流中的内容
*
* @param conn HTTP连接
* @return 成功或失败的内容
* @throws IOException 可能的异常
*/
public static String getResponseError(HttpURLConnection conn) throws IOException
{
InputStream stream = conn.getErrorStream();
if (stream == null)
return "调用服务端接口失败,错误码:"+conn.getResponseCode();
boolean isGzip = isResponseGzip(conn);
String charset = getResponseCharset(conn.getContentType());
String message = null;
if (isGzip)
message = Streams.getStringGzip(stream, charset);
else
message = Streams.getString(stream, charset);
if (Validates.isEmptyBlank(message))
message = "调用服务端接口失败,错误码:"+conn.getResponseCode();
return message;
}
/**
* 通过连接获取下载名称
*
* @param conn HttpURLConnection
* @return fileName
*/
public static String getFileName(HttpURLConnection conn)
{
String contentDisposition = conn.getHeaderField(_CONTENT_DISPOSITION_);
if (contentDisposition == null)
return null;
Matcher matcher = _REGEX_FILE_NAME_.matcher(contentDisposition);
if (matcher.find())
return Stringx.trim(matcher.group(1));
return null;
}
/**
* 获取上传文件时文本参数配置
*
* @param name 参数名
* @param encoding 参数编码
* @return 参数配置说明
* @throws IOException 异常
*/
public static byte[] getTextDisposition(String name, String encoding) throws IOException
{
StringBuilder strb = new StringBuilder()
.append("Content-Disposition: form-data; name=\"").append(name).append("\"").append(_BR_)
.append(_BR_);
return strb.toString().getBytes(encoding);
}
/**
* 获取上传文件时文件参数配置
*
* @param name 文件参数名
* @param fileName 文件名
* @param mimeType 文件类型
* @param encoding 编码
* @return 参数配置说明
* @throws IOException 异常
*/
public static byte[] getFileDisposition(String name, String fileName, String mimeType, String encoding) throws IOException
{
StringBuilder strb = new StringBuilder()
.append("Content-Disposition: form-data; name=\"").append(name).append("\"; filename=\"").append(fileName).append("\"").append(_BR_)
.append("Content-Type:").append(mimeType).append(_BR_)
.append(_BR_);
return strb.toString().getBytes(encoding);
}
}