From f77777a0555c1e54c9cf6a67dc106b407722fe8f Mon Sep 17 00:00:00 2001
From: Bravepping <1131302745@qq.com>
Date: Mon, 21 Apr 2025 11:17:19 +0800
Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E9=A1=B9=E7=9B=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.idea/mybatisx/templates.xml | 4 +-
pom.xml | 9 ++
.../java/com/ping/study/config/WebMvc.java | 17 ++-
.../ping/study/controller/NbaController.java | 6 +
.../controller/tx/LiveInfoController.java | 24 ++++
.../study/controller/tx/MatchController.java | 50 ++++++++
.../controller/tx/TokenRefreshController.java | 22 ++++
.../com/ping/study/mapper/GamesMapper.java | 5 +-
.../study/model/dto/tx/LiveInfoRequest.java | 42 +++++++
.../study/model/dto/tx/MatchListRequest.java | 18 +++
.../com/ping/study/model/vo/tx/MatchInfo.java | 11 ++
.../ping/study/model/vo/tx/MatchResponse.java | 14 +++
src/main/java/com/ping/study/pojo/Games.java | 10 +-
.../study/service/tx/LiveInfoService.java | 77 +++++++++++++
.../ping/study/service/tx/MatchService.java | 60 ++++++++++
.../study/service/tx/QQCookieService.java | 36 ++++++
.../study/service/tx/QQRequestService.java | 49 ++++++++
.../service/tx/QQTokenRefreshService.java | 50 ++++++++
.../study/service/tx/SportsQqService.java | 36 ++++++
.../tx/TxSportTokenRefreshService.java | 108 ++++++++++++++++++
.../java/com/ping/study/utils/NbaApi.java | 48 ++++++--
.../ping/study/utils/tx/CKeyGenerator.java | 46 ++++++++
src/main/resources/application.yml | 4 +
src/main/resources/mapper/GamesMapper.xml | 26 +++--
24 files changed, 747 insertions(+), 25 deletions(-)
create mode 100644 src/main/java/com/ping/study/controller/tx/LiveInfoController.java
create mode 100644 src/main/java/com/ping/study/controller/tx/MatchController.java
create mode 100644 src/main/java/com/ping/study/controller/tx/TokenRefreshController.java
create mode 100644 src/main/java/com/ping/study/model/dto/tx/LiveInfoRequest.java
create mode 100644 src/main/java/com/ping/study/model/dto/tx/MatchListRequest.java
create mode 100644 src/main/java/com/ping/study/model/vo/tx/MatchInfo.java
create mode 100644 src/main/java/com/ping/study/model/vo/tx/MatchResponse.java
create mode 100644 src/main/java/com/ping/study/service/tx/LiveInfoService.java
create mode 100644 src/main/java/com/ping/study/service/tx/MatchService.java
create mode 100644 src/main/java/com/ping/study/service/tx/QQCookieService.java
create mode 100644 src/main/java/com/ping/study/service/tx/QQRequestService.java
create mode 100644 src/main/java/com/ping/study/service/tx/QQTokenRefreshService.java
create mode 100644 src/main/java/com/ping/study/service/tx/SportsQqService.java
create mode 100644 src/main/java/com/ping/study/service/tx/TxSportTokenRefreshService.java
create mode 100644 src/main/java/com/ping/study/utils/tx/CKeyGenerator.java
diff --git a/.idea/mybatisx/templates.xml b/.idea/mybatisx/templates.xml
index 840a8f8..58e393c 100644
--- a/.idea/mybatisx/templates.xml
+++ b/.idea/mybatisx/templates.xml
@@ -48,8 +48,8 @@
diff --git a/pom.xml b/pom.xml
index a242365..3be4919 100644
--- a/pom.xml
+++ b/pom.xml
@@ -53,6 +53,15 @@
spring-boot-starter-validation
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+
+
+
+
junit
junit
diff --git a/src/main/java/com/ping/study/config/WebMvc.java b/src/main/java/com/ping/study/config/WebMvc.java
index 87445bf..a07de3f 100644
--- a/src/main/java/com/ping/study/config/WebMvc.java
+++ b/src/main/java/com/ping/study/config/WebMvc.java
@@ -2,14 +2,27 @@ package com.ping.study.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvc implements WebMvcConfigurer {
- @Bean
- public WebClient webClient() {
+ // 原有的 NBA WebClient
+ @Bean("nbaWebClient")
+ public WebClient nbaWebClient() {
return WebClient.create("https://api.nba.cn/sib/v2");
}
+
+ // 新增的腾讯视频 WebClient
+ @Bean("tencentWebClient")
+ public WebClient tencentWebClient() {
+ return WebClient.create("https://infozb6.video.qq.com");
+ }
+
+ @Bean
+ public RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
}
diff --git a/src/main/java/com/ping/study/controller/NbaController.java b/src/main/java/com/ping/study/controller/NbaController.java
index be7941f..b305f9c 100644
--- a/src/main/java/com/ping/study/controller/NbaController.java
+++ b/src/main/java/com/ping/study/controller/NbaController.java
@@ -48,6 +48,12 @@ public class NbaController {
log.info("执行定时方法添加当天赛程");
return nbaApi.addGames();
}
+ @Scheduled(cron = "0 0 0 * * ?")
+ @RequestMapping("/updateLive")
+ public void updateLive() {
+ log.info("执行定时方法更新当天赛程直播链接");
+
+ }
@RequestMapping("/games")
public List getGames() {
log.info("获取所有赛程");
diff --git a/src/main/java/com/ping/study/controller/tx/LiveInfoController.java b/src/main/java/com/ping/study/controller/tx/LiveInfoController.java
new file mode 100644
index 0000000..766ad25
--- /dev/null
+++ b/src/main/java/com/ping/study/controller/tx/LiveInfoController.java
@@ -0,0 +1,24 @@
+package com.ping.study.controller.tx;
+
+import com.ping.study.service.tx.LiveInfoService;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import reactor.core.publisher.Mono;
+
+@RestController
+@RequestMapping("/tx/nba")
+public class LiveInfoController {
+
+ private final LiveInfoService liveInfoService;
+
+ public LiveInfoController(LiveInfoService liveInfoService) {
+ this.liveInfoService = liveInfoService;
+ }
+
+ @GetMapping("/live/{cnlid}")
+ public String getLiveInfo(@PathVariable String cnlid) {
+ return liveInfoService.getLiveInfo(cnlid);
+ }
+}
diff --git a/src/main/java/com/ping/study/controller/tx/MatchController.java b/src/main/java/com/ping/study/controller/tx/MatchController.java
new file mode 100644
index 0000000..97cbbec
--- /dev/null
+++ b/src/main/java/com/ping/study/controller/tx/MatchController.java
@@ -0,0 +1,50 @@
+package com.ping.study.controller.tx;
+
+import com.ping.study.model.dto.tx.MatchListRequest;
+import com.ping.study.service.tx.MatchService;
+import com.ping.study.service.tx.SportsQqService;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import reactor.core.publisher.Mono;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@RestController
+@RequestMapping("/tx/nba")
+public class MatchController {
+ private final SportsQqService sportsQqService;
+ private final MatchService matchService;
+
+ public MatchController(MatchService matchService,SportsQqService sportsQqService) {
+ this.sportsQqService = sportsQqService;
+ this.matchService = matchService;
+ }
+
+ @GetMapping("/matches")
+ public Mono getMatches(
+ @RequestParam(required = false, defaultValue = "100000") Integer columnId,
+ @RequestParam String startTime,
+ @RequestParam String endTime) {
+
+ MatchListRequest request = new MatchListRequest();
+ request.setColumnId(columnId);
+ request.setStartTime(LocalDate.parse(startTime));
+ request.setEndTime(LocalDate.parse(endTime));
+
+ return sportsQqService.getMatchList(request);
+ }
+
+ @GetMapping("/lives")
+ public List getPlayoffLiveIds(
+ @RequestParam String startTime,
+ @RequestParam String endTime) {
+
+ LocalDate startDate = LocalDate.parse(startTime);
+ LocalDate endDate = LocalDate.parse(endTime);
+
+ return matchService.getPlayoffLiveIdsBlocking(startDate, endDate);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/ping/study/controller/tx/TokenRefreshController.java b/src/main/java/com/ping/study/controller/tx/TokenRefreshController.java
new file mode 100644
index 0000000..2b40fbc
--- /dev/null
+++ b/src/main/java/com/ping/study/controller/tx/TokenRefreshController.java
@@ -0,0 +1,22 @@
+package com.ping.study.controller.tx;
+
+
+import com.ping.study.service.tx.TxSportTokenRefreshService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/tx")
+public class TokenRefreshController {
+
+ @Autowired
+ private TxSportTokenRefreshService txSportTokenRefreshService;
+
+
+ @RequestMapping("/refresh")
+ public Boolean refreshToken()
+ {
+ return txSportTokenRefreshService.refreshCookies();
+ }
+}
diff --git a/src/main/java/com/ping/study/mapper/GamesMapper.java b/src/main/java/com/ping/study/mapper/GamesMapper.java
index 684058a..85222ad 100644
--- a/src/main/java/com/ping/study/mapper/GamesMapper.java
+++ b/src/main/java/com/ping/study/mapper/GamesMapper.java
@@ -5,9 +5,9 @@ import com.ping.study.pojo.Games;
import java.util.List;
/**
-* @author Administrator
+* @author Ping01
* @description 针对表【games】的数据库操作Mapper
-* @createDate 2025-04-17 21:23:08
+* @createDate 2025-04-20 20:13:51
* @Entity com.ping.study.pojo.Games
*/
public interface GamesMapper {
@@ -30,4 +30,5 @@ public interface GamesMapper {
//删除所有赛程
void deleteAllGames();
+
}
diff --git a/src/main/java/com/ping/study/model/dto/tx/LiveInfoRequest.java b/src/main/java/com/ping/study/model/dto/tx/LiveInfoRequest.java
new file mode 100644
index 0000000..dfade6e
--- /dev/null
+++ b/src/main/java/com/ping/study/model/dto/tx/LiveInfoRequest.java
@@ -0,0 +1,42 @@
+package com.ping.study.model.dto.tx;
+
+import lombok.Data;
+import java.time.DayOfWeek;
+import java.util.Map;
+
+@Data
+public class LiveInfoRequest {
+
+ private String ckey;
+ private String encryptVer;
+ private String platform;
+ private String tm;
+ private String cnlid;
+ //private String cookie =
+
+ public static final String getCookie() {
+ return "pgv_pvid=67939534; fqm_pvqid=5e0a1a80-2ffb-42c9-8878-99ef08c0bd21; RK=dudkRjOGUW; ptcz=d9e319494b15cb621d9f54a8e03a1b55fb6c6c3564ff6c4985d1ff7b4797ce4e; video_platform=2; qq_domain_video_guid_verify=119f9c981e9ffd34; _qimei_uuid42=184170b170810037e9eacb93c4fe35a57c7df28f38; _qimei_q36=; _qimei_h38=215914e0566ee066f810eb4b0200000e81840b; video_guid=119f9c981e9ffd34; tvfe_boss_uuid=d41b10b066856291; eas_sid=E1i7L1k4j4D7q1D0Q5J894p636; livelink_pvid=7900946432; check_16=584445b5d815fd331bb7206205f8c603; _qimei_fingerprint=3c06d28104a1e802703470a164d81dca; vqq_refresh_token=; vqq_next_refresh_time=6196; vqq_login_time_init=1745153828; v_qq_com_session_lapse_time=1745160024778; vqq_appid=101481799; vqq_openid=2E6A77E3002C87A9CA68908FB058D4E5; vqq_access_token=308C7CAFBC867AF65212034AC90E71D9; vqq_vuserid=3468482246; vqq_vusession=Kcz0B9FBUDZuIvwHKErD3g.N";
+ }
+
+ // 密钥映射表
+ private static final Map WEEKDAY_KEYS = Map.of(
+ DayOfWeek.MONDAY, "06fc1464",
+ DayOfWeek.TUESDAY, "4244ce1b",
+ DayOfWeek.WEDNESDAY, "77de31c5",
+ DayOfWeek.THURSDAY, "e0149fa2",
+ DayOfWeek.FRIDAY, "60394ced",
+ DayOfWeek.SATURDAY, "2da639f0",
+ DayOfWeek.SUNDAY, "c2f0cf9f"
+ );
+
+ // 生成加密版本号
+ public static String generateEncryptVer(DayOfWeek dayOfWeek) {
+ int dayValue = dayOfWeek == DayOfWeek.SUNDAY ? 7 : dayOfWeek.getValue();
+ return "7." + dayValue;
+ }
+
+ // 获取当天密钥
+ public static String getTodaySecretKey() {
+ return WEEKDAY_KEYS.get(DayOfWeek.from(java.time.LocalDate.now()));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/ping/study/model/dto/tx/MatchListRequest.java b/src/main/java/com/ping/study/model/dto/tx/MatchListRequest.java
new file mode 100644
index 0000000..f1bdb7b
--- /dev/null
+++ b/src/main/java/com/ping/study/model/dto/tx/MatchListRequest.java
@@ -0,0 +1,18 @@
+package com.ping.study.model.dto.tx;
+
+import lombok.Data;
+import java.time.LocalDate;
+
+@Data
+public class MatchListRequest {
+ private Integer columnId = 100000; // 默认值
+ private LocalDate startTime;
+ private LocalDate endTime;
+
+ // 自定义参数校验逻辑(可选)
+ public void validate() {
+ if (startTime.isAfter(endTime)) {
+ throw new IllegalArgumentException("开始时间不能晚于结束时间");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/ping/study/model/vo/tx/MatchInfo.java b/src/main/java/com/ping/study/model/vo/tx/MatchInfo.java
new file mode 100644
index 0000000..1f516fa
--- /dev/null
+++ b/src/main/java/com/ping/study/model/vo/tx/MatchInfo.java
@@ -0,0 +1,11 @@
+package com.ping.study.model.vo.tx;
+
+import lombok.Data;
+
+@Data
+public class MatchInfo {
+
+ private String liveId;
+ private String matchType;
+ // 其他需要的字段...
+}
diff --git a/src/main/java/com/ping/study/model/vo/tx/MatchResponse.java b/src/main/java/com/ping/study/model/vo/tx/MatchResponse.java
new file mode 100644
index 0000000..89de24b
--- /dev/null
+++ b/src/main/java/com/ping/study/model/vo/tx/MatchResponse.java
@@ -0,0 +1,14 @@
+package com.ping.study.model.vo.tx;
+
+import lombok.Data;
+import java.util.List;
+import java.util.Map;
+
+@Data
+public class MatchResponse {
+ private Integer code;
+ private String msg;
+ private Map> data;
+
+
+}
diff --git a/src/main/java/com/ping/study/pojo/Games.java b/src/main/java/com/ping/study/pojo/Games.java
index 12b1cc1..b865b9d 100644
--- a/src/main/java/com/ping/study/pojo/Games.java
+++ b/src/main/java/com/ping/study/pojo/Games.java
@@ -1,5 +1,6 @@
package com.ping.study.pojo;
+import java.io.Serializable;
import java.util.Date;
import lombok.Data;
@@ -8,7 +9,7 @@ import lombok.Data;
* @TableName games
*/
@Data
-public class Games {
+public class Games implements Serializable {
/**
*
*/
@@ -24,6 +25,11 @@ public class Games {
*/
private String gameId;
+ /**
+ *
+ */
+ private String playId;
+
/**
*
*/
@@ -48,4 +54,6 @@ public class Games {
*
*/
private String awayTeamLogoDark;
+
+ private static final long serialVersionUID = 1L;
}
\ No newline at end of file
diff --git a/src/main/java/com/ping/study/service/tx/LiveInfoService.java b/src/main/java/com/ping/study/service/tx/LiveInfoService.java
new file mode 100644
index 0000000..a827be4
--- /dev/null
+++ b/src/main/java/com/ping/study/service/tx/LiveInfoService.java
@@ -0,0 +1,77 @@
+package com.ping.study.service.tx;
+
+import com.ping.study.model.dto.tx.LiveInfoRequest;
+import com.ping.study.utils.tx.CKeyGenerator;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Qualifier;
+
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Service;
+import org.springframework.web.reactive.function.client.WebClient;
+import reactor.core.publisher.Mono;
+
+import java.time.DayOfWeek;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Service
+@Slf4j
+public class LiveInfoService {
+
+ private final WebClient webClient;
+ private final CKeyGenerator cKeyGenerator;
+
+ private StringRedisTemplate stringRedisTemplate;
+
+ public LiveInfoService(@Qualifier("tencentWebClient")WebClient webClient, CKeyGenerator cKeyGenerator, StringRedisTemplate stringRedisTemplate) {
+ this.webClient = webClient;
+ this.cKeyGenerator = cKeyGenerator;
+ this.stringRedisTemplate = stringRedisTemplate;
+ }
+
+ // 2. 远程调用时拼接 Cookie
+ public String getCookieForRequest() {
+// 读取
+ String cookie = stringRedisTemplate.opsForValue().get("tx_sports_cookie");
+ return cookie;
+ }
+
+ public String getLiveInfo(String cnlid) {
+ String platform = "40201";
+ String ckey = cKeyGenerator.generateCKey(cnlid, platform);
+
+ // 1. 打印请求参数
+ String queryParams = String.format(
+ "ckey=%s&encrypt_ver=%s&platform=%s&tm=%d&cnlid=%s",
+ ckey,
+ LiveInfoRequest.generateEncryptVer(DayOfWeek.from(LocalDate.now())),
+ platform,
+ Instant.now().getEpochSecond(),
+ cnlid
+ );
+ log.info("请求参数: {}", queryParams);
+
+ // 2. 打印请求头(Cookie)
+ String cookie = getCookieForRequest();
+ log.info("请求头 Cookie: {}", cookie);
+
+ // 3. 发起请求
+ return webClient.get()
+ .uri(uriBuilder -> uriBuilder
+ .path("/cgi-bin/getliveinfo")
+ .queryParam("ckey", ckey)
+ .queryParam("encrypt_ver", LiveInfoRequest.generateEncryptVer(
+ DayOfWeek.from(LocalDate.now())))
+ .queryParam("platform", platform)
+ .queryParam("tm", Instant.now().getEpochSecond())
+ .queryParam("cnlid", cnlid)
+ .build())
+ .header("Cookie", "pgv_pvid=67939534; fqm_pvqid=5e0a1a80-2ffb-42c9-8878-99ef08c0bd21; RK=dudkRjOGUW; ptcz=d9e319494b15cb621d9f54a8e03a1b55fb6c6c3564ff6c4985d1ff7b4797ce4e; video_platform=2; qq_domain_video_guid_verify=119f9c981e9ffd34; _qimei_uuid42=184170b170810037e9eacb93c4fe35a57c7df28f38; _qimei_q36=; _qimei_h38=215914e0566ee066f810eb4b0200000e81840b; video_guid=119f9c981e9ffd34; tvfe_boss_uuid=d41b10b066856291; eas_sid=E1i7L1k4j4D7q1D0Q5J894p636; livelink_pvid=7900946432; check_16=584445b5d815fd331bb7206205f8c603; o2_uin=941039061; uin_cookie=o0941039061; ied_qq=o0941039061; o_cookie=941039061; pac_uid=0_ePEHB57t75p7c; LW_sid=31h7T2M8f3O5O280q0K0L365H2; LW_uid=P1J7P2i8S3R5a2r0j020t3n543; ptui_loginuin=1131302745; qq_nick=A; qq_head=https://tvpic.gtimg.cn/head/dbb128053992612c0c1327e8e32e95f8da39a3ee5e6b4b0d3255bfef95601890afd80709/346; vqq_refresh_token=; vqq_next_refresh_time=6505; vqq_login_time_init=1745154214; _qimei_fingerprint=829539b60aaa7ed28f0e5f604c391a63; main_login=qq; vqq_appid=101481799; vqq_openid=2E6A77E3002C87A9CA68908FB058D4E5; vqq_access_token=308C7CAFBC867AF65212034AC90E71D9; vqq_vuserid=3468482246; vqq_vusession=H1-ZxeRN0vDUVk4_wKLkyA.N")
+ .retrieve()
+ .bodyToMono(String.class)
+ .block();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/ping/study/service/tx/MatchService.java b/src/main/java/com/ping/study/service/tx/MatchService.java
new file mode 100644
index 0000000..22fbdda
--- /dev/null
+++ b/src/main/java/com/ping/study/service/tx/MatchService.java
@@ -0,0 +1,60 @@
+package com.ping.study.service.tx;
+
+import com.ping.study.model.vo.tx.MatchInfo;
+import com.ping.study.model.vo.tx.MatchResponse;
+import org.springframework.stereotype.Service;
+import org.springframework.web.reactive.function.client.WebClient;
+import reactor.core.publisher.Flux;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+public class MatchService {
+
+ private final WebClient webClient;
+ private static final DateTimeFormatter DATE_FORMATTER =
+ DateTimeFormatter.ofPattern("yyyy-MM-dd");
+
+ public MatchService(WebClient.Builder webClientBuilder) {
+ this.webClient = webClientBuilder
+ .baseUrl("https://matchweb.sports.qq.com")
+ .build();
+ }
+
+ /**
+ * 获取指定日期范围内所有NBA季后赛(matchType=2)的直播ID
+ */
+ public List getPlayoffLiveIdsBlocking(LocalDate startDate, LocalDate endDate) {
+ return webClient.get()
+ .uri(uriBuilder -> uriBuilder
+ .path("/matchUnion/list")
+ .queryParam("columnId", 100000)
+ .queryParam("startTime", startDate.format(DATE_FORMATTER))
+ .queryParam("endTime", endDate.format(DATE_FORMATTER))
+ .build())
+ .retrieve()
+ .bodyToMono(MatchResponse.class)
+ .flatMapMany(response -> {
+ if (response.getCode() != 0 || response.getData() == null) {
+ return Flux.error(new RuntimeException("API返回异常: " + response.getMsg()));
+ }
+ // 提取所有matchType=2的比赛
+ List liveIds = response.getData().values().stream()
+ .flatMap(List::stream)
+ .filter(match -> "2".equals(match.getMatchType()))
+ .map(MatchInfo::getLiveId)
+ .collect(Collectors.toList());
+ return Flux.fromIterable(liveIds);
+ })
+ .collectList()
+ .block(); // 阻塞等待结果
+ }
+
+ /**
+ * 获取完整比赛信息(过滤matchType=2)
+ */
+}
\ No newline at end of file
diff --git a/src/main/java/com/ping/study/service/tx/QQCookieService.java b/src/main/java/com/ping/study/service/tx/QQCookieService.java
new file mode 100644
index 0000000..4a3d062
--- /dev/null
+++ b/src/main/java/com/ping/study/service/tx/QQCookieService.java
@@ -0,0 +1,36 @@
+package com.ping.study.service.tx;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+@Service
+public class QQCookieService {
+ @Autowired
+ private StringRedisTemplate stringRedisTemplate;
+
+ private static final String REDIS_KEY = "user:nba"; // 固定 Key
+
+ // 存储 Cookie(无需 uin 参数)
+ public void saveCookie(Map cookies) {
+ stringRedisTemplate.opsForHash().putAll(REDIS_KEY, cookies);
+ stringRedisTemplate.expire(REDIS_KEY, 30, TimeUnit.DAYS);
+ }
+
+ // 获取 Cookie(无需 uin 参数)
+ public Map getCookie() {
+ Map