package com.kingdee.eas.custom.beisen.utils; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import okhttp3.*; import org.apache.log4j.Logger; import java.io.IOException; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class BeisenTokenManager { private static final Logger logger = Logger.getLogger(BeisenTokenManager.class); private static final MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json; charset=utf-8"); private static final long EXPIRY_BUFFER = 300_000; // 5分钟缓冲时间 private final OkHttpClient httpClient; private final Lock lock = new ReentrantLock(); private volatile TokenState tokenState; private final String appKey; private final String appSecret; private final String tokenUrl; // 添加单例实例 private static volatile BeisenTokenManager instance; // 私有化构造器 private BeisenTokenManager() { this(Config.APP_KEY, Config.APP_SECRET, Config.TOKEN_URL); } // 获取单例方法 public static BeisenTokenManager getInstance() { if (instance == null) { synchronized (BeisenTokenManager.class) { if (instance == null) { instance = new BeisenTokenManager(); } } } return instance; } public BeisenTokenManager(String appKey, String appSecret, String tokenUrl) { this.appKey = appKey; this.appSecret = appSecret; this.tokenUrl = tokenUrl; this.httpClient = buildHttpClient(); this.tokenState = loadInitialToken(); } public String getAccessToken() throws IOException { TokenState currentState = tokenState; if (currentState != null && !isTokenExpired(currentState)) { return currentState.getAccessToken(); } if (currentState == null || isTokenExpired(currentState)) { lock.lock(); try { currentState = tokenState; if (currentState == null || isTokenExpired(currentState)) { currentState = fetchNewToken(); tokenState = currentState; } } finally { lock.unlock(); } } return currentState.getAccessToken(); } public void refreshToken() throws IOException { TokenState currentState = tokenState; if (currentState == null || currentState.getRefreshToken() == null) { tokenState = fetchNewToken(); return; } if (isTokenExpired(currentState)) { lock.lock(); try { currentState = tokenState; if (isTokenExpired(currentState)) { tokenState = refreshToken(currentState.getRefreshToken()); } } finally { lock.unlock(); } } } private boolean isTokenExpired(TokenState state) { // 添加缓冲时间,避免在token即将过期时使用 return System.currentTimeMillis() > (state.getExpireTime() - EXPIRY_BUFFER); } private TokenState loadInitialToken() { try { return fetchNewToken(); } catch (Exception e) { logger.error("Failed to initialize token", e); throw new RuntimeException("Token initialization failed", e); } } private TokenState fetchNewToken() throws IOException { JSONObject requestBody = new JSONObject(); requestBody.put("grant_type", "client_credentials"); requestBody.put("app_key", appKey); requestBody.put("app_secret", appSecret); return executeTokenRequest(requestBody); } private TokenState refreshToken(String refreshToken) throws IOException { JSONObject requestBody = new JSONObject(); requestBody.put("grant_type", "refresh_token"); requestBody.put("refresh_token", refreshToken); return executeTokenRequest(requestBody); } private TokenState executeTokenRequest(JSONObject requestBody) throws IOException { Request request = new Request.Builder().url(tokenUrl).post(RequestBody.create(JSON_MEDIA_TYPE, requestBody.toJSONString())).build(); try (Response response = httpClient.newCall(request).execute()) { if (!response.isSuccessful()) { String errorBody = response.body() != null ? response.body().string() : "null"; logger.error("Token request failed. Code: " + response.code() + ", Body: " + errorBody); throw new IOException("Token request failed with code: " + response.code()); } String responseBody = response.body().string(); JSONObject jsonResponse = JSON.parseObject(responseBody); String accessToken = jsonResponse.getString("access_token"); String refreshToken = jsonResponse.getString("refresh_token"); Long expiresIn = jsonResponse.getLong("expires_in"); // 更健壮的空值检查 if (accessToken == null || expiresIn == null || expiresIn <= 0) { throw new IOException("Invalid token response: " + responseBody); } return new TokenState(accessToken, System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(expiresIn), refreshToken); } } private OkHttpClient buildHttpClient() { return new OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS).writeTimeout(10, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS).retryOnConnectionFailure(true).build(); } private static class TokenState { private final String accessToken; private final long expireTime; private final String refreshToken; public TokenState(String accessToken, long expireTime, String refreshToken) { this.accessToken = accessToken; this.expireTime = expireTime; this.refreshToken = refreshToken; } public String getAccessToken() { return accessToken; } public long getExpireTime() { return expireTime; } public String getRefreshToken() { return refreshToken; } } public static class Config { private static final String BESON_CONFIG_PATH = "/server/properties/beisen/BeiSenConfig.properties"; // public static String APP_KEY = "FFEC5C62AB444567AFC11E8D394CC072"; // public static String APP_SECRET = "74FE75BEE476496EAF531C2219EC10E57EDCE01D74F64557BADEEC78FBFF3B26"; // public static String TOKEN_URL = "https://openapi.italent.cn/token"; // 测试环境 // public static String APP_KEY = "FFEC5C62AB444567AFC11E8D394CC072"; // public static String APP_SECRET = "74FE75BEE476496EAF531C2219EC10E57EDCE01D74F64557BADEEC78FBFF3B26"; // 生产环境 // public static String APP_KEY = "C16FE3483B4E42FCA97686B6D01F1B3C"; // public static String APP_SECRET = "DE0EED6E741149A3842BAA89143415B3D5C76FC304AB4FCF8D4D708B8D1F1E04"; public static String TOKEN_URL = "https://openapi.italent.cn/token"; public static String APP_KEY = ""; public static String APP_SECRET = ""; static { // 从配置文件中读取配置 try { BeisenParamByPropertiesUtil beisenParamByProperties = new BeisenParamByPropertiesUtil(BESON_CONFIG_PATH); Map config = beisenParamByProperties.getConfig(); // 如果配置文件中存在配置,则覆盖默认配置 if (config != null) { // 如果配置文件中存在appKey,则覆盖默认appKey if (config.containsKey("APP_KEY")) { APP_KEY = config.get("APP_KEY"); } // 如果配置文件中存在appSecret,则覆盖默认appSecret if (config.containsKey("APP_SECRET")) { APP_SECRET = config.get("APP_SECRET"); } // 如果配置文件中存在tokenUrl,则覆盖默认tokenUrl if (config.containsKey("ACCESSTOKEN_URL")) { TOKEN_URL = config.get("ACCESSTOKEN_URL"); } } } catch (IOException e) { throw new RuntimeException(e); } } } }