| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- package com.malk.shunfeng.service.impl;
- import com.alibaba.fastjson.JSON;
- import com.alibaba.fastjson.JSONObject;
- import com.malk.server.common.McException;
- import com.malk.shunfeng.server.zoom.ZoomConf;
- import com.malk.shunfeng.server.zoom.ZoomR;
- import com.malk.shunfeng.service.ZoomClient;
- import com.malk.utils.UtilHttp;
- import com.malk.utils.UtilMap;
- import com.malk.utils.UtilToken;
- import lombok.extern.slf4j.Slf4j;
- import org.apache.commons.lang3.StringUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import java.util.Map;
- /**
- * Zoom 会议 API 客户端实现
- * -
- * 使用 OAuth 2.0 Account Credentials,Token 通过 UtilToken 缓存复用(key="sf-zoom-token")
- */
- @Slf4j
- @Service
- public class ZoomClientImpl implements ZoomClient {
- @Autowired
- private ZoomConf zoomConf;
- /** UtilToken 缓存 key */
- private static final String TOKEN_KEY = "sf-zoom-token";
- /** Zoom 会议接口路径前缀 */
- private static final String PATH_USERS_ME_MEETINGS = "/users/me/meetings";
- /**
- * 创建会议
- * POST /users/me/meetings
- */
- @Override
- public ZoomR createMeeting(Map body) {
- String url = zoomConf.getApiHost() + PATH_USERS_ME_MEETINGS;
- Map header = buildAuthHeader();
- String rsp = UtilHttp.doPost(url, header, null, body);
- return parseAndAssert(rsp, "创建 Zoom 会议失败");
- }
- /**
- * 更新会议(PATCH,成功响应 204 No Content)
- * PATCH /meetings/{meetingId}
- * fixme: 204 响应无 body,parseAndAssert 不做调用
- */
- @Override
- public void updateMeeting(String meetingId, Map body) {
- String url = zoomConf.getApiHost() + "/meetings/" + meetingId;
- Map header = buildAuthHeader();
- String rsp = UtilHttp.doPatch(url, header, null, body);
- // fixme: PATCH 成功返回 204 空响应,只打印日志,不解析
- log.debug("[Zoom] updateMeeting 响应: {}", rsp);
- if (StringUtils.isNotBlank(rsp)) {
- ZoomR r = JSON.parseObject(rsp, ZoomR.class);
- r.assertSuccess();
- }
- }
- /**
- * 删除会议
- * DELETE /meetings/{meetingId}
- */
- @Override
- public void deleteMeeting(String meetingId) {
- String url = zoomConf.getApiHost() + "/meetings/" + meetingId;
- Map header = buildAuthHeader();
- String rsp = UtilHttp.doDelete(url, header, null, (Map) null);
- log.debug("[Zoom] deleteMeeting 响应: {}", rsp);
- if (StringUtils.isNotBlank(rsp)) {
- ZoomR r = JSON.parseObject(rsp, ZoomR.class);
- r.assertSuccess();
- }
- }
- /**
- * 查询会议详情
- * GET /meetings/{meetingId}
- */
- @Override
- public ZoomR getMeeting(String meetingId) {
- String url = zoomConf.getApiHost() + "/meetings/" + meetingId;
- Map header = buildAuthHeader();
- String rsp = UtilHttp.doGet(url, header, null);
- return parseAndAssert(rsp, "查询 Zoom 会议失败");
- }
- /**
- * 获取 Access Token(缓存复用,过期自动刷新)
- * POST {oauthUrl}?grant_type=account_credentials&account_id={accountId}
- * Basic Auth: clientId:clientSecret
- */
- private String getAccessToken() {
- // ppExt: 先从缓存取,命中则直接返回,避免重复申请
- String cached = UtilToken.get(TOKEN_KEY);
- if (StringUtils.isNotBlank(cached)) {
- return cached;
- }
- Map param = UtilMap.map("grant_type, account_id", "account_credentials", zoomConf.getAccountId());
- String rsp = UtilHttp.doRequest(
- UtilHttp.METHOD.POST,
- zoomConf.getOauthUrl(),
- null, param, null, null,
- zoomConf.getClientId(), zoomConf.getClientSecret()
- );
- McException.assertException(StringUtils.isBlank(rsp), "ZOOM_TOKEN_NULL", "Zoom Token 获取失败");
- JSONObject tokenJson = JSON.parseObject(rsp);
- String accessToken = tokenJson.getString("access_token");
- Long expiresIn = tokenJson.getLong("expires_in");
- McException.assertException(StringUtils.isBlank(accessToken), "ZOOM_TOKEN_EMPTY", "Zoom Token 为空");
- // fixme: expiresIn 单位为秒,UtilToken.put 单位为毫秒,内部冗余 5s 容错
- UtilToken.put(TOKEN_KEY, accessToken, expiresIn * 1000);
- return accessToken;
- }
- /**
- * 构建 Zoom Bearer Token 请求 Header
- */
- private Map buildAuthHeader() {
- return UtilMap.map("Authorization", "Bearer " + getAccessToken());
- }
- private ZoomR parseAndAssert(String rsp, String errMsg) {
- log.debug("[Zoom] 响应: {}", rsp);
- McException.assertException(StringUtils.isBlank(rsp), "ZOOM_RSP_NULL", errMsg);
- ZoomR r = JSON.parseObject(rsp, ZoomR.class);
- r.assertSuccess();
- return r;
- }
- }
|