diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fb07f4d..348c52c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -25,10 +25,10 @@ build: ' > $HOME/.m2/settings.xml artifacts: - name: stock-market.war + name: india_market_java.jar expire_in: 1 day paths: - - ./target/stock-market.war + - ./target/india_market_java.jar script: - echo ">>>>>>Start Building<<<<<<" - pwd @@ -36,22 +36,17 @@ build: - mvn -v - mvn clean install -Dmaven.test.skip=true - ls - #- apt-get install -y curl - #- curl --max-time 20 http://43.128.20.12:11113/api/webhook/justpull?project=api\&setenv_file=alpha.sh\&publish_env=alpha - echo ">>>>>>Finish Building<<<<<<" webhook: stage: webhook - #tags: - # - gz only: - - main - develop script: - echo ">>>>>>Start Deploy<<<<<<" - ls - apt-get update - apt-get install -y curl - - curl --max-time 30 http://43.139.146.165:11113/api/webhook/justpull?project=market\&setenv_file=alpha.sh\&publish_env=alpha\&shell=deploy-alpha.sh + - curl --max-time 30 http://124.156.133.209:11113/api/webhook/justpull?project=india_market_java\&setenv_file=alpha.sh\&publish_env=alpha\&shell=india/deploy-test.sh - echo ">>>>>>Start Deploy Finish<<<<<<" diff --git a/pom.xml b/pom.xml index 24199f9..097f3d6 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - war + jar cn.qutaojing qutaojing-micro-pom @@ -20,6 +20,11 @@ 股票行情 股票行情 + + com.squareup + javapoet + 1.11.1 + org.springframework.boot spring-boot-starter-tomcat @@ -176,18 +181,59 @@ - stock-market + india_market_java - + org.apache.maven.plugins maven-compiler-plugin 3.8.1 + + + org.springframework.boot + spring-boot-maven-plugin + 2.3.9.RELEASE + + true + JAR + + + + + + repackage + + + false + + + + + + + + com.mysema.maven + apt-maven-plugin + 1.1.3 + + + + process + + + src/main/generated + com.querydsl.apt.jpa.JPAAnnotationProcessor + + + + + com.mysema.maven @@ -219,38 +265,5 @@ true - \ No newline at end of file diff --git a/src/main/generated/cn/stock/market/infrastructure/db/po/QBtodayStockPO.java b/src/main/generated/cn/stock/market/infrastructure/db/po/QBtodayStockPO.java new file mode 100644 index 0000000..9811eca --- /dev/null +++ b/src/main/generated/cn/stock/market/infrastructure/db/po/QBtodayStockPO.java @@ -0,0 +1,53 @@ +package cn.stock.market.infrastructure.db.po; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.Generated; +import com.querydsl.core.types.Path; + + +/** + * QBtodayStockPO is a Querydsl query type for BtodayStockPO + */ +@Generated("com.querydsl.codegen.EntitySerializer") +public class QBtodayStockPO extends EntityPathBase { + + private static final long serialVersionUID = 1079736803L; + + public static final QBtodayStockPO btodayStockPO = new QBtodayStockPO("btodayStockPO"); + + public final StringPath coCode = createString("coCode"); + + public final NumberPath id = createNumber("id", Integer.class); + + public final DateTimePath lastUpdateTime = createDateTime("lastUpdateTime", java.util.Date.class); + + public final StringPath selfUrl = createString("selfUrl"); + + public final StringPath stockCode = createString("stockCode"); + + public final StringPath stockName = createString("stockName"); + + public final StringPath stockSpell = createString("stockSpell"); + + public final StringPath stockType = createString("stockType"); + + public final StringPath url = createString("url"); + + public QBtodayStockPO(String variable) { + super(BtodayStockPO.class, forVariable(variable)); + } + + public QBtodayStockPO(Path path) { + super(path.getType(), path.getMetadata()); + } + + public QBtodayStockPO(PathMetadata metadata) { + super(BtodayStockPO.class, metadata); + } + +} + diff --git a/src/main/generated/cn/stock/market/infrastructure/stockdb/po/QSiteSettingPO.java b/src/main/generated/cn/stock/market/infrastructure/db/po/QSiteSettingPO.java similarity index 89% rename from src/main/generated/cn/stock/market/infrastructure/stockdb/po/QSiteSettingPO.java rename to src/main/generated/cn/stock/market/infrastructure/db/po/QSiteSettingPO.java index c9e4d71..546e01c 100644 --- a/src/main/generated/cn/stock/market/infrastructure/stockdb/po/QSiteSettingPO.java +++ b/src/main/generated/cn/stock/market/infrastructure/db/po/QSiteSettingPO.java @@ -1,4 +1,4 @@ -package cn.stock.market.infrastructure.stockdb.po; +package cn.stock.market.infrastructure.db.po; import static com.querydsl.core.types.PathMetadataFactory.*; @@ -15,7 +15,7 @@ import com.querydsl.core.types.Path; @Generated("com.querydsl.codegen.EntitySerializer") public class QSiteSettingPO extends EntityPathBase { - private static final long serialVersionUID = -51441337L; + private static final long serialVersionUID = 926298165L; public static final QSiteSettingPO siteSettingPO = new QSiteSettingPO("siteSettingPO"); diff --git a/src/main/generated/cn/stock/market/infrastructure/db/po/QStockIpoPO.java b/src/main/generated/cn/stock/market/infrastructure/db/po/QStockIpoPO.java new file mode 100644 index 0000000..b29a919 --- /dev/null +++ b/src/main/generated/cn/stock/market/infrastructure/db/po/QStockIpoPO.java @@ -0,0 +1,63 @@ +package cn.stock.market.infrastructure.db.po; + +import static com.querydsl.core.types.PathMetadataFactory.*; + +import com.querydsl.core.types.dsl.*; + +import com.querydsl.core.types.PathMetadata; +import javax.annotation.Generated; +import com.querydsl.core.types.Path; + + +/** + * QStockIpoPO is a Querydsl query type for StockIpoPO + */ +@Generated("com.querydsl.codegen.EntitySerializer") +public class QStockIpoPO extends EntityPathBase { + + private static final long serialVersionUID = 1023664740L; + + public static final QStockIpoPO stockIpoPO = new QStockIpoPO("stockIpoPO"); + + public final StringPath apply = createString("apply"); + + public final DateTimePath createDate = createDateTime("createDate", java.util.Date.class); + + public final NumberPath id = createNumber("id", Integer.class); + + public final NumberPath isList = createNumber("isList", Integer.class); + + public final NumberPath isShow = createNumber("isShow", Integer.class); + + public final DateTimePath listingDate = createDateTime("listingDate", java.util.Date.class); + + public final NumberPath peRatio = createNumber("peRatio", java.math.BigDecimal.class); + + public final StringPath sourceType = createString("sourceType"); + + public final StringPath stockCode = createString("stockCode"); + + public final StringPath stockName = createString("stockName"); + + public final NumberPath stockPrice = createNumber("stockPrice", java.math.BigDecimal.class); + + public final DateTimePath subscriptionDate = createDateTime("subscriptionDate", java.util.Date.class); + + public final NumberPath totalNumber = createNumber("totalNumber", Integer.class); + + public final DateTimePath updateDate = createDateTime("updateDate", java.util.Date.class); + + public QStockIpoPO(String variable) { + super(StockIpoPO.class, forVariable(variable)); + } + + public QStockIpoPO(Path path) { + super(path.getType(), path.getMetadata()); + } + + public QStockIpoPO(PathMetadata metadata) { + super(StockIpoPO.class, metadata); + } + +} + diff --git a/src/main/generated/cn/stock/market/infrastructure/stockdb/po/QStockPO.java b/src/main/generated/cn/stock/market/infrastructure/db/po/QStockPO.java similarity index 87% rename from src/main/generated/cn/stock/market/infrastructure/stockdb/po/QStockPO.java rename to src/main/generated/cn/stock/market/infrastructure/db/po/QStockPO.java index 5dd97b5..79fce48 100644 --- a/src/main/generated/cn/stock/market/infrastructure/stockdb/po/QStockPO.java +++ b/src/main/generated/cn/stock/market/infrastructure/db/po/QStockPO.java @@ -1,4 +1,4 @@ -package cn.stock.market.infrastructure.stockdb.po; +package cn.stock.market.infrastructure.db.po; import static com.querydsl.core.types.PathMetadataFactory.*; @@ -15,7 +15,7 @@ import com.querydsl.core.types.Path; @Generated("com.querydsl.codegen.EntitySerializer") public class QStockPO extends EntityPathBase { - private static final long serialVersionUID = -1246401708L; + private static final long serialVersionUID = 2143409346L; public static final QStockPO stockPO = new QStockPO("stockPO"); @@ -33,6 +33,8 @@ public class QStockPO extends EntityPathBase { public final StringPath stockCode = createString("stockCode"); + public final StringPath stockExchangeId = createString("stockExchangeId"); + public final StringPath stockGid = createString("stockGid"); public final StringPath stockName = createString("stockName"); @@ -43,6 +45,8 @@ public class QStockPO extends EntityPathBase { public final NumberPath stockState = createNumber("stockState", Integer.class); + public final StringPath stockSymbol = createString("stockSymbol"); + public final StringPath stockType = createString("stockType"); public QStockPO(String variable) { diff --git a/src/main/java/cn/stock/market/application/CommonApis.java b/src/main/java/cn/stock/market/application/CommonApis.java index b20ffee..e8a240f 100644 --- a/src/main/java/cn/stock/market/application/CommonApis.java +++ b/src/main/java/cn/stock/market/application/CommonApis.java @@ -47,7 +47,7 @@ public class CommonApis { public Map stockDetailMap(List code) { Function> func = (source) -> { return code.stream() - .filter(val -> val != null && source == val.getSource()) +// .filter(val -> val != null && source == val.getSource()) .collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(StockCode::getCode))), ArrayList::new)); }; diff --git a/src/main/java/cn/stock/market/application/assembler/BtodayStockAssembler.java b/src/main/java/cn/stock/market/application/assembler/BtodayStockAssembler.java new file mode 100644 index 0000000..7fce4d3 --- /dev/null +++ b/src/main/java/cn/stock/market/application/assembler/BtodayStockAssembler.java @@ -0,0 +1,35 @@ +package cn.stock.market.application.assembler; + +import cn.qutaojing.common.utils.Beans; +import cn.qutaojing.common.utils.SpringUtils; +import cn.stock.market.domain.basic.entity.BtodayStock; +import cn.stock.market.dto.BtodayStockDTO; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +/** + * BtodayStockAssembler + * + * @author rplees + * @email rplees.i.ly@gmail.com + * @created 2023/12/25 + */ +@Component +@Lazy +public class BtodayStockAssembler { + public BtodayStockDTO toDTO(BtodayStock e) { + BtodayStockDTO dto = Beans.mapper(e, BtodayStockDTO.class); + if(dto == null) return dto; + fill(e, dto); + return dto; + } + + protected void fill(BtodayStock e, BtodayStockDTO dto) { + if(dto == null) return; + return; + } + + public static BtodayStockAssembler of() { + return SpringUtils.getBean(BtodayStockAssembler.class); + } +} diff --git a/src/main/java/cn/stock/market/application/assembler/StockIpoAssembler.java b/src/main/java/cn/stock/market/application/assembler/StockIpoAssembler.java new file mode 100644 index 0000000..1afe643 --- /dev/null +++ b/src/main/java/cn/stock/market/application/assembler/StockIpoAssembler.java @@ -0,0 +1,35 @@ +package cn.stock.market.application.assembler; + +import cn.qutaojing.common.utils.Beans; +import cn.qutaojing.common.utils.SpringUtils; +import cn.stock.market.domain.basic.entity.StockIpo; +import cn.stock.market.dto.StockIpoDTO; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +/** + * StockIpoAssembler + * + * @author rplees + * @email rplees.i.ly@gmail.com + * @created 2023/12/28 + */ +@Component +@Lazy +public class StockIpoAssembler { + public StockIpoDTO toDTO(StockIpo e) { + StockIpoDTO dto = Beans.mapper(e, StockIpoDTO.class); + if(dto == null) return dto; + fill(e, dto); + return dto; + } + + protected void fill(StockIpo e, StockIpoDTO dto) { + if(dto == null) return; + return; + } + + public static StockIpoAssembler of() { + return SpringUtils.getBean(StockIpoAssembler.class); + } +} diff --git a/src/main/java/cn/stock/market/constant/StockData.java b/src/main/java/cn/stock/market/constant/StockData.java new file mode 100644 index 0000000..48013f6 --- /dev/null +++ b/src/main/java/cn/stock/market/constant/StockData.java @@ -0,0 +1,16 @@ +package cn.stock.market.constant; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@AllArgsConstructor +@NoArgsConstructor +@Data +public class StockData { + private String upd_date; + private BigDecimal price; + +} diff --git a/src/main/java/cn/stock/market/domain/basic/convert/BtodayStockConvert.java b/src/main/java/cn/stock/market/domain/basic/convert/BtodayStockConvert.java new file mode 100644 index 0000000..bd71919 --- /dev/null +++ b/src/main/java/cn/stock/market/domain/basic/convert/BtodayStockConvert.java @@ -0,0 +1,23 @@ +package cn.stock.market.domain.basic.convert; + +import cn.qutaojing.common.domain.convert.SimpleEntityPOConvert; +import cn.qutaojing.common.utils.SpringUtils; +import cn.stock.market.domain.basic.entity.BtodayStock; +import cn.stock.market.infrastructure.db.po.BtodayStockPO; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +/** + * BtodayStockConvert + * + * @author rplees + * @email rplees.i.ly@gmail.com + * @created 2023/12/25 + */ +@Component +@Lazy +public class BtodayStockConvert extends SimpleEntityPOConvert { + public static BtodayStockConvert of() { + return SpringUtils.getBean(BtodayStockConvert.class); + } +} diff --git a/src/main/java/cn/stock/market/domain/basic/convert/SiteSettingConvert.java b/src/main/java/cn/stock/market/domain/basic/convert/SiteSettingConvert.java index 60ac1f2..ced1e3b 100644 --- a/src/main/java/cn/stock/market/domain/basic/convert/SiteSettingConvert.java +++ b/src/main/java/cn/stock/market/domain/basic/convert/SiteSettingConvert.java @@ -6,7 +6,7 @@ import org.springframework.stereotype.Component; import cn.qutaojing.common.domain.convert.SimpleEntityPOConvert; import cn.qutaojing.common.utils.SpringUtils; import cn.stock.market.domain.basic.entity.SiteSetting; -import cn.stock.market.infrastructure.stockdb.po.SiteSettingPO; +import cn.stock.market.infrastructure.db.po.SiteSettingPO; /** * StockConvert diff --git a/src/main/java/cn/stock/market/domain/basic/convert/StockConvert.java b/src/main/java/cn/stock/market/domain/basic/convert/StockConvert.java index d2978de..b3d65e1 100644 --- a/src/main/java/cn/stock/market/domain/basic/convert/StockConvert.java +++ b/src/main/java/cn/stock/market/domain/basic/convert/StockConvert.java @@ -3,7 +3,7 @@ package cn.stock.market.domain.basic.convert; import cn.qutaojing.common.domain.convert.SimpleEntityPOConvert; import cn.qutaojing.common.utils.SpringUtils; import cn.stock.market.domain.basic.entity.Stock; -import cn.stock.market.infrastructure.stockdb.po.StockPO; +import cn.stock.market.infrastructure.db.po.StockPO; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; diff --git a/src/main/java/cn/stock/market/domain/basic/convert/StockIpoConvert.java b/src/main/java/cn/stock/market/domain/basic/convert/StockIpoConvert.java new file mode 100644 index 0000000..1cfec5a --- /dev/null +++ b/src/main/java/cn/stock/market/domain/basic/convert/StockIpoConvert.java @@ -0,0 +1,23 @@ +package cn.stock.market.domain.basic.convert; + +import cn.qutaojing.common.domain.convert.SimpleEntityPOConvert; +import cn.qutaojing.common.utils.SpringUtils; +import cn.stock.market.domain.basic.entity.StockIpo; +import cn.stock.market.infrastructure.db.po.StockIpoPO; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +/** + * StockIpoConvert + * + * @author rplees + * @email rplees.i.ly@gmail.com + * @created 2023/12/28 + */ +@Component +@Lazy +public class StockIpoConvert extends SimpleEntityPOConvert { + public static StockIpoConvert of() { + return SpringUtils.getBean(StockIpoConvert.class); + } +} diff --git a/src/main/java/cn/stock/market/domain/basic/entity/BtodayStock.java b/src/main/java/cn/stock/market/domain/basic/entity/BtodayStock.java new file mode 100644 index 0000000..e9d3cf7 --- /dev/null +++ b/src/main/java/cn/stock/market/domain/basic/entity/BtodayStock.java @@ -0,0 +1,28 @@ +package cn.stock.market.domain.basic.entity; + +import cn.qutaojing.common.utils.Beans; +import cn.stock.market.dto.command.BtodayStockCreateCommand; +import cn.stock.market.infrastructure.db.po.BtodayStockPO; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * BtodayStock + * + * @author rplees + * @email rplees.i.ly@gmail.com + * @created 2023/12/25 + */ +@Data +@NoArgsConstructor +@SuperBuilder +@EqualsAndHashCode( + callSuper = false +) +public class BtodayStock extends BtodayStockPO { + public void update(BtodayStockCreateCommand cmd) { + Beans.copyProperties(cmd, this); + } +} diff --git a/src/main/java/cn/stock/market/domain/basic/entity/SiteSetting.java b/src/main/java/cn/stock/market/domain/basic/entity/SiteSetting.java index b9f0d99..e3f8684 100644 --- a/src/main/java/cn/stock/market/domain/basic/entity/SiteSetting.java +++ b/src/main/java/cn/stock/market/domain/basic/entity/SiteSetting.java @@ -10,7 +10,7 @@ import com.google.common.collect.Lists; import cn.qutaojing.common.utils.Beans; import cn.stock.market.dto.command.StockCreateCommand; -import cn.stock.market.infrastructure.stockdb.po.SiteSettingPO; +import cn.stock.market.infrastructure.db.po.SiteSettingPO; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; diff --git a/src/main/java/cn/stock/market/domain/basic/entity/Stock.java b/src/main/java/cn/stock/market/domain/basic/entity/Stock.java index 6c4cfa2..b5fa629 100644 --- a/src/main/java/cn/stock/market/domain/basic/entity/Stock.java +++ b/src/main/java/cn/stock/market/domain/basic/entity/Stock.java @@ -2,7 +2,7 @@ package cn.stock.market.domain.basic.entity; import cn.qutaojing.common.utils.Beans; import cn.stock.market.dto.command.StockCreateCommand; -import cn.stock.market.infrastructure.stockdb.po.StockPO; +import cn.stock.market.infrastructure.db.po.StockPO; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; diff --git a/src/main/java/cn/stock/market/domain/basic/entity/StockIpo.java b/src/main/java/cn/stock/market/domain/basic/entity/StockIpo.java new file mode 100644 index 0000000..7ba804c --- /dev/null +++ b/src/main/java/cn/stock/market/domain/basic/entity/StockIpo.java @@ -0,0 +1,28 @@ +package cn.stock.market.domain.basic.entity; + +import cn.qutaojing.common.utils.Beans; +import cn.stock.market.dto.command.StockIpoCreateCommand; +import cn.stock.market.infrastructure.db.po.StockIpoPO; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * StockIpo + * + * @author rplees + * @email rplees.i.ly@gmail.com + * @created 2023/12/28 + */ +@Data +@NoArgsConstructor +@SuperBuilder +@EqualsAndHashCode( + callSuper = false +) +public class StockIpo extends StockIpoPO { + public void update(StockIpoCreateCommand cmd) { + Beans.copyProperties(cmd, this); + } +} diff --git a/src/main/java/cn/stock/market/domain/basic/factory/BtodayStockFactory.java b/src/main/java/cn/stock/market/domain/basic/factory/BtodayStockFactory.java new file mode 100644 index 0000000..4941df7 --- /dev/null +++ b/src/main/java/cn/stock/market/domain/basic/factory/BtodayStockFactory.java @@ -0,0 +1,28 @@ +package cn.stock.market.domain.basic.factory; + +import cn.qutaojing.common.utils.SpringUtils; +import cn.stock.market.domain.basic.entity.BtodayStock; +import cn.stock.market.dto.command.BtodayStockCreateCommand; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +/** + * BtodayStockFactory + * + * @author rplees + * @email rplees.i.ly@gmail.com + * @created 2023/12/25 + */ +@Component +@Lazy +public class BtodayStockFactory { + public static BtodayStockFactory of() { + return SpringUtils.getBean(BtodayStockFactory.class); + } + + public BtodayStock from(BtodayStockCreateCommand cmd) { + BtodayStock e = BtodayStock.builder().build(); + e.update(cmd); + return e; + } +} diff --git a/src/main/java/cn/stock/market/domain/basic/factory/StockIpoFactory.java b/src/main/java/cn/stock/market/domain/basic/factory/StockIpoFactory.java new file mode 100644 index 0000000..a451316 --- /dev/null +++ b/src/main/java/cn/stock/market/domain/basic/factory/StockIpoFactory.java @@ -0,0 +1,28 @@ +package cn.stock.market.domain.basic.factory; + +import cn.qutaojing.common.utils.SpringUtils; +import cn.stock.market.domain.basic.entity.StockIpo; +import cn.stock.market.dto.command.StockIpoCreateCommand; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +/** + * StockIpoFactory + * + * @author rplees + * @email rplees.i.ly@gmail.com + * @created 2023/12/28 + */ +@Component +@Lazy +public class StockIpoFactory { + public static StockIpoFactory of() { + return SpringUtils.getBean(StockIpoFactory.class); + } + + public StockIpo from(StockIpoCreateCommand cmd) { + StockIpo e = StockIpo.builder().build(); + e.update(cmd); + return e; + } +} diff --git a/src/main/java/cn/stock/market/domain/basic/repository/BtodayStockRepository.java b/src/main/java/cn/stock/market/domain/basic/repository/BtodayStockRepository.java new file mode 100644 index 0000000..554c39e --- /dev/null +++ b/src/main/java/cn/stock/market/domain/basic/repository/BtodayStockRepository.java @@ -0,0 +1,54 @@ +package cn.stock.market.domain.basic.repository; + +import cn.qutaojing.common.domain.convert.IEntityPOConvert; +import cn.qutaojing.common.domain.respostory.SimplePoConvertEntityRepository; +import cn.qutaojing.common.utils.SpringUtils; +import cn.stock.market.domain.basic.convert.BtodayStockConvert; +import cn.stock.market.domain.basic.entity.BtodayStock; +import cn.stock.market.domain.basic.entity.Stock; +import cn.stock.market.infrastructure.db.po.BtodayStockPO; +import cn.stock.market.infrastructure.db.po.QBtodayStockPO; +import cn.stock.market.infrastructure.db.repo.BtodayStockRepo; +import com.rp.spring.jpa.GenericJpaRepository; +import java.lang.Integer; +import java.lang.Override; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +/** + * BtodayStockRepository + * + * @author rplees + * @email rplees.i.ly@gmail.com + * @created 2023/12/25 + */ +@Repository +@RequiredArgsConstructor( + onConstructor = @__(@Autowired) +) +public class BtodayStockRepository extends SimplePoConvertEntityRepository { + final BtodayStockRepo repo; + + final BtodayStockConvert convert; + + final QBtodayStockPO q = QBtodayStockPO.btodayStockPO; + + @Override + public GenericJpaRepository repo() { + return repo; + } + + @Override + public IEntityPOConvert convert() { + return convert; + } + + public static BtodayStockRepository of() { + return SpringUtils.getBean(BtodayStockRepository.class); + } + + public BtodayStock findBtStockByCoCode(String coCode,String stockType) { + return findOneIfMutil(q.coCode.eq(coCode),q.stockType.eq(stockType)); + } +} diff --git a/src/main/java/cn/stock/market/domain/basic/repository/SiteSettingRepository.java b/src/main/java/cn/stock/market/domain/basic/repository/SiteSettingRepository.java index fa455d8..8c183a4 100644 --- a/src/main/java/cn/stock/market/domain/basic/repository/SiteSettingRepository.java +++ b/src/main/java/cn/stock/market/domain/basic/repository/SiteSettingRepository.java @@ -10,8 +10,8 @@ import cn.qutaojing.common.domain.respostory.LocalCacheRepository; import cn.qutaojing.common.utils.SpringUtils; import cn.stock.market.domain.basic.convert.SiteSettingConvert; import cn.stock.market.domain.basic.entity.SiteSetting; -import cn.stock.market.infrastructure.stockdb.po.SiteSettingPO; -import cn.stock.market.infrastructure.stockdb.repo.SiteSettingRepo; +import cn.stock.market.infrastructure.db.po.SiteSettingPO; +import cn.stock.market.infrastructure.db.repo.SiteSettingRepo; import lombok.RequiredArgsConstructor; /** diff --git a/src/main/java/cn/stock/market/domain/basic/repository/StockIpoRepository.java b/src/main/java/cn/stock/market/domain/basic/repository/StockIpoRepository.java new file mode 100644 index 0000000..c3c7c9a --- /dev/null +++ b/src/main/java/cn/stock/market/domain/basic/repository/StockIpoRepository.java @@ -0,0 +1,46 @@ +package cn.stock.market.domain.basic.repository; + +import cn.qutaojing.common.domain.convert.IEntityPOConvert; +import cn.qutaojing.common.domain.respostory.SimplePoConvertEntityRepository; +import cn.qutaojing.common.utils.SpringUtils; +import cn.stock.market.domain.basic.convert.StockIpoConvert; +import cn.stock.market.domain.basic.entity.StockIpo; +import cn.stock.market.infrastructure.db.po.StockIpoPO; +import cn.stock.market.infrastructure.db.repo.StockIpoRepo; +import com.rp.spring.jpa.GenericJpaRepository; +import java.lang.Integer; +import java.lang.Override; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +/** + * StockIpoRepository + * + * @author rplees + * @email rplees.i.ly@gmail.com + * @created 2023/12/28 + */ +@Repository +@RequiredArgsConstructor( + onConstructor = @__(@Autowired) +) +public class StockIpoRepository extends SimplePoConvertEntityRepository { + final StockIpoRepo repo; + + final StockIpoConvert convert; + + @Override + public GenericJpaRepository repo() { + return repo; + } + + @Override + public IEntityPOConvert convert() { + return convert; + } + + public static StockIpoRepository of() { + return SpringUtils.getBean(StockIpoRepository.class); + } +} diff --git a/src/main/java/cn/stock/market/domain/basic/repository/StockRepository.java b/src/main/java/cn/stock/market/domain/basic/repository/StockRepository.java index 6eb589e..bd02858 100644 --- a/src/main/java/cn/stock/market/domain/basic/repository/StockRepository.java +++ b/src/main/java/cn/stock/market/domain/basic/repository/StockRepository.java @@ -5,6 +5,7 @@ import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import cn.stock.market.infrastructure.db.po.QStockPO; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; @@ -21,9 +22,8 @@ import cn.qutaojing.common.jpa.ConditionBuilder; import cn.qutaojing.common.utils.SpringUtils; import cn.stock.market.domain.basic.convert.StockConvert; import cn.stock.market.domain.basic.entity.Stock; -import cn.stock.market.infrastructure.stockdb.po.QStockPO; -import cn.stock.market.infrastructure.stockdb.po.StockPO; -import cn.stock.market.infrastructure.stockdb.repo.StockRepo; +import cn.stock.market.infrastructure.db.po.StockPO; +import cn.stock.market.infrastructure.db.repo.StockRepo; import lombok.RequiredArgsConstructor; /** diff --git a/src/main/java/cn/stock/market/domain/basic/service/BtodayStockService.java b/src/main/java/cn/stock/market/domain/basic/service/BtodayStockService.java new file mode 100644 index 0000000..e19479a --- /dev/null +++ b/src/main/java/cn/stock/market/domain/basic/service/BtodayStockService.java @@ -0,0 +1,38 @@ +package cn.stock.market.domain.basic.service; + +import cn.qutaojing.common.utils.SpringUtils; +import cn.stock.market.domain.basic.entity.BtodayStock; +import cn.stock.market.domain.basic.factory.BtodayStockFactory; +import cn.stock.market.domain.basic.repository.BtodayStockRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * BtodayStockService + * + * @author rplees + * @email rplees.i.ly@gmail.com + * @created 2023/12/25 + */ +@Service +@RequiredArgsConstructor( + onConstructor = @__(@Autowired) +) +public class BtodayStockService { + final BtodayStockRepository repository; + + final BtodayStockFactory factory; + + public BtodayStockRepository repository() { + return repository; + } + + public static BtodayStockService of() { + return SpringUtils.getBean(BtodayStockService.class); + } + + public BtodayStock findBtStockByCoCode(String coCode,String stockType){ + return repository.findBtStockByCoCode(coCode,stockType); + } +} diff --git a/src/main/java/cn/stock/market/domain/basic/service/StockIpoService.java b/src/main/java/cn/stock/market/domain/basic/service/StockIpoService.java new file mode 100644 index 0000000..81a2a48 --- /dev/null +++ b/src/main/java/cn/stock/market/domain/basic/service/StockIpoService.java @@ -0,0 +1,33 @@ +package cn.stock.market.domain.basic.service; + +import cn.qutaojing.common.utils.SpringUtils; +import cn.stock.market.domain.basic.factory.StockIpoFactory; +import cn.stock.market.domain.basic.repository.StockIpoRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * StockIpoService + * + * @author rplees + * @email rplees.i.ly@gmail.com + * @created 2023/12/28 + */ +@Service +@RequiredArgsConstructor( + onConstructor = @__(@Autowired) +) +public class StockIpoService { + final StockIpoRepository repository; + + final StockIpoFactory factory; + + public StockIpoRepository repository() { + return repository; + } + + public static StockIpoService of() { + return SpringUtils.getBean(StockIpoService.class); + } +} 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 024e58a..fa8d0c9 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 @@ -1,23 +1,42 @@ package cn.stock.market.domain.basic.service; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; import java.math.BigDecimal; +import java.net.URL; +import java.net.URLConnection; 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.investing.IndiaIndexVo; +import cn.stock.market.infrastructure.api.investing.IndiaStockVO; +import cn.stock.market.infrastructure.api.investing.InvestingApis; +import cn.stock.market.infrastructure.api.investing.InvestingInvokerApis; import cn.stock.market.infrastructure.api.sina.vo.HotSearchVO; +import cn.stock.market.utils.*; +import com.ag.utils.CollectionUtils; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.google.common.base.Stopwatch; +import okhttp3.OkHttpClient; +import okhttp3.Protocol; +import okhttp3.Request; +import okhttp3.Request.Builder; import org.apache.commons.lang3.StringUtils; +import cn.stock.market.infrastructure.db.po.QStockPO; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; @@ -43,7 +62,6 @@ import cn.stock.market.infrastructure.api.sina.vo.MarketVO; 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; @@ -238,6 +256,38 @@ public class StockService { return ServerResponse.createBySuccess(marketVO); } + public String getNews() { + String result = ""; + try { + // 使用Jsoup连接到网页 + Document doc = Jsoup.connect("https://www.business-standard.com/markets/news") + .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36") + .header("Referer", "https://www.business-standard.com/") + .header("Accept-Language", "en-US,en;q=0.9") + .get(); + result = doc.html().substring(doc.html().indexOf("
"),doc.html().lastIndexOf("
")+500); + } catch (Exception e) { + return e.toString(); + } + return result; + } + + public String getNewsInfo(String url) { + String result = ""; + try { + // 使用Jsoup连接到网页 + Document doc = Jsoup.connect(url) + .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36") + .header("Referer", "https://www.business-standard.com/") + .header("Accept-Language", "en-US,en;q=0.9") + .get(); + result = doc.html().substring(doc.html().indexOf("articleBody") + 15, doc.html().indexOf(",\"author\":") - 1); + } catch (Exception e) { + return e.toString(); + } + return result; + } + public ServerResponse getStock(int pageNum, int pageSize, String keyWords, String stockPlate, String stockType, HttpServletRequest request) { Page page = repository.findStockListByKeyWords(keyWords, stockPlate, stockType, 0, PageParam.of(pageNum, pageSize)); @@ -711,4 +761,215 @@ 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); + } + } + + public ServerResponse syncIndiaData(){ + log.info("同步股票数据开始。。。。"); + Map stockMap = StockRepository.of().cacheCodeMap(); + Stopwatch stopwatch = Stopwatch.createStarted(); + List list = Lists.newArrayList(); + int currentTotal = 0; + int pageNum =1; + int pageSize = 300; + try { + for(int i = 0;i < pageNum;i ++) { + String tmpl = "https://api.investing.com/api/financialdata/assets/equitiesByCountry/default?fields-list=id,name,symbol,high,low,last,lastPairDecimal,change,changePercent,volume,time,isOpen,url,flag,countryNameTranslated,exchangeId,performanceDay,performanceWeek,performanceMonth,performanceYtd,performanceYear,performance3Year,technicalHour,technicalDay,technicalWeek,technicalMonth,avgVolume,fundamentalMarketCap,fundamentalRevenue,fundamentalRatio,fundamentalBeta,pairType&country-id=14&page={}&page-size={}&include-major-indices=false&include-additional-indices=false&include-primary-sectors=false&include-other-indices=false&limit=0"; + String url = StrFormatter.format(tmpl, pageNum - 1, pageSize); +// String str = HttpClientRequest.doGet(url); + JSONObject jsonObject = InvestingInvokerApis.of().__page(pageNum, pageSize); +// JSONObject jsonObject = JSON.parseObject(str); + int total = 0; + if(jsonObject.containsKey("total")){ + total = Integer.parseInt(jsonObject.get("total").toString()); + } + JSONArray dataObjArray = new JSONArray(); + if(jsonObject.containsKey("data")){ + dataObjArray = JSON.parseArray(jsonObject.get("data").toString()); + } + for (Object obj : dataObjArray) { + JSONObject jsonObject2 = JSON.parseObject(obj.toString()); + String code = jsonObject2.get("Id").toString(); + String name = jsonObject2.get("Name").toString(); + String stockSymbol = jsonObject2.get("Symbol").toString(); + String exchangeId = jsonObject2.get("ExchangeId").toString(); + if (stockMap.containsKey(code)) { + log.info("已经存在 {} 信息, 跳过", code); + continue; + } + + if(! Utils.isShOrSzOrBJ(code)) { + log.info("{} 非 sh 或者 sz 或者 bj , 跳过", code); + continue; + } + Stock stock = new Stock(); + stock.setStockSymbol(stockSymbol); + stock.setStockExchangeId(exchangeId); + stock.setStockName(name); + stock.setStockCode(code); + stock.setIsLock(0); + stock.setIsShow(0); + stock.setAddTime(new Date()); + stock.setStockState(0); + list.add(stock); + } + currentTotal += pageSize; + if((total - currentTotal) < pageSize ){ + pageSize = total - currentTotal; + } + if(total <= currentTotal){ + break; + } + pageNum ++; + } + if(CollectionUtils.isNotEmpty(list)) { + StockRepository.of().saveAll(list); + } + int count = list.size(); + log.info("syncAFutureStockList执行, 受影响数{}, 耗时:{}毫秒", count, stopwatch.elapsed(TimeUnit.MILLISECONDS)); + log.info("同步股票数据结束。。。。"); + return ServerResponse.createBySuccess(); + } catch (Exception e) { + log.info("同步股票数据异常,异常信息{}。。。。",e.getMessage()); + return ServerResponse.createByErrorMsg(e.getMessage()); + } + } + public void syncIndiaData2(){ + log.info("同步股票数据开始。。。。"); + Map stockMap = StockRepository.of().cacheCodeMap(); + Stopwatch stopwatch = Stopwatch.createStarted(); + List list = Lists.newArrayList(); + int currentTotal = 0; + int pageNum =1; + int pageSize = 300; + try { + + String str = Utils.readTxt(); + JSONObject jsonObject = JSON.parseObject(str); + JSONArray dataObjArray = JSON.parseArray(jsonObject.get("data").toString()); + for (Object obj : dataObjArray) { + JSONObject jsonObject2 = JSON.parseObject(obj.toString()); + String code = jsonObject2.get("Id").toString(); + String name = jsonObject2.get("Name").toString(); + String stockSymbol = jsonObject2.get("Symbol").toString(); + String exchangeId = jsonObject2.get("ExchangeId").toString(); + String fundamentalMarketCap = null; + if(jsonObject2.containsKey("FundamentalMarketCap") && jsonObject2.get("FundamentalMarketCap") != null){ + fundamentalMarketCap = jsonObject2.get("FundamentalMarketCap").toString(); + } + if (stockMap.containsKey(code)) { + log.info("已经存在 {} 信息, 跳过", code); + continue; + } + + if(! Utils.isShOrSzOrBJ(code)) { + log.info("{} 非 sh 或者 sz 或者 bj , 跳过", code); + continue; + } + Stock stock = new Stock(); + stock.setStockSymbol(stockSymbol); + stock.setStockExchangeId(exchangeId); + stock.setStockName(name); + stock.setStockCode(code); + stock.setIsLock(0); + stock.setIsShow(0); + stock.setAddTime(new Date()); + stock.setStockState(0); +// stock.setFundamentalMarketCap(fundamentalMarketCap); + list.add(stock); + } + + if(CollectionUtils.isNotEmpty(list)) { + StockRepository.of().saveAll(list); + } + int count = list.size(); + log.info("syncAFutureStockList执行, 受影响数{}, 耗时:{}毫秒", count, stopwatch.elapsed(TimeUnit.MILLISECONDS)); + log.info("同步股票数据结束。。。。"); + } catch (Exception e) { + log.info("同步股票数据异常,异常信息{}。。。。",e.getMessage()); + } + + } + + public String jsoupByUrl(String url) { + String result = ""; + try { + // 使用Jsoup连接到网页 + Document doc = Jsoup.connect(url) + .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36") + .header("Referer", "https://www.business-standard.com/") + .header("Accept-Language", "en-US,en;q=0.9") + .get(); + result = doc.html(); + } catch (Exception e) { + return e.toString(); + } + return result; + } + + public ServerResponse getIndiaIndex() { + List indexVoList = new ArrayList<>(); + //获取BSESENSEX指数 + + try { + IndiaIndexVo vo1 = new IndiaIndexVo(); + String stockCode = "39929"; + IndiaStockVO market = InvestingApis.of().market(StockCode.of(stockCode)); + market.setName("BSESENSEX指数"); + vo1.setIndexVo(market); + + String type = "min"; + List list = InvestingApis.of().kline(StockCode.of(stockCode), type); + if(list == null || list.size() == 0){ + type = "day"; + list = InvestingApis.of().kline(StockCode.of(stockCode), type); + } + vo1.setKLine(list); + indexVoList.add(vo1); + } catch (IOException e) { + log.info("获取BSESENSEX指数数据异常,异常信息{}。。。。",e.getMessage()); + } + try { + IndiaIndexVo vo2 = new IndiaIndexVo(); + String stockCode = "8985"; //"17940"; + IndiaStockVO market = InvestingApis.of().market(StockCode.of(stockCode)); + market.setName("NIFTY50指数"); + vo2.setIndexVo(market); + + String type = "min"; + List list = InvestingApis.of().kline(StockCode.of(stockCode), type); + if(list == null || list.size() == 0){ + type = "day"; + list = InvestingApis.of().kline(StockCode.of(stockCode), type); + } + vo2.setKLine(list); + indexVoList.add(vo2); + } catch (IOException e) { + log.info("获取NIFTY50指数数据异常,异常信息{}。。。。",e.getMessage()); + } + return ServerResponse.createBySuccess(indexVoList); + } } \ No newline at end of file diff --git a/src/main/java/cn/stock/market/dto/BtodayStockDTO.java b/src/main/java/cn/stock/market/dto/BtodayStockDTO.java new file mode 100644 index 0000000..d6d0bf3 --- /dev/null +++ b/src/main/java/cn/stock/market/dto/BtodayStockDTO.java @@ -0,0 +1,23 @@ +package cn.stock.market.dto; + +import cn.stock.market.infrastructure.db.po.BtodayStockPO; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * BtodayStockDTO + * + * @author rplees + * @email rplees.i.ly@gmail.com + * @created 2023/12/25 + */ +@Data +@NoArgsConstructor +@SuperBuilder +@EqualsAndHashCode( + callSuper = false +) +public class BtodayStockDTO extends BtodayStockPO { +} diff --git a/src/main/java/cn/stock/market/dto/StockDTO.java b/src/main/java/cn/stock/market/dto/StockDTO.java index 8dc74a6..7a51af1 100644 --- a/src/main/java/cn/stock/market/dto/StockDTO.java +++ b/src/main/java/cn/stock/market/dto/StockDTO.java @@ -1,6 +1,6 @@ package cn.stock.market.dto; -import cn.stock.market.infrastructure.stockdb.po.StockPO; +import cn.stock.market.infrastructure.db.po.StockPO; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; diff --git a/src/main/java/cn/stock/market/dto/StockIpoDTO.java b/src/main/java/cn/stock/market/dto/StockIpoDTO.java new file mode 100644 index 0000000..8d3cb67 --- /dev/null +++ b/src/main/java/cn/stock/market/dto/StockIpoDTO.java @@ -0,0 +1,23 @@ +package cn.stock.market.dto; + +import cn.stock.market.infrastructure.db.po.StockIpoPO; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * StockIpoDTO + * + * @author rplees + * @email rplees.i.ly@gmail.com + * @created 2023/12/28 + */ +@Data +@NoArgsConstructor +@SuperBuilder +@EqualsAndHashCode( + callSuper = false +) +public class StockIpoDTO extends StockIpoPO { +} diff --git a/src/main/java/cn/stock/market/dto/command/BtodayStockCreateCommand.java b/src/main/java/cn/stock/market/dto/command/BtodayStockCreateCommand.java new file mode 100644 index 0000000..db71552 --- /dev/null +++ b/src/main/java/cn/stock/market/dto/command/BtodayStockCreateCommand.java @@ -0,0 +1,54 @@ +package cn.stock.market.dto.command; + +import java.lang.Integer; +import java.lang.String; +import java.util.Date; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * BtodayStockCreateCommand + * + * @author rplees + * @email rplees.i.ly@gmail.com + * @created 2023/12/25 + */ +@Data +@SuperBuilder +@NoArgsConstructor +public class BtodayStockCreateCommand { + /** + * 主键 */ + Integer id; + + /** + * 股票名称 */ + String stockName; + + /** + * 股票code */ + String stockCode; + + /** + * 类型 */ + String stockType; + + String stockSpell; + + /** + * btoday的业务id */ + String coCode; + + /** + * 主页的http链接 */ + String selfUrl; + + /** + * url */ + String url; + + /** + * 上次更新时间 */ + Date lastUpdateTime; +} diff --git a/src/main/java/cn/stock/market/dto/command/BtodayStockModifyCommand.java b/src/main/java/cn/stock/market/dto/command/BtodayStockModifyCommand.java new file mode 100644 index 0000000..0982df3 --- /dev/null +++ b/src/main/java/cn/stock/market/dto/command/BtodayStockModifyCommand.java @@ -0,0 +1,24 @@ +package cn.stock.market.dto.command; + +import java.lang.Integer; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * BtodayStockModifyCommand + * + * @author rplees + * @email rplees.i.ly@gmail.com + * @created 2023/12/25 + */ +@Data +@SuperBuilder +@NoArgsConstructor +@EqualsAndHashCode( + callSuper = false +) +public class BtodayStockModifyCommand extends BtodayStockCreateCommand { + Integer id; +} diff --git a/src/main/java/cn/stock/market/dto/command/StockIpoCreateCommand.java b/src/main/java/cn/stock/market/dto/command/StockIpoCreateCommand.java new file mode 100644 index 0000000..ba75cc2 --- /dev/null +++ b/src/main/java/cn/stock/market/dto/command/StockIpoCreateCommand.java @@ -0,0 +1,69 @@ +package cn.stock.market.dto.command; + +import java.lang.Integer; +import java.lang.String; +import java.math.BigDecimal; +import java.util.Date; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * StockIpoCreateCommand + * + * @author rplees + * @email rplees.i.ly@gmail.com + * @created 2023/12/28 + */ +@Data +@SuperBuilder +@NoArgsConstructor +public class StockIpoCreateCommand { + Integer id; + + /** + * 股票代码 */ + String stockCode; + + /** + * 股票名称 */ + String stockName; + + /** + * 发行价格 */ + BigDecimal stockPrice; + + /** + * 申购日期 */ + Date subscriptionDate; + + /** + * 上市日期 */ + Date listingDate; + + /** + * 是否显示【1 显示,2 不显示】 */ + Integer isShow; + + /** + * 是否上市【1 未上市,2 已上市】 */ + Integer isList; + + Date createDate; + + Date updateDate; + + /** + * 发行总数 */ + Integer totalNumber; + + /** + * 申请总额 */ + String apply; + + /** + * 市盈率 */ + BigDecimal peRatio; + + String sourceType; +} diff --git a/src/main/java/cn/stock/market/dto/command/StockIpoModifyCommand.java b/src/main/java/cn/stock/market/dto/command/StockIpoModifyCommand.java new file mode 100644 index 0000000..005dbd4 --- /dev/null +++ b/src/main/java/cn/stock/market/dto/command/StockIpoModifyCommand.java @@ -0,0 +1,24 @@ +package cn.stock.market.dto.command; + +import java.lang.Integer; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * StockIpoModifyCommand + * + * @author rplees + * @email rplees.i.ly@gmail.com + * @created 2023/12/28 + */ +@Data +@SuperBuilder +@NoArgsConstructor +@EqualsAndHashCode( + callSuper = false +) +public class StockIpoModifyCommand extends StockIpoCreateCommand { + Integer id; +} diff --git a/src/main/java/cn/stock/market/dto/model/StockCode.java b/src/main/java/cn/stock/market/dto/model/StockCode.java index 9da5156..d537f51 100644 --- a/src/main/java/cn/stock/market/dto/model/StockCode.java +++ b/src/main/java/cn/stock/market/dto/model/StockCode.java @@ -14,17 +14,20 @@ import lombok.experimental.SuperBuilder; @ApiModel public class StockCode { String code; - StockSource source; +// StockSource source; public static StockCode a(String code) { - return of(code, StockSource.A); + return StockCode.builder().code(code) + .build(); } - - public static StockCode of(String code, String source) { - return of(code, StockSource.of(source)); + public static StockCode of(String code) { + return StockCode.builder().code(code) + .build(); } public static StockCode of(String code, StockSource source) { - return StockCode.builder().code(code).source(source).build(); + return StockCode.builder().code(code) +// .source(source) + .build(); } } diff --git a/src/main/java/cn/stock/market/dto/model/StockVO.java b/src/main/java/cn/stock/market/dto/model/StockVO.java index 45e088d..c141ff8 100644 --- a/src/main/java/cn/stock/market/dto/model/StockVO.java +++ b/src/main/java/cn/stock/market/dto/model/StockVO.java @@ -61,7 +61,16 @@ public class StockVO { private String monthImg; private Integer depositAmt; - + private String volume; + + public String getVolume() { + return volume; + } + + public void setVolume(String volume) { + this.volume = volume; + } + public static StockVO from(StockDetail detail, Stock stock) { StockVO vo = new StockVO(); if(stock != null) { diff --git a/src/main/java/cn/stock/market/infrastructure/api/TodayApis.java b/src/main/java/cn/stock/market/infrastructure/api/TodayApis.java new file mode 100644 index 0000000..bd50302 --- /dev/null +++ b/src/main/java/cn/stock/market/infrastructure/api/TodayApis.java @@ -0,0 +1,114 @@ +package cn.stock.market.infrastructure.api; + +import cn.stock.market.utils.HttpClientRequest; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +/** + * 数据来源网站:https://www.businesstoday.in/stocks + * + * @auther xiaoliuhu + */ +public class TodayApis { + + static String get(String url) { + return HttpClientRequest.doGet(url); + } + + //获取Top Gainers + public static List getTopGainers(String exchange){ + String url = "https://marketapi.intoday.in/widget/topgainer/view?exchange=" + exchange; + //返回字符串对象格式:{"status_code":1,"success":true,"data":[{}],"message":"Successful","fromredis":true} + String str = get(url); + JSONObject object = JSON.parseObject(str); + boolean bool = false; + if(object.containsKey("success")){ + bool = object.getBoolean("success"); + } + if(!bool){ + return null; + } + //进行数据转换 + List dataObject = new ArrayList<>(); + JSONArray jsonArray = JSON.parseArray(object.getString("data")); + for (Object obj : jsonArray){ + JSONObject entity = JSON.parseObject(obj.toString()); + dataObject.add(entity); + } + return dataObject; + } + //获取Top Losers + public static List getTopLosers(String exchange){ + String url = "https://marketapi.intoday.in/widget/toploser/view?exchange=" + exchange; + //返回字符串对象格式:{"status_code":1,"success":true,"data":[{}],"message":"Successful","fromredis":true} + String str = get(url); + JSONObject object = JSON.parseObject(str); + boolean bool = false; + if(object.containsKey("success")){ + bool = object.getBoolean("success"); + } + if(!bool){ + return null; + } + //进行数据转换 + List dataObject = new ArrayList<>(); + JSONArray jsonArray = JSON.parseArray(object.getString("data")); + for (Object obj : jsonArray){ + JSONObject entity = JSON.parseObject(obj.toString()); + dataObject.add(entity); + } + return dataObject; + } + //获取Most Active Volume + public static List getMostActiveVolume(String exchange){ + String url = "https://marketapi.intoday.in/widget/mostactivetopper/view?exchange=" + exchange; + //返回字符串对象格式:{"status_code":1,"success":true,"data":[{}],"message":"Successful","fromredis":true} + String str = get(url); + JSONObject object = JSON.parseObject(str); + boolean bool = false; + if(object.containsKey("success")){ + bool = object.getBoolean("success"); + } + if(!bool){ + return null; + } + //进行数据转换 + List dataObject = new ArrayList<>(); + JSONArray jsonArray = JSON.parseArray(object.getString("data")); + for (Object obj : jsonArray){ + JSONObject entity = JSON.parseObject(obj.toString()); + dataObject.add(entity); + } + return dataObject; + } + //获取Most Active Value + public static List getMostActiveValue(String exchange){ + String url = "https://marketapi.intoday.in/widget/mostactivetopperbyvalue/view?exchange=" + exchange; + //返回字符串对象格式:{"status_code":1,"success":true,"data":[{}],"message":"Successful","fromredis":true} + String str = get(url); + JSONObject object = JSON.parseObject(str); + boolean bool = false; + if(object.containsKey("success")){ + bool = object.getBoolean("success"); + } + if(!bool){ + return null; + } + //进行数据转换 + List dataObject = new ArrayList<>(); + JSONArray jsonArray = JSON.parseArray(object.getString("data")); + for (Object obj : jsonArray){ + JSONObject entity = JSON.parseObject(obj.toString()); + dataObject.add(entity); + } + return dataObject; + } + + public static void main(String[] args) { + System.out.println(getTopGainers("nse")); + } +} diff --git a/src/main/java/cn/stock/market/infrastructure/api/investing/IndiaIndexVo.java b/src/main/java/cn/stock/market/infrastructure/api/investing/IndiaIndexVo.java new file mode 100644 index 0000000..031d2fc --- /dev/null +++ b/src/main/java/cn/stock/market/infrastructure/api/investing/IndiaIndexVo.java @@ -0,0 +1,17 @@ +package cn.stock.market.infrastructure.api.investing; + +import com.alibaba.fastjson.JSONObject; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +@Data +@ApiModel(value = "指数信息") +public class IndiaIndexVo { + @ApiModelProperty(value = "指数详情") + private IndiaStockVO indexVo; + @ApiModelProperty(value = "指数k线") + private List kLine; +} diff --git a/src/main/java/cn/stock/market/infrastructure/api/investing/IndiaStockVO.java b/src/main/java/cn/stock/market/infrastructure/api/investing/IndiaStockVO.java new file mode 100644 index 0000000..ebf6d4f --- /dev/null +++ b/src/main/java/cn/stock/market/infrastructure/api/investing/IndiaStockVO.java @@ -0,0 +1,82 @@ +package cn.stock.market.infrastructure.api.investing; + +import cn.qutaojing.common.utils.BigDecimals; +import cn.stock.market.dto.model.StockVO; +import lombok.Data; + +@Data +public class IndiaStockVO { + private Integer id; + /** + * 股票名称 + */ + private String name; + /** + * 股票中文名称 + */ + private String cname; + /** + * 股票代码 + */ + private String code; + + private Integer isLock; + + private Integer isShow; + + /** + * 股票价格 + */ + private String nowPrice; + + private String open; + + private String high; + + private String low; + + private String close; + + /** + * 成交额(暂未获取到) + */ + private String turnover; + + /** + * 成交量 + */ + private String volume; + + private String marketValue; + + /** + * 股票涨跌幅 + */ + private String number; + + /** + * 股票涨跌幅百分比 + */ + private String rate; + + /*是否添加自选:1、添加自选,0、未添加自选*/ + private String isOption; + private String time; + private String type; //股票类型 + String url; + String targetId; + + public StockVO toStockVo() { + StockVO vo = new StockVO(); + vo.setName(name); + vo.setCode(code); + vo.setNowPrice(nowPrice); + vo.setHcrate(BigDecimals.divide(BigDecimals.p(rate), 100)); + vo.setToday_max(high); + vo.setToday_min(low); + vo.setOpen_px(open); + vo.setPreclose_px(close); + vo.setVolume(volume); + return vo; + } +} diff --git a/src/main/java/cn/stock/market/infrastructure/api/investing/InvestingApis.java b/src/main/java/cn/stock/market/infrastructure/api/investing/InvestingApis.java new file mode 100644 index 0000000..0720def --- /dev/null +++ b/src/main/java/cn/stock/market/infrastructure/api/investing/InvestingApis.java @@ -0,0 +1,259 @@ +package cn.stock.market.infrastructure.api.investing; + +import java.io.IOException; +import java.util.Date; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import org.apache.commons.lang.StringUtils; + +import com.ag.utils.CollectionUtils; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.PageInfo; +import com.google.common.base.Stopwatch; +import com.google.common.collect.Lists; + +import cn.hutool.core.date.DateUtil; +import cn.qutaojing.common.utils.BigDecimals; +import cn.stock.market.dto.model.StockCode; +import cn.stock.market.utils.RequestCacheUtils; +import cn.stock.market.utils.ServerResponse; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class InvestingApis { + + public IndiaStockVO market(StockCode code) { + List list = batchMarket(Lists.newArrayList(code)); + return CollectionUtils.isNotEmpty(list) ? list.get(0) : null; + } + + public List batchMarket(List list) { + List retList = Lists.newArrayList(); + for (StockCode code : list) { + ServerResponse response = RequestCacheUtils.cache("_INDIA_", "targetId_" + code.getCode(), (string) -> { + IndiaStockVO vo = _market(code); + return ServerResponse.createBySuccess(vo); + }); + + if(response.getData() != null) { + retList.add(response.getData()); + } + } + + return retList; + } + + public IndiaStockVO _market(StockCode code) { + try { + JSONObject json = InvestingInvokerApis.of().__market(code); + JSONArray pairs_data = json + .getJSONArray("data").getJSONObject(0) + .getJSONObject("screen_data").getJSONArray("pairs_data"); + IndiaStockVO vo = new IndiaStockVO(); + JSONArray overview_table = pairs_data.getJSONObject(0).getJSONArray("overview_table"); + JSONObject info_header = pairs_data.getJSONObject(0).getJSONObject("info_header"); + String pair_name_base = info_header.getString("pair_name_base"); + String pair_ID = info_header.getString("pair_ID"); + + vo.setName(pair_name_base); + vo.setCname(pair_name_base); + vo.setCode(pair_ID); + vo.setTargetId(pair_ID); + + String 昨收 = find_overview_table_value_with_key(overview_table, "昨收"); + vo.setClose(numberToString(昨收)); + String 开盘 = find_overview_table_value_with_key(overview_table, "开盘"); + String 成交量 = find_overview_table_value_with_key(overview_table, "成交量"); //658,477,949 + vo.setVolume(numberToString(成交量)); + + if(StringUtils.isNotBlank(开盘)) { + vo.setOpen(numberToString(开盘)); + } + String 当日幅度 = find_overview_table_value_with_key(overview_table, "当日幅度"); //6.91 - 7.89 + if(StringUtils.isNotBlank(当日幅度)) { + String[] split = 当日幅度.trim().split("-"); + vo.setLow(numberToString(split[0])); + vo.setHigh(numberToString(split[1])); + } else { + } + + String last = info_header.getString("last"); //当前价 + vo.setNowPrice(numberToString(last)); + + String percent_tooltip_value = info_header.getString("percent_tooltip_value"); //涨幅 + vo.setRate(percent_tooltip_value); + String change = info_header.getString("change"); //涨幅值 ("+0.65") + if(change.startsWith("+")) { + vo.setNumber(numberToString(change.substring(1))); + } else { + vo.setNumber(numberToString(change)); + } + + if(BigDecimals.loeZero(vo.getNowPrice())) { + log.warn("{} 当前价非法, 将忽略.", JSON.toJSONString(vo)); + return null; + } else { + return vo; + } + } catch (IOException e) { + log.error("batchIndiaStockMarketData>>code:{}, 失败. 跳过", code, e); + } + return null; + } + + public static String numberToString(String string) { + return StringUtils.replace(string, ",", ""); + } + + 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; + } + + /** + * "AvgVolume": 3741486, + "Chg": -9.55, + "ChgPct": -5.25, + "CountryNameTranslated": "India", + "ExchangeId": "46", + "Flag": "IN", + "FundamentalBeta": 0.916, + "FundamentalMarketCap": 448530000000, + "FundamentalRatio": 8.41, + "FundamentalRevenue": "250.56B", + "High": 183, + "Id": "7310", + "IsOpen": "0", + "Last": 172.35, + "LastPairDecimal": 2, + "Low": 171.45, + "Name": "Aditya Birla Capital", + "PairType": "Equities", + "Performance3Year": 150.69, + "PerformanceDay": -5.25, + "PerformanceMonth": -2.38, + "PerformanceWeek": -5.67, + "PerformanceYear": 48.71, + "PerformanceYtd": 14.75, + "Symbol": "ADTB", + "TechnicalDay": "strong_sell", + "TechnicalHour": "strong_sell", + "TechnicalMonth": "strong_buy", + "TechnicalWeek": "sell", + "Time": "1698055197", + "Url": "/equities/aditya-birla", + "Volume": 3693615 + * @param httpClient + * @param currPage + * @param pageSize + * @return + * @throws IOException + */ + public PageInfo page(int currPage, int pageSize) throws IOException { + JSONObject json = InvestingInvokerApis.of().__page(currPage, pageSize); + + int totalPages = (json.getIntValue("total") / json.getIntValue("pageSize")) + 1; + log.info("总页码数: {}", totalPages); + + List items = json.getJSONArray("data").stream().map(val -> { + JSONObject j = (JSONObject) val; + IndiaStockVO vo = new IndiaStockVO(); + vo.setName(j.getString("Name")); + vo.setCname(j.getString("Name")); + vo.setCode(j.getString("Symbol")); + vo.setIsLock(0); + vo.setIsShow(0); + vo.setNowPrice(numberToString(j.getString("Last"))); + vo.setOpen("--"); + vo.setClose("--"); + vo.setNumber(numberToString(j.getString("Chg"))); + vo.setRate(numberToString(j.getString("ChgPct"))); + vo.setHigh(numberToString(j.getString("High"))); + vo.setLow(numberToString(j.getString("Low"))); + vo.setUrl(numberToString(j.getString("Url"))); + vo.setTargetId(j.getString("Id")); + vo.setType("印度"); + return vo; + }).collect(Collectors.toList()); + + PageInfo page = new PageInfo<>(); + page.setPageNum(currPage); + page.setPageSize(pageSize); + page.setTotal(json.getIntValue("total")); + page.setPages(totalPages); + page.setList(items); + return page; + } + + public List thirdIndiaList() throws IOException { + List list = Lists.newArrayList(); + Stopwatch stopwatch = Stopwatch.createStarted(); + int totalPages = 0; + int currPage = 0; + do { + try { + PageInfo page = page(currPage, 100); + + totalPages = page.getPages(); + currPage ++; + list.addAll(page.getList()); + } catch(Exception e) { + log.error("发送错误, 跳过", e); + continue; + } + } while(currPage < totalPages); + + log.info("获取印度股票列表执行完毕, 查询到数据 {} 条, 耗时: {} 毫秒", list.size(), stopwatch.elapsed(TimeUnit.MILLISECONDS)); + return list; + } + + /** + * + * @param code + * @param string min/day/week/month + * @return + * @throws IOException + */ + public List kline(StockCode code, String string) throws IOException { + if(code == null) { + throw new RuntimeException("找不到股票信息"); + } + Date nowDate = new Date(); + JSONObject json = InvestingInvokerApis.of().__kline(code, string); + return json + .getJSONArray("data") + .stream() + .map(val -> { + JSONArray _ar = (JSONArray) val; + JSONObject item = new JSONObject(); + item.put("date", _ar.get(0)); + item.put("open", _ar.get(1)); + item.put("high", _ar.get(2)); + item.put("low", _ar.get(3)); + item.put("close", _ar.get(4)); + item.put("volume", _ar.get(5)); + return item; + }).filter(val -> { + if("min".equalsIgnoreCase(string)) { + return DateUtil.isSameDay(nowDate, new Date(val.getLong("date"))); + } + return true; + }) + .collect(Collectors.toList()) + ; + } + + public static InvestingApis of() { + return new InvestingApis(); + } +} diff --git a/src/main/java/cn/stock/market/infrastructure/api/investing/InvestingInvokerApis.java b/src/main/java/cn/stock/market/infrastructure/api/investing/InvestingInvokerApis.java new file mode 100644 index 0000000..57924da --- /dev/null +++ b/src/main/java/cn/stock/market/infrastructure/api/investing/InvestingInvokerApis.java @@ -0,0 +1,219 @@ +package cn.stock.market.infrastructure.api.investing; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLConnection; +import java.util.Arrays; +import java.util.Collections; +import java.util.concurrent.TimeUnit; + +import javax.net.ssl.X509TrustManager; + +import org.apache.commons.lang.StringUtils; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.google.common.base.Stopwatch; + +import cn.hutool.core.text.StrFormatter; +import cn.stock.market.dto.model.StockCode; +import lombok.extern.slf4j.Slf4j; +import okhttp3.OkHttpClient; +import okhttp3.Protocol; +import okhttp3.Request; +import okhttp3.Request.Builder; + +@Slf4j +public class InvestingInvokerApis { + public static final int COUNTRY_ID = 14; // INDIA + 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" + + ""; + public static final String API_HEADER_LIST = "Host: api.investing.com\n" + + "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/119.0\n" + + "Accept: application/json, text/plain, */*\n" + + "Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2\n" + + "domain-id: cn\n" + + "Origin: https://cn.investing.com\n" + + "Connection: keep-alive\n" + + "Referer: https://cn.investing.com/\n" + + "Sec-Fetch-Dest: empty\n" + + "Sec-Fetch-Mode: cors\n" + + "Sec-Fetch-Site: same-site\n" + + "Pragma: no-cache\n" + + "Cache-Control: no-cache\n" + + "TE: trailers"; + + 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 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); + } + } + + public static Builder builderGet(String url) { + return new Request.Builder().url(url).method("GET", null); + } + + public JSONObject __market(StockCode code) throws IOException { + Stopwatch stopwatch = Stopwatch.createStarted(); + 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, code.getCode()); + log.info("url: {}", url); + Builder builder = builderGet(url); + addHeader(builder, API_HEADER); + String body = httpClient().newCall(builder.build()).execute().body().string(); + log.info("india market cost: {} ms, url: {}, body: {}", stopwatch.elapsed(TimeUnit.MILLISECONDS), url, body); + return JSON.parseObject(body); + } + + public static String numberToString(String string) { + return StringUtils.replace(string, ",", ""); + } + + 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 JSONObject __page(int pageNum, int pageSize) throws IOException { + String tmpl = "https://api.investing.com/api/financialdata/assets/equitiesByCountry/default?fields-list=id,name,symbol,high,low,last,lastPairDecimal,change,changePercent,volume,time,isOpen,url,flag,countryNameTranslated,exchangeId,performanceDay,performanceWeek,performanceMonth,performanceYtd,performanceYear,performance3Year,technicalHour,technicalDay,technicalWeek,technicalMonth,avgVolume,fundamentalMarketCap,fundamentalRevenue,fundamentalRatio,fundamentalBeta,pairType&country-id=14&page={}&page-size={}&include-major-indices=false&include-additional-indices=false&include-primary-sectors=false&include-other-indices=false&limit=0"; + String url = StrFormatter.format(tmpl, pageNum - 1, pageSize); + Stopwatch stopwatch = Stopwatch.createStarted(); + log.info("url: {}", url); + Builder builder = builderGet(url); + String body = httpClient().newCall(builder.build()).execute().body().string(); + log.info("第{}页码, 耗时: {} 毫秒, 返回原始值: {}, 准备解析中.", pageNum, stopwatch.elapsed(TimeUnit.MILLISECONDS), body); + return JSON.parseObject(body); + } + + /** + * 与 __page 的区别 + * api/financialdata/assets/equitiesByCountry/default + * api/financialdata/assets/equitiesByCountry/17943 + * @param pageNum + * @param pageSize + * @return + * @throws IOException + */ + public JSONObject __page_nifty100(int pageNum, int pageSize) throws IOException { + String tmpl = "https://api.investing.com/api/financialdata/assets/equitiesByIndices/17943?fields-list=id%2Cname%2Csymbol%2Chigh%2Clow%2Clast%2ClastPairDecimal%2Cchange%2CchangePercent%2Cvolume%2Ctime%2CisOpen%2Curl%2Cflag%2CcountryNameTranslated%2CexchangeId%2CperformanceDay%2CperformanceWeek%2CperformanceMonth%2CperformanceYtd%2CperformanceYear%2Cperformance3Year%2CtechnicalHour%2CtechnicalDay%2CtechnicalWeek%2CtechnicalMonth%2CavgVolume%2CfundamentalMarketCap%2CfundamentalRevenue%2CfundamentalRatio%2CfundamentalBeta%2CpairType&country-id=14&page={}&page-size={}&include-major-indices=false&include-additional-indices=false&include-primary-sectors=false&include-other-indices=false&limit=0"; +// String tmpl = "https://api.investing.com/api/financialdata/assets/equitiesByCountry/17943?fields-list=id,name,symbol,high,low,last,lastPairDecimal,change,changePercent,volume,time,isOpen,url,flag,countryNameTranslated,exchangeId,performanceDay,performanceWeek,performanceMonth,performanceYtd,performanceYear,performance3Year,technicalHour,technicalDay,technicalWeek,technicalMonth,avgVolume,fundamentalMarketCap,fundamentalRevenue,fundamentalRatio,fundamentalBeta,pairType&country-id=14&page={}&page-size={}&include-major-indices=false&include-additional-indices=false&include-primary-sectors=false&include-other-indices=false&limit=0"; + String url = StrFormatter.format(tmpl, pageNum - 1, pageSize); + Stopwatch stopwatch = Stopwatch.createStarted(); + log.info("url: {}", url); + Builder builder = builderGet(url); + String body = httpClient().newCall(builder.build()).execute().body().string(); + log.info("第{}页码, 耗时: {} 毫秒, 返回原始值: {}, 准备解析中.", pageNum, stopwatch.elapsed(TimeUnit.MILLISECONDS), body); + return JSON.parseObject(body); + } + + /** + * + * @param code + * @param string min/day/week/month + * @return + * @throws IOException + */ + public JSONObject __kline(StockCode code, String string) throws IOException { + if(code == null) { + throw new RuntimeException("找不到股票信息"); + } + String interval = null; + String period = null; + if("min".equalsIgnoreCase(string)) { + interval = "PT5M"; + } else if("day".equalsIgnoreCase(string)) { + interval = "P1D"; + } else if("week".equalsIgnoreCase(string)) { + interval = "P1W"; + } else if("month".equalsIgnoreCase(string)) { + interval = "P1M"; + } else if("3month".equalsIgnoreCase(string)) { + interval = "P1D"; + period = "P3M"; + } else if("6month".equalsIgnoreCase(string)) { + interval = "P1D"; + period = "P6M"; + } else if("year".equalsIgnoreCase(string)) { + interval = "P1W"; + period = "P1Y"; + } + + if(StringUtils.isBlank(interval)) { + interval = string; + } + + String url = null; + if(StringUtils.isNotBlank(period)) { + String tmpl = "https://api.investing.com/api/financialdata/{}/historical/chart/?period={}&interval={}&pointscount=160"; + url = StrFormatter.format(tmpl, code.getCode(), period, interval); + } else { + String tmpl = "https://api.investing.com/api/financialdata/{}/historical/chart/?interval={}&pointscount=160"; + url = StrFormatter.format(tmpl, code.getCode(), interval); + } + + Builder builder = builderGet(url); + + String body = httpClient().newCall(builder.build()).execute().body().string(); + return JSON.parseObject(body); + } + + public static InvestingInvokerApis of() { + return new InvestingInvokerApis(); + } + + public static void main(String[] args) throws IOException { + JSONObject __market = of().__page(1,100); + System.out.println(__market); + + JSONObject __page = of().__page(1, 10); + JSONObject __page_nifty100 = of().__page_nifty100(1, 10); + + System.out.println(__page); + System.out.println(__page_nifty100); + } +} diff --git a/src/main/java/cn/stock/market/infrastructure/api/investing/SSLSocketClientUtil.java b/src/main/java/cn/stock/market/infrastructure/api/investing/SSLSocketClientUtil.java new file mode 100644 index 0000000..1bfdd7d --- /dev/null +++ b/src/main/java/cn/stock/market/infrastructure/api/investing/SSLSocketClientUtil.java @@ -0,0 +1,60 @@ +package cn.stock.market.infrastructure.api.investing; + +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; + } +} diff --git a/src/main/java/cn/stock/market/infrastructure/db/config/MarketDatasourceConfig.java b/src/main/java/cn/stock/market/infrastructure/db/config/MarketDatasourceConfig.java index c6eda87..d4d7a94 100644 --- a/src/main/java/cn/stock/market/infrastructure/db/config/MarketDatasourceConfig.java +++ b/src/main/java/cn/stock/market/infrastructure/db/config/MarketDatasourceConfig.java @@ -37,14 +37,12 @@ import com.rp.spring.jpa.GenericJpaRepositoryImpl; * @created Jan 26, 2018 3:57:47 PM */ @Configuration -@ComponentScan({ "cn.stock.**.db.po", "com.stock.**.db.repo","cn.qutaojing.**.po", "cn.qutaojing.**.repo" }) +@ComponentScan({ "cn.stock.**.db.po", "cn.stock.**.db.repo"}) @EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactory", transactionManagerRef = "transactionManager", repositoryBaseClass = GenericJpaRepositoryImpl.class, repositoryFactoryBeanClass = GenericJpaRepositoryFactoryBean.class, basePackages = { - "cn.qutaojing.ipay.infrastructure.db.po", "cn.qutaojing.ipay.infrastructure.db.repo", - "cn.stock.trade.infrastructure.db.po", "cn.stock.trade.infrastructure.db.repo", "cn.stock.market.infrastructure.db.po", "cn.stock.market.infrastructure.db.repo"}) public class MarketDatasourceConfig { @Autowired HibernateProperties hibernateProperties; diff --git a/src/main/java/cn/stock/market/infrastructure/db/po/BtodayStockPO.java b/src/main/java/cn/stock/market/infrastructure/db/po/BtodayStockPO.java new file mode 100644 index 0000000..fddb048 --- /dev/null +++ b/src/main/java/cn/stock/market/infrastructure/db/po/BtodayStockPO.java @@ -0,0 +1,74 @@ +package cn.stock.market.infrastructure.db.po; + +import java.lang.Integer; +import java.lang.String; +import java.util.Date; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Generated; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.hibernate.annotations.DynamicInsert; +import org.hibernate.annotations.DynamicUpdate; + +/** + * BtodayStockPO + * + * @author rplees + * @email rplees.i.ly@gmail.com + * @created 2023/12/25 + */ +@SuperBuilder +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +@DynamicInsert +@DynamicUpdate +@Table( + name = "btoday_stock" +) +public class BtodayStockPO { + /** + * 主键 */ + @Id + @GeneratedValue( + strategy = GenerationType.IDENTITY + ) + Integer id; + + /** + * 股票名称 */ + String stockName; + + /** + * 股票code */ + String stockCode; + + /** + * 类型 */ + String stockType; + + String stockSpell; + + /** + * btoday的业务id */ + String coCode; + + /** + * 主页的http链接 */ + String selfUrl; + + /** + * url */ + String url; + + /** + * 上次更新时间 */ + Date lastUpdateTime; +} diff --git a/src/main/java/cn/stock/market/infrastructure/stockdb/po/SiteSettingPO.java b/src/main/java/cn/stock/market/infrastructure/db/po/SiteSettingPO.java similarity index 93% rename from src/main/java/cn/stock/market/infrastructure/stockdb/po/SiteSettingPO.java rename to src/main/java/cn/stock/market/infrastructure/db/po/SiteSettingPO.java index 8f26340..e359b18 100644 --- a/src/main/java/cn/stock/market/infrastructure/stockdb/po/SiteSettingPO.java +++ b/src/main/java/cn/stock/market/infrastructure/db/po/SiteSettingPO.java @@ -1,4 +1,4 @@ -package cn.stock.market.infrastructure.stockdb.po; +package cn.stock.market.infrastructure.db.po; import javax.persistence.Entity; import javax.persistence.GeneratedValue; @@ -33,6 +33,6 @@ public class SiteSettingPO { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) Integer id; - + String marketServerList; } diff --git a/src/main/java/cn/stock/market/infrastructure/db/po/StockIpoPO.java b/src/main/java/cn/stock/market/infrastructure/db/po/StockIpoPO.java new file mode 100644 index 0000000..b228275 --- /dev/null +++ b/src/main/java/cn/stock/market/infrastructure/db/po/StockIpoPO.java @@ -0,0 +1,87 @@ +package cn.stock.market.infrastructure.db.po; + +import java.lang.Integer; +import java.lang.String; +import java.math.BigDecimal; +import java.util.Date; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.hibernate.annotations.DynamicInsert; +import org.hibernate.annotations.DynamicUpdate; + +/** + * StockIpoPO + * + * @author rplees + * @email rplees.i.ly@gmail.com + * @created 2023/12/28 + */ +@SuperBuilder +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +@DynamicInsert +@DynamicUpdate +@Table( + name = "stock_ipo" +) +public class StockIpoPO { + @Id + @GeneratedValue( + strategy = javax.persistence.GenerationType.IDENTITY + ) + Integer id; + + /** + * 股票代码 */ + String stockCode; + + /** + * 股票名称 */ + String stockName; + + /** + * 发行价格 */ + BigDecimal stockPrice; + + /** + * 申购日期 */ + Date subscriptionDate; + + /** + * 上市日期 */ + Date listingDate; + + /** + * 是否显示【1 显示,2 不显示】 */ + Integer isShow; + + /** + * 是否上市【1 未上市,2 已上市】 */ + Integer isList; + + Date createDate; + + Date updateDate; + + /** + * 发行总数 */ + Integer totalNumber; + + /** + * 申请总额 */ + String apply; + + /** + * 市盈率 */ + BigDecimal peRatio; + + String sourceType; +} diff --git a/src/main/java/cn/stock/market/infrastructure/stockdb/po/StockPO.java b/src/main/java/cn/stock/market/infrastructure/db/po/StockPO.java similarity index 92% rename from src/main/java/cn/stock/market/infrastructure/stockdb/po/StockPO.java rename to src/main/java/cn/stock/market/infrastructure/db/po/StockPO.java index 40b07b0..398dba2 100644 --- a/src/main/java/cn/stock/market/infrastructure/stockdb/po/StockPO.java +++ b/src/main/java/cn/stock/market/infrastructure/db/po/StockPO.java @@ -1,4 +1,4 @@ -package cn.stock.market.infrastructure.stockdb.po; +package cn.stock.market.infrastructure.db.po; import java.lang.Integer; import java.lang.String; @@ -63,6 +63,10 @@ public class StockPO { * 涨幅比例 */ BigDecimal increaseRatio; - + Integer stockState; + + String stockExchangeId; + + String stockSymbol; } diff --git a/src/main/java/cn/stock/market/infrastructure/db/repo/BtodayStockRepo.java b/src/main/java/cn/stock/market/infrastructure/db/repo/BtodayStockRepo.java new file mode 100644 index 0000000..5b3da4a --- /dev/null +++ b/src/main/java/cn/stock/market/infrastructure/db/repo/BtodayStockRepo.java @@ -0,0 +1,15 @@ +package cn.stock.market.infrastructure.db.repo; + +import cn.stock.market.infrastructure.db.po.BtodayStockPO; +import com.rp.spring.jpa.GenericJpaRepository; +import java.lang.Integer; + +/** + * BtodayStockRepo + * + * @author rplees + * @email rplees.i.ly@gmail.com + * @created 2023/12/25 + */ +public interface BtodayStockRepo extends GenericJpaRepository { +} diff --git a/src/main/java/cn/stock/market/infrastructure/stockdb/repo/SiteSettingRepo.java b/src/main/java/cn/stock/market/infrastructure/db/repo/SiteSettingRepo.java similarity index 67% rename from src/main/java/cn/stock/market/infrastructure/stockdb/repo/SiteSettingRepo.java rename to src/main/java/cn/stock/market/infrastructure/db/repo/SiteSettingRepo.java index b238935..210e12a 100644 --- a/src/main/java/cn/stock/market/infrastructure/stockdb/repo/SiteSettingRepo.java +++ b/src/main/java/cn/stock/market/infrastructure/db/repo/SiteSettingRepo.java @@ -1,8 +1,8 @@ -package cn.stock.market.infrastructure.stockdb.repo; +package cn.stock.market.infrastructure.db.repo; import com.rp.spring.jpa.GenericJpaRepository; -import cn.stock.market.infrastructure.stockdb.po.SiteSettingPO; +import cn.stock.market.infrastructure.db.po.SiteSettingPO; /** * StockRepo diff --git a/src/main/java/cn/stock/market/infrastructure/db/repo/StockIpoRepo.java b/src/main/java/cn/stock/market/infrastructure/db/repo/StockIpoRepo.java new file mode 100644 index 0000000..3e47807 --- /dev/null +++ b/src/main/java/cn/stock/market/infrastructure/db/repo/StockIpoRepo.java @@ -0,0 +1,15 @@ +package cn.stock.market.infrastructure.db.repo; + +import cn.stock.market.infrastructure.db.po.StockIpoPO; +import com.rp.spring.jpa.GenericJpaRepository; +import java.lang.Integer; + +/** + * StockIpoRepo + * + * @author rplees + * @email rplees.i.ly@gmail.com + * @created 2023/12/28 + */ +public interface StockIpoRepo extends GenericJpaRepository { +} diff --git a/src/main/java/cn/stock/market/infrastructure/stockdb/repo/StockRepo.java b/src/main/java/cn/stock/market/infrastructure/db/repo/StockRepo.java similarity index 69% rename from src/main/java/cn/stock/market/infrastructure/stockdb/repo/StockRepo.java rename to src/main/java/cn/stock/market/infrastructure/db/repo/StockRepo.java index 0d1a734..97e36b0 100644 --- a/src/main/java/cn/stock/market/infrastructure/stockdb/repo/StockRepo.java +++ b/src/main/java/cn/stock/market/infrastructure/db/repo/StockRepo.java @@ -1,8 +1,8 @@ -package cn.stock.market.infrastructure.stockdb.repo; +package cn.stock.market.infrastructure.db.repo; import com.rp.spring.jpa.GenericJpaRepository; -import cn.stock.market.infrastructure.stockdb.po.StockPO; +import cn.stock.market.infrastructure.db.po.StockPO; import java.lang.Integer; diff --git a/src/main/java/cn/stock/market/infrastructure/job/InvestingTask.java b/src/main/java/cn/stock/market/infrastructure/job/InvestingTask.java new file mode 100644 index 0000000..e74913e --- /dev/null +++ b/src/main/java/cn/stock/market/infrastructure/job/InvestingTask.java @@ -0,0 +1,97 @@ +package cn.stock.market.infrastructure.job; + +import cn.stock.market.domain.basic.entity.Stock; +import cn.stock.market.domain.basic.repository.StockRepository; +import cn.stock.market.infrastructure.api.investing.InvestingInvokerApis; +import cn.stock.market.utils.Utils; +import com.ag.utils.CollectionUtils; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.google.common.base.Stopwatch; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +@Slf4j +@Component +public class InvestingTask { + +// @Scheduled(cron = "0 0 6 * * ?") + public void syncIndiaData(){ + log.info("同步股票数据开始。。。。"); + Map stockMap = StockRepository.of().cacheCodeMap(); + Stopwatch stopwatch = Stopwatch.createStarted(); + List list = Lists.newArrayList(); + int currentTotal = 0; + int pageNum =1; + int pageSize = 300; + try { + for(int i = 0;i < pageNum;i ++) { + JSONObject jsonObject = InvestingInvokerApis.of().__page(pageNum, pageSize); + int total = 0; + if(jsonObject.containsKey("total")){ + total = Integer.parseInt(jsonObject.get("total").toString()); + } + JSONArray dataObjArray = new JSONArray(); + if(jsonObject.containsKey("data")){ + dataObjArray = JSON.parseArray(jsonObject.get("data").toString()); + } + for (Object obj : dataObjArray) { + JSONObject jsonObject2 = JSON.parseObject(obj.toString()); + String code = jsonObject2.get("Id").toString(); + String name = jsonObject2.get("Name").toString(); + String stockSymbol = jsonObject2.get("Symbol").toString(); + String exchangeId = jsonObject2.get("ExchangeId").toString(); + if (stockMap.containsKey(code)) { + log.info("已经存在 {} 信息, 跳过", code); + continue; + } + + if(! Utils.isShOrSzOrBJ(code)) { + log.info("{} 非 sh 或者 sz 或者 bj , 跳过", code); + continue; + } + Stock stock = new Stock(); + stock.setStockSymbol(stockSymbol); + stock.setStockExchangeId(exchangeId); + if("46".equals(exchangeId)){ + stock.setStockType("NSE"); + } + stock.setStockName(name); + stock.setStockCode(code); + stock.setStockGid(code); + stock.setIsLock(0); + stock.setIsShow(0); + stock.setAddTime(new Date()); + stock.setStockState(0); + list.add(stock); + } + currentTotal += pageSize; + if((total - currentTotal) < pageSize ){ + pageSize = total - currentTotal; + } + if(total <= currentTotal){ + break; + } + pageNum ++; + } + if(CollectionUtils.isNotEmpty(list)) { + StockRepository.of().saveAll(list); + } + int count = list.size(); + log.info("syncAFutureStockList执行, 受影响数{}, 耗时:{}毫秒", count, stopwatch.elapsed(TimeUnit.MILLISECONDS)); + log.info("同步股票数据结束。。。。"); + } catch (Exception e) { + log.info("同步股票数据异常,异常信息{}。。。。",e.getMessage()); + } + + } +} diff --git a/src/main/java/cn/stock/market/infrastructure/job/JobBoot.java b/src/main/java/cn/stock/market/infrastructure/job/JobBoot.java index d9de463..a3aa98f 100644 --- a/src/main/java/cn/stock/market/infrastructure/job/JobBoot.java +++ b/src/main/java/cn/stock/market/infrastructure/job/JobBoot.java @@ -13,7 +13,7 @@ import cn.stock.market.domain.basic.service.SiteNewsService; import lombok.extern.slf4j.Slf4j; @Slf4j -@Component +//@Component public class JobBoot { /** * cronExpression表达式定义:  diff --git a/src/main/java/cn/stock/market/infrastructure/job/Scraper.java b/src/main/java/cn/stock/market/infrastructure/job/Scraper.java new file mode 100644 index 0000000..fa3e607 --- /dev/null +++ b/src/main/java/cn/stock/market/infrastructure/job/Scraper.java @@ -0,0 +1,351 @@ +package cn.stock.market.infrastructure.job; + +import cn.stock.market.domain.basic.entity.BtodayStock; +import cn.stock.market.domain.basic.entity.StockIpo; +import cn.stock.market.domain.basic.repository.BtodayStockRepository; +import cn.stock.market.domain.basic.repository.StockIpoRepository; +import cn.stock.market.dto.StockIpoDTO; +import cn.stock.market.infrastructure.db.po.QStockIpoPO; +import cn.stock.market.infrastructure.db.po.StockIpoPO; +import cn.stock.market.infrastructure.db.repo.BtodayStockRepo; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.io.IOException; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.stream.Collectors; + +@Slf4j +@RestController +public class Scraper { + + @Autowired + private BtodayStockRepository btodayStockRepo; + @Autowired + private StockIpoRepository stockIpoRepository; + + private final ExecutorService executorService = Executors.newFixedThreadPool(5); + + + @Scheduled(cron = "0 0 1 */2 * ?") + @RequestMapping("/testScraperGetBusinessToday") + public void schedule() { + String BASE_URL = "https://akm-img-a-in.tosshub.com/businesstoday/resource/market-widgets/prod/company-master-23-01-2023.json"; + String company_name = "Bhagawati Oxygen Ltd"; + + try { + // 获取 JSON 数据 + String json_data = scrapePage(BASE_URL); + // 解析 JSON 数据 + if (json_data != null) { + List all = btodayStockRepo.findAll(); + Map sefUrlList = getSefUrl(json_data, company_name); + sefUrlList = sefUrlList.entrySet().stream() + .filter(entry -> all.stream().noneMatch(stock -> stock.getStockName().equals(entry.getKey()))) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + + // 将 Map 中的数据分成 5 个线程处理 + int batchSize = sefUrlList.size() / 5; // 假设分成 5 个线程 + int threadCount = 5; + CompletableFuture[] futures = new CompletableFuture[threadCount]; + for (int i = 0; i < threadCount; i++) { + int startIndex = i * batchSize; + int endIndex = (i == threadCount - 1) ? sefUrlList.size() : (i + 1) * batchSize; + + Map subMap = sefUrlList.entrySet().stream() + .skip(startIndex) + .limit(endIndex - startIndex) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + + futures[i] = CompletableFuture.runAsync(() -> processSubMap(subMap), executorService); + } + // 等待所有异步任务完成 + CompletableFuture.allOf(futures).get(); + } + } catch (Exception e) { + log.error("IOException occurred while processing the JSON data", e); + }finally { + // 关闭线程池 + executorService.shutdown(); + } + } + + + + + + @Scheduled(cron = "0 0 5 * * ?") + @RequestMapping("/testScraperGetMoneyControllerNewIPO") + public void schedule2() { + // 目标 URL + String url = "https://www.moneycontrol.com/ipo/open-upcoming-ipos"; + // 创建 HttpClient 实例 + HttpClient client = HttpClients.createDefault(); + // 创建 HttpGet 请求 + HttpGet request = new HttpGet(url); + try { + // 执行请求 + HttpResponse response = client.execute(request); + + // 检查请求是否成功 + if (response.getStatusLine().getStatusCode() == 200) { + // 获取响应体 + String responseBody = EntityUtils.toString(response.getEntity()); + + // 使用 Jsoup 解析 HTML + Document doc = Jsoup.parse(responseBody); + + // 找到包含 JSON 数据的