diff --git a/src/main/java/cn/stock/market/domain/basic/service/StockService.java b/src/main/java/cn/stock/market/domain/basic/service/StockService.java index b165c8f..b91edc7 100644 --- a/src/main/java/cn/stock/market/domain/basic/service/StockService.java +++ b/src/main/java/cn/stock/market/domain/basic/service/StockService.java @@ -2,19 +2,25 @@ package cn.stock.market.domain.basic.service; import java.math.BigDecimal; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Objects; +import java.util.*; +import java.util.concurrent.TimeUnit; +import javax.net.ssl.X509TrustManager; import javax.persistence.EntityExistsException; import javax.servlet.http.HttpServletRequest; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.text.StrFormatter; import cn.stock.market.dto.model.*; import cn.stock.market.infrastructure.api.sina.vo.HotSearchVO; +import cn.stock.market.utils.*; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import okhttp3.OkHttpClient; +import okhttp3.Protocol; +import okhttp3.Request; +import okhttp3.Request.Builder; import org.apache.commons.lang3.StringUtils; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; @@ -44,11 +50,6 @@ import cn.stock.market.infrastructure.api.sina.vo.MarketVOResult; import cn.stock.market.infrastructure.api.sina.vo.k.MinDataVO; import cn.stock.market.infrastructure.api.sina.vo.k.echarts.EchartsDataVO; import cn.stock.market.infrastructure.stockdb.po.QStockPO; -import cn.stock.market.utils.GetPyByChinese; -import cn.stock.market.utils.HttpClientRequest; -import cn.stock.market.utils.PropertiesUtil; -import cn.stock.market.utils.ServerResponse; -import cn.stock.market.utils.Utils; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.client.RestTemplate; @@ -70,6 +71,41 @@ public class StockService { String apikey = "VF7SHRYOFIYHCIKE"; + public static final String API_HEADER = ":method: GET\n" + + ":scheme: https\n" + + ":path: /get_screen.php?screen_ID=22&skinID=1&overview_table_order=1&time_utc_offset=28800&pair_ID=1156730&additionalTimeframes=Yes&lang_ID=6&include_pair_attr=true&v2=1\n" + + ":authority: cnappapi.investing.com\n" + + "cache-control: no-cache\n" + + "user-agent: Investing.China/64 CFNetwork/1390 Darwin/22.0.0\n" + + "x-os: ios\n" + + "x-idfa-perm: 0\n" + + "x-os-ver: 16.0\n" + + "x-app-ver: 156\n" + + "apf_src: no\n" + + "x-meta-ver: 14\n" + + "accept-language: zh-CN,zh-Hans;q=0.9\n" + + "accept: */*\n" + + "ccode: CN\n" + + ""; + + static OkHttpClient httpClient; + public static OkHttpClient httpClient() { + if(httpClient == null) { + X509TrustManager manager = SSLSocketClientUtil.getX509TrustManager(); + httpClient = new OkHttpClient.Builder() + .followRedirects(true) // 为了制造非200状态码,禁止302跳转 + .protocols(Collections.unmodifiableList(Arrays.asList(Protocol.HTTP_1_1, Protocol.HTTP_2)))// 启用http2.0协议 //, Protocol.HTTP_2 + .sslSocketFactory(SSLSocketClientUtil.getSocketFactory(manager), manager) + .hostnameVerifier(SSLSocketClientUtil.getHostnameVerifier())//忽略校验 + .retryOnConnectionFailure(true) + .connectTimeout(60, TimeUnit.SECONDS) + .readTimeout(60, TimeUnit.SECONDS) + .build(); + } + + return httpClient; + } + public ServerResponse getMarket() { String market_url = "https://hq.sinajs.cn/rn=1520407404627&list=s_sh000001,s_sz399001,s_sz399006,s_sz399300,s_sz399005,s_sz399673,s_sz399106,s_sz399004,s_sz399100"; String result = null; @@ -623,6 +659,53 @@ public class StockService { return null; } + //印度股票个股详情 英财 + public ServerResponse getYCStockInfo(String codeId) { + String sina_result = ""; + + try { + INDStockInfo indStockInfo = new INDStockInfo(); + String tmpl = "https://cnappapi.investing.com/get_screen.php?v2=1&additionalTimeframes=Yes&time_utc_offset=28800&overview_table_order=0&skinID=1&lang_ID=6&include_pair_attr=true&screen_ID=22&pair_ID={}"; + String url = StrFormatter.format(tmpl, codeId); + log.info("url: {}", url); + Builder builder = new Request.Builder().url(url).method("GET", null); + addHeader(builder, API_HEADER); + sina_result = httpClient().newCall(builder.build()).execute().body().string(); + JSONArray pairs_data = JSON.parseObject(sina_result) + .getJSONArray("data").getJSONObject(0) + .getJSONObject("screen_data").getJSONArray("pairs_data"); + + JSONArray overview_table = pairs_data.getJSONObject(0).getJSONArray("overview_table"); + JSONObject info_header = pairs_data.getJSONObject(0).getJSONObject("info_header"); + indStockInfo.setClose(find_overview_table_value_with_key(overview_table, "昨收")); + indStockInfo.setVolume(find_overview_table_value_with_key(overview_table, "成交量")); + indStockInfo.setOpen(find_overview_table_value_with_key(overview_table, "开盘")); + String range = find_overview_table_value_with_key(overview_table, "当日幅度"); //6.91 - 7.89 + if(StringUtils.isNotBlank(range)) { + String[] split = range.trim().split("-"); + indStockInfo.setLow(numberToString(split[0])); + indStockInfo.setHigh(numberToString(split[1])); + } + String last = info_header.getString("last"); //当前价 + indStockInfo.setPrice(numberToString(last)); + + String percent_tooltip_value = info_header.getString("percent_tooltip_value"); //涨幅 + indStockInfo.setPrice(percent_tooltip_value); + String change = info_header.getString("change"); //涨幅值 ("+0.65") + if(change.startsWith("+")) { + indStockInfo.setChange(numberToString(change.substring(1))); + } else { + indStockInfo.setChange(numberToString(change)); + } + + return ServerResponse.createBySuccess(indStockInfo); + + } catch (Exception e) { + log.error("获取出错,错误信息 = {}", e); + } + return null; + } + //印度股票时线-K线 public ServerResponse getTimeK(String stockCode) { String sina_result = ""; @@ -643,7 +726,7 @@ public class StockService { String sina_result = ""; try { - sina_result = HttpClientRequest.http2Get("https://api.investing.com/api/financialdata/7310/historical/chart/?interval=PT5M&pointscount="+codeId); + sina_result = HttpClientRequest.http2Get("https://api.investing.com/api/financialdata/"+codeId+"/historical/chart/?interval=PT5M&pointscount=160"); JSONObject json = JSONObject.parseObject(sina_result).getJSONObject("Time Series (Daily)"); return ServerResponse.createBySuccess(json); @@ -673,7 +756,7 @@ public class StockService { String sina_result = ""; try { - sina_result = HttpClientRequest.http2Get("https://api.investing.com/api/financialdata/17984/historical/chart/?interval=P1D&pointscount="+codeId); + sina_result = HttpClientRequest.http2Get("https://api.investing.com/api/financialdata/"+codeId+"/historical/chart/?interval=P1D&pointscount=160"); JSONObject json = JSONObject.parseObject(sina_result).getJSONObject("Time Series (Daily)"); return ServerResponse.createBySuccess(json); @@ -704,7 +787,7 @@ public class StockService { String sina_result = ""; try { - sina_result = HttpClientRequest.http2Get("https://api.investing.com/api/financialdata/17984/historical/chart/?interval=P1W&pointscount="+codeId); + sina_result = HttpClientRequest.http2Get("https://api.investing.com/api/financialdata/"+codeId+"/historical/chart/?interval=P1W&pointscount=160"); JSONObject json = JSONObject.parseObject(sina_result).getJSONObject("Time Series (Daily)"); return ServerResponse.createBySuccess(json); @@ -734,7 +817,7 @@ public class StockService { String sina_result = ""; try { - sina_result = HttpClientRequest.http2Get("https://api.investing.com/api/financialdata/17984/historical/chart/?interval=P1M&pointscount="+codeId); + sina_result = HttpClientRequest.http2Get("https://api.investing.com/api/financialdata/"+codeId+"/historical/chart/?interval=P1M&pointscount=160"); JSONObject json = JSONObject.parseObject(sina_result).getJSONObject("Time Series (Daily)"); return ServerResponse.createBySuccess(json); @@ -771,4 +854,29 @@ public class StockService { } return ServerResponse.createByErrorMsg("请求失败"); } + + public static String find_overview_table_value_with_key(JSONArray overview_table_value, String key) { + for (Object obj : overview_table_value) { + JSONObject item = (JSONObject) obj; + if(StringUtils.equals(item.getString("key"), key)) { + return item.getString("val"); + } + } + + return null; + } + + public static String numberToString(String string) { + return StringUtils.replace(string, ",", ""); + } + + public static void addHeader(Builder builder,String headerLines) { + String[] headers = StringUtils.split(headerLines, "\n"); + for (String header : headers) { + String[] split2 = StringUtils.split(header, ": "); + String key = split2[0]; + String value = StringUtils.substring(header, key.length() + 2); + builder.header(key, value); + } + } } \ No newline at end of file diff --git a/src/main/java/cn/stock/market/utils/SSLSocketClientUtil.java b/src/main/java/cn/stock/market/utils/SSLSocketClientUtil.java new file mode 100644 index 0000000..65020f6 --- /dev/null +++ b/src/main/java/cn/stock/market/utils/SSLSocketClientUtil.java @@ -0,0 +1,60 @@ +package cn.stock.market.utils; + +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +public class SSLSocketClientUtil { + + public static SSLSocketFactory getSocketFactory(TrustManager manager) { + SSLSocketFactory socketFactory = null; + try { + SSLContext sslContext = SSLContext.getInstance("SSL"); + sslContext.init(null, new TrustManager[]{manager}, new SecureRandom()); + socketFactory = sslContext.getSocketFactory(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (KeyManagementException e) { + e.printStackTrace(); + } + return socketFactory; + } + + public static X509TrustManager getX509TrustManager() { + return new X509TrustManager() { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + }; + } + + public static HostnameVerifier getHostnameVerifier() { + HostnameVerifier hostnameVerifier = new HostnameVerifier() { + @Override + public boolean verify(String s, SSLSession sslSession) { + return true; + } + }; + return hostnameVerifier; + } +} \ No newline at end of file diff --git a/src/main/java/cn/stock/market/web/StockApiController.java b/src/main/java/cn/stock/market/web/StockApiController.java index dc05731..3c7f9e5 100644 --- a/src/main/java/cn/stock/market/web/StockApiController.java +++ b/src/main/java/cn/stock/market/web/StockApiController.java @@ -119,7 +119,7 @@ public class StockApiController { @ApiOperation(value = "印度股票个股详情", httpMethod = "GET") @ResponseBody public ServerResponse getINDStockInfo(@RequestParam("stockCode") String stockCode) { - return this.stockService.getStockInfo(stockCode); + return this.stockService.getYCStockInfo(stockCode); } //印度股票时线-K线