|
|
@@ -58,7 +58,11 @@ public class IpadSendUtils {
|
|
|
private final QwUserMapper qwUserMapper;
|
|
|
private final RedisCache redisCacheUrl;
|
|
|
private final String FILE_KEY = "ipad:upload:";
|
|
|
+ private final String UPLOAD_LOCK_KEY = "ipad:upload:lock:";
|
|
|
private final String USER_KEY = "ipad:user:";
|
|
|
+ private static final long UPLOAD_LOCK_MINUTES = 5;
|
|
|
+ private static final long UPLOAD_WAIT_MS = 120_000;
|
|
|
+ private static final long UPLOAD_POLL_MS = 500;
|
|
|
|
|
|
/**
|
|
|
* 发送卡片消息
|
|
|
@@ -87,24 +91,67 @@ public class IpadSendUtils {
|
|
|
return wxWorkService.SendTextMsg(dto, vo.getServerId());
|
|
|
}
|
|
|
|
|
|
- // 公共文件获取
|
|
|
- private <T> T getFile(String key, Class<T> clazz, Supplier<T> supplier) {
|
|
|
- String obj = redisCache.getCacheObject(key);
|
|
|
- T t;
|
|
|
- if(StringUtils.isEmpty(obj)){
|
|
|
- t = supplier.get();
|
|
|
- redisCache.setCacheObject(key, JSON.toJSONString(t), 3, TimeUnit.DAYS);
|
|
|
- }else{
|
|
|
- t = JSON.parseObject(obj, clazz);
|
|
|
+ private String buildUploadCacheKey(String type, Long serverId, String url) {
|
|
|
+ return FILE_KEY + type + ":" + serverId + ":" + url;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 按 iPad 服务器 + 资源 URL 缓存 CDN 上传结果,并用分布式锁避免并发重复下载/上传。
|
|
|
+ */
|
|
|
+ private <T> T getFile(Long serverId, String type, String url, Class<T> clazz, Supplier<T> supplier) {
|
|
|
+ String cacheKey = buildUploadCacheKey(type, serverId, url);
|
|
|
+ String cached = redisCache.getCacheObject(cacheKey);
|
|
|
+ if (StringUtils.isNotEmpty(cached)) {
|
|
|
+ return JSON.parseObject(cached, clazz);
|
|
|
+ }
|
|
|
+
|
|
|
+ String lockKey = UPLOAD_LOCK_KEY + type + ":" + serverId + ":" + url;
|
|
|
+ boolean locked = false;
|
|
|
+ try {
|
|
|
+ long deadline = System.currentTimeMillis() + UPLOAD_WAIT_MS;
|
|
|
+ while (System.currentTimeMillis() < deadline) {
|
|
|
+ cached = redisCache.getCacheObject(cacheKey);
|
|
|
+ if (StringUtils.isNotEmpty(cached)) {
|
|
|
+ return JSON.parseObject(cached, clazz);
|
|
|
+ }
|
|
|
+ locked = redisCacheUrl.setIfAbsent(lockKey, "1", UPLOAD_LOCK_MINUTES, TimeUnit.MINUTES);
|
|
|
+ if (locked) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ Thread.sleep(UPLOAD_POLL_MS);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!locked) {
|
|
|
+ cached = redisCache.getCacheObject(cacheKey);
|
|
|
+ if (StringUtils.isNotEmpty(cached)) {
|
|
|
+ return JSON.parseObject(cached, clazz);
|
|
|
+ }
|
|
|
+ throw new BaseException("等待文件上传超时,请稍后重试");
|
|
|
+ }
|
|
|
+
|
|
|
+ cached = redisCache.getCacheObject(cacheKey);
|
|
|
+ if (StringUtils.isNotEmpty(cached)) {
|
|
|
+ return JSON.parseObject(cached, clazz);
|
|
|
+ }
|
|
|
+
|
|
|
+ T result = supplier.get();
|
|
|
+ redisCache.setCacheObject(cacheKey, JSON.toJSONString(result), 3, TimeUnit.DAYS);
|
|
|
+ return result;
|
|
|
+ } catch (InterruptedException e) {
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
+ throw new BaseException("等待文件上传被中断");
|
|
|
+ } finally {
|
|
|
+ if (locked) {
|
|
|
+ redisCacheUrl.deleteObject(lockKey);
|
|
|
+ }
|
|
|
}
|
|
|
- return t;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 发送图片
|
|
|
*/
|
|
|
public WxWorkResponseDTO<WxwSendCDNImgMsgRespDTO> sendImg(FileVo vo){
|
|
|
- WxCdnUploadImgLinkResp resp = getFile(FILE_KEY + "img:" + vo.getUrl(), WxCdnUploadImgLinkResp.class, () -> uploadImage(vo.getUuid(), vo.getServerId(), vo.getUrl()));
|
|
|
+ WxCdnUploadImgLinkResp resp = getFile(vo.getServerId(), "img", vo.getUrl(), WxCdnUploadImgLinkResp.class, () -> uploadImage(vo.getUuid(), vo.getServerId(), vo.getUrl()));
|
|
|
WxwSendCDNImgMsgDTO dto = new WxwSendCDNImgMsgDTO();
|
|
|
dto.setCdnkey(resp.getCdn_key());
|
|
|
dto.setAeskey(resp.getAes_key());
|
|
|
@@ -128,7 +175,7 @@ public class IpadSendUtils {
|
|
|
* 发送文件
|
|
|
*/
|
|
|
public WxWorkResponseDTO<WxwSendCDNFileMsgRespDTO> sendFile(FileVo vo){
|
|
|
- WxwUploadCdnLinkFileRespDTO resp = getFile(FILE_KEY + "file:" + vo.getUrl(), WxwUploadCdnLinkFileRespDTO.class, () -> uploadFile(vo.getUuid(), vo.getServerId(), vo.getUrl()));
|
|
|
+ WxwUploadCdnLinkFileRespDTO resp = getFile(vo.getServerId(), "file", vo.getUrl(), WxwUploadCdnLinkFileRespDTO.class, () -> uploadFile(vo.getUuid(), vo.getServerId(), vo.getUrl()));
|
|
|
WxwSendCDNFileMsgDTO dto = new WxwSendCDNFileMsgDTO();
|
|
|
dto.setCdnkey(resp.getCdn_key());
|
|
|
dto.setAeskey(resp.getAes_key());
|
|
|
@@ -148,7 +195,7 @@ public class IpadSendUtils {
|
|
|
* 发送文件
|
|
|
*/
|
|
|
public WxWorkResponseDTO<WxwSendCDNVoiceMsgRespDTO> sendVoice(FileVo vo){
|
|
|
- WxwUploadCdnLinkFileRespDTO resp = getFile(FILE_KEY + "voice:" + vo.getUrl(), WxwUploadCdnLinkFileRespDTO.class, () -> uploadFile(vo.getUuid(), vo.getServerId(), vo.getUrl()));
|
|
|
+ WxwUploadCdnLinkFileRespDTO resp = getFile(vo.getServerId(), "voice", vo.getUrl(), WxwUploadCdnLinkFileRespDTO.class, () -> uploadFile(vo.getUuid(), vo.getServerId(), vo.getUrl()));
|
|
|
WxwSendCDNVoiceMsgDTO dto = new WxwSendCDNVoiceMsgDTO();
|
|
|
dto.setCdnkey(resp.getCdn_key());
|
|
|
dto.setVoice_time(vo.getVoiceTime());
|
|
|
@@ -164,7 +211,7 @@ public class IpadSendUtils {
|
|
|
* 发送文件
|
|
|
*/
|
|
|
public WxWorkResponseDTO<WxwSendCDNVideoMsgRespDTO> sendVideo(FileVo vo){
|
|
|
- WxCdnUploadVideoResp resp = getFile(FILE_KEY + "voice:" + vo.getUrl(), WxCdnUploadVideoResp.class, () -> uploadVideo(vo.getUuid(), vo.getServerId(), vo.getUrl()));
|
|
|
+ WxCdnUploadVideoResp resp = getFile(vo.getServerId(), "video", vo.getUrl(), WxCdnUploadVideoResp.class, () -> uploadVideo(vo.getUuid(), vo.getServerId(), vo.getUrl()));
|
|
|
WxwSendCDNVideoMsgDTO dto = new WxwSendCDNVideoMsgDTO();
|
|
|
dto.setCdnkey(resp.getCdn_key());
|
|
|
dto.setAeskey(resp.getAes_key());
|
|
|
@@ -198,7 +245,7 @@ public class IpadSendUtils {
|
|
|
* 发送小程序
|
|
|
*/
|
|
|
public WxWorkResponseDTO<WxWorkSendAppMsgRespDTO> sendMiniProgram(MiniProgramVo vo){
|
|
|
- WxCdnUploadImgLinkResp resp = getFile(FILE_KEY + "voice:" + vo.getImgUrl(), WxCdnUploadImgLinkResp.class, () -> uploadImage(vo.getUuid(), vo.getServerId(), vo.getImgUrl()));
|
|
|
+ WxCdnUploadImgLinkResp resp = getFile(vo.getServerId(), "img", vo.getImgUrl(), WxCdnUploadImgLinkResp.class, () -> uploadImage(vo.getUuid(), vo.getServerId(), vo.getImgUrl()));
|
|
|
WxWorkSendAppMsgDTO dto = new WxWorkSendAppMsgDTO();
|
|
|
dto.setCdnkey(resp.getCdn_key());
|
|
|
dto.setAeskey(resp.getAes_key());
|