123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- package com.kingdee.eas.custom.beisen.utils;
- import com.alibaba.fastjson.JSON;
- import com.alibaba.fastjson.JSONArray;
- import com.alibaba.fastjson.JSONObject;
- import okhttp3.*;
- import org.apache.log4j.Logger;
- import java.io.IOException;
- import java.util.concurrent.TimeUnit;
- /**
- * 北森API调用工具类(单例模式)
- */
- public class BeisenApiClient {
- private static final Logger logger = Logger.getLogger(BeisenApiClient.class);
- private static final MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json; charset=utf-8");
- private static final int MAX_RETRIES = 3;
- // 单例实例
- private static volatile BeisenApiClient instance;
- private final OkHttpClient httpClient;
- private final BeisenTokenManager tokenManager;
- // 私有构造函数
- private BeisenApiClient() {
- this.httpClient = buildHttpClient();
- this.tokenManager = BeisenTokenManager.getInstance();
- }
- /**
- * 获取单例实例
- */
- public static BeisenApiClient getInstance() {
- if (instance == null) {
- synchronized (BeisenApiClient.class) {
- if (instance == null) {
- instance = new BeisenApiClient();
- }
- }
- }
- return instance;
- }
- /**
- * api调用qun
- *
- * @param apiUrl
- * @param requestData
- * @return
- * @throws IOException
- */
- public JSONObject callApi(String apiUrl, JSONObject requestData) throws IOException {
- return callApi(apiUrl, requestData, "POST");
- }
- public JSONObject callApi(String apiUrl, JSONArray dataArray) throws IOException {
- return callApi(apiUrl, dataArray, "POST");
- }
- public JSONObject callPutApi(String apiUrl, JSONObject requestData) throws IOException {
- return callApi(apiUrl, requestData, "PUT");
- }
- public JSONObject callGetApi(String apiUrl, JSONObject requestData) throws IOException {
- return callApi(apiUrl, requestData, "GET");
- }
- public JSONObject callGetApi(String apiUrl, JSONArray dataArray) throws IOException {
- return callApi(apiUrl, dataArray, "GET");
- }
- /**
- * api调用
- *
- * @param apiUrl
- * @param requestData
- * @return
- * @throws IOException
- */
- public JSONObject callApi(String apiUrl, JSONObject requestData, String method) throws IOException {
- return callApiInternal(apiUrl, requestData, true, method);
- }
- public JSONObject callApi(String apiUrl, JSONArray dataArray, String method) throws IOException {
- return callApiInternal(apiUrl, dataArray, true, method);
- }
- // 核心API调用逻辑----------------------------------------------------------
- /**
- * 通用API调用方法
- *
- * @param requestBody 支持JSONObject/JSONArray
- */
- private JSONObject callApiInternal(String apiUrl, Object requestBody, boolean retryOnTokenExpired, String method)
- throws IOException {
- int retryCount = 0;
- JSONObject handleResponse = new JSONObject();
- while (retryCount <= MAX_RETRIES) {
- try {
- String accessToken = tokenManager.getAccessToken();
- Request request = buildRequest(apiUrl, requestBody, accessToken, method);
- try (Response response = httpClient.newCall(request).execute()) {
- handleResponse = handleResponse(response, apiUrl, method);
- return handleResponse;
- }
- } catch (IOException e) {
- if (shouldRetry(retryOnTokenExpired, retryCount, e)) {
- retryCount++;
- handleTokenRefresh(retryCount);
- continue;
- }else {
- retryCount++;
- break;
- }
- }
- }
- return handleResponse;
- //不抛出,使用调用的地方存储msg
- // throw new IOException("API request failed after " + MAX_RETRIES + " attempts");
- }
- // 响应处理逻辑-------------------------------------------------------------
- private JSONObject handleResponse(Response response, String apiUrl, String method) throws IOException {
- String responseBody = response.body() != null ? response.body().string() : "null";
-
- if (!response.isSuccessful()) {
- handleHttpError(responseBody, apiUrl, method);
- }
-
- JSONObject jsonResponse = parseResponse(responseBody, apiUrl);
- validateBusinessStatus(jsonResponse, apiUrl);
- return jsonResponse;
- }
- private void handleHttpError(String errorBody, String apiUrl, String method) throws IOException {
-
- logger.error("API request failed "+
- ", URL: " + apiUrl + ", Method: " + method +
- ", Body: " + errorBody);
- System.out.print("调用错误"+errorBody);
- // throw new IOException("HTTP error: " + response.code());
- }
- private JSONObject parseResponse(String responseBody, String apiUrl) throws IOException {
- try {
- return JSON.parseObject(responseBody);
- } catch (Exception e) {
- logger.error("Invalid JSON response from API. URL: " + apiUrl + ", Response: " + responseBody);
- throw new IOException("Failed to parse API response", e);
- }
- }
- private void validateBusinessStatus(JSONObject jsonResponse, String apiUrl) throws IOException {
- int apiCode = jsonResponse.getIntValue("code");
- if (apiCode != 200) {
- String apiMessage = jsonResponse.getString("message");
- logger.error("API business error. Code: " + apiCode +
- ", Message: " + apiMessage + ", URL: " + apiUrl);
- // throw new IOException("Business error: " + apiMessage + " (code: " + apiCode + ")");
- }
- }
- // Token重试逻辑-----------------------------------------------------------
- private boolean shouldRetry(boolean retryOnTokenExpired, int retryCount, Exception e) {
- return retryOnTokenExpired &&
- isTokenExpiredError(e) &&
- retryCount < MAX_RETRIES;
- }
- private void handleTokenRefresh(int retryCount) {
- logger.warn("Token may have expired, refreshing and retrying... (" +
- retryCount + "/" + MAX_RETRIES + ")");
- try {
- tokenManager.refreshToken();
- } catch (IOException ex) {
- logger.error("Failed to refresh token during retry", ex);
- }
- }
- // 请求构建----------------------------------------------------------------
- private Request buildRequest(String apiUrl, Object requestBody, String accessToken, String method) {
- String jsonString = convertToJsonString(requestBody);
- RequestBody body = RequestBody.create(JSON_MEDIA_TYPE, jsonString);
- if (requestBody instanceof JSONObject) {
- if (((JSONObject) requestBody).size() == 0) {
- body = null;
- }
- }
- return new Request.Builder()
- .url(apiUrl)
- .addHeader("Authorization", "Bearer " + accessToken)
- .addHeader("Content-Type", "application/json")
- .method(method, body)
- .build();
- }
- private String convertToJsonString(Object data) {
- if (data instanceof JSONObject) {
- return ((JSONObject) data).toJSONString();
- } else if (data instanceof JSONArray) {
- return ((JSONArray) data).toJSONString();
- }
- throw new IllegalArgumentException("Unsupported request data type: " + data.getClass());
- }
- // 辅助方法---------------------------------------------------------------
- private boolean isTokenExpiredError(Exception e) {
- String msg = e.getMessage();
- return msg != null && (msg.contains("401") ||
- msg.contains("Unauthorized") ||
- msg.contains("token"));
- }
- private OkHttpClient buildHttpClient() {
- return new OkHttpClient.Builder()
- .connectTimeout(15, TimeUnit.SECONDS)
- .writeTimeout(15, TimeUnit.SECONDS)
- .readTimeout(45, TimeUnit.SECONDS)
- .connectionPool(new ConnectionPool(50, 5, TimeUnit.MINUTES))
- .retryOnConnectionFailure(true)
- .build();
- }
- }
|