package com.nq.utils.redis; import com.alibaba.fastjson2.JSONObject; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; import com.nq.enums.EStockType; import com.nq.pojo.DataStockBean; import com.nq.pojo.Stock; import com.nq.pojo.StockRealTimeBean; import com.nq.utils.PropertiesUtil; import com.nq.utils.stock.sina.StockApi; import org.apache.http.util.TextUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStream; import java.math.BigDecimal; import java.net.HttpURLConnection; import java.net.URL; import java.util.Map; import java.util.concurrent.locks.ReentrantLock; public class RedisKeyUtil { private static final Logger log = LoggerFactory.getLogger(RedisKeyUtil.class); /** * 缓存股票数据源到redis * */ public static void setCaCheKeyBaseStock(EStockType eStockType, DataStockBean dataStockBean){ RedisShardedPoolUtils.set(RedisKeyConstant.RK_BASE_STOCK+":"+eStockType.getCode()+":"+dataStockBean.getId(), new Gson().toJson(dataStockBean)); } /** * 获取股票数据 * */ public static DataStockBean getCacheBaseStock(Stock stock){ String cacheBaseData = RedisShardedPoolUtils.get(RedisKeyConstant.RK_BASE_STOCK+":"+stock.getStockType()+":"+stock.getStockCode()); return new Gson().fromJson(cacheBaseData, DataStockBean.class); } /** * 保存实时数据到redis * */ public static void setCacheRealTimeStock(EStockType eStockType, StockRealTimeBean stockRealTimeBean){ RedisShardedPoolUtils.set(RedisKeyConstant.RK_REAL_TIME_STOCK+":"+eStockType.getCode()+":"+stockRealTimeBean.getPid(), new Gson().toJson(stockRealTimeBean)); } public static StockRealTimeBean getCacheRealTimeStock(Stock stock){ StockRealTimeBean stockRealTimeBean = null; String cacheBaseData = RedisShardedPoolUtils.get(RedisKeyConstant.RK_REAL_TIME_STOCK+":"+stock.getStockType()+":"+stock.getStockCode()); if(!TextUtils.isEmpty(cacheBaseData)){ stockRealTimeBean = new Gson().fromJson(cacheBaseData, StockRealTimeBean.class); } if(stockRealTimeBean == null){ String s = doPost(stock.getStockCode()); Map stringObjectMap = jsonToMap(s); stockRealTimeBean = new StockRealTimeBean(); stockRealTimeBean.setPcp(stringObjectMap.get("ChgPct").toString()); stockRealTimeBean.setLast(stringObjectMap.get("Last").toString()); stockRealTimeBean.setHigh(stringObjectMap.get("High").toString()); stockRealTimeBean.setLow(stringObjectMap.get("Low").toString()); stockRealTimeBean.setBid(stringObjectMap.get("Id").toString()); stockRealTimeBean.setPc(stringObjectMap.get("PrevClose").toString()); stockRealTimeBean.setAsk(stringObjectMap.get("Ask").toString()); } stockRealTimeBean.setPcp(stockRealTimeBean.getPcp().replace("%","")); return stockRealTimeBean; } public static Map jsonToMap(String json) { ObjectMapper objectMapper = new ObjectMapper(); try { Object[] array = objectMapper.readValue(json, Object[].class); Gson gson = new Gson(); String s = gson.toJson(array[0]); Map map = objectMapper.readValue(s, Map.class); return map; } catch (JsonProcessingException e) { throw new RuntimeException(e); } } private static final ReentrantLock lock = new ReentrantLock(); private static String lastResult = null; private static long lastExecuteTime = 0; private static final long MIN_INTERVAL_MS = 3000; public static String doPost(String pid) { // 快速检查缓存 long currentTime = System.currentTimeMillis(); if (lastResult != null && (currentTime - lastExecuteTime) < MIN_INTERVAL_MS) { return lastResult; } // 需要获取锁执行新请求 return executeWithLock(pid); } private static String executeWithLock(String pid) { String apiUrl = PropertiesUtil.getProperty("JS_IN_HTTP_URL") + "stock?key=" + PropertiesUtil.getProperty("JS_IN_KEY"); lock.lock(); try { // 双检锁:再次检查缓存 long currentTime = System.currentTimeMillis(); if (lastResult != null && (currentTime - lastExecuteTime) < MIN_INTERVAL_MS) { return lastResult; } // 执行POST请求 String result = null; try { URL url = new URL(apiUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); connection.setDoOutput(true); String postData = "pid=" + pid; try (OutputStream os = connection.getOutputStream()) { byte[] input = postData.getBytes("utf-8"); os.write(input, 0, input.length); } BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream())); String inputLine; StringBuilder response = new StringBuilder(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); result = response.toString(); // 更新缓存 lastResult = result; lastExecuteTime = System.currentTimeMillis(); } catch (Exception e) { e.printStackTrace(); // 请求失败时返回缓存 if (lastResult != null) { return lastResult; } } return result; } finally { lock.unlock(); } } public static void setCacheCompanies(Stock stock,String companiesInfo){ RedisShardedPoolUtils.set(RedisKeyConstant.RK_COMPANY_INFO+":"+stock.getStockType()+":"+stock.getStockCode(), new Gson().toJson(companiesInfo)); } public static JSONObject getCacheCompanies(Stock stock){ String companiesInfo = RedisShardedPoolUtils.get(RedisKeyConstant.RK_COMPANY_INFO+":"+stock.getStockType()+":"+stock.getStockCode()); if(companiesInfo.isEmpty()){ return null; } return JSONObject.parseObject(companiesInfo); } }