+ * 这个异常标识传入的SDK方法的参数错误 + *
+ * + *+ * 通常情况下{@link ClientException}开发者额外处理它,因为它通常出现在开发的时候, + *
+ * + *+ * 例如: 调用重命名文件的接口,要求源文件路径和新的文件名是必填的参数, + * 如果开发者在调用的过程中没填装个参数,则程序会抛出{@link ClientException} + *
+ * + * @author yanlongqi + * @date 2024/1/31 10:36 + */ +public class ArgsException extends RuntimeException { + + /** + * 用户名 + */ + private String username; + + /** + * 错误信息 + */ + private String errorMessage; + + /** + * 构建一个没有任何参数的异常实例 + */ + public ArgsException() { + super(); + } + + /** + * 创建具有异常的实例 + * + * @param cause 一个异常 + */ + public ArgsException(Throwable cause) { + this(null, cause); + } + + + /** + * 创建一个包含错误消息和异常的实例 + * + * @param errorMessage 错误信息 + * @param cause 一个异常 + */ + public ArgsException(String errorMessage, Throwable cause) { + super(null, cause); + this.errorMessage = errorMessage; + } + + + /** + * 创建一个包含错误消息的实例。 + * + * @param errorMessage 错误信息 + */ + public ArgsException(String errorMessage) { + this(errorMessage, null); + } + + @Override + public String getMessage() { + return String.format("[ErrorMessage]:%s", errorMessage); + } + + /** + * 获取一个错误信息 + * + * @return 错误信息 + */ + public String getErrorMessage() { + return errorMessage; + } + +} diff --git a/src/main/java/com/jhinno/sdk/openapi/ClientErrorCode.java b/src/main/java/com/jhinno/sdk/openapi/ClientErrorCode.java new file mode 100644 index 0000000..36b223e --- /dev/null +++ b/src/main/java/com/jhinno/sdk/openapi/ClientErrorCode.java @@ -0,0 +1,54 @@ +package com.jhinno.sdk.openapi; + +/** + * 客户端错误相关常亮的定义 + * + * @author yanlongqi + * @date 2024/1/30 13:25 + */ +public class ClientErrorCode { + /** + * 未知错误。这意味着错误不是预期的。 + */ + public static final String UNKNOWN = "Unknown"; + + /** + * 未知主机。当引发{@link java.net.UnknownHostException}时返回此错误。 + */ + public static final String UNKNOWN_HOST = "UnknownHost"; + + /** + * 连接超时。 + */ + public static final String CONNECTION_TIMEOUT = "ConnectionTimeout"; + + /** + * Socket超时 + */ + public static final String SOCKET_TIMEOUT = "SocketTimeout"; + + /** + * Socket异常 + */ + public static final String SOCKET_EXCEPTION = "SocketException"; + + /** + * 服务器端拒绝连接。 + */ + public static final String CONNECTION_REFUSED = "ConnectionRefused"; + + /** + * 输入流不可重复读取。 + */ + public static final String NONREPEATABLE_REQUEST = "NonRepeatableRequest"; + + /** + * 读取输入流时线程中断。 + */ + public static final String INPUTSTREAM_READING_ABORTED = "InputStreamReadingAborted"; + + /** + * SSL异常 + */ + public static final String SSL_EXCEPTION = "SslException"; +} diff --git a/src/main/java/com/jhinno/sdk/openapi/ClientException.java b/src/main/java/com/jhinno/sdk/openapi/ClientException.java new file mode 100644 index 0000000..2ab5af9 --- /dev/null +++ b/src/main/java/com/jhinno/sdk/openapi/ClientException.java @@ -0,0 +1,152 @@ +package com.jhinno.sdk.openapi; + +/** + *+ * 这个异常是客户端访问景行API时抛出的异常。 + *
+ * + *+ * {@link ClientException}表示景行API客户端任何异常的类。 + * 一般情况下,{@link ClientException}要么发生在发送请求之前,要么发生在收到OSS服务器端的响应之后。 + * 例如:如果在尝试发送请求时网络断开,则SDK将抛出{@link ClientException}实例。 + *
+ * + *+ * {@link ServiceException}是从景行API响应的错误代码转换而来的。 + * 例如,当请求的接口参数错误时,SDK会抛出一个{@link ServiceException}或其子类实例, + * 并带有特定的错误代码,调用者可以用特定的逻辑来处理。 + *
+ * + * @author yanlongqi + * @date 2024/1/30 11:27 + */ +public class ClientException extends RuntimeException { + + /** + * 请求id + */ + private String requestId; + + /** + * 错误编号 + */ + private String errorCode; + + + /** + * 错误信息 + */ + private String errorMessage; + + /** + * 创建一个默认的实例 + */ + public ClientException() { + super(); + } + + /** + * 创建一个包含错误消息的实例。 + * + * @param errorMessage 错误信息 + */ + public ClientException(String errorMessage) { + this(errorMessage, null); + } + + /** + * 创建具有异常的实例 + * + * @param cause 一个异常 + */ + public ClientException(Throwable cause) { + this(null, cause); + } + + /** + * 创建一个包含错误消息和异常的实例 + * + * @param errorMessage 错误信息 + * @param cause 一个异常 + */ + public ClientException(String errorMessage, Throwable cause) { + super(null, cause); + this.errorMessage = errorMessage; + this.errorCode = ClientErrorCode.UNKNOWN; + this.requestId = ClientErrorCode.UNKNOWN; + } + + /** + * 使用错误消息、错误代码、请求Id创建实例 + * + * @param errorMessage 错误信息 + * @param errorCode 错误编码 + * @param requestId 请求id + */ + public ClientException(String errorMessage, String errorCode, String requestId) { + this(errorMessage, errorCode, requestId, null); + } + + /** + * 创建包含错误消息、错误代码、请求Id和异常的实例。 + * + * @param errorMessage 错误信息 + * @param errorCode 错误编码 + * @param requestId 请求id + * @param cause 一个异常 + */ + public ClientException(String errorMessage, String errorCode, String requestId, Throwable cause) { + this(errorMessage, cause); + this.errorCode = errorCode; + this.requestId = requestId; + } + + /** + * 创建包含错误消息、错误代码、异常的实例。 + * + * @param errorMessage 错误信息 + * @param errorCode 错误编码 + * @param cause 一个异常 + */ + public ClientException(String errorMessage, String errorCode, Throwable cause) { + this(errorMessage, cause); + this.errorCode = errorCode; + } + + /** + * 获取请求id。 + * + * @return 请求Id + */ + public String getRequestId() { + return requestId; + } + + /** + * 获取错误代码。 + * + * @return 错误代码 + */ + public String getErrorCode() { + return errorCode; + } + + /** + * 获取错误消息。 + * + * @return 字符串中的错误消息 + */ + public String getErrorMessage() { + return errorMessage; + } + + @Override + public String getMessage() { + return String.format( + "%s\n[ErrorCode]: %s\n[RequestId]:%s", + getErrorMessage(), + errorCode != null ? errorCode : "", + requestId != null ? requestId : "" + ); + } +} diff --git a/src/main/java/com/jhinno/sdk/openapi/CommonConstant.java b/src/main/java/com/jhinno/sdk/openapi/CommonConstant.java new file mode 100644 index 0000000..5fb3a9b --- /dev/null +++ b/src/main/java/com/jhinno/sdk/openapi/CommonConstant.java @@ -0,0 +1,24 @@ +package com.jhinno.sdk.openapi; + +/** + * @author yanlongqi + * @date 2024/1/31 10:17 + */ +public class CommonConstant { + + /** + * 请求成功时的标识 + */ + public static final String SUCCESS = "success"; + + /** + * 请求失败时的标识 + */ + public static final String FAILED = "failed"; + + + /** + * 默认的token有效时间(单位:分钟) + */ + public static final int DEFAULT_TOKEN_EFFECTIVE_TIME = 30; +} diff --git a/src/main/java/com/jhinno/sdk/openapi/ServiceException.java b/src/main/java/com/jhinno/sdk/openapi/ServiceException.java new file mode 100644 index 0000000..2205f75 --- /dev/null +++ b/src/main/java/com/jhinno/sdk/openapi/ServiceException.java @@ -0,0 +1,64 @@ +package com.jhinno.sdk.openapi; + +/** + *+ * 这是表示任何预期或意外的景行API服务器端错误的基本异常类。 + *
+ * + *+ * {@link ServiceException}是从景行API响应的错误代码转换而来的。 + * 例如,当请求的接口参数错误时,SDK会抛出一个{@link ServiceException}或其子类实例, + * 并带有特定的错误代码,调用者可以用特定的逻辑来处理。 + *
+ * + *+ * 另一方面{@link ClientException}表示景行API客户端任何异常的类。 + * 一般情况下,{@link ClientException}要么发生在发送请求之前,要么发生在收到OSS服务器端的响应之后。 + * 例如,如果在尝试发送请求时网络断开,则SDK将抛出{@link ClientException}实例。 + *
+ * + *+ * 所以一般来说,调用者只需要正确处理{@link ServiceException}, + * 因为它意味着请求被处理,但由于不同的错误而没有完全完成。 + * 异常中的错误代码是良好的诊断信息。有时这些例外是完全预料到的。 + *
+ * + * @author yanlongqi + * @date 2024/1/30 11:35 + */ +public class ServiceException extends RuntimeException { + + /** + * 错误信息 + */ + private String errorMessage; + + /** + * 创建一个默认的实例 + */ + public ServiceException() { + super(); + } + + + /** + * 创建一个包含错误消息的实例。 + * + * @param errorMessage 错误信息 + */ + public ServiceException(String errorMessage) { + this(errorMessage, null); + } + + + /** + * 创建一个包含错误消息和异常的实例 + * + * @param errorMessage 错误信息 + * @param cause 一个异常 + */ + public ServiceException(String errorMessage, Throwable cause) { + super(null, cause); + this.errorMessage = errorMessage; + } +} diff --git a/src/main/java/com/jhinno/sdk/openapi/api/JHApiExecution.java b/src/main/java/com/jhinno/sdk/openapi/api/JHApiExecution.java new file mode 100644 index 0000000..60685b8 --- /dev/null +++ b/src/main/java/com/jhinno/sdk/openapi/api/JHApiExecution.java @@ -0,0 +1,74 @@ +package com.jhinno.sdk.openapi.api; + +import com.alibaba.fastjson2.TypeReference; +import com.jhinno.sdk.openapi.ArgsException; +import com.jhinno.sdk.openapi.CommonConstant; +import com.jhinno.sdk.openapi.ServiceException; +import com.jhinno.sdk.openapi.api.auth.AuthPathConstant; +import com.jhinno.sdk.openapi.api.auth.Token; +import com.jhinno.sdk.openapi.client.JHApiClient; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author yanlongqi + * @date 2024/1/30 19:39 + */ +public class JHApiExecution { + + /** + * JHApiClient实例 + */ + private static JHApiClient JH_API_CLIENT; + + + /** + * 用户令牌的缓存 + */ + private static final Map+ * 通过{@link DefaultHttpClientConfig}默认配置的最大连接数和服务每次能并行接收的请求数量构建一个JHApiClient实例 + *
+ * + * @param baseUrl 景行接口服务的基础地址 + * @return JHApiClient的实例 + */ + public static JHApiClient build(String baseUrl) { + return build(createHttpClients(DefaultHttpClientConfig.MAX_TOTAL, DefaultHttpClientConfig.MAX_PER_ROUT), baseUrl); + } + + /** + * 通过外部传入的{@link CloseableHttpClient}构建一个请求客户端 + *
+ *
+ * @param httpClient 请求连接池
+ * @param baseUrl 景行接口服务的基础地址
+ * @return JHApiClient的实例
+ */
+ public static JHApiClient build(CloseableHttpClient httpClient, String baseUrl) {
+ return new JHApiClient(httpClient, baseUrl);
+ }
+
+
+ /**
+ * 初始化一个HTTP客户端实例
+ *
+ * @param maxTotal 设置最大连接数
+ * @param maxPerRoute 服务每次能并行接收的请求数量
+ * @return 返回一个可关闭的HTTP客户端示例
+ */
+ public static CloseableHttpClient createHttpClients(int maxTotal, int maxPerRoute) {
+ SSLContextBuilder builder = new SSLContextBuilder();
+ try {
+ builder.loadTrustMaterial(null, (x509Certificates, s) -> true);
+ SSLConnectionSocketFactory sslref = new SSLConnectionSocketFactory(builder.build(), NoopHostnameVerifier.INSTANCE);
+ Registry
+ * 设置一个HTTP请求的配置
+ *
+ * {@link JHApiClient } 默认只配置了 socket连接超时的时间(socketTimeout) 、连接超时的时间(connectTimeout)、
+ * 请求超时的时间(connectionRequestTimeout)这三项,其默认配置在{@link DefaultHttpClientConfig}中。
+ * 如果你要自定义你自己的配置,则可以通过{@link HttpClients}构建自己的RequestConfig来请求接口
+ *