项目完善,全自动获取腾讯体育NBA比赛直播源
This commit is contained in:
@@ -48,12 +48,6 @@ public class NbaController {
|
||||
log.info("执行定时方法添加当天赛程");
|
||||
return nbaApi.addGames();
|
||||
}
|
||||
@Scheduled(cron = "0 0 0 * * ?")
|
||||
@RequestMapping("/updateLive")
|
||||
public void updateLive() {
|
||||
log.info("执行定时方法更新当天赛程直播链接");
|
||||
|
||||
}
|
||||
@RequestMapping("/games")
|
||||
public List<Games> getGames() {
|
||||
log.info("获取所有赛程");
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.ping.study.controller.tx;
|
||||
|
||||
import com.ping.study.service.tx.LiveInfoService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
@@ -10,6 +11,7 @@ import reactor.core.publisher.Mono;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/tx/nba")
|
||||
@Slf4j
|
||||
public class LiveInfoController {
|
||||
|
||||
private final LiveInfoService liveInfoService;
|
||||
@@ -19,7 +21,7 @@ public class LiveInfoController {
|
||||
}
|
||||
|
||||
@GetMapping("/live/{cnlid}")
|
||||
public String getLiveInfo(@PathVariable String cnlid) {
|
||||
public String getLiveInfo(@PathVariable String cnlid) throws Exception {
|
||||
return liveInfoService.getLiveInfo(cnlid);
|
||||
}
|
||||
|
||||
@@ -27,7 +29,8 @@ public class LiveInfoController {
|
||||
//定时任务 从北京时间凌晨到12点,每过半个小时执行一次
|
||||
@Scheduled(cron = "0 0/30 0-11 * * ?")
|
||||
@RequestMapping("/live/refresh")
|
||||
public String refreshLiveInfo() {
|
||||
public String refreshLiveInfo() throws Exception {
|
||||
log.info("=========开始执行更新直播链接=========");
|
||||
return liveInfoService.refreshLiveInfo();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,13 +26,15 @@ public class MatchController {
|
||||
@GetMapping("/matches")
|
||||
public Mono<String> getMatches(
|
||||
@RequestParam(required = false, defaultValue = "100000") Integer columnId,
|
||||
@RequestParam String startTime,
|
||||
@RequestParam String endTime) {
|
||||
@RequestParam(required = false) String startTime,
|
||||
@RequestParam(required = false) String endTime) {
|
||||
|
||||
MatchListRequest request = new MatchListRequest();
|
||||
request.setColumnId(columnId);
|
||||
request.setStartTime(LocalDate.parse(startTime));
|
||||
request.setEndTime(LocalDate.parse(endTime));
|
||||
|
||||
LocalDate currentDate = LocalDate.now();
|
||||
request.setStartTime(startTime != null ? LocalDate.parse(startTime) : currentDate);
|
||||
request.setEndTime(endTime != null ? LocalDate.parse(endTime) : currentDate);
|
||||
|
||||
return sportsQqService.getMatchList(request);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ public interface UrlsMapper {
|
||||
int updateByPrimaryKeySelective(Urls record);
|
||||
|
||||
int updateByPrimaryKey(Urls record);
|
||||
|
||||
List<String> selectGameIds();
|
||||
|
||||
List<LiveUrl> selectUrlsListByGameId(String gameId);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.ping.study.service.tx;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ping.study.mapper.GamesMapper;
|
||||
import com.ping.study.mapper.UrlsMapper;
|
||||
@@ -35,6 +37,8 @@ public class LiveInfoService {
|
||||
private GamesMapper gamesMapper;
|
||||
@Autowired
|
||||
private UrlsMapper urlsMapper;
|
||||
@Autowired
|
||||
private TxSportTokenRefreshService txSportTokenRefreshService;;
|
||||
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
@@ -45,13 +49,18 @@ public class LiveInfoService {
|
||||
}
|
||||
|
||||
// 2. 远程调用时拼接 Cookie
|
||||
public String getCookieForRequest() {
|
||||
public String getCookieForRequest() throws JsonProcessingException {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
// 读取
|
||||
String cookie = stringRedisTemplate.opsForValue().get("tx_sports_cookie");
|
||||
return cookie;
|
||||
String cookieJson = stringRedisTemplate.opsForValue().get("tx_sports_cookie_map");
|
||||
Map<String, String> cookieMap = objectMapper.readValue(cookieJson, new TypeReference<>() {});
|
||||
return buildCookieHeader(cookieMap);
|
||||
}
|
||||
|
||||
public String getLiveInfo(String cnlid) {
|
||||
public String getLiveInfo(String cnlid) throws Exception {
|
||||
//先调用刷新cookie
|
||||
txSportTokenRefreshService.refreshCookies();
|
||||
Thread.sleep(100);
|
||||
String platform = "40201";
|
||||
String ckey = cKeyGenerator.generateCKey(cnlid, platform);
|
||||
|
||||
@@ -71,7 +80,7 @@ public class LiveInfoService {
|
||||
log.info("请求头 Cookie: {}", cookie);
|
||||
|
||||
// 3. 发起请求
|
||||
return webClient.get()
|
||||
String res = webClient.get()
|
||||
.uri(uriBuilder -> uriBuilder
|
||||
.path("/cgi-bin/getliveinfo")
|
||||
.queryParam("ckey", ckey)
|
||||
@@ -80,30 +89,51 @@ public class LiveInfoService {
|
||||
.queryParam("platform", platform)
|
||||
.queryParam("tm", Instant.now().getEpochSecond())
|
||||
.queryParam("cnlid", cnlid)
|
||||
.queryParam("defn","fhd")
|
||||
.queryParam("ufps","auto")
|
||||
.build())
|
||||
.header("Cookie", "_qimei_q32=b6ff8aedc45c2d93874747a3e7f5e3dd; ptui_loginuin=1131302745; vqq_access_token=308C7CAFBC867AF65212034AC90E71D9; lcad_appuser=CCC4A35B6047F544; tvfe_boss_uuid=d41b10b066856291; _qimei_uuid42=184170b170810037e9eacb93c4fe35a57c7df28f38; LW_sid=31h7T2M8f3O5O280q0K0L365H2; o_cookie=941039061; lcad_LDERturn=503; last_nick=%E8%85%BE%E8%AE%AF%E7%BD%91%E5%8F%8B; uin_cookie=o0941039061; lcad_LPDFturn=43; spt_uid=1829817828670177361; RK=dudkRjOGUW; ied_qq=o0941039061; lcad_LPVLturn=470; lcad_o_minduid=OCcytZR6an_BFYcypXv6ZzuBX65okAHc; pgv_pvid=67939534; lcad_LVINturn=636; pgv_info=ssid=s6516917000; last_main_login=qq; eas_sid=E1i7L1k4j4D7q1D0Q5J894p636; fqm_pvqid=5e0a1a80-2ffb-42c9-8878-99ef08c0bd21; last_avatar=https://mat1.gtimg.com/sports/sportapp/default_profile_big_after_v1_4.png; lcad_LPPBturn=28; lcad_LPSJturn=135; livelink_pvid=7900946432; LW_uid=P1J7P2i8S3R5a2r0j020t3n543; o2_uin=941039061; pac_uid=0_ePEHB57t75p7c; ptcz=d9e319494b15cb621d9f54a8e03a1b55fb6c6c3564ff6c4985d1ff7b4797ce4e; qq_domain_video_guid_verify=119f9c981e9ffd34; vqq_appid=101481799; vqq_openid=2E6A77E3002C87A9CA68908FB058D4E5; vqq_vuserid=3468482246; _qimei_fingerprint=aaf3a442da56251083fbe4352a04dc72; _qimei_q36=09d3b683102573c400e0b201300015518b19; _qimei_h38=fdedada2b12cacb7c731c46802000004418b19; vqq_vusession=jjtKD6NC-SPkVdItUGl3Sg.N; ts_last=sports.qq.com/kbsweb/mycenter.htm; ts_uid=9292458684; ukey=174520991101356433; boss_user=loginType=1&nbaVipType=0&qq=&wxOpenId=2E6A77E3002C87A9CA68908FB058D4E5&wxAppId=101481799&uKey=174520991101356433; ptag=film_video_qq_com|; main_login=qq; spt_session=CLuygiIQ7MONwAYY8ZWXwAYg1wE; spt_token=roxqAw5zstnrHn4H7DMOSbTeSkCVC0JjQGPz6Lp5Jx1-rxtW6mfo-wgg8jq41xEi; next_refresh_time=1745216492421; bossv2_isvip=-1")
|
||||
.header("Cookie", cookie)
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.block();
|
||||
|
||||
List<String> list = extractPlayUrls(res);
|
||||
log.info("提取到的播放URL: {}", list);
|
||||
return res;
|
||||
}
|
||||
|
||||
private String buildCookieHeader(Map<String, String> cookieMap) {
|
||||
return cookieMap.entrySet().stream()
|
||||
.map(e -> e.getKey() + "=" + e.getValue())
|
||||
.collect(Collectors.joining("; "));
|
||||
}
|
||||
|
||||
public List<String> extractPlayUrls(String liveInfoJson) throws Exception {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
LiveInfoResponse response = mapper.readValue(liveInfoJson, LiveInfoResponse.class);
|
||||
|
||||
// 首先将JSON字符串解析为Map结构
|
||||
Map<String, Object> responseMap = mapper.readValue(liveInfoJson, new TypeReference<Map<String, Object>>() {});
|
||||
|
||||
List<String> urls = new ArrayList<>();
|
||||
if (response.getPlay_list() != null) {
|
||||
for (LiveInfoResponse.PlayItem item : response.getPlay_list()) {
|
||||
if (item.getUrls() != null) {
|
||||
urls.addAll(item.getUrls());
|
||||
|
||||
// 检查play_list是否存在
|
||||
if (responseMap.containsKey("play_list")) {
|
||||
List<Map<String, Object>> playList = (List<Map<String, Object>>) responseMap.get("play_list");
|
||||
|
||||
for (Map<String, Object> playItem : playList) {
|
||||
// 检查urls是否存在
|
||||
if (playItem.containsKey("urls")) {
|
||||
List<String> itemUrls = (List<String>) playItem.get("urls");
|
||||
urls.addAll(itemUrls);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.info("提取到的播放URL数量: {}", urls.size());
|
||||
return urls;
|
||||
}
|
||||
|
||||
public String refreshLiveInfo() {
|
||||
public String refreshLiveInfo() throws Exception {
|
||||
List<Games> gamesList = gamesMapper.selectAll();
|
||||
for (Games games : gamesList) {
|
||||
String playId = games.getPlayId();
|
||||
@@ -112,7 +142,7 @@ public class LiveInfoService {
|
||||
try {
|
||||
List<String> urls = extractPlayUrls(liveInfo);
|
||||
log.info("提取到的播放URL: {}", urls);
|
||||
urlsMapper.updateUrlsWithGameId(games.getGameId(), urls.get(0));
|
||||
urlsMapper.updateUrlsWithGameId(games.getGameId(), urls.get(urls.size()-1));
|
||||
// 这里可以保存urls到数据库或其他处理
|
||||
} catch (Exception e) {
|
||||
log.error("解析直播信息失败");
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
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<String, String> cookies) {
|
||||
stringRedisTemplate.opsForHash().putAll(REDIS_KEY, cookies);
|
||||
stringRedisTemplate.expire(REDIS_KEY, 30, TimeUnit.DAYS);
|
||||
}
|
||||
|
||||
// 获取 Cookie(无需 uin 参数)
|
||||
public Map<String, String> getCookie() {
|
||||
Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries(REDIS_KEY);
|
||||
Map<String, String> result = new HashMap<>();
|
||||
|
||||
entries.forEach((key, value) ->
|
||||
result.put(key.toString(), value.toString())
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package com.ping.study.service.tx;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class QQRequestService {
|
||||
@Autowired
|
||||
private RestTemplate restTemplate; // 现在可以正常注入
|
||||
@Autowired
|
||||
private QQCookieService qqCookieService;
|
||||
@Autowired
|
||||
private QQTokenRefreshService tokenRefreshService;
|
||||
|
||||
// 发起请求(自动处理 Cookie 和 Token 刷新)
|
||||
public String fetchData(String uin, String apiUrl) throws IOException {
|
||||
Map<String, String> cookies = qqCookieService.getCookie();
|
||||
|
||||
// 检查 Token 是否即将过期
|
||||
long expiresIn = Long.parseLong(cookies.getOrDefault("vqq_next_refresh_time", "0"));
|
||||
if (expiresIn < 300) { // 剩余 <5 分钟时刷新
|
||||
tokenRefreshService.refreshToken();
|
||||
cookies = qqCookieService.getCookie(); // 重新加载
|
||||
}
|
||||
|
||||
// 构造请求头(模拟浏览器)
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
|
||||
cookies.forEach((name, value) -> headers.add("Cookie", name + "=" + value));
|
||||
|
||||
// 发起请求
|
||||
ResponseEntity<String> response = restTemplate.exchange(
|
||||
apiUrl,
|
||||
HttpMethod.GET,
|
||||
new HttpEntity<>(headers),
|
||||
String.class
|
||||
);
|
||||
|
||||
return response.getBody();
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package com.ping.study.service.tx;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class QQTokenRefreshService {
|
||||
@Autowired
|
||||
private QQCookieService qqCookieService;
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
// 刷新 Token
|
||||
public boolean refreshToken() throws IOException {
|
||||
Map<String, String> cookies = qqCookieService.getCookie();
|
||||
String refreshToken = cookies.get("vqq_refresh_token");
|
||||
if (refreshToken == null || refreshToken.isEmpty()) {
|
||||
throw new IllegalStateException("No refresh_token available, need re-login");
|
||||
}
|
||||
|
||||
// 调用 QQ 的 Token 刷新接口(示例,需替换真实 API)
|
||||
String url = "https://xui.ptlogin2.qq.com/refresh?refresh_token=" + refreshToken;
|
||||
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
|
||||
|
||||
if (response.getStatusCode().is2xxSuccessful()) {
|
||||
// 解析新 Token 并更新 Cookie
|
||||
String newAccessToken = parseNewToken(response.getBody());
|
||||
cookies.put("vqq_access_token", newAccessToken);
|
||||
cookies.put("vqq_next_refresh_time", "7200"); // 假设新有效期 2 小时
|
||||
qqCookieService.saveCookie(cookies);
|
||||
return true;
|
||||
} else {
|
||||
return false; // 刷新失败,需重新登录
|
||||
}
|
||||
}
|
||||
|
||||
private String parseNewToken(String responseBody) throws IOException {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode root = mapper.readTree(responseBody);
|
||||
return root.get("access_token").asText();
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,8 @@
|
||||
package com.ping.study.service.tx;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ping.study.model.vo.live.LiveInfoResponse;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
@@ -24,7 +19,8 @@ public class TxSportTokenRefreshService {
|
||||
|
||||
private final WebClient webClient;
|
||||
private final StringRedisTemplate redisTemplate;
|
||||
private static final String REDIS_COOKIE_KEY = "tx_sports_cookie";
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
private static final String REDIS_COOKIE_MAP_KEY = "tx_sports_cookie_map";
|
||||
|
||||
public TxSportTokenRefreshService(WebClient.Builder builder,
|
||||
StringRedisTemplate redisTemplate) {
|
||||
@@ -32,106 +28,65 @@ public class TxSportTokenRefreshService {
|
||||
this.redisTemplate = redisTemplate;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void initBaseCookies() {
|
||||
String baseCookies = "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; ptui_loginuin=1131302745";
|
||||
redisTemplate.opsForValue().set(REDIS_COOKIE_KEY, baseCookies, 30, TimeUnit.DAYS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新Cookie并存储到Redis
|
||||
*/
|
||||
// 在首次成功时,分离并存储基础登录态Cookie
|
||||
public boolean refreshCookies() {
|
||||
try {
|
||||
// 1. 从Redis获取基础登录态Cookie(首次需手动初始化)
|
||||
String baseCookie = redisTemplate.opsForValue().get(REDIS_COOKIE_KEY);
|
||||
log.info("当前Cookie: {}", baseCookie);
|
||||
// 2. 携带基础Cookie发起请求
|
||||
String cookieJson = redisTemplate.opsForValue().get(REDIS_COOKIE_MAP_KEY);
|
||||
if (cookieJson == null) {
|
||||
log.error("Redis 中未找到 Cookie,无法刷新");
|
||||
return false;
|
||||
}
|
||||
|
||||
Map<String, String> baseCookies = objectMapper.readValue(cookieJson, new TypeReference<>() {});
|
||||
String cookieHeader = buildCookieHeader(baseCookies);
|
||||
|
||||
String response = webClient.get()
|
||||
.uri("/init/refresh?os=web")
|
||||
.header("Cookie", baseCookie) // 关键点:始终携带基础登录态
|
||||
.header("Cookie", cookieHeader)
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.block();
|
||||
// 3. 合并新旧Cookie(保留基础登录态)
|
||||
JsonNode data = new ObjectMapper().readTree(response).path("data");
|
||||
String newCookie = extractNewCookies(data); // 提取spt_token等
|
||||
String finalCookie = mergeCookies(baseCookie, newCookie);
|
||||
|
||||
// 4. 存储到Redis
|
||||
JsonNode data = objectMapper.readTree(response).path("data");
|
||||
Map<String, String> newCookies = extractNewCookieMap(data);
|
||||
|
||||
baseCookies.putAll(newCookies);
|
||||
|
||||
redisTemplate.opsForValue().set(
|
||||
REDIS_COOKIE_KEY,
|
||||
finalCookie,
|
||||
REDIS_COOKIE_MAP_KEY,
|
||||
objectMapper.writeValueAsString(baseCookies),
|
||||
Long.parseLong(data.path("tokenTTL").asText()),
|
||||
TimeUnit.SECONDS
|
||||
);
|
||||
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("刷新失败", e);
|
||||
log.error("刷新 Cookie 失败", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 从腾讯API响应中提取新的Cookie信息
|
||||
*/
|
||||
private String extractNewCookies(JsonNode dataNode) {
|
||||
if (dataNode == null || !dataNode.has("cookie")) {
|
||||
return "";
|
||||
|
||||
private Map<String, String> extractNewCookieMap(JsonNode dataNode) {
|
||||
Map<String, String> result = new HashMap<>();
|
||||
if (dataNode != null && dataNode.has("cookie")) {
|
||||
for (JsonNode cookie : dataNode.get("cookie")) {
|
||||
result.put(cookie.get("name").asText(), cookie.get("value").asText());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
StringBuilder cookieStr = new StringBuilder();
|
||||
Iterator<JsonNode> cookies = dataNode.path("cookie").elements();
|
||||
|
||||
while (cookies.hasNext()) {
|
||||
JsonNode cookie = cookies.next();
|
||||
cookieStr.append(cookie.path("name").asText())
|
||||
.append("=")
|
||||
.append(cookie.path("value").asText())
|
||||
.append("; ");
|
||||
}
|
||||
|
||||
return cookieStr.toString();
|
||||
}
|
||||
|
||||
|
||||
// 合并Cookie的工具方法
|
||||
private String mergeCookies(String base, String news) {
|
||||
Map<String, String> map = new LinkedHashMap<>();
|
||||
// 先解析基础Cookie
|
||||
Arrays.stream(base.split("; "))
|
||||
.forEach(c -> {
|
||||
String[] kv = c.split("=", 2);
|
||||
if (kv.length == 2) map.put(kv[0], kv[1]);
|
||||
});
|
||||
// 用新Cookie覆盖
|
||||
Arrays.stream(news.split("; "))
|
||||
.forEach(c -> {
|
||||
String[] kv = c.split("=", 2);
|
||||
if (kv.length == 2) map.put(kv[0], kv[1]);
|
||||
});
|
||||
// 重新拼接
|
||||
return map.entrySet().stream()
|
||||
private String buildCookieHeader(Map<String, String> cookieMap) {
|
||||
return cookieMap.entrySet().stream()
|
||||
.map(e -> e.getKey() + "=" + e.getValue())
|
||||
.collect(Collectors.joining("; "));
|
||||
}
|
||||
|
||||
/**
|
||||
* 定时刷新任务(每1小时执行一次)
|
||||
*/
|
||||
// @Scheduled(fixedRate = 3600000)
|
||||
// 可选:定时自动刷新(你可以打开)
|
||||
@Scheduled(fixedRate = 3600000)
|
||||
public void scheduledRefresh() {
|
||||
log.info("定时刷新Cookie");
|
||||
if (!refreshCookies()) {
|
||||
log.warn("首次刷新失败,尝试重新初始化基础Cookie...");
|
||||
initBaseCookies();
|
||||
// try {
|
||||
// Thread.sleep(30000); // 等待30秒后重试
|
||||
// if (!refreshCookies()) {
|
||||
// log.error("重试刷新仍然失败");
|
||||
// }
|
||||
// } catch (InterruptedException e) {
|
||||
// Thread.currentThread().interrupt();
|
||||
// }
|
||||
log.warn("Cookie 刷新失败,Redis 中可能缺失数据");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
package com.ping.study.utils;
|
||||
|
||||
import com.ping.study.mapper.UrlsMapper;
|
||||
import com.ping.study.model.dto.NbaStatsRequestDto;
|
||||
import com.ping.study.model.vo.ApiResponse;
|
||||
import com.ping.study.model.vo.Game;
|
||||
import com.ping.study.model.vo.Group;
|
||||
import com.ping.study.pojo.Games;
|
||||
import com.ping.study.pojo.Urls;
|
||||
import com.ping.study.service.GamesService;
|
||||
import com.ping.study.service.tx.MatchService;
|
||||
import lombok.Data;
|
||||
@@ -34,6 +36,9 @@ public class NbaApi {
|
||||
@Autowired
|
||||
private MatchService matchService;
|
||||
|
||||
@Autowired
|
||||
private UrlsMapper urlsMapper;
|
||||
|
||||
public NbaApi(@Qualifier("nbaWebClient")WebClient webClient) {
|
||||
this.webClient = webClient;
|
||||
}
|
||||
@@ -86,7 +91,29 @@ public class NbaApi {
|
||||
// 处理异常或设置默认值
|
||||
entity.setStartTime(null);
|
||||
}
|
||||
|
||||
for (int j = 0; j < 4; j++){
|
||||
Urls urls = new Urls(); // 每次新建一个对象
|
||||
urls.setGameId(entity.getGameId());
|
||||
switch (j) {
|
||||
case 0:
|
||||
urls.setType("tx");
|
||||
urls.setUrl("");
|
||||
break;
|
||||
case 1:
|
||||
urls.setType("wl");
|
||||
urls.setUrl("");
|
||||
break;
|
||||
case 2:
|
||||
urls.setType("mg");
|
||||
urls.setUrl("");
|
||||
break;
|
||||
case 3:
|
||||
urls.setType("nba");
|
||||
urls.setUrl("");
|
||||
break;
|
||||
}
|
||||
urlsMapper.insertSelective(urls);
|
||||
}
|
||||
gamesService.insertGames(entity);
|
||||
entities.add(entity);
|
||||
}
|
||||
|
||||
@@ -96,6 +96,6 @@
|
||||
</delete>
|
||||
|
||||
<update id="updateUrlsWithGameId" parameterType="map">
|
||||
update urls set url = #{s},type = 'tx' where game_id = #{gameId}
|
||||
update urls set url = #{s} where game_id = #{gameId} and type = 'tx'
|
||||
</update>
|
||||
</mapper>
|
||||
|
||||
Reference in New Issue
Block a user