因爲之前寫的項目中有使用到淘寶sdk中的WebUtils工具類,功能方面還是比較全,由於近期的項目又要調用外部api,在百度上面找了一圈後沒有自己喜歡的,因此在淘寶sdk中將該方法提了出來。該工具支持攜帶頭部消息(cookie等),使用起來也非常的方便。
自己只是簡單測試了一下可以使用,功能是否完全正常未知!
先看看工具類的方法吧(因爲是直接從淘寶sdk中拿過來的,所以可能有多餘無用方法,同時部分類不是從淘寶sdk中複製過來的)
調用演示
攜帶頭部消息調用演示
代碼部分
WebUtils.java
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.zip.GZIPInputStream;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
/**
* 網絡工具類。
*
* @author carver.gu
* @since 1.0, Sep 12, 2009
*/
public abstract class WebUtils {
private static final String DEFAULT_CHARSET = Constants.CHARSET_UTF8;
private static boolean ignoreSSLCheck = true; // 忽略SSL檢查
private static boolean ignoreHostCheck = true; // 忽略HOST檢查
public static class TrustAllTrustManager implements X509TrustManager {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
}
private WebUtils() {
}
public static void setIgnoreSSLCheck(boolean ignoreSSLCheck) {
WebUtils.ignoreSSLCheck = ignoreSSLCheck;
}
public static void setIgnoreHostCheck(boolean ignoreHostCheck) {
WebUtils.ignoreHostCheck = ignoreHostCheck;
}
/**
* 執行HTTP POST請求。
*
* @param url 請求地址
* @param params 請求參數
* @return 響應字符串
*/
public static String doPost(String url, Map<String, String> params, int connectTimeout, int readTimeout) throws IOException {
return doPost(url, params, DEFAULT_CHARSET, connectTimeout, readTimeout);
}
/**
* 執行HTTP POST請求。
*
* @param url 請求地址
* @param params 請求參數
* @param charset 字符集,如UTF-8, GBK, GB2312
* @return 響應字符串
*/
public static String doPost(String url, Map<String, String> params, String charset, int connectTimeout, int readTimeout) throws IOException {
return doPost(url, params, charset, connectTimeout, readTimeout, null, null);
}
public static String doPost(String url, Map<String, String> params, String charset, int connectTimeout, int readTimeout, Map<String, String> headerMap, Proxy proxy) throws IOException {
String ctype = "application/x-www-form-urlencoded;charset=" + charset;
String query = buildQuery(params, charset);
byte[] content = {};
if (query != null) {
content = query.getBytes(charset);
}
return _doPost(url, ctype, content, connectTimeout, readTimeout, headerMap, proxy);
}
public static String doPost(String url, String apiBody, String charset, int connectTimeout, int readTimeout, Map<String, String> headerMap) throws IOException {
String ctype = "text/plain;charset=" + charset;
byte[] content = apiBody.getBytes(charset);
return _doPost(url, ctype, content, connectTimeout, readTimeout, headerMap, null);
}
/**
* 執行HTTP POST請求。
*
* @param url 請求地址
* @param ctype 請求類型
* @param content 請求字節數組
* @return 響應字符串
*/
public static String doPost(String url, String ctype, byte[] content, int connectTimeout, int readTimeout) throws IOException {
return _doPost(url, ctype, content, connectTimeout, readTimeout, null, null);
}
/**
* 執行HTTP POST請求。
*
* @param url 請求地址
* @param ctype 請求類型
* @param content 請求字節數組
* @param headerMap 請求頭部參數
* @return 響應字符串
*/
public static String doPost(String url, String ctype, byte[] content, int connectTimeout, int readTimeout, Map<String, String> headerMap, Proxy proxy) throws IOException {
return _doPost(url, ctype, content, connectTimeout, readTimeout, headerMap, proxy);
}
private static String _doPost(String url, String ctype, byte[] content, int connectTimeout, int readTimeout, Map<String, String> headerMap, Proxy proxy) throws IOException {
HttpURLConnection conn = null;
OutputStream out = null;
String rsp = null;
try {
conn = getConnection(new URL(url), Constants.METHOD_POST, ctype, headerMap, proxy);
conn.setConnectTimeout(connectTimeout);
conn.setReadTimeout(readTimeout);
out = conn.getOutputStream();
out.write(content);
rsp = getResponseAsString(conn);
} finally {
if (out != null) {
out.close();
}
if (conn != null) {
conn.disconnect();
}
}
return rsp;
}
/**
* 執行帶文件上傳的HTTP POST請求。
*
* @param url 請求地址
* @param fileParams 文件請求參數
* @return 響應字符串
*/
public static String doPost(String url, Map<String, String> params, Map<String, FileItem> fileParams, int connectTimeout, int readTimeout) throws IOException {
if (fileParams == null || fileParams.isEmpty()) {
return doPost(url, params, DEFAULT_CHARSET, connectTimeout, readTimeout);
} else {
return doPost(url, params, fileParams, DEFAULT_CHARSET, connectTimeout, readTimeout);
}
}
public static String doPost(String url, Map<String, String> params, Map<String, FileItem> fileParams, String charset, int connectTimeout, int readTimeout) throws IOException {
return doPost(url, params, fileParams, charset, connectTimeout, readTimeout, null);
}
/**
* 執行帶文件上傳的HTTP POST請求。
*
* @param url 請求地址
* @param fileParams 文件請求參數
* @param charset 字符集,如UTF-8, GBK, GB2312
* @param headerMap 需要傳遞的header頭,可以爲空
* @return 響應字符串
*/
public static String doPost(String url, Map<String, String> params, Map<String, FileItem> fileParams, String charset,
int connectTimeout, int readTimeout, Map<String, String> headerMap) throws IOException {
if (fileParams == null || fileParams.isEmpty()) {
return doPost(url, params, charset, connectTimeout, readTimeout, headerMap, null);
} else {
return _doPostWithFile(url, params, fileParams, charset, connectTimeout, readTimeout, headerMap);
}
}
/**
* 執行請求
* content_type: aplication/json
*
* @param url
* @param params
* @param charset
* @param connectTimeout
* @param readTimeout
* @return
* @throws IOException
*/
public static String doPostWithJson(String url, Map<String, Object> params, String charset, int connectTimeout, int readTimeout) throws IOException {
String ctype = "application/json;charset=" + charset;
byte[] content = {};
String body = JsonUtils.objectToJson(params);
if (body != null) {
content = body.getBytes(charset);
}
return _doPost(url, ctype, content, connectTimeout, readTimeout, null, null);
}
private static String _doPostWithFile(String url, Map<String, String> params, Map<String, FileItem> fileParams,
String charset, int connectTimeout, int readTimeout, Map<String, String> headerMap) throws IOException {
String boundary = String.valueOf(System.nanoTime()); // 隨機分隔線
HttpURLConnection conn = null;
OutputStream out = null;
String rsp = null;
try {
String ctype = "multipart/form-data;charset=" + charset + ";boundary=" + boundary;
conn = getConnection(new URL(url), Constants.METHOD_POST, ctype, headerMap, null);
conn.setConnectTimeout(connectTimeout);
conn.setReadTimeout(readTimeout);
out = conn.getOutputStream();
byte[] entryBoundaryBytes = ("\r\n--" + boundary + "\r\n").getBytes(charset);
// 組裝文本請求參數
Set<Entry<String, String>> textEntrySet = params.entrySet();
for (Entry<String, String> textEntry : textEntrySet) {
byte[] textBytes = getTextEntry(textEntry.getKey(), textEntry.getValue(), charset);
out.write(entryBoundaryBytes);
out.write(textBytes);
}
// 組裝文件請求參數
Set<Entry<String, FileItem>> fileEntrySet = fileParams.entrySet();
for (Entry<String, FileItem> fileEntry : fileEntrySet) {
FileItem fileItem = fileEntry.getValue();
if (!fileItem.isValid()) {
throw new IOException("FileItem is invalid");
}
byte[] fileBytes = getFileEntry(fileEntry.getKey(), fileItem.getFileName(), fileItem.getMimeType(), charset);
out.write(entryBoundaryBytes);
out.write(fileBytes);
fileItem.write(out);
}
// 添加請求結束標誌
byte[] endBoundaryBytes = ("\r\n--" + boundary + "--\r\n").getBytes(charset);
out.write(endBoundaryBytes);
rsp = getResponseAsString(conn);
} finally {
if (out != null) {
out.close();
}
if (conn != null) {
conn.disconnect();
}
}
return rsp;
}
private static byte[] getTextEntry(String fieldName, String fieldValue, String charset) throws IOException {
StringBuilder entry = new StringBuilder();
entry.append("Content-Disposition:form-data;name=\"");
entry.append(fieldName);
entry.append("\"\r\nContent-Type:text/plain\r\n\r\n");
entry.append(fieldValue);
return entry.toString().getBytes(charset);
}
private static byte[] getFileEntry(String fieldName, String fileName, String mimeType, String charset) throws IOException {
StringBuilder entry = new StringBuilder();
entry.append("Content-Disposition:form-data;name=\"");
entry.append(fieldName);
entry.append("\";filename=\"");
entry.append(fileName);
entry.append("\"\r\nContent-Type:");
entry.append(mimeType);
entry.append("\r\n\r\n");
return entry.toString().getBytes(charset);
}
/**
* 執行HTTP GET請求。
*
* @param url 請求地址
* @param params 請求參數
* @return 響應字符串
*/
public static String doGet(String url, Map<String, String> params) throws IOException {
return doGet(url, params, DEFAULT_CHARSET);
}
/**
* 執行HTTP GET請求。
*
* @param url 請求地址
* @param params 請求參數
* @param charset 字符集,如UTF-8, GBK, GB2312
* @return 響應字符串
*/
public static String doGet(String url, Map<String, String> params, String charset) throws IOException {
HttpURLConnection conn = null;
String rsp = null;
try {
String ctype = "application/x-www-form-urlencoded;charset=" + charset;
String query = buildQuery(params, charset);
conn = getConnection(buildGetUrl(url, query), Constants.METHOD_GET, ctype, null, null);
rsp = getResponseAsString(conn);
} finally {
if (conn != null) {
conn.disconnect();
}
}
return rsp;
}
private static HttpURLConnection getConnection(URL url, String method, String ctype, Map<String, String> headerMap, Proxy proxy) throws IOException {
HttpURLConnection conn = null;
if(proxy == null) {
conn = (HttpURLConnection) url.openConnection();
} else {
conn = (HttpURLConnection) url.openConnection(proxy);
}
if (conn instanceof HttpsURLConnection) {
HttpsURLConnection connHttps = (HttpsURLConnection) conn;
if (ignoreSSLCheck) {
try {
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, new TrustManager[] { new TrustAllTrustManager() }, new SecureRandom());
connHttps.setSSLSocketFactory(ctx.getSocketFactory());
connHttps.setHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
} catch (Exception e) {
throw new IOException(e.toString());
}
} else {
if (ignoreHostCheck) {
connHttps.setHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
}
}
conn = connHttps;
}
conn.setRequestMethod(method);
conn.setDoInput(true);
conn.setDoOutput(true);
if(headerMap != null && headerMap.get(Constants.TOP_HTTP_DNS_HOST) != null){
conn.setRequestProperty("Host", headerMap.get(Constants.TOP_HTTP_DNS_HOST));
}else{
conn.setRequestProperty("Host", url.getHost());
}
conn.setRequestProperty("Accept", "text/xml,text/javascript");
conn.setRequestProperty("User-Agent", "top-sdk-java");
conn.setRequestProperty("Content-Type", ctype);
if (headerMap != null) {
for (Map.Entry<String, String> entry : headerMap.entrySet()) {
if(!Constants.TOP_HTTP_DNS_HOST.equals(entry.getKey())){
conn.setRequestProperty(entry.getKey(), entry.getValue());
}
}
}
return conn;
}
private static URL buildGetUrl(String url, String query) throws IOException {
if (StringUtils.isEmpty(query)) {
return new URL(url);
}
return new URL(buildRequestUrl(url, query));
}
public static String buildRequestUrl(String url, String... queries) {
if (queries == null || queries.length == 0) {
return url;
}
StringBuilder newUrl = new StringBuilder(url);
boolean hasQuery = url.contains("?");
boolean hasPrepend = url.endsWith("?") || url.endsWith("&");
for (String query : queries) {
if (!StringUtils.isEmpty(query)) {
if (!hasPrepend) {
if (hasQuery) {
newUrl.append("&");
} else {
newUrl.append("?");
hasQuery = true;
}
}
newUrl.append(query);
hasPrepend = false;
}
}
return newUrl.toString();
}
public static String buildQuery(Map<String, String> params, String charset) throws IOException {
if (params == null || params.isEmpty()) {
return null;
}
StringBuilder query = new StringBuilder();
Set<Entry<String, String>> entries = params.entrySet();
boolean hasParam = false;
for (Entry<String, String> entry : entries) {
String name = entry.getKey();
String value = entry.getValue();
// 忽略參數名或參數值爲空的參數
if (StringUtils.areNotEmpty(name, value)) {
if (hasParam) {
query.append("&");
} else {
hasParam = true;
}
query.append(name).append("=").append(URLEncoder.encode(value, charset));
}
}
return query.toString();
}
protected static String getResponseAsString(HttpURLConnection conn) throws IOException {
String charset = getResponseCharset(conn.getContentType());
if (conn.getResponseCode() < HttpURLConnection.HTTP_BAD_REQUEST) {
String contentEncoding = conn.getContentEncoding();
if (Constants.CONTENT_ENCODING_GZIP.equalsIgnoreCase(contentEncoding)) {
return getStreamAsString(new GZIPInputStream(conn.getInputStream()), charset);
} else {
return getStreamAsString(conn.getInputStream(), charset);
}
} else {
// OAuth bad request always return 400 status
if (conn.getResponseCode() == HttpURLConnection.HTTP_BAD_REQUEST) {
InputStream error = conn.getErrorStream();
if (error != null) {
return getStreamAsString(error, charset);
}
}
// Client Error 4xx and Server Error 5xx
throw new IOException(conn.getResponseCode() + " " + conn.getResponseMessage());
}
}
public static String getStreamAsString(InputStream stream, String charset) throws IOException {
try {
Reader reader = new InputStreamReader(stream, charset);
StringBuilder response = new StringBuilder();
final char[] buff = new char[1024];
int read = 0;
while ((read = reader.read(buff)) > 0) {
response.append(buff, 0, read);
}
return response.toString();
} finally {
if (stream != null) {
stream.close();
}
}
}
public static String getResponseCharset(String ctype) {
String charset = DEFAULT_CHARSET;
if (!StringUtils.isEmpty(ctype)) {
String[] params = ctype.split(";");
for (String param : params) {
param = param.trim();
if (param.startsWith("charset")) {
String[] pair = param.split("=", 2);
if (pair.length == 2) {
if (!StringUtils.isEmpty(pair[1])) {
charset = pair[1].trim();
}
}
break;
}
}
}
return charset;
}
/**
* 使用默認的UTF-8字符集反編碼請求參數值。
*
* @param value 參數值
* @return 反編碼後的參數值
*/
public static String decode(String value) {
return decode(value, DEFAULT_CHARSET);
}
/**
* 使用默認的UTF-8字符集編碼請求參數值。
*
* @param value 參數值
* @return 編碼後的參數值
*/
public static String encode(String value) {
return encode(value, DEFAULT_CHARSET);
}
/**
* 使用指定的字符集反編碼請求參數值。
*
* @param value 參數值
* @param charset 字符集
* @return 反編碼後的參數值
*/
public static String decode(String value, String charset) {
String result = null;
if (!StringUtils.isEmpty(value)) {
try {
result = URLDecoder.decode(value, charset);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return result;
}
/**
* 使用指定的字符集編碼請求參數值。
*
* @param value 參數值
* @param charset 字符集
* @return 編碼後的參數值
*/
public static String encode(String value, String charset) {
String result = null;
if (!StringUtils.isEmpty(value)) {
try {
result = URLEncoder.encode(value, charset);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return result;
}
/**
* 從URL中提取所有的參數。
*
* @param query URL地址
* @return 參數映射
*/
public static Map<String, String> splitUrlQuery(String query) {
Map<String, String> result = new HashMap<String, String>();
String[] pairs = query.split("&");
if (pairs != null && pairs.length > 0) {
for (String pair : pairs) {
String[] param = pair.split("=", 2);
if (param != null && param.length == 2) {
result.put(param[0], param[1]);
}
}
}
return result;
}
}
Constants.java
/**
* 公用常量類。
*
* @author carver.gu
* @since 1.0, Sep 12, 2009
*/
public abstract class Constants {
/** TOP協議入參共享參數 **/
public static final String APP_KEY = "app_key";
public static final String FORMAT = "format";
public static final String METHOD = "method";
public static final String TIMESTAMP = "timestamp";
public static final String VERSION = "v";
public static final String SIGN = "sign";
public static final String SIGN_METHOD = "sign_method";
public static final String PARTNER_ID = "partner_id";
public static final String SESSION = "session";
public static final String SIMPLIFY = "simplify";
public static final String TARGET_APP_KEY = "target_app_key";
/** TOP協議出參共享參數 */
public static final String ERROR_RESPONSE = "error_response";
public static final String ERROR_CODE = "code";
public static final String ERROR_MSG = "msg";
public static final String ERROR_SUB_CODE = "sub_code";
public static final String ERROR_SUB_MSG = "sub_msg";
/** 奇門協議共享參數 */
public static final String QIMEN_CLOUD_ERROR_RESPONSE = "response";
public static final String QM_ROOT_TAG = "request";
public static final String QM_CUSTOMER_ID = "customerId";
public static final String QM_CONTENT_TYPE = "text/xml;charset=utf-8";
public static final String QM_CONTENT_TYPE_JSON = "application/json;charset=utf-8";
/** TOP默認時間格式 **/
public static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
/** TOP Date默認時區 **/
public static final String DATE_TIMEZONE = "GMT+8";
/** UTF-8字符集 **/
public static final String CHARSET_UTF8 = "UTF-8";
/** HTTP請求相關 **/
public static final String METHOD_POST = "POST";
public static final String METHOD_GET = "GET";
public static final String CTYPE_FORM_DATA = "application/x-www-form-urlencoded";
public static final String CTYPE_FILE_UPLOAD = "multipart/form-data";
public static final String CTYPE_TEXT_XML = "text/xml";
public static final String CTYPE_APPLICATION_XML = "application/xml";
public static final String CTYPE_TEXT_PLAIN = "text/plain";
public static final String CTYPE_APP_JSON = "application/json";
/** GBK字符集 **/
public static final String CHARSET_GBK = "GBK";
/** TOP JSON 應格式 */
public static final String FORMAT_JSON = "json";
/** TOP XML 應格式 */
public static final String FORMAT_XML = "xml";
/** TOP JSON 新格式 */
public static final String FORMAT_JSON2 = "json2";
/** TOP XML 新格式 */
public static final String FORMAT_XML2 = "xml2";
/** MD5簽名方式 */
public static final String SIGN_METHOD_MD5 = "md5";
/** HMAC簽名方式 */
public static final String SIGN_METHOD_HMAC = "hmac";
/** HMAC-SHA256簽名方式 */
public static final String SIGN_METHOD_HMAC_SHA256 = "hmac-sha256";
/** SDK版本號 */
public static final String SDK_VERSION = "top-sdk-java-20190108";
/** 異步多活SDK版本號 */
public static final String SDK_VERSION_CLUSTER = "top-sdk-java-cluster-20190108";
/** httpdns SDK版本號 */
public static final String SDK_VERSION_HTTPDNS = "top-sdk-java-httpdns-20190108";
/** httpdns SDK版本號 */
public static final String QIMEN_SDK_VERSION_HTTPDNS = "top-qimen-sdk-java-httpdns";
/** 響應編碼 */
public static final String ACCEPT_ENCODING = "Accept-Encoding";
public static final String CONTENT_ENCODING = "Content-Encoding";
public static final String CONTENT_ENCODING_GZIP = "gzip";
/** 默認媒體類型 **/
public static final String MIME_TYPE_DEFAULT = "application/octet-stream";
/** 默認流式讀取緩衝區大小 **/
public static final int READ_BUFFER_SIZE = 1024 * 4;
public static final String TOP_HTTP_DNS_HOST = "TOP_HTTP_DNS_HOST";
/** API網關請求content type **/
public static final String CONTENT_TYPE_XML = "xml";
public static final String CONTENT_TYPE_JSON = "json";
public static final String CONTENT_TYPE_FORM = "form";
public static final String RESPONSE_TYPE_TOP = "top";
public static final String RESPONSE_TYPE_QIMEN = "qimen1";
public static final String RESPONSE_TYPE_QIMEN2 = "qimen2";
public static final String RESPONSE_TYPE_DINGTALK_OAPI = "dingtalk";
/** 釘釘調用方式 TOP標準格式,form-data */
public static final String CALL_TYPE_TOP = "top";
/** 釘釘調用方式 OAPI兼容格式,application/json */
public static final String CALL_TYPE_OAPI = "oapi";
}
FileItem.java
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* 文件包裝類,支持本地文件、字節數組和輸入流三種方式。
*
* @author carver.gu
* @since 1.0, Sep 12, 2009
*/
public class FileItem {
private Contract contract;
/**
* 基於本地文件的構造器,適用於上傳本地文件。
*
* @param file 本地文件
*/
public FileItem(final File file) {
this.contract = new LocalContract(file);
}
/**
* 基於文件絕對路徑的構造器,適用於上傳本地文件。
*
* @param filePath 文件絕對路徑
*/
public FileItem(String filePath) {
this(new File(filePath));
}
/**
* 基於文件名和字節數組的構造器。
*
* @param fileName 文件名
* @param content 文件字節數組
*/
public FileItem(String fileName, byte[] content) {
this(fileName, content, null);
}
/**
* 基於文件名、字節數組和媒體類型的構造器。
*
* @param fileName 文件名
* @param content 文件字節數組
* @param mimeType 媒體類型,如:image/jpeg, text/plain
*/
public FileItem(String fileName, byte[] content, String mimeType) {
this.contract = new ByteArrayContract(fileName, content, mimeType);
}
/**
* 基於文件名和字節流的構造器,適應於全流式上傳,減少本地內存開銷。
*
* @param fileName 文件名
* @param content 文件字節流
*/
public FileItem(String fileName, InputStream stream) {
this(fileName, stream, null);
}
/**
* 基於文件名、字節流和媒體類型的構造器,適應於全流式上傳,減少本地內存開銷。
*
* @param fileName 文件名
* @param content 文件字節流
* @param mimeType 媒體類型,如:image/jpeg, text/plain
*/
public FileItem(String fileName, InputStream stream, String mimeType) {
this.contract = new StreamContract(fileName, stream, mimeType);
}
public boolean isValid() {
return this.contract.isValid();
}
public String getFileName() {
return this.contract.getFileName();
}
public String getMimeType() throws IOException {
return this.contract.getMimeType();
}
public long getFileLength() {
return this.contract.getFileLength();
}
public void write(OutputStream output) throws IOException {
this.contract.write(output);
}
private static interface Contract {
public boolean isValid();
public String getFileName();
public String getMimeType();
public long getFileLength();
public void write(OutputStream output) throws IOException;
}
private static class LocalContract implements Contract {
private File file;
public LocalContract(File file) {
this.file = file;
}
public boolean isValid() {
return this.file != null && this.file.exists() && this.file.isFile();
}
public String getFileName() {
return this.file.getName();
}
public String getMimeType() {
return Constants.MIME_TYPE_DEFAULT;
}
public long getFileLength() {
return this.file.length();
}
public void write(OutputStream output) throws IOException {
InputStream input = null;
try {
input = new FileInputStream(this.file);
byte[] buffer = new byte[Constants.READ_BUFFER_SIZE];
int n = 0;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
}
} finally {
if (input != null) {
input.close();
}
}
}
}
private static class ByteArrayContract implements Contract {
private String fileName;
private byte[] content;
private String mimeType;
public ByteArrayContract(String fileName, byte[] content, String mimeType) {
this.fileName = fileName;
this.content = content;
this.mimeType = mimeType;
}
public boolean isValid() {
return this.content != null && this.fileName != null;
}
public String getFileName() {
return this.fileName;
}
public String getMimeType() {
if (this.mimeType == null) {
return Constants.MIME_TYPE_DEFAULT;
} else {
return this.mimeType;
}
}
public long getFileLength() {
return this.content.length;
}
public void write(OutputStream output) throws IOException {
output.write(this.content);
}
}
private static class StreamContract implements Contract {
private String fileName;
private InputStream stream;
private String mimeType;
public StreamContract(String fileName, InputStream stream, String mimeType) {
this.fileName = fileName;
this.stream = stream;
this.mimeType = mimeType;
}
public boolean isValid() {
return this.stream != null && this.fileName != null;
}
public String getFileName() {
return this.fileName;
}
public String getMimeType() {
if (this.mimeType == null) {
return Constants.MIME_TYPE_DEFAULT;
} else {
return this.mimeType;
}
}
public long getFileLength() {
return 0L;
}
public void write(OutputStream output) throws IOException {
try {
byte[] buffer = new byte[Constants.READ_BUFFER_SIZE];
int n = 0;
while (-1 != (n = stream.read(buffer))) {
output.write(buffer, 0, n);
}
} finally {
if (stream != null) {
stream.close();
}
}
}
}
}
StringUtils.java
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 字符串工具類。
*
* @author carver.gu
* @since 1.0, Sep 12, 2009
*/
public abstract class StringUtils {
/**
* An empty immutable <code>String</code> array.
*/
public static final String[] EMPTY_STRING_ARRAY = new String[0];
private static final TimeZone TZ_GMT8 = TimeZone.getTimeZone(Constants.DATE_TIMEZONE);
private static final Pattern PATTERN_CIDR = Pattern.compile("^(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})/(\\d{1,2})$");
private static final String QUOT = """;
private static final String AMP = "&";
private static final String APOS = "'";
private static final String GT = ">";
private static final String LT = "<";
private StringUtils() {}
/**
* 檢查指定的字符串是否爲空。
* <ul>
* <li>SysUtils.isEmpty(null) = true</li>
* <li>SysUtils.isEmpty("") = true</li>
* <li>SysUtils.isEmpty(" ") = true</li>
* <li>SysUtils.isEmpty("abc") = false</li>
* </ul>
*
* @param value 待檢查的字符串
* @return true/false
*/
public static boolean isEmpty(String value) {
int strLen;
if (value == null || (strLen = value.length()) == 0) {
return true;
}
for (int i = 0; i < strLen; i++) {
if ((Character.isWhitespace(value.charAt(i)) == false)) {
return false;
}
}
return true;
}
/**
* 檢查對象是否爲數字型字符串,包含負數開頭的。
*/
public static boolean isNumeric(Object obj) {
if (obj == null) {
return false;
}
char[] chars = obj.toString().toCharArray();
int length = chars.length;
if(length < 1)
return false;
int i = 0;
if(length > 1 && chars[0] == '-')
i = 1;
for (; i < length; i++) {
if (!Character.isDigit(chars[i])) {
return false;
}
}
return true;
}
/**
* 檢查指定的字符串列表是否不爲空。
*/
public static boolean areNotEmpty(String... values) {
boolean result = true;
if (values == null || values.length == 0) {
result = false;
} else {
for (String value : values) {
result &= !isEmpty(value);
}
}
return result;
}
/**
* 把通用字符編碼的字符串轉化爲漢字編碼。
*/
public static String unicodeToChinese(String unicode) {
StringBuilder out = new StringBuilder();
if (!isEmpty(unicode)) {
for (int i = 0; i < unicode.length(); i++) {
out.append(unicode.charAt(i));
}
}
return out.toString();
}
/**
* 把名稱轉換爲小寫加下劃線的形式。
*/
public static String toUnderlineStyle(String name) {
StringBuilder newName = new StringBuilder();
int len = name.length();
for (int i = 0; i < len; i++) {
char c = name.charAt(i);
if (Character.isUpperCase(c)) {
if (i > 0) {
newName.append("_");
}
newName.append(Character.toLowerCase(c));
} else {
newName.append(c);
}
}
return newName.toString();
}
/**
* 把名稱轉換爲首字母小寫的駝峯形式。
*/
public static String toCamelStyle(String name) {
StringBuilder newName = new StringBuilder();
int len = name.length();
for (int i = 0; i < len; i++) {
char c = name.charAt(i);
if (i == 0) {
newName.append(Character.toLowerCase(c));
} else {
newName.append(c);
}
}
return newName.toString();
}
/**
* 把字符串解釋爲日期對象,採用yyyy-MM-dd HH:mm:ss的格式。
*/
public static Date parseDateTime(String str) {
DateFormat format = new SimpleDateFormat(Constants.DATE_TIME_FORMAT);
format.setTimeZone(TZ_GMT8);
try {
return format.parse(str);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
/**
* 對日期進行字符串格式化,採用yyyy-MM-dd HH:mm:ss的格式。
*/
public static String formatDateTime(Date date) {
DateFormat format = new SimpleDateFormat(Constants.DATE_TIME_FORMAT);
format.setTimeZone(TZ_GMT8);
return format.format(date);
}
/**
* 對日期進行字符串格式化,採用指定的格式。
*/
public static String formatDateTime(Date date, String pattern) {
DateFormat format = new SimpleDateFormat(pattern);
format.setTimeZone(TZ_GMT8);
return format.format(date);
}
/**
* XML字符轉義包括(<,>,',&,")五個字符.
*
* @param value 所需轉義的字符串
*
* @return 轉義後的字符串 @
*/
public static String escapeXml(String value) {
StringBuilder writer = new StringBuilder();
char[] chars = value.trim().toCharArray();
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
switch (c) {
case '<':
writer.append(LT);
break;
case '>':
writer.append(GT);
break;
case '\'':
writer.append(APOS);
break;
case '&':
writer.append(AMP);
break;
case '\"':
writer.append(QUOT);
break;
default:
if ((c == 0x9) || (c == 0xA) || (c == 0xD) || ((c >= 0x20) && (c <= 0xD7FF))
|| ((c >= 0xE000) && (c <= 0xFFFD)) || ((c >= 0x10000) && (c <= 0x10FFFF)))
writer.append(c);
}
}
return writer.toString();
}
/**
* 獲取類的get/set屬性名稱集合。
*
* @param clazz 類
* @param isGet 是否獲取讀方法,true爲讀方法,false爲寫方法
* @return 屬性名稱集合
*/
public static Set<String> getClassProperties(Class<?> clazz, boolean isGet) {
Set<String> propNames = new HashSet<String>();
try {
if(clazz == null){
return propNames;
}
BeanInfo info = Introspector.getBeanInfo(clazz);
PropertyDescriptor[] props = info.getPropertyDescriptors();
for (PropertyDescriptor prop : props) {
String name = prop.getName();
Method method;
if (isGet) {
method = prop.getReadMethod();
} else {
method = prop.getWriteMethod();
}
if (!"class".equals(name) && method != null) {
propNames.add(name);
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return propNames;
}
//-----------------------------------------------------------------------
/**
* <p>Checks whether the <code>String</code> contains only
* digit characters.</p>
*
* <p><code>Null</code> and empty String will return
* <code>false</code>.</p>
*
* @param str the <code>String</code> to check
* @return <code>true</code> if str contains only unicode numeric
*/
public static boolean isDigits(String str) {
if (StringUtils.isEmpty(str)) {
return false;
}
for (int i = 0; i < str.length(); i++) {
if (!Character.isDigit(str.charAt(i))) {
return false;
}
}
return true;
}
/**
* <p>Splits the provided text into an array, separator specified.
* This is an alternative to using StringTokenizer.</p>
*
* <p>The separator is not included in the returned String array.
* Adjacent separators are treated as one separator.
* For more control over the split use the StrTokenizer class.</p>
*
* <p>A <code>null</code> input String returns <code>null</code>.</p>
*
* <pre>
* StringUtils.split(null, *) = null
* StringUtils.split("", *) = []
* StringUtils.split("a.b.c", '.') = ["a", "b", "c"]
* StringUtils.split("a..b.c", '.') = ["a", "b", "c"]
* StringUtils.split("a:b:c", '.') = ["a:b:c"]
* StringUtils.split("a b c", ' ') = ["a", "b", "c"]
* </pre>
*
* @param str the String to parse, may be null
* @param separatorChar the character used as the delimiter
* @return an array of parsed Strings, <code>null</code> if null String input
* @since 2.0
*/
public static String[] split(String str, char separatorChar) {
return splitWorker(str, separatorChar, false);
}
/**
* Performs the logic for the <code>split</code> and
* <code>splitPreserveAllTokens</code> methods that do not return a
* maximum array length.
*
* @param str the String to parse, may be <code>null</code>
* @param separatorChar the separate character
* @param preserveAllTokens if <code>true</code>, adjacent separators are
* treated as empty token separators; if <code>false</code>, adjacent
* separators are treated as one separator.
* @return an array of parsed Strings, <code>null</code> if null String input
*/
private static String[] splitWorker(String str, char separatorChar, boolean preserveAllTokens) {
// Performance tuned for 2.0 (JDK1.4)
if (str == null) {
return null;
}
int len = str.length();
if (len == 0) {
return EMPTY_STRING_ARRAY;
}
List<String> list = new ArrayList<String>();
int i = 0, start = 0;
boolean match = false;
boolean lastMatch = false;
while (i < len) {
if (str.charAt(i) == separatorChar) {
if (match || preserveAllTokens) {
list.add(str.substring(start, i));
match = false;
lastMatch = true;
}
start = ++i;
continue;
}
lastMatch = false;
match = true;
i++;
}
if (match || (preserveAllTokens && lastMatch)) {
list.add(str.substring(start, i));
}
return (String[]) list.toArray(new String[list.size()]);
}
/**
* Performs the logic for the <code>split</code> and
* <code>splitPreserveAllTokens</code> methods that return a maximum array
* length.
*
* @param str the String to parse, may be <code>null</code>
* @param separatorChars the separate character
* @param max the maximum number of elements to include in the
* array. A zero or negative value implies no limit.
* @param preserveAllTokens if <code>true</code>, adjacent separators are
* treated as empty token separators; if <code>false</code>, adjacent
* separators are treated as one separator.
* @return an array of parsed Strings, <code>null</code> if null String input
*/
private static String[] splitWorker(String str, String separatorChars, int max, boolean preserveAllTokens) {
// Performance tuned for 2.0 (JDK1.4)
// Direct code is quicker than StringTokenizer.
// Also, StringTokenizer uses isSpace() not isWhitespace()
if (str == null) {
return null;
}
int len = str.length();
if (len == 0) {
return EMPTY_STRING_ARRAY;
}
List<String> list = new ArrayList<String>();
int sizePlus1 = 1;
int i = 0, start = 0;
boolean match = false;
boolean lastMatch = false;
if (separatorChars == null) {
// Null separator means use whitespace
while (i < len) {
if (Character.isWhitespace(str.charAt(i))) {
if (match || preserveAllTokens) {
lastMatch = true;
if (sizePlus1++ == max) {
i = len;
lastMatch = false;
}
list.add(str.substring(start, i));
match = false;
}
start = ++i;
continue;
}
lastMatch = false;
match = true;
i++;
}
} else if (separatorChars.length() == 1) {
// Optimise 1 character case
char sep = separatorChars.charAt(0);
while (i < len) {
if (str.charAt(i) == sep) {
if (match || preserveAllTokens) {
lastMatch = true;
if (sizePlus1++ == max) {
i = len;
lastMatch = false;
}
list.add(str.substring(start, i));
match = false;
}
start = ++i;
continue;
}
lastMatch = false;
match = true;
i++;
}
} else {
// standard case
while (i < len) {
if (separatorChars.indexOf(str.charAt(i)) >= 0) {
if (match || preserveAllTokens) {
lastMatch = true;
if (sizePlus1++ == max) {
i = len;
lastMatch = false;
}
list.add(str.substring(start, i));
match = false;
}
start = ++i;
continue;
}
lastMatch = false;
match = true;
i++;
}
}
if (match || (preserveAllTokens && lastMatch)) {
list.add(str.substring(start, i));
}
return (String[]) list.toArray(new String[list.size()]);
}
/**
* <p>Splits the provided text into an array, separators specified.
* This is an alternative to using StringTokenizer.</p>
*
* <p>The separator is not included in the returned String array.
* Adjacent separators are treated as one separator.
* For more control over the split use the StrTokenizer class.</p>
*
* <p>A <code>null</code> input String returns <code>null</code>.
* A <code>null</code> separatorChars splits on whitespace.</p>
*
* <pre>
* StringUtils.split(null, *) = null
* StringUtils.split("", *) = []
* StringUtils.split("abc def", null) = ["abc", "def"]
* StringUtils.split("abc def", " ") = ["abc", "def"]
* StringUtils.split("abc def", " ") = ["abc", "def"]
* StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
* </pre>
*
* @param str the String to parse, may be null
* @param separatorChars the characters used as the delimiters,
* <code>null</code> splits on whitespace
* @return an array of parsed Strings, <code>null</code> if null String input
*/
public static String[] split(String str, String separatorChars) {
return splitWorker(str, separatorChars, -1, false);
}
/**
* 判斷指定的IP地址是否在IP段裏面。
*
* @param ipAddr IP地址
* @param cidrAddr 用CIDR表示法的IP段信息
* @return true/false
*/
public static boolean isIpInRange(String ipAddr, String cidrAddr) {
Matcher matcher = PATTERN_CIDR.matcher(cidrAddr);
if (!matcher.matches()) {
throw new IllegalArgumentException("Invalid CIDR address: " + cidrAddr);
}
int[] minIpParts = new int[4];
int[] maxIpParts = new int[4];
String[] ipParts = matcher.group(1).split("\\.");
int intMask = Integer.parseInt(matcher.group(2));
for (int i = 0; i < ipParts.length; i++) {
int ipPart = Integer.parseInt(ipParts[i]);
if (intMask >= 8) {
minIpParts[i] = ipPart;
maxIpParts[i] = ipPart;
intMask -= 8;
} else if (intMask > 0) {
minIpParts[i] = ipPart >> intMask;
maxIpParts[i] = ipPart | (0xFF >> intMask);
intMask = 0;
} else {
minIpParts[i] = 1;
maxIpParts[i] = 0xFF - 1;
}
}
String[] realIpParts = ipAddr.split("\\.");
for (int i = 0; i < realIpParts.length; i++) {
int realIp = Integer.parseInt(realIpParts[i]);
if (realIp < minIpParts[i] || realIp > maxIpParts[i]) {
return false;
}
}
return true;
}
/**
* 將列表中的對象連接成字符串
*
* @param objs
* @param sep
* @return
*/
public static String join(Iterable<?> objs, String sep) {
StringBuilder buf = new StringBuilder();
join(buf, objs, sep);
return buf.toString();
}
/** 將列表中的對象連接起來。 */
public static void join(StringBuilder buf, Iterable<?> objs, String sep) {
try {
join((Appendable) buf, objs, sep);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/** 將列表中的對象連接起來。 */
public static void join(Appendable buf, Iterable<?> objs, String sep) throws IOException {
if (objs == null) {
return;
}
if (sep == null) {
sep = "";
}
for (Iterator<?> i = objs.iterator(); i.hasNext();) {
buf.append(String.valueOf(i.next()));
if (i.hasNext()) {
buf.append(sep);
}
}
}
}
JsonUtils.java
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List;
public class JsonUtils {
// 定義jackson對象
private static final ObjectMapper MAPPER = new ObjectMapper();
/**
* 將對象轉換成json字符串。
* @param data
* @return
*/
public static String objectToJson(Object data) {
try {
String string = MAPPER.writeValueAsString(data);
return string;
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
/**
* 將json結果集轉化爲對象
*
* @param jsonData json數據
* @param
* @return
*/
public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {
try {
T t = MAPPER.readValue(jsonData, beanType);
return t;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 將json數據轉換成pojo對象list
* <p>Title: jsonToList</p>
* <p>Description: </p>
* @param jsonData
* @param beanType
* @return
*/
public static <T>List<T> jsonToList(String jsonData, Class<T> beanType) {
JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
try {
List<T> list = MAPPER.readValue(jsonData, javaType);
return list;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}