1、A股大盘数据采集
1.1 A股大盘数据采集准备
1.1.1 配置ID生成器bean
A股大盘数据采集入库时,主键ID保证唯一,所以在stock_job工程配置ID生成器:
@Configuration
public class CommonConfig {
/**
* 配置基于雪花算法生成全局唯一id
* 参与元算的参数: 时间戳 + 机房id + 机器id + 序列号
* 保证id唯一
* @return
*/
@Bean
public IdWorker idWorker(){
//指定当前为1号机房的2号机器生成
return new IdWorker(2L,1L);
}
}
1.1.2 股票常量数据配置
1) 配置股票地址参数
在stock_job工程下,定义股票相关配置文件application-stock.yml,该文件与stock_backend下的配置一致,然后我们把大盘、板块、股票相关的通用参数配置进来:
# 配置股票相关的参数
stock:
inner: # 国内大盘ID
- sh000001 # 上证ID
- sz399001 # 深证ID
outer: # 外盘ID
- int_dji # 道琼斯
- int_nasdaq # 纳斯达克
- int_hangseng # 恒生
- int_nikkei # 日经指数
- b_TWSE # 台湾加权
- b_FSSTI # 新加坡
marketUrl: http://hq.sinajs.cn/list=
blockUrl: http://vip.stock.finance.sina.com.cn/q/view/newSinaHy.php
2)股票常量数据封装
在stock_common工程继续完善StockInfoConfig类:
package com.itheima.stock.pojo.domain;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;
/**
* @author by itheima
* @Date 2021/12/30
* @Description
*/
@ConfigurationProperties(prefix = "stock")
@Data
public class StockInfoConfig {
//a股大盘ID集合
private List<String> inner;
//外盘ID集合
private List<String> outer;
//大盘参数获取url
private String marketUrl;
//板块参数获取url
private String blockUrl;
}
2) 在公共配置类上开启配置
@EnableConfigurationProperties(StockInfoConfig.class)//开启常用参数配置bean
@Configuration
public class CommonConfig {
//......
}
1.1.3 A股大盘响应数据说明
var hq_str_sh000001="上证指数,3358.9338,3361.5177,3398.6161,3417.0085,3358.9338,0,0,381243178,510307202948,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2022-06-30,15:30:39,00,";
参数说明:
0:指数名称
1:开盘点
2:前收盘点
3:当前点
4:最高点
5:最低点
8:成交量
9:成交金额
30:当前日期
31:当前时间
1.2 java正则回顾
上一小结我们发现,采集的大盘数据是标准的Js格式数据(非json),需要我们自行解析处理,显然在批量解析数据时,我们可借助java的正则实现,所以接下来我们回顾下前面讲的关于正则的一些知识点。
重点应用:
- 正则表达式理解;
- 捕获组理解;
- 核心类:Pattern、Matcher;
参考:day05\资料\基础知识点预习\Java正则表达式.mhtml
@Test
public void testRep2(){
// 按指定模式在字符串查找
String line = "This order was placed for QT3000! OK?";
String pattern = "(\\D*)(\\d+)(.*)";
// 创建 Pattern 对象
Pattern r = Pattern.compile(pattern);
// 现在创建 matcher 对象
Matcher m = r.matcher(line);
if (m.find( )) {
System.out.println("Found value: " + m.group(0) );
System.out.println("Found value: " + m.group(1) );
System.out.println("Found value: " + m.group(2) );
System.out.println("Found value: " + m.group(3) );
} else {
System.out.println("NO MATCH");
}
}
1.3 A股大盘数据采集实现
1.3.1 定义A股大盘数据采集服务
在stock_job工程下定义服务接口:
/**
* @author by itheima
* @Description 定义采集股票数据的定时任务的服务接口
*/
public interface StockTimerTaskService {
/**
* 获取国内大盘的实时数据信息
*/
void getInnerMarketInfo();
}
定义服务接口实现:
@Service("stockTimerTaskService")
@Slf4j
public class StockTimerTaskServiceImpl implements StockTimerTaskService {
@Autowired
private RestTemplate restTemplate;
@Autowired
private StockInfoConfig stockInfoConfig;
@Autowired
private IdWorker idWorker;
@Override
public void getInnerMarketInfo() {
//1.定义采集的url接口
String url=stockInfoConfig.getMarketUrl() + String.join(",",stockInfoConfig.getInner());
//2.调用restTemplate采集数据
//2.1 组装请求头
HttpHeaders headers = new HttpHeaders();
//必须填写,否则数据采集不到
headers.add("Referer","https://finance.sina.com.cn/stock/");
headers.add("User-Agent","Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36");
//2.2 组装请求对象
HttpEntity<Object> entity = new HttpEntity<>(headers);
//2.3 resetTemplate发起请求
String resString = restTemplate.postForObject(url, entity, String.class);
//log.info("当前采集的数据:{}",resString);
//3.数据解析(重要)
// var hq_str_sh000001="上证指数,3267.8103,3283.4261,3236.6951,3290.2561,3236.4791,0,0,402626660,398081845473,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2022-04-07,15:01:09,00,";
// var hq_str_sz399001="深证成指,12101.371,12172.911,11972.023,12205.097,11971.334,0.000,0.000,47857870369,524892592190.995,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,0,0.000,2022-04-07,15:00:03,00";
String reg="var hq_str_(.+)=\"(.+)\";";
//编译表达式,获取编译对象
Pattern pattern = Pattern.compile(reg);
//匹配字符串
Matcher matcher = pattern.matcher(resString);
ArrayList<StockMarketIndexInfo> list = new ArrayList<>();
//判断是否有匹配的数值
while (matcher.find()){
//获取大盘的code
String marketCode = matcher.group(1);
//获取其它信息,字符串以逗号间隔
String otherInfo=matcher.group(2);
//以逗号切割字符串,形成数组
String[] splitArr = otherInfo.split(",");
//大盘名称
String marketName=splitArr[0];
//获取当前大盘的开盘点数
BigDecimal openPoint=new BigDecimal(splitArr[1]);
//前收盘点
BigDecimal preClosePoint=new BigDecimal(splitArr[2]);
//获取大盘的当前点数
BigDecimal curPoint=new BigDecimal(splitArr[3]);
//获取大盘最高点
BigDecimal maxPoint=new BigDecimal(splitArr[4]);
//获取大盘的最低点
BigDecimal minPoint=new BigDecimal(splitArr[5]);
//获取成交量
Long tradeAmt=Long.valueOf(splitArr[8]);
//获取成交金额
BigDecimal tradeVol=new BigDecimal(splitArr[9]);
//时间
Date curTime = DateTimeUtil.getDateTimeWithoutSecond(splitArr[30] + " " + splitArr[31]).toDate();
//组装entity对象
StockMarketIndexInfo info = StockMarketIndexInfo.builder()
.id(idWorker.nextId())
.marketCode(marketCode)
.marketName(marketName)
.curPoint(curPoint)
.openPoint(openPoint)
.preClosePoint(preClosePoint)
.maxPoint(maxPoint)
.minPoint(minPoint)
.tradeVolume(tradeVol)
.tradeAmount(tradeAmt)
.curTime(curTime)
.build();
//收集封装的对象,方便批量插入
list.add(info);
}
log.info("采集的当前大盘数据:{}",list);
//批量插入
if (CollectionUtils.isEmpty(list)) {
return;
}
//TODO 后续完成批量插入功能
}
}
1.3.2 A股大盘数据采集测试
package com.itheima.stock;
import com.itheima.stock.job.service.StockTimerService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @author by itheima
* @Date 2022/1/1
* @Description
*/
@SpringBootTest
public class TestStockTimerService {
@Autowired
private StockTimerTaskService stockTimerService;
/**
* 获取大盘数据
*/
@Test
public void test01(){
stockTimerService.getInnerMarketInfo();
}
}
效果:
1.4 A股大盘批量保存
1.4.1 定义mapper接口方法
在StockMarketIndexInfoMapper接口添加方法:
/**
* 批量插入股票大盘数据
* @param infos
*/
int insertBatch(List<StockMarketIndexInfo> infos);
1.4.2 绑定xml
在StockMarketIndexInfoMapper.xml添加SQL:
<insert id="insertBatch">
insert into stock_market_index_info
( id,mark_Id,cur_time
,mark_name,cur_point,current_price
,updown_rate,trade_account,trade_volume
)
values
<foreach collection="list" item="smi" separator=",">
(#{smi.id,jdbcType=BIGINT},#{smi.markId,jdbcType=CHAR},#{smi.curTime,jdbcType=TIMESTAMP}
,#{smi.markName,jdbcType=VARCHAR},#{smi.curPoint,jdbcType=DECIMAL},#{smi.currentPrice,jdbcType=DECIMAL}
,#{smi.updownRate,jdbcType=DECIMAL},#{smi.tradeAccount,jdbcType=BIGINT},#{smi.tradeVolume,jdbcType=BIGINT}
)
</foreach>
</insert>
1.4.3 国内大盘数据批量插入实现
注入mapper,然后批量插入:
@Autowired
private StockMarketIndexInfoMapper stockMarketIndexInfoMapper;
/**
* 获取国内大盘数据
*/
@Override
public void getInnerMarketInfo() {
//....省略N行....
//批量插入
int count = this.stockMarketIndexInfoMapper.insertBatch(infos);
log.info("批量插入了:{}条数据",count);
}