com.feingto.cloud.kit.http.ClientResponse Maven / Gradle / Ivy
package com.feingto.cloud.kit.http;
import com.fasterxml.jackson.databind.JsonNode;
import com.feingto.cloud.kit.json.JSON;
import lombok.Data;
import lombok.experimental.Accessors;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import java.io.ByteArrayInputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* 客户端Http响应
*
* @author longfei
*/
@Data
@Accessors(chain = true)
public class ClientResponse implements HttpInputMessage, Closeable {
public static final String STATUS_CODE_KEY = "code";
public static final String MESSAGE_KEY = "message";
public static final HttpHeaders JSON_HEADER = buildHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
private int statusCode;
private String message;
private HttpHeaders headers;
private InputStream body;
/**
* 路由响应结果键, 默认为url最后一个"/"之后的字符串
*/
private String responseKey;
private boolean successful;
private static HttpHeaders buildHeader(String name, String value) {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add(name, value);
return httpHeaders;
}
public static ClientResponse success(String result) {
return success(new ByteArrayInputStream(result.getBytes(StandardCharsets.UTF_8)));
}
public static ClientResponse success(InputStream is) {
return new ClientResponse()
.setStatusCode(HttpStatus.OK.value())
.setBody(is)
.setSuccessful(true);
}
public static ClientResponse error(HttpStatus status, String message) {
JsonNode jsonNode = JSON.JSONObject().put(STATUS_CODE_KEY, status.value()).put(MESSAGE_KEY, message);
return new ClientResponse()
.setStatusCode(status.value())
.setHeaders(JSON_HEADER)
.setBody(new ByteArrayInputStream(jsonNode.toString().getBytes(StandardCharsets.UTF_8)))
.setMessage(message)
.setSuccessful(false);
}
public static ClientResponse requestTimeout() {
return error(HttpStatus.REQUEST_TIMEOUT);
}
public static ClientResponse gatewayTimeout() {
return error(HttpStatus.GATEWAY_TIMEOUT);
}
public static ClientResponse badRequest() {
return error(HttpStatus.BAD_REQUEST);
}
public static ClientResponse badGateway() {
return error(HttpStatus.BAD_GATEWAY);
}
public static ClientResponse methodNotAllowed() {
return error(HttpStatus.METHOD_NOT_ALLOWED);
}
public static ClientResponse notFound() {
return error(HttpStatus.NOT_FOUND);
}
public static ClientResponse internalServerError() {
return error(HttpStatus.INTERNAL_SERVER_ERROR);
}
public static ClientResponse serviceUnavailable() {
return error(HttpStatus.SERVICE_UNAVAILABLE);
}
public static ClientResponse unAuthrized() {
return error(HttpStatus.UNAUTHORIZED);
}
public static ClientResponse forbidden() {
return error(HttpStatus.FORBIDDEN);
}
public static ClientResponse tooManyRequests() {
return error(HttpStatus.TOO_MANY_REQUESTS);
}
public static ClientResponse error(HttpStatus status) {
return error(status, status.getReasonPhrase());
}
public static ClientResponse error(String message) {
return error(HttpStatus.INTERNAL_SERVER_ERROR, message);
}
public static ClientResponse merge(List clientResponses) {
if (Objects.isNull(clientResponses)) {
return ClientResponse.error("No result return");
}
if (clientResponses.stream().anyMatch(Objects::isNull)) {
return ClientResponse.error("Some requests has no result return");
}
return clientResponses.stream()
.filter(response -> !response.isSuccessful())
.findFirst()
.orElseGet(() -> Optional.of(clientResponses)
// 单路由
.filter(responses -> responses.size() == 1)
.map(responses -> Optional.of(responses.get(0))
.filter(response -> response.getHeaders().containsKey(HttpHeaders.CONTENT_DISPOSITION))
// 不包含二进制头的单路由返回响应结果
.orElseGet(() -> ClientResponse
.success(responses.get(0).getBody())
.setHeaders(responses.get(0).getHeaders())))
// 多路由
.orElseGet(() -> {
// 合并响应头
MultiValueMap headers = new LinkedMultiValueMap<>();
clientResponses.forEach(clientResponse ->
clientResponse.getHeaders().entrySet().stream()
.filter(entry -> !headers.containsKey(entry.getKey()))
.forEach(entry -> headers.put(entry.getKey(), entry.getValue())));
// 返回合并后的响应结果
return ClientResponse
.success(JSON.reduce(clientResponses.stream()
.map(response -> {
if (StringUtils.hasText(response.getResponseKey())) {
return JSON.JSONObject()
.set(response.getResponseKey(), response.getJsonNode());
} else {
return response.getJsonNode();
}
})
.collect(Collectors.toList())))
.setHeaders(new HttpHeaders(headers));
}));
}
public String getResponseBody() {
try (InputStream is = this.body) {
return StreamUtils.copyToString(is, StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
public JsonNode getJsonNode() {
return Optional.ofNullable(this.getResponseBody())
.filter(StringUtils::hasText)
.map(JSON::read)
.orElse(JSON.JSONObject());
}
public void toXml(String contentType) {
this.body = new ByteArrayInputStream(Optional.of(contentType)
.filter(it -> it.contains("_"))
.map(it -> it.split("_"))
.filter(it -> it.length > 1)
.map(it -> it[1].toUpperCase())
.map(it -> String.format("%s", it, System.lineSeparator()))
.orElse("")
.concat(Optional.ofNullable(this.getResponseBody())
.filter(StringUtils::hasText)
.map(JSON::json2xml)
.orElse("")).getBytes(StandardCharsets.UTF_8));
}
@Override
public void close() throws IOException {
if (Objects.nonNull(this.body)) {
this.body.close();
}
}
}