1
zj
2025-04-24 c134d6137dff1d4533b12a07f85e44a1d7d57362
src/main/java/com/nq/service/impl/StockServiceImpl.java
@@ -1,20 +1,28 @@
package com.nq.service.impl;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import com.nq.common.ServerResponse;
import com.nq.config.StockPoll;
import com.nq.constant.StockConstant;
import com.nq.dao.*;
import com.nq.enums.EStockType;
import com.nq.pojo.*;
import com.nq.pojo.reponse.RPageInfo;
import com.nq.service.*;
import com.nq.utils.HttpClientRequest;
import com.nq.utils.http.HttpClientRequest;
import com.nq.utils.PropertiesUtil;
import com.nq.utils.redis.RedisKeyConstant;
import com.nq.utils.redis.RedisKeyUtil;
import com.nq.utils.redis.RedisShardedPoolUtils;
import com.nq.utils.stock.pinyin.GetPyByChinese;
import com.nq.utils.stock.qq.QqStockApi;
@@ -31,20 +39,30 @@
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.Data;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import static com.nq.utils.DateTimeUtil.getWeekDay;
import static com.nq.utils.timeutil.DateTimeUtil.getWeekDay;
@Service("iStockService")
public class StockServiceImpl implements IStockService {
@@ -83,6 +101,11 @@
    @Resource
    StockDzMapper stockDzMapper;
    @Autowired
    IPriceServices iPriceServices;
    public ServerResponse getMarket() {
        String market_url = PropertiesUtil.getProperty("sina.market.url");
        String result = null;
@@ -119,7 +142,7 @@
        List<Stock> stockList = new ArrayList<>();
        if (stockType.equals("99")) {
            PageHelper.startPage(pageNum, pageSize);
            stockList.addAll(stockMapper.findZtStockListByKeyWords(keyWords, stockPlate, "IN", Integer.valueOf(0)));
            stockList.addAll(stockMapper.findZtStockListByKeyWords(keyWords, stockPlate, EStockType.ST.getCode(), Integer.valueOf(0)));
        } else if (stockType.equals("100")) {
            User user = iUserService.getCurrentRefreshUser(request);
            if (user == null) {
@@ -162,175 +185,102 @@
        if (stockList.size() > 0){
            stockListVOS.addAll(Objects.requireNonNull(StockApi.getStockReailTimes(stockList)));
        }
        PageInfo pageInfo = new PageInfo(stockList);
        RPageInfo<StockListVO> pageInfo = new RPageInfo<StockListVO>();
        if(null != orderBy && orderBy.equals("asc")){
            stockListVOS = stockListVOS.stream().sorted(Comparator.comparing(StockListVO::getHcrate)).collect(Collectors.toList());
        }
        if(null != orderBy && orderBy.equals("desc")){
            stockListVOS = stockListVOS.stream()
                    .sorted(Comparator.comparing(StockListVO::getHcrate).reversed())
                    .collect(Collectors.toList());
        }
        pageInfo.setList(stockListVOS);
        pageInfo.setStockType(stockType);
        return ServerResponse.createBySuccess(pageInfo);
    }
    public ServerResponse getDateline(HttpServletResponse response, String code) {
        if (StringUtils.isBlank(code))
            return ServerResponse.createByErrorMsg("");
        Stock stock = this.stockMapper.findStockByCode(code);
        if (stock == null)
            return ServerResponse.createByErrorMsg("");
        response.setHeader("Access-Control-Allow-Origin", "*");
        Date time = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String end = sdf.format(time);
        Calendar c = Calendar.getInstance();
        c.setTime(new Date());
        c.add(2, -3);
        Date m = c.getTime();
        String mon = sdf.format(m);
        String methodUrl = "http://q.stock.sohu.com/hisHq?code=cn_" + code + "+&start=" + mon + "&end=" + end + "&stat=1&order=D";
        HttpURLConnection connection = null;
        BufferedReader reader = null;
        String line = null;
        EchartsDataVO echartsDataVO = new EchartsDataVO();
        try {
            URL url = new URL(methodUrl);
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.connect();
            if (connection.getResponseCode() == 200) {
                reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "gbk"));
                StringBuilder result = new StringBuilder();
                while ((line = reader.readLine()) != null)
                    result.append(line).append(System.getProperty("line.separator"));
                JSONArray jsonArray = JSONArray.fromObject(result.toString());
                JSONObject json = jsonArray.getJSONObject(0);
                JSONArray jsonArray1 = JSONArray.fromObject(json.get("hq"));
                Collections.reverse((List<?>) jsonArray1);
                double[][] values = (double[][]) null;
                Object[][] volumes = (Object[][]) null;
                String[] date = null;
                values = new double[jsonArray1.size()][5];
                volumes = new Object[jsonArray1.size()][3];
                date = new String[jsonArray1.size()];
                for (int i = 0; i < jsonArray1.size(); i++) {
                    JSONArray js = JSONArray.fromObject(jsonArray1.get(i));
                    date[i] = js.get(0).toString();
                    values[i][0] = Double.valueOf(js.get(1).toString()).doubleValue();
                    values[i][1] = Double.valueOf(js.get(2).toString()).doubleValue();
                    values[i][2] = Double.valueOf(js.get(5).toString()).doubleValue();
                    values[i][3] = Double.valueOf(js.get(6).toString()).doubleValue();
                    values[i][4] = Double.valueOf(js.get(7).toString()).doubleValue();
                    volumes[i][0] = Integer.valueOf(i);
                    volumes[i][1] = Double.valueOf(js.get(7).toString());
                    volumes[i][2] = Integer.valueOf((Double.valueOf(js.get(3).toString()).doubleValue() > 0.0D) ? 1 : -1);
                }
                echartsDataVO.setDate(date);
                echartsDataVO.setValues(values);
                echartsDataVO.setVolumes(volumes);
                echartsDataVO.setStockCode(stock.getStockCode());
                echartsDataVO.setStockName(stock.getStockName());
                ServerResponse.createBySuccess(echartsDataVO);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            connection.disconnect();
        }
        return ServerResponse.createBySuccess(echartsDataVO);
    @Override
    public ServerResponse getDateline(HttpServletResponse paramHttpServletResponse, String paramString) {
        return null;
    }
    public ServerResponse getSingleStock(String code, HttpServletRequest request) {
        if(code.equals("GOLD")){
            String price =  RedisShardedPoolUtils.get(RedisKeyConstant.gold);
            StockVO stockVO = new StockVO();
            stockVO.setNowPrice(price);
            stockVO.setName(code);
            Map map = Maps.newHashMap();
            map.put("stock", stockVO);
            return ServerResponse.createBySuccess(map);
        }else if(code.equals("CRUDE OIL")){
            String price = RedisShardedPoolUtils.get(RedisKeyConstant.crude_oil);
            StockVO stockVO = new StockVO();
            stockVO.setNowPrice(price);
            stockVO.setName(code);
            Map map = Maps.newHashMap();
            map.put("stock", stockVO);
            return ServerResponse.createBySuccess(map);
        }else{
            if (StringUtils.isBlank(code))
                return ServerResponse.createByErrorMsg("");
            Stock stock = stockMapper.findStockByCode(code);
            DataStockBean cacheBaseStock = RedisKeyUtil.getCacheBaseStock(stock);
            Integer depositAmt = 0;
            String introduction = null;
            StockVO   stockVO = StockApi.assembleInStockVO(stock);
            stockVO.setDepositAmt(depositAmt);
            stockVO.setNowPrice(iPriceServices.getNowPrice(stock.getStockCode()).toString());
            stockVO.setType(stock.getStockType());
            stockVO.setId(stock.getId().intValue());
            stockVO.setCode(stock.getStockCode());
            stockVO.setName(stock.getStockName());
            stockVO.setSpell(stock.getStockSpell());
            stockVO.setGid(stock.getStockGid().toUpperCase());
            Map<String, Object> newStock = iPriceServices.getNewStock(stock.getStockCode());
            stockVO.setHcrate(newStock.get("ChgPct").toString().replaceAll("%", ""));
            stockVO.setToday_max(newStock.get("High").toString());
            stockVO.setToday_min(newStock.get("Low").toString());
            if(null != cacheBaseStock){
                stockVO.setOpen_px(cacheBaseStock.getOpen());
                stockVO.setPreclose_px(cacheBaseStock.getPrevClose());
            }
            Map map = Maps.newHashMap();
            map.put("introduction", introduction);
            map.put("stock", stockVO);
            return ServerResponse.createBySuccess(map);
        }
    }
    public Map getSingleStock(String code) {
        if (StringUtils.isBlank(code))
            return ServerResponse.createByErrorMsg("");
        Stock stock = new Stock();
            return null;
        Stock stock = stockMapper.findStockByCode(code);
        DataStockBean cacheBaseStock = RedisKeyUtil.getCacheBaseStock(stock);
        Integer depositAmt = 0;
        String introduction = null;
        String result = null;
        com.alibaba.fastjson2.JSONObject json = null;
        //期货
        String url = null;
        if (code.contains("hf")) {
            StockFutures futmodel = stockFuturesMapper.selectFuturesByCode(code.replace("hf_", ""));
            stock.setStockGid(futmodel.getFuturesGid());
            stock.setStockCode(futmodel.getFuturesCode());
            stock.setStockName(futmodel.getFuturesName());
            stock.setAddTime(futmodel.getAddTime());
            stock.setId(futmodel.getId());
            stock.setStockSpell("0");
            depositAmt = futmodel.getDepositAmt();
            url = PropertiesUtil.getProperty("sina.single.futures.introduction.url") + futmodel.getFuturesCode() + "&app=source&type=1";
        } else if (code.contains("sh") || code.contains("sz") || code.contains("hk") || code.contains("us")) { //指数
            StockIndex model = stockIndexMapper.selectIndexByCode(code.replace("sh", "").replace("sz", "").replace("hk", "").replace("us", ""));
            stock.setStockGid(model.getIndexGid());
            stock.setStockCode(model.getIndexCode());
            stock.setStockName(model.getIndexName());
            stock.setAddTime(model.getAddTime());
            stock.setId(model.getId());
            stock.setStockSpell("0");
            depositAmt = model.getDepositAmt();
            introduction = model.getIntroduction();
        } else {//股票
            stock = this.stockMapper.findStockByCode(code);
            if (stock == null)
                return ServerResponse.createByErrorMsg("");
            //简介
            if (stock.getStockGid().contains("hk")) {
                url = PropertiesUtil.getProperty("hk.stock.introduction.url") + "%22" + stock.getStockCode() + ".HK%22)";
                result = HttpClientRequest.doGet(url);
                if (result.length() < 20) {
                    introduction = "暂无数据";
                } else {
                    json = com.alibaba.fastjson2.JSONObject.parseObject(result);
                    introduction = json.getJSONObject("result")
                            .getJSONArray("data")
                            .getJSONObject(0)
                            .getString("ORG_PROFILE");
                    if (request.getHeader("lang") != null && !request.getHeader("lang").equals("zh-CN") && !request.getHeader("lang").equals("tww") && !request.getHeader("lang").equals("")) {
                        GoogleTranslateUtil googleTranslateUtil = new GoogleTranslateUtil();
                        try {
                            introduction = googleTranslateUtil.translate(introduction, request.getHeader("lang"));
                        } catch (Exception e) {
                            log.error("翻译失败");
                        }
                    }
                }
            } else {
                try {
                    url = PropertiesUtil.getProperty("sina.single.stock.introduction.url") + stock.getStockGid();
                    result = HttpClientRequest.doGet(url);
                    json = com.alibaba.fastjson2.JSONObject.parseObject(result);
                    //取json里result里的data里的introduction
                    introduction = json.getJSONObject("result").getJSONObject("data").getString("introduction");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        String gid = stock.getStockGid();
        //股票数据
        StockVO stockVO = new StockVO();
        if (gid.contains("hk") && "hk".equals(stock.getStockType())) {
            String hkStock = RedisShardedPoolUtils.get(stock.getStockGid(), 1);
            stockVO = StockApi.otherStockVO(hkStock);
        } else if (gid.contains("hk") || gid.contains("us")) {
            String index = RedisShardedPoolUtils.get(stock.getStockGid(), 3);
            stockVO = StockApi.otherStockVO(index);
        } else {
            stockVO = StockApi.assembleInStockVO(stock);
        }
        StockVO   stockVO = StockApi.assembleInStockVO(stock);
        stockVO.setDepositAmt(depositAmt);
        stockVO.setNowPrice(iPriceServices.getNowPrice(stock.getStockCode()).toString());
        stockVO.setType(stock.getStockType());
        stockVO.setId(stock.getId().intValue());
        stockVO.setCode(stock.getStockCode());
        stockVO.setName(stock.getStockName());
        stockVO.setSpell(stock.getStockSpell());
        stockVO.setGid(stock.getStockGid().toUpperCase());
        if(null != cacheBaseStock){
            stockVO.setOpen_px(cacheBaseStock.getOpen());
            stockVO.setPreclose_px(cacheBaseStock.getPrevClose());
        }
        Map map = Maps.newHashMap();
        map.put("introduction", introduction);
        map.put("stock", stockVO);
        return ServerResponse.createBySuccess(map);
        return map;
    }
@@ -508,18 +458,131 @@
        EchartsDataVO echartsDataVO = StockApi.assembleEchartsDataVO(minDataVO);
        return ServerResponse.createBySuccess(echartsDataVO);
    }
    @lombok.Data
    class kData {
        long t;
        String c;
        String o;
        String h;
        String l;
        String v;
        String vo;
    }
    /*股票日线-K线*/
    //黄金
    private static final String gold_API_URL = "http://139.196.211.109/ldMetal_k.action?username=Qq112233&password=3ce25a66d5b3a8cd661024fea6c79388&id=AUUSDO&num=-100&period=";
    //原油
    private static final String crude_oil_API_URL = "http://47.112.169.122/fOption_k.action?username=Qq112233&password=3ce25a66d5b3a8cd661024fea6c79388&id=@CL0W&num=-100&period=";
        /*股票日线-K线*/
    @Override
    public Object getKData(String pid, String interval, String stockType) {
        EStockType eStockType = null;
        if(stockType.equals("US")){
            eStockType = EStockType.US;
        if(stockType.equals("GOLD")){
            // 使用RestTemplate发起HTTP请求
            String response = RedisShardedPoolUtils.get("k_gold_"+interval.toLowerCase());
            return parseData(interval,response, stockType);
        }else if(stockType.equals("CRUDE OIL")){
            // 使用RestTemplate发起HTTP请求
            RestTemplate restTemplate = new RestTemplate();
            String response = RedisShardedPoolUtils.get("k_crude_oil_"+interval.toLowerCase());
            return parseData(interval,response, stockType);
        }else{
            eStockType = EStockType.IN;
            EStockType eStockType = EStockType.getEStockTypeByCode(stockType);
            Object object = HttpUtil.get(eStockType.stockUrl + "kline?pid=" + pid + "&interval=" + interval + "&key=" + eStockType.stockKey);
            Gson gson = new Gson();
            List<kData> dataList = gson.fromJson(object.toString(), new TypeToken<List<kData>>(){}.getType());
            Stock stock = stockMapper.selectOne(new LambdaQueryWrapper<Stock>().eq(Stock::getStockCode, pid).eq(Stock::getStockType, EStockType.ST.getCode()));
            BigDecimal nowPrice = iPriceServices.getNowPrice(stock.getStockCode());
            Map singleStock = getSingleStock(stock.getStockCode());
            StockVO stockVO = (StockVO)singleStock.get("stock");
            // 修改 List 中的最后一条数据
            kData lastData = dataList.get(dataList.size() - 1);
            lastData.setC(nowPrice.toString());
            lastData.setO(stockVO.getOpen_px());
            lastData.setH(stockVO.getToday_max());
            lastData.setL(stockVO.getToday_min());
            return gson.toJson(dataList);
        }
        String string = HttpUtil.get(eStockType.stockUrl + "kline?pid=" + pid + "&interval=" + interval + "&key=" + eStockType.stockKey);
        return string;
    }
    public List<kData> parseData(String interval,String data,String key) {
        String price = null;
        if(key.equals("GOLD")){
            price =  RedisShardedPoolUtils.get(RedisKeyConstant.gold);
        }else if(key.equals("CRUDE OIL")){
            price = RedisShardedPoolUtils.get(RedisKeyConstant.crude_oil);
        }
        List<kData> kDataList = new ArrayList<>();
        // 将数据按行分割
        String[] lines = data.split("\n");
        // 跳过第一行(列名)
        for (int i = 1; i < lines.length; i++) {
            String line = lines[i].trim();
            // 确保行不为空
            if (!line.isEmpty()) {
                String[] fields = line.split(",");
                // 确保每行有至少7个字段:日期、开盘价、最高价、最低价、收盘价、成交量、持仓量
                if ((key.equals("CRUDE OIL") && fields.length == 7) || (key.equals("GOLD") && fields.length == 5)) {
                    kData kData = new kData();
                    kData.setT(convDate(fields[0],interval));
                    kData.setC(fields[4]);
                    kData.setO(fields[1]);
                    kData.setH(fields[2]);
                    kData.setL(fields[3]);
                    if(key.equals("CRUDE OIL")){
                        kData.setV(fields[5]);
                        kData.setVo(fields[6]);
                    }else{
                        kData.setV("0");
                        kData.setVo("0");
                    }
                    // 将每一条 KData 对象添加到列表中
                    kDataList.add(kData);
                }
            }
        }
        kDataList.get(kDataList.size() - 1).setC(price);
        return kDataList;
    }
    // 常量,定义日期格式
    private static final String DATE_PATTERN = "yyyyMMdd";
    private static final String DATE_TIME_PATTERN = "yyyyMMdd HH:mm";
    public long convDate(String dateStr, String interval) {
        // 输入校验,确保 dateStr 和 interval 不为 null 或空
        if (dateStr == null || dateStr.trim().isEmpty() || interval == null || interval.trim().isEmpty()) {
            throw new IllegalArgumentException("日期字符串或时间间隔不能为空。");
        }
        // 根据 interval 的值,选择日期格式
        String pattern = (interval.equalsIgnoreCase("D") || interval.equalsIgnoreCase("W") || interval.equalsIgnoreCase("M"))
                ? DATE_PATTERN : DATE_TIME_PATTERN;
        // 创建 DateTimeFormatter,使用合适的格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        try {
            // 根据是否包含时间部分,选择 LocalDate 或 LocalDateTime 进行解析
            if (pattern.equals(DATE_PATTERN)) {
                LocalDate localDate = LocalDate.parse(dateStr, formatter);
                Instant timestamp = localDate.atStartOfDay(ZoneOffset.UTC).toInstant();
                return timestamp.getEpochSecond();
            } else {
                LocalDateTime localDateTime = LocalDateTime.parse(dateStr, formatter);
                Instant timestamp = localDateTime.toInstant(ZoneOffset.UTC);
                return timestamp.getEpochSecond();
            }
        } catch (Exception e) {
            throw new IllegalArgumentException("无效的日期格式: " + dateStr, e);
        }
    }
    @Override
@@ -528,41 +591,7 @@
        if (user == null) {
            return ServerResponse.createByErrorMsg("Please log in");
        }
        return ServerResponse.createBySuccess();
//        List<Stock> stockList = stockMapper.findOptions(user.getId() + "");
////    List<Stock> stockList = stockMapper.findOptions("485");
//        List<StockListVO> stockListVOS = Lists.newArrayList();
//        if (stockList.size() > 0)
//            for (Stock stock : stockList) {
//                StockListVO stockListVO = new StockListVO();
//                QueryWrapper<InStockBean> queryWrapper = new QueryWrapper<>();
//                queryWrapper.eq("id", stock.getStockCode());
//                InStockBean inStockBean = inStockMapper.selectOne(queryWrapper);
//                if (inStockBean == null) {
//                    continue;
//                }
//                stockListVO.setNowPrice(inStockBean.getLast());
//                stockListVO.setToday_max(inStockBean.getHigh());
//                stockListVO.setToday_min(inStockBean.getLow());
//                stockListVO.setHcrate(BigDecimal.valueOf(Double.parseDouble(inStockBean.getChgPct())));
//                stockListVO.setBusiness_amount(inStockBean.getVolume());
//                stockListVO.setBusiness_balance(inStockBean.getAvgVolume());
//                stockListVO.setPreclose_px(inStockBean.getPrevClose());
//                stockListVO.setOpen_px(inStockBean.getOpen());
//                stockListVO.setName(stock.getStockName());
//                stockListVO.setCode(stock.getStockCode());
//                stockListVO.setSpell(stock.getStockSpell());
//                stockListVO.setGid(stock.getStockGid());
//                BigDecimal day3Rate = (BigDecimal) selectRateByDaysAndStockCode(stock.getStockCode(), 3).getData();
//                stockListVO.setDay3Rate(day3Rate);
//                stockListVO.setStock_plate(stock.getStockPlate());
//                stockListVO.setStock_type(stock.getStockType());
//                stockListVOS.add(stockListVO);
//            }
//        PageInfo pageInfo = new PageInfo(stockList);
//        pageInfo.setList(stockListVOS);
    }
    public ServerResponse<Stock> findStockByName(String name) {
@@ -577,9 +606,9 @@
        return ServerResponse.createBySuccess(this.stockMapper.selectByPrimaryKey(stockId));
    }
    public ServerResponse<PageInfo> listByAdmin(Integer showState, Integer lockState, String code, String name, String stockPlate, String stockType, int pageNum, int pageSize, HttpServletRequest request) {
    public ServerResponse<PageInfo> listByAdmin(String stockGid,Integer showState, Integer lockState, String code, String name, String stockPlate, String stockType, int pageNum, int pageSize, HttpServletRequest request) {
        PageHelper.startPage(pageNum, pageSize);
        List<Stock> stockList = this.stockMapper.listByAdmin(showState, lockState, code, name, stockPlate, stockType);
        List<Stock> stockList = this.stockMapper.listByAdmin(stockGid,showState, lockState, code, name, stockPlate, stockType);
        List<StockAdminListVO> stockAdminListVOS = Lists.newArrayList();
        for (Stock stock : stockList) {
            StockAdminListVO stockAdminListVO = assembleStockAdminListVO(stock);