org.nervousync.beans.servlet.response.ResponseInfo Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of utils-jdk11 Show documentation
Show all versions of utils-jdk11 Show documentation
Java utility collections, development by Nervousync Studio (NSYC)
/*
* Licensed to the Nervousync Studio (NSYC) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.nervousync.beans.servlet.response;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.http.HttpResponse;
import java.util.*;
import java.util.zip.GZIPInputStream;
import javax.net.ssl.HttpsURLConnection;
import org.nervousync.http.header.SimpleHeader;
import org.nervousync.utils.FileUtils;
import org.nervousync.utils.IOUtils;
import org.nervousync.commons.Globals;
import org.nervousync.utils.LoggerUtils;
import org.nervousync.utils.StringUtils;
/**
* Response information define
* 网络响应信息定义
*
* @author Steven Wee [email protected]
* @version $Revision: 1.1.2 $ $Date: Nov 11, 2022 12:25:33 $
*/
public final class ResponseInfo {
/**
* Logger instance
* 日志实例
*/
private final LoggerUtils.Logger logger = LoggerUtils.getLogger(this.getClass());
/**
* Response HTTP status code
* 响应的HTTP状态代码
*/
private int statusCode;
/**
* Response header information map
* 响应头信息映射表
*/
private final Map headerMaps = new HashMap<>();
/**
* String value for http response header "Content-Type"
* 响应头"Content-Type"的字符串值
*/
private String contentType;
/**
* Character encoding for http response data
* 响应数据使用的编码集
*/
private String charset = null;
/**
* String value of response header "identified"
* 响应头"identified"的字符串值
*/
private String identifiedCode;
/**
* Response content length
* 响应数据的长度
*/
private int contentLength;
/**
* Response content binary data bytes
* 响应数据的二进制字节数组
*/
private byte[] responseContent;
/**
* Constructor for ResponseInfo
* Parse response information from HttpResponse.ResponseInfo and ResponseBody input stream
* ResponseInfo的构造函数
* 从HttpResponse.ResponseInfo实例对象和响应体输入数据流中解析响应数据
*
* @param responseInfo Instance of HttpResponse.ResponseInfo
* HttpResponse.ResponseInfo实例对象
* @see java.net.http.HttpResponse.ResponseInfo
* @param inputStream ResponseBody input stream
* 响应体输入数据流
*/
public ResponseInfo(final HttpResponse.ResponseInfo responseInfo, final InputStream inputStream) {
this.statusCode = responseInfo.statusCode();
responseInfo.headers().map().forEach((key, values) -> {
if (key != null && values != null && !values.isEmpty()) {
StringBuilder stringBuilder = new StringBuilder();
for (String headerValue : values) {
stringBuilder.append(" ").append(headerValue);
}
this.headerMaps.put(key.toUpperCase(), stringBuilder.substring(1));
}
});
this.contentType = this.headerMaps.get("CONTENT-TYPE");
if (this.contentType != null && this.contentType.contains("charset=")) {
this.charset = this.contentType.substring(this.contentType.indexOf("charset="));
if (this.contentType.contains("\"")) {
this.charset = this.charset.substring(0, this.charset.indexOf("\""));
}
this.charset = this.charset.substring(this.charset.indexOf("=") + 1);
if (this.charset.contains(";")) {
this.charset = this.charset.substring(0, this.charset.indexOf(";"));
}
}
this.identifiedCode = this.headerMaps.get("IDENTIFIED");
GZIPInputStream gzipInputStream = null;
try {
if (this.headerMaps.getOrDefault("CONTENT-ENCODING", Globals.DEFAULT_VALUE_STRING).contains("gzip")) {
gzipInputStream = new GZIPInputStream(inputStream);
this.responseContent = IOUtils.readBytes(gzipInputStream);
} else {
this.responseContent = IOUtils.readBytes(inputStream);
}
} catch (IOException e) {
this.responseContent = new byte[0];
} finally {
IOUtils.closeStream(gzipInputStream);
IOUtils.closeStream(inputStream);
}
this.contentLength = this.responseContent.length;
}
/**
* Constructor for ResponseInfo
* Parse response information from HttpURLConnection instance
* ResponseInfo的构造函数
* 从HttpURLConnection实例对象解析响应数据
*
* @param urlConnection Instance of HttpURLConnection
* HttpURLConnection实例对象
* @see java.net.HttpURLConnection
*/
public ResponseInfo(final HttpURLConnection urlConnection) {
InputStream inputStream = null;
ByteArrayOutputStream byteArrayOutputStream = null;
try {
this.statusCode = urlConnection.getResponseCode();
this.contentLength = urlConnection.getContentLength();
if (this.statusCode == HttpsURLConnection.HTTP_OK) {
this.contentType = urlConnection.getContentType();
if (this.contentType != null
&& this.contentType.contains("charset=")) {
this.charset = this.contentType.substring(this.contentType.indexOf("charset="));
if (this.contentType.contains("\"")) {
this.charset = this.charset.substring(0, this.charset.indexOf("\""));
}
this.charset = this.charset.substring(this.charset.indexOf("=") + 1);
if (this.charset.contains(";")) {
this.charset = this.charset.substring(0, this.charset.indexOf(";"));
}
}
inputStream = urlConnection.getInputStream();
if (Optional.ofNullable(urlConnection.getContentEncoding())
.map(contentEncoding -> contentEncoding.toLowerCase().contains("gzip"))
.orElse(Boolean.FALSE)) {
inputStream = new GZIPInputStream(inputStream);
}
} else {
inputStream = urlConnection.getErrorStream();
}
Map> headerFields = urlConnection.getHeaderFields();
if (headerFields != null && !headerFields.isEmpty()) {
for (Map.Entry> entry : headerFields.entrySet()) {
List headerValues = entry.getValue();
if (entry.getKey() != null && headerValues != null && !headerValues.isEmpty()) {
StringBuilder stringBuilder = new StringBuilder();
for (String headerValue : headerValues) {
stringBuilder.append(" ").append(headerValue);
}
this.headerMaps.put(entry.getKey().toUpperCase(), stringBuilder.substring(1));
}
}
}
byteArrayOutputStream = new ByteArrayOutputStream(Globals.DEFAULT_BUFFER_SIZE);
byte[] buffer = new byte[Globals.DEFAULT_BUFFER_SIZE];
if (inputStream != null) {
int readLength;
while ((readLength = inputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, readLength);
}
}
this.responseContent = byteArrayOutputStream.toByteArray();
if (this.charset == null) {
String tempContent = new String(this.responseContent, Globals.DEFAULT_ENCODING);
if (tempContent.contains("charset=")) {
this.charset = tempContent.substring(tempContent.indexOf("charset="));
this.charset = this.charset.substring(0, this.charset.indexOf("\""));
this.charset = this.charset.substring(this.charset.indexOf("=") + 1);
if (this.charset.contains(";")) {
this.charset = this.charset.substring(0, this.charset.indexOf(";"));
}
} else {
this.charset = Globals.DEFAULT_ENCODING;
}
}
this.identifiedCode = urlConnection.getHeaderField("identified");
} catch (IOException e) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Response_Data_Error", e);
}
} finally {
IOUtils.closeStream(inputStream);
IOUtils.closeStream(byteArrayOutputStream);
}
}
/**
* Getter method for response HTTP status code
* 响应的HTTP状态代码的Getter方法
*/
public int getStatusCode() {
return statusCode;
}
/**
* Getter method for response header map
* 响应头信息映射表的Getter方法
*/
public Map getHeaderMaps() {
return headerMaps;
}
/**
* Getter method for response content type
* 响应头"Content-Type"字符串值的Getter方法
*/
public String getContentType() {
return contentType;
}
/**
* Getter method for response character encoding
* 响应数据使用的编码集的Getter方法
*/
public String getCharset() {
return charset;
}
/**
* Getter method for string value of response header "identified"
* 响应头"identified"字符串值的Getter方法
*/
public String getIdentifiedCode() {
return identifiedCode;
}
/**
* Getter method for response content length
* 响应数据的长度的Getter方法
*/
public int getContentLength() {
return contentLength;
}
/**
* Getter method for response content binary data bytes
* 响应数据的二进制字节数组的Getter方法
*/
public byte[] getResponseContent() {
return responseContent == null ? new byte[0] : responseContent.clone();
}
/**
* Parse response data to the instance list of given class type
* 转换响应数据为指定类型的对象列表
*
* @param clazz Class type
* 数据对象类
* @param Template type of list
* 列表的参数化类型
*
* @return instance list of given class type, or empty list if has error
* 数据对象列表,当有异常时返回空列表
*/
public List parseList(final Class clazz) {
return StringUtils.stringToList(this.parseString(), this.charset, clazz);
}
/**
* Parse response data to the instance of given class type
* 转换响应数据为指定类型的对象
*
* @param clazz Class type
* 数据对象类
* @param Template type of list
* 列表的参数化类型
*
* @return instance of given class type, or null if has error
* 转换后的数据实例对象,当有异常时返回null
*/
public T parseObject(final Class clazz) {
if (StringUtils.notBlank(this.contentType)
&& (this.contentType.toLowerCase().contains("xml")
|| this.contentType.toLowerCase().contains("json")
|| this.contentType.toLowerCase().contains("yaml")
|| this.contentType.toLowerCase().contains("yml"))) {
return StringUtils.stringToObject(this.parseString(), clazz);
}
ByteArrayInputStream byteArrayInputStream = null;
ObjectInputStream objectInputStream = null;
try {
byteArrayInputStream = new ByteArrayInputStream(this.responseContent);
objectInputStream = new ObjectInputStream(byteArrayInputStream);
return clazz.cast(objectInputStream.readObject());
} catch (Exception e) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Convert_Object_Error", e);
}
return null;
} finally {
IOUtils.closeStream(byteArrayInputStream);
IOUtils.closeStream(objectInputStream);
}
}
/**
* Parse response data to string
* 转换响应数据为字符串
*
* @return String value of response data or empty string if an UnsupportedEncodingException occurs
* 响应数据字符串,当有UnsupportedEncodingException异常时返回空字符串
*/
public String parseString() {
String charsetName = StringUtils.isEmpty(this.charset) ? Globals.DEFAULT_ENCODING : this.charset;
try {
String string = new String(this.getResponseContent(), charsetName);
while (string.charAt(string.length() - 1) == '\n') {
string = string.substring(0, string.length() - 1);
}
while (string.charAt(string.length() - 1) == '\r') {
string = string.substring(0, string.length() - 1);
}
return string;
} catch (UnsupportedEncodingException e) {
this.logger.error("Response_Data_Error", e);
return Globals.DEFAULT_VALUE_STRING;
}
}
/**
* Parse response data to local file and save to target path
* 转换响应数据为文件,并写入数据到目标地址
*
* @param savePath Target save path
* 目标地址
*
* @return Instance of java.io.File
* java.io.File实例对象
* @throws FileNotFoundException
* If an error occurs when save binary data to target path
* 当写入数据到目标地址时捕获异常
*/
public File parseFile(final String savePath) throws FileNotFoundException {
return FileUtils.saveFile(this.getResponseContent(), savePath) ? FileUtils.getFile(savePath) : null;
}
/**
* Retrieve response header value by given header name
* 根据给定的响应头键值读取对应的数据值
*
* @param headerName Response header name
* 响应头键值
*
* @return Response header value or empty string if header name not exists
* 响应头数据值,如果数据不存在则返回空字符串
*/
public String getHeader(final String headerName) {
return this.headerMaps.getOrDefault(headerName.toUpperCase(), Globals.DEFAULT_VALUE_STRING);
}
/**
* Retrieve response header list
* 获取响应头数据列表
*
* @return Response header list. Convert key-value to SimpleHeader instance
* 响应头数据列表,转换键-值为SimpleHeader实例对象
*/
public List headerList() {
List headerList = new ArrayList<>();
for (Map.Entry entry : this.headerMaps.entrySet()) {
headerList.add(new SimpleHeader(entry.getKey(), entry.getValue()));
}
return headerList;
}
}