Merge branch 'develop' into 'main'

Develop

See merge request india/india_market_java!1
This commit is contained in:
rplees
2023-12-31 11:13:55 +00:00
100 changed files with 5556 additions and 209 deletions

View File

@@ -25,10 +25,10 @@ build:
</settings>' > $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<<<<<<"

87
pom.xml
View File

@@ -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">
<modelVersion>4.0.0</modelVersion>
<packaging>war</packaging>
<packaging>jar</packaging>
<parent>
<groupId>cn.qutaojing</groupId>
<artifactId>qutaojing-micro-pom</artifactId>
@@ -20,6 +20,11 @@
<name>股票行情</name>
<description>股票行情</description>
<dependencies>
<dependency>
<groupId>com.squareup</groupId>
<artifactId>javapoet</artifactId>
<version>1.11.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
@@ -176,18 +181,59 @@
</dependencies>
<build>
<finalName>stock-market</finalName>
<finalName>india_market_java</finalName>
<plugins>
<plugin>
<!--<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.1</version>
</plugin>
</plugin>-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.9.RELEASE</version>
<configuration>
<executable>true</executable>
<layout>JAR</layout>
<!-- <includes> <include> 排除所有Jar <groupId>nothing</groupId> <artifactId>nothing</artifactId>
</include> </includes> -->
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<attach>false</attach>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>src/main/generated</outputDirectory>
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.mysema.maven</groupId>
@@ -219,38 +265,5 @@
<enabled>true</enabled>
</snapshots>
</repository>
<!--<repository>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>public</id>
<url>http://nexus.rplees.com/nexus/content/repositories/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
<checksumPolicy>warn</checksumPolicy>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/libs-milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>-->
</repositories>
</project>

View File

@@ -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<BtodayStockPO> {
private static final long serialVersionUID = 1079736803L;
public static final QBtodayStockPO btodayStockPO = new QBtodayStockPO("btodayStockPO");
public final StringPath coCode = createString("coCode");
public final NumberPath<Integer> id = createNumber("id", Integer.class);
public final DateTimePath<java.util.Date> 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<? extends BtodayStockPO> path) {
super(path.getType(), path.getMetadata());
}
public QBtodayStockPO(PathMetadata metadata) {
super(BtodayStockPO.class, metadata);
}
}

View File

@@ -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<SiteSettingPO> {
private static final long serialVersionUID = -51441337L;
private static final long serialVersionUID = 926298165L;
public static final QSiteSettingPO siteSettingPO = new QSiteSettingPO("siteSettingPO");

View File

@@ -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<StockIpoPO> {
private static final long serialVersionUID = 1023664740L;
public static final QStockIpoPO stockIpoPO = new QStockIpoPO("stockIpoPO");
public final StringPath apply = createString("apply");
public final DateTimePath<java.util.Date> createDate = createDateTime("createDate", java.util.Date.class);
public final NumberPath<Integer> id = createNumber("id", Integer.class);
public final NumberPath<Integer> isList = createNumber("isList", Integer.class);
public final NumberPath<Integer> isShow = createNumber("isShow", Integer.class);
public final DateTimePath<java.util.Date> listingDate = createDateTime("listingDate", java.util.Date.class);
public final NumberPath<java.math.BigDecimal> 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<java.math.BigDecimal> stockPrice = createNumber("stockPrice", java.math.BigDecimal.class);
public final DateTimePath<java.util.Date> subscriptionDate = createDateTime("subscriptionDate", java.util.Date.class);
public final NumberPath<Integer> totalNumber = createNumber("totalNumber", Integer.class);
public final DateTimePath<java.util.Date> updateDate = createDateTime("updateDate", java.util.Date.class);
public QStockIpoPO(String variable) {
super(StockIpoPO.class, forVariable(variable));
}
public QStockIpoPO(Path<? extends StockIpoPO> path) {
super(path.getType(), path.getMetadata());
}
public QStockIpoPO(PathMetadata metadata) {
super(StockIpoPO.class, metadata);
}
}

View File

@@ -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<StockPO> {
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<StockPO> {
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<StockPO> {
public final NumberPath<Integer> stockState = createNumber("stockState", Integer.class);
public final StringPath stockSymbol = createString("stockSymbol");
public final StringPath stockType = createString("stockType");
public QStockPO(String variable) {

View File

@@ -47,7 +47,7 @@ public class CommonApis {
public Map<String, StockVO> stockDetailMap(List<StockCode> code) {
Function<StockSource, List<StockCode>> 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));
};

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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<BtodayStock, BtodayStockPO> {
public static BtodayStockConvert of() {
return SpringUtils.getBean(BtodayStockConvert.class);
}
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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<StockIpo, StockIpoPO> {
public static StockIpoConvert of() {
return SpringUtils.getBean(StockIpoConvert.class);
}
}

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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<BtodayStock, BtodayStockPO, Integer> {
final BtodayStockRepo repo;
final BtodayStockConvert convert;
final QBtodayStockPO q = QBtodayStockPO.btodayStockPO;
@Override
public GenericJpaRepository<BtodayStockPO, Integer> repo() {
return repo;
}
@Override
public IEntityPOConvert<BtodayStock, BtodayStockPO> 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));
}
}

View File

@@ -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;
/**

View File

@@ -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<StockIpo, StockIpoPO, Integer> {
final StockIpoRepo repo;
final StockIpoConvert convert;
@Override
public GenericJpaRepository<StockIpoPO, Integer> repo() {
return repo;
}
@Override
public IEntityPOConvert<StockIpo, StockIpoPO> convert() {
return convert;
}
public static StockIpoRepository of() {
return SpringUtils.getBean(StockIpoRepository.class);
}
}

View File

@@ -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;
/**

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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("<div class=\"short-video-img\">"),doc.html().lastIndexOf("<div class=\"short-video-img\">")+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<Stock> 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<String, Stock> stockMap = StockRepository.of().cacheCodeMap();
Stopwatch stopwatch = Stopwatch.createStarted();
List<Stock> 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<String, Stock> stockMap = StockRepository.of().cacheCodeMap();
Stopwatch stopwatch = Stopwatch.createStarted();
List<Stock> 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<IndiaIndexVo> 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<JSONObject> 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<JSONObject> 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);
}
}

View File

@@ -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 {
}

View File

@@ -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;

View File

@@ -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 {
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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();
}
}

View File

@@ -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) {

View File

@@ -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<JSONObject> 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<JSONObject> 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<JSONObject> 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<JSONObject> 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<JSONObject> 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<JSONObject> 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<JSONObject> 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<JSONObject> 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"));
}
}

View File

@@ -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<JSONObject> kLine;
}

View File

@@ -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;
}
}

View File

@@ -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<IndiaStockVO> list = batchMarket(Lists.newArrayList(code));
return CollectionUtils.isNotEmpty(list) ? list.get(0) : null;
}
public List<IndiaStockVO> batchMarket(List<StockCode> list) {
List<IndiaStockVO> retList = Lists.newArrayList();
for (StockCode code : list) {
ServerResponse<IndiaStockVO> 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<IndiaStockVO> 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<IndiaStockVO> 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<IndiaStockVO> page = new PageInfo<>();
page.setPageNum(currPage);
page.setPageSize(pageSize);
page.setTotal(json.getIntValue("total"));
page.setPages(totalPages);
page.setList(items);
return page;
}
public List<IndiaStockVO> thirdIndiaList() throws IOException {
List<IndiaStockVO> list = Lists.newArrayList();
Stopwatch stopwatch = Stopwatch.createStarted();
int totalPages = 0;
int currPage = 0;
do {
try {
PageInfo<IndiaStockVO> 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<JSONObject> 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();
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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<BtodayStockPO, Integer> {
}

View File

@@ -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

View File

@@ -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<StockIpoPO, Integer> {
}

View File

@@ -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;

View File

@@ -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<String, Stock> stockMap = StockRepository.of().cacheCodeMap();
Stopwatch stopwatch = Stopwatch.createStarted();
List<Stock> 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());
}
}
}

View File

@@ -13,7 +13,7 @@ import cn.stock.market.domain.basic.service.SiteNewsService;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
//@Component
public class JobBoot {
/**
* cronExpression表达式定义 

View File

@@ -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<BtodayStock> all = btodayStockRepo.findAll();
Map<String, String> 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<Void>[] 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<String, String> 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 数据的 <script> 标签
Element scriptTag = doc.selectFirst("script#__NEXT_DATA__");
if (scriptTag != null) {
// 获取 JSON 数据
String jsonDataStr = scriptTag.html();
// 将 JSON 字符串解析为 Java JSONObject
JSONObject jsonObject = JSONObject.parseObject(jsonDataStr);
log.info(jsonObject.toJSONString());
JSONObject pageProps = jsonObject.getJSONObject("props").getJSONObject("pageProps");
JSONObject ipoTableData = pageProps.getJSONObject("ipoTableData");
// 解析 openData 和 upcomingData
JSONArray openData = ipoTableData.getJSONArray("openData");
JSONArray upcomingData = ipoTableData.getJSONArray("upcomingData");
List<StockIpo> listStockIpoList = new ArrayList<>();
for (int i = 0; i < openData.size(); i++) {
JSONObject entry = openData.getJSONObject(i);
StockIpo stockIpo = new StockIpo();
stockIpo.setStockCode(entry.getString("sc_id"));
stockIpo.setStockName(entry.getString("company_name"));
stockIpo.setStockPrice(entry.getBigDecimal("issue_price"));
stockIpo.setSubscriptionDate(convertStringToTimestamp(entry.getString("open_date")));
stockIpo.setListingDate(convertStringToTimestamp(entry.getString("listing_date")));
stockIpo.setTotalNumber(entry.getInteger("lot_size"));
stockIpo.setApply(entry.getString("total_subs"));
stockIpo.setCreateDate(new Date());
stockIpo.setUpdateDate(new Date());
stockIpo.setSourceType("2");
listStockIpoList.add(stockIpo);
}
for (int i = 0; i < upcomingData.size(); i++) {
JSONObject entry = upcomingData.getJSONObject(i);
StockIpo stockIpo = new StockIpo();
stockIpo.setStockCode(entry.getString("sc_id"));
stockIpo.setStockName(entry.getString("company_name"));
stockIpo.setStockPrice(entry.getBigDecimal("issue_price"));
stockIpo.setSubscriptionDate(convertStringToTimestamp(entry.getString("open_date")));
stockIpo.setListingDate(convertStringToTimestamp(entry.getString("listing_date")));
stockIpo.setTotalNumber(entry.getInteger("lot_size"));
stockIpo.setApply(entry.getString("total_subs"));
stockIpo.setCreateDate(new Date());
stockIpo.setUpdateDate(new Date());
stockIpo.setSourceType("3");
listStockIpoList.add(stockIpo);
}
// stockIpoRepository.saveAll(listStockIpoList);
List<String> nameList = Lists.transform(listStockIpoList, StockIpo::getStockName);
List<StockIpo> existStockIpoList = stockIpoRepository.findAll(QStockIpoPO.stockIpoPO.stockName.in(nameList));
List<String> existingStockNames = existStockIpoList.stream()
.map(StockIpo::getStockName)
.collect(Collectors.toList());
listStockIpoList = listStockIpoList.stream()
.filter(stockIpos -> !existingStockNames.contains(stockIpos.getStockName()))
.collect(Collectors.toList());
//保存全部的新股
stockIpoRepository.saveAll(listStockIpoList);
// 输出整个 JSON 数据
} else {
log.info("未找到包含 JSON 数据的 <script> 标签");
}
} else {
log.info("HTTP请求失败状态码" + response.getStatusLine().getStatusCode());
}
} catch (IOException e) {
log.error("获取新股接口发生异常",e);
}
}
private static Timestamp convertStringToTimestamp(String dateString) {
// 实现将字符串转换为 Timestamp 的逻辑
// 这里假设 dateString 是合法的日期时间字符串
if(StringUtils.isNotBlank(dateString)){
return Timestamp.valueOf(dateString + " 00:00:00");
}else {
return null;
}
}
private void processSubMap(Map<String, String> sefUrlList) {
for (Map.Entry<String, String> entry : sefUrlList.entrySet()) {
String companyName = entry.getKey();
String url = entry.getValue();
// 获取网页 HTML
String webHtml = null;
int maxRetries = 5;
int retryCount = 0;
while (retryCount < maxRetries) {
try {
webHtml = getWebsiteHtml(url);
break; // If successful, break out of the loop
} catch (java.net.SocketTimeoutException e) {
log.warn("Socket timeout exception occurred. Retrying... (" + (retryCount + 1) + "/" + maxRetries + ")");
retryCount++;
} catch (IOException e) {
log.warn("IOException occurred. Retrying... (" + (retryCount + 1) + "/" + maxRetries + ")");
retryCount++;
}
}
if (webHtml != null) {
// 获取公司代码
String coCode = getCompanyCode(webHtml);
if (coCode != null) {
// 获取股票市场列表
String[] stockMarketList = getStockMarket(webHtml);
for (String stockMarket : stockMarketList) {
// 获取网页详情
String detailUrl = buildWebDetailUrl(coCode, stockMarket);
// String webInfo = getWebDetail(detailUrl);
log.info("Stock detail coCode:{}, stockMarket:{}: ,detailUrl:{}", coCode, stockMarket,detailUrl);
BtodayStock btodayStock = new BtodayStock();
btodayStock.setStockName(companyName);
btodayStock.setCoCode(coCode);
btodayStock.setStockType(stockMarket);
btodayStock.setSelfUrl(url);
btodayStock.setUrl(detailUrl);
btodayStock.setLastUpdateTime(new Date());
btodayStockRepo.save(btodayStock);
/* if (webInfo != null) {
log.info("Stock detail for {} in {}: {}", coCode, stockMarket, webInfo);
log.info(webInfo);
} else {
log.warn("Failed to retrieve web detail information.");
}*/
}
} else {
log.warn("Failed to retrieve company code.");
}
} else {
log.warn("Failed to retrieve website HTML.");
}
}
}
private static String buildWebDetailUrl(String coCode, String stockMarket) {
return "https://marketapi.intoday.in/widget/stockdetail/pullview?co_code=" + coCode + "&exchange=" + stockMarket;
}
private static String scrapePage(String url) throws IOException {
log.info("Scraping " + url + "...");
return Jsoup.connect(url).ignoreContentType(true).execute().body();
}
private static Map<String, String> getSefUrl(String json_data, String companyName) {
Map<String, String> sefUrls = new HashMap<>();
// 在这里放入你的模糊匹配逻辑
JSONArray jsonArray = JSONArray.parseArray(json_data);
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject item = jsonArray.getJSONObject(i);
// 在这里放入你的模糊匹配逻辑
String sef_url = item.getString("sef_url");
String company_name = item.getString("companyname");
if (company_name != null && sef_url != null/* && company_name.equals(companyName)*/) {
sefUrls.put(company_name, sef_url);
}
}
return sefUrls;
}
private static String getWebsiteHtml(String url) throws IOException {
log.info("Getting website URL: " + url + "...");
return Jsoup.connect(url).timeout(10000).get().html();
}
private static String getCompanyCode(String text) {
Document document = Jsoup.parse(text);
Element companyCodeInput = document.selectFirst("input[id=comapnyCodeId]");
if (companyCodeInput != null) {
return companyCodeInput.attr("value");
} else {
log.warn("No <input> with id=\"companyCodeId\" found on the website.");
return null;
}
}
private static String[] getStockMarket(String text) {
Document document = Jsoup.parse(text);
Elements ulElements = document.select("ul[class*=wdg_rhs_hdr_ul]");
List<String> stockMarketList = new ArrayList<>();
for (Element ulElement : ulElements) {
Elements liElements = ulElement.select("li");
for (Element liElement : liElements) {
Element spanElement = liElement.selectFirst("span[class=wdg_rhs_hdr_lnk]");
if (spanElement != null) {
stockMarketList.add(spanElement.text());
} else {
log.warn("Invalid status code while scraping.");
}
}
}
return stockMarketList.toArray(new String[0]);
}
private static String getWebDetail(String url) throws IOException {
log.info("Getting web detail URL: " + url + "...");
return Jsoup.connect(url).ignoreContentType(true).execute().body();
}
}

View File

@@ -1,6 +1,7 @@
package cn.stock.market.infrastructure.job;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
@@ -10,6 +11,11 @@ import java.util.concurrent.TimeUnit;
import javax.annotation.PostConstruct;
import cn.stock.market.domain.basic.entity.SiteNews;
import cn.stock.market.domain.basic.repository.SiteNewsRepository;
import cn.stock.market.domain.basic.service.SiteNewsService;
import cn.stock.market.domain.basic.service.StockService;
import cn.stock.market.infrastructure.db.po.QSiteNewsPO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
@@ -37,10 +43,12 @@ import cn.stock.market.web.config.Config;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
//@Component
public class StockTask {
@Autowired RealtimeRepository realtimeRepository;
@Autowired StockRepository stockRepository;
@Autowired StockService stockService;
@Autowired SiteNewsRepository newsRepository;
ThreadPoolExecutor pool;
@PostConstruct
@@ -202,7 +210,7 @@ public class StockTask {
}
/*同步股票列表*/
@Scheduled(cron = "0 5 6 * * ?")
// @Scheduled(cron = "0 5 6 * * ?")
public void syncBjsStockList() {
MdcUtil.setTraceIdIfAbsent();
boolean flag = true;
@@ -339,4 +347,32 @@ public class StockTask {
//
// log.info("syncAStockList执行, 受影响数{}, 耗时:{}毫秒", count, stopwatch.elapsed(TimeUnit.MILLISECONDS));
// }
/*新闻接口*/
@Scheduled(cron = "0 0 1 * * ?")
public void saveStockNews() {
String news = stockService.getNews();
List<String> newsList = Arrays.asList(news.split("<a href="));
newsList = newsList.subList(1, newsList.size());
newsList.forEach( n -> {
String contentUrl = n.substring(1, n.indexOf("class=\"img-smllnews\"") - 2);
String id = contentUrl.substring(contentUrl.lastIndexOf("-") + 1, contentUrl.lastIndexOf("_"));
String imgUrl = n.substring(n.indexOf("img src=") + 9, n.indexOf("?"));
String time = n.substring(n.indexOf("Last Updated") + 23, n.indexOf("IST") - 9);
String title = n.substring(n.indexOf("html\">") + 6, n.indexOf("<div class=\"short-video-img\">") - 47);
SiteNews siteNews = new SiteNews();
siteNews.setAddTime(new Date());
siteNews.setSourceId(id);
siteNews.setTitle(title);
siteNews.setDescription(time);
siteNews.setImgurl(imgUrl);
siteNews.setContent(stockService.getNewsInfo(contentUrl));
List<SiteNews> list = newsRepository.findAll(QSiteNewsPO.siteNewsPO.sourceId.eq(id));
if (list.size() == 0) {
newsRepository.save(siteNews);
}
});
}
}

View File

@@ -1,77 +1,77 @@
package cn.stock.market.infrastructure.stockdb.config;
import java.util.Map;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.rp.spring.jpa.GenericJpaRepositoryFactoryBean;
import com.rp.spring.jpa.GenericJpaRepositoryImpl;
/**
*
* title: ErpDatasourceConfig.java
* ERP 数据源设置
*
* @author rplees
* @email rplees.i.ly@gmail.com
* @version 1.0
* @created Jan 5, 2018 11:44:49 AM
*/
@Configuration
@ComponentScan({ "cn.stock.market.infrastructure.stockdb.po", "cn.stock.market.infrastructure.stockdb.repo"})
@EnableJpaRepositories(
repositoryBaseClass = GenericJpaRepositoryImpl.class,
repositoryFactoryBeanClass = GenericJpaRepositoryFactoryBean.class,
entityManagerFactoryRef = "stockEntityManagerFactory",
transactionManagerRef = "stockTransactionManager",
basePackages = { "cn.stock.market.infrastructure.stockdb.po", "cn.stock.market.infrastructure.stockdb.repo"})
public class StockDatasourceConfig {
@Autowired HibernateProperties hibernateProperties;
@Bean(name = "stockDataSource")
@ConfigurationProperties(prefix="spring.datasource.stock")
public DataSource dataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "stockJpaProperties")
@ConfigurationProperties(prefix = "spring.jpa")
public JpaProperties jpaProperties() {
return new JpaProperties();
}
@Bean(name = "stockEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
EntityManagerFactoryBuilder builder,
@Qualifier("stockJpaProperties") JpaProperties jpaProperties,
@Qualifier("stockDataSource") DataSource dataSource) {
Map<String, Object> properties = hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
return builder
.dataSource(dataSource)
.properties(properties)
.packages("cn.stock.market.infrastructure.stockdb.po")
.persistenceUnit("stock")
.build();
}
@Bean(name = "stockTransactionManager")
public PlatformTransactionManager transactionManager(@Qualifier("stockEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
}
//package cn.stock.market.infrastructure.stockdb.config;
//
//import java.util.Map;
//
//import javax.persistence.EntityManagerFactory;
//import javax.sql.DataSource;
//
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.beans.factory.annotation.Qualifier;
//import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
//import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
//import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
//import org.springframework.boot.context.properties.ConfigurationProperties;
//import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.ComponentScan;
//import org.springframework.context.annotation.Configuration;
//import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
//import org.springframework.orm.jpa.JpaTransactionManager;
//import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
//import org.springframework.transaction.PlatformTransactionManager;
//
//import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
//import com.rp.spring.jpa.GenericJpaRepositoryFactoryBean;
//import com.rp.spring.jpa.GenericJpaRepositoryImpl;
//
///**
// *
// * title: ErpDatasourceConfig.java
// * ERP 数据源设置
// *
// * @author rplees
// * @email rplees.i.ly@gmail.com
// * @version 1.0
// * @created Jan 5, 2018 11:44:49 AM
// */
//@Configuration
//@ComponentScan({ "cn.stock.market.infrastructure.stockdb.po", "cn.stock.market.infrastructure.stockdb.repo"})
//@EnableJpaRepositories(
// repositoryBaseClass = GenericJpaRepositoryImpl.class,
// repositoryFactoryBeanClass = GenericJpaRepositoryFactoryBean.class,
// entityManagerFactoryRef = "stockEntityManagerFactory",
// transactionManagerRef = "stockTransactionManager",
// basePackages = { "cn.stock.market.infrastructure.stockdb.po", "cn.stock.market.infrastructure.stockdb.repo"})
//public class StockDatasourceConfig {
// @Autowired HibernateProperties hibernateProperties;
// @Bean(name = "stockDataSource")
// @ConfigurationProperties(prefix="spring.datasource.stock")
// public DataSource dataSource() {
// return DruidDataSourceBuilder.create().build();
// }
//
// @Bean(name = "stockJpaProperties")
// @ConfigurationProperties(prefix = "spring.jpa")
// public JpaProperties jpaProperties() {
// return new JpaProperties();
// }
//
// @Bean(name = "stockEntityManagerFactory")
// public LocalContainerEntityManagerFactoryBean entityManagerFactory(
// EntityManagerFactoryBuilder builder,
// @Qualifier("stockJpaProperties") JpaProperties jpaProperties,
// @Qualifier("stockDataSource") DataSource dataSource) {
// Map<String, Object> properties = hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
// return builder
// .dataSource(dataSource)
// .properties(properties)
// .packages("cn.stock.market.infrastructure.stockdb.po")
// .persistenceUnit("stock")
// .build();
// }
//
// @Bean(name = "stockTransactionManager")
// public PlatformTransactionManager transactionManager(@Qualifier("stockEntityManagerFactory") EntityManagerFactory entityManagerFactory) {
// return new JpaTransactionManager(entityManagerFactory);
// }
//}

View File

@@ -0,0 +1,119 @@
package cn.stock.market.utils;
import cn.hutool.core.codec.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
/**
* AES工具类
* @author lxiaol
* @date 2021年12月23日 13:58
*/
public class AESUtil {
/**
* 128位的AESkey
*/
private static final byte[] AES_KEY = PropertiesUtil.getProperty("aes.key","Jy112211Kj112211").getBytes(StandardCharsets.UTF_8);
/**
* AES解密
*
* @param data 待解密内容
* @return 字节数组
*/
public static byte[] decrypt(byte[] data) throws InvalidKeyException, NoSuchAlgorithmException,
NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = getCipher(AES_KEY, Cipher.DECRYPT_MODE);
return cipher.doFinal(data);
}
/**
* AES 加密操作
*
* @param data 待加密内容
* @return 字节数组
*/
public static byte[] encrypt(byte[] data) throws InvalidKeyException, NoSuchAlgorithmException,
NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = getCipher(AES_KEY, Cipher.ENCRYPT_MODE);
return cipher.doFinal(data);
}
/**
* AES 加密操作
*
* @param text 待加密内容
* @return Base64转码后的加密数据
*/
public static String encrypt(String text) {
byte[] byteContent = text.getBytes(StandardCharsets.UTF_8);
try {
byte[] result = encrypt(byteContent);// 加密
return Base64.encode(result);//通过Base64转码返回
} catch (Exception e) {
// log.info("Error message: {}", e.getMessage());
e.printStackTrace();
}
return null;
}
/**
* AES 解密操作
*
* @param text
* @return
*/
public static String decrypt(String text) {
byte[] bytes = Base64.decode(text);
try {
byte[] result = decrypt(bytes);
return new String(result, StandardCharsets.UTF_8);
} catch (Exception e) {
// log.info("Error message: {}", e.getMessage());
e.printStackTrace();
return text;
}
}
/**
* 获取加密器
* @param key
* @param model
* @return
* @throws NoSuchAlgorithmException
* @throws NoSuchPaddingException
* @throws InvalidKeyException
*/
private static Cipher getCipher(byte[] key, int model)
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(model, secretKeySpec);
return cipher;
}
public static void main(String[] args) {
String s = "{\n" +
" \"mobile\": \"17570717251\",\n" +
" \"password\": \"Dd112211\",\n" +
" \"platType\": 1,\n" +
" \"loginType\": 0,\n" +
" \"sourceType\": 1,\n" +
" \"equipmentModel\": \"IPHONE\",\n" +
" \"version\":1\n" +
"}";
System.out.println(encrypt(s));
System.out.println("Dd112211Ds112211".length());
System.out.println(decrypt("Z3aCERCWi+nDUzv67h1/8PqS3CCuCgoj/YRTzkFNa0aNRvagi+wxpj9RsutL7nk2oo65ypyEYbjQXCI8fze8V4kMoVAb2rmoXqO3/DudVeTtY1J2784eXw+DS1QWZlZeHAHKiBaEwLcYe4XcsU9tpQIu6fE6cuSPGNetwN3C7qg6/78t4yUjCf49WW7u0/kErfgsSjMajGaVV/LOg74d2RlUcVBIIq6Us8JW3fFWPQA="));
}
}

View File

@@ -10,6 +10,7 @@ import java.util.Map;
import java.util.Set;
import com.github.pagehelper.StringUtil;
import okhttp3.*;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
@@ -73,6 +74,29 @@ public class HttpClientRequest {
}
return result;
}
public static String http2Get(String url) throws IOException {
OkHttpClient client = new OkHttpClient.Builder()
.protocols(java.util.Arrays.asList(Protocol.HTTP_2, Protocol.HTTP_1_1))
.build();
Request request = new Request.Builder()
.url(url) // 替换为你要请求的URL
.addHeader("Cf-Ray", "82e0bc56ccabfabe-SJC")
.addHeader("X-Correlation-Id", "a3120e84-ab22-4a03-81bc-270bbb373c1f")
.addHeader("Server", "cloudflare")
.addHeader("Cf-Cache-Status", "DYNAMIC")
.addHeader("Alt-Svc", "h3=\":443\"; ma=86400")
.addHeader("Date", "Thu, 30 Nov 2023 05:36:57 GMT")
.addHeader("Content-Encoding", "br")
.addHeader("Content-Type", "application/json")
.addHeader("X-Envoy-Upstream-Service", "434")
.addHeader("Via", "1.1 google")
.addHeader("X-App-Version", "1.45.3")
.addHeader("Cf-Cache-Status", "DYNAMIC")
.build();
Call call = client.newCall(request);
Response response = call.execute();
return response.body().string();
}
/**
* 获取cooike
* @param url
@@ -187,4 +211,10 @@ public class HttpClientRequest {
}
return result;
}
public static void main(String[] args) {
String url = "https://marketapi.intoday.in/widget/topgainer/view?exchange=nse";
String str = doGet(url);
System.out.println(str);
}
}

View File

@@ -0,0 +1,60 @@
package cn.stock.market.utils;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class SSLSocketClientUtil {
public static SSLSocketFactory getSocketFactory(TrustManager manager) {
SSLSocketFactory socketFactory = null;
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[]{manager}, new SecureRandom());
socketFactory = sslContext.getSocketFactory();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
return socketFactory;
}
public static X509TrustManager getX509TrustManager() {
return new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
};
}
public static HostnameVerifier getHostnameVerifier() {
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
};
return hostnameVerifier;
}
}

View File

@@ -0,0 +1,53 @@
package cn.stock.market.utils;
import lombok.extern.slf4j.Slf4j;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Objects;
/**
* 流工具类
* @author zhouyl
* @date 2023年12月09日 15:11
*/
@Slf4j
public class StreamUtil {
private static final Integer BUFFER_SIZE = 128;
/**
* 将requestBody的数据转成字符串
*
* @param inputStream
* @return
*/
public static String getBodyString(InputStream inputStream) {
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
if (Objects.nonNull(inputStream)) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
int bytesRead;
char[] charBuffer = new char[BUFFER_SIZE];
while ((bytesRead = bufferedReader.read(charBuffer)) != -1) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
}
} catch (IOException e) {
log.error("get body fail{}", e.getMessage());
throw new RuntimeException(e);
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return stringBuilder.toString();
}
}

View File

@@ -1,16 +1,18 @@
package cn.stock.market.utils;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
@@ -394,13 +396,55 @@ public final class Utils {
return returnStr;
}
//读取txt文本内容
public static String readTxt() {
FileReader fr = null;
BufferedReader br = null;
StringBuilder buffer = new StringBuilder();
try {
String file = Objects.requireNonNull(Utils.class.getResource("/2036.txt")).getPath();
fr = new FileReader(file);
br = new BufferedReader(fr);
String line = "";
while ((line = br.readLine()) != null) {
buffer.append(line);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
return buffer.toString();
}
public static void main(String[] args) {
System.out.println(getFirstLetter("0L神鼎ds飞#@#丹砂"));
System.out.println(getFirstLetter("0L神鼎ds飞#@#丹砂"));
System.out.println(highVersion("1.0.8", "1.0.9"));
System.out.println(highVersion("1.0.9", "1.0.10"));
System.out.println(highVersion("1.0.10", "1.0.11"));
System.out.println(highVersion("1.0.10", "1.0.9"));
// System.out.println(getFirstLetter("0L神鼎ds飞#@#丹砂"));
// System.out.println(getFirstLetter("0L神鼎ds飞#@#丹砂"));
// System.out.println(highVersion("1.0.8", "1.0.9"));
// System.out.println(highVersion("1.0.9", "1.0.10"));
// System.out.println(highVersion("1.0.10", "1.0.11"));
// System.out.println(highVersion("1.0.10", "1.0.9"));
String str = readTxt();
JSONArray jsonArray = JSON.parseArray(str);
System.out.println(Arrays.toString(jsonArray.toArray()));
// for (Object object : jsonArray){
// object.
// }
}
}

View File

@@ -0,0 +1,175 @@
package cn.stock.market.web;
import cn.stock.market.domain.basic.entity.BtodayStock;
import cn.stock.market.domain.basic.service.BtodayStockService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
//import net.sf.json.JSONArray;
//import net.sf.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
@RestController
@Api(tags="bToday获取详情接口")
public class BTodayStockController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private BtodayStockService btodayStockService;
@GetMapping("/api/bToday/kLine")
@ApiOperation(value = "股票详情K线图",httpMethod = "GET")
@ApiImplicitParams({
@ApiImplicitParam(name="exchange",value = "BSE或者NSE"),
@ApiImplicitParam(name="co_code",value = "BToday的coCode值"),
@ApiImplicitParam(name="format",value = "S(1D的时候传S),H(5D的时候传H),H(3M的时候传H),H(1Y的时候传H),H(5Y的时候传H),H(10Y的时候传H)"),
@ApiImplicitParam(name="durationtype",value = "D(1D的时候传D),D(5D的时候传D),M(3M的时候传M),Y(1Y的时候传Y),Y(5Y的时候传Y),Y(10Y的时候传Y)"),
@ApiImplicitParam(name="duration",value = "1(1D的时候传1),5(5D的时候传5),3(3M的时候传3),1(1Y的时候传1),5(5Y的时候传5),10(10Y的时候传10)"),
})
public JSONArray getPriceChartCompanyPullView(
@RequestParam(value = "exchange") String exchange,
@RequestParam(value = "co_code") String coCode,
@RequestParam(value = "format") String format,
@RequestParam(value = "durationtype") String durationType,
@RequestParam(value = "duration") String duration) {
if (StringUtils.isBlank(exchange) || StringUtils.isBlank(coCode) || StringUtils.isBlank(format) || StringUtils.isBlank(durationType) || StringUtils.isBlank(duration)) {
return new JSONArray();
}
// 构建请求URL
String apiUrl = buildApiUrl(exchange, coCode, format, durationType, duration);
// 发起REST请求并获取响应数据
Map<String, Object> response = restTemplate.getForObject(apiUrl, Map.class);
List<Map<String, Object>> data = (List<Map<String, Object>>) response.get("data");
// 转换为StockData列表
JSONArray jsonArray = new JSONArray();
data.forEach(item -> {
String updateDate = (String) item.get("upd_date");
BigDecimal price = new BigDecimal(String.valueOf(item.get("price")));
// 创建JSONObject并放入数据
JSONObject jsonObject = new JSONObject();
jsonObject.put("updateDate", updateDate);
jsonObject.put("price", price);
jsonArray.add(jsonObject);
});
return jsonArray;
}
@ApiOperation(value = "股票详情信息",httpMethod = "GET")
@ApiImplicitParams({
@ApiImplicitParam(name="exchange",value = "BSE或者NSE"),
@ApiImplicitParam(name="co_code",value = "coCode值"),
})
@ApiResponses(value = {
@ApiResponse(code = 200, message = "这个接口返回的 JSON 字段说明如下:\n" +
"status_code: 操作状态码1 表示成功。\n" +
"success: 操作是否成功true 表示成功。\n" +
"data: 包含具体数据的部分,是一个数组,包含了以下关于公司 \"Gujarat Fluorochemicals Ltd\" 的信息:\n" +
"exchange: 交易所,这里是 NSE国家股票交易所\n" +
"sc_code: 股票代码。\n" +
"symbol: 股票符号。\n" +
"companyname: 公司全名,英文。\n" +
"companyshortname: 公司简称,英文。\n" +
"companyname_hi: 公司全名,印地文。\n" +
"companyshortname_hi: 公司简称,印地文。\n" +
"co_code: 公司代码。\n" +
"mcap_val: 市值。\n" +
"mcaptype: 市值类型,这里是 Mid Cap中型市值\n" +
"co_image: 公司图标的 URL。\n" +
"sef_url: 公司的链接。\n" +
"ros_sef_url: 公司 ROS 链接。\n" +
"sectorname: 公司所属行业。\n" +
"sc_group: 股票组别。\n" +
"upd_time: 最后更新时间。\n" +
"cmot_upd_time: CMOT 最后更新时间。\n" +
"open_price: 开盘价。\n" +
"high_price: 最高价。\n" +
"cmot_high_price: CMOT 最高价。\n" +
"price: 最新交易价。\n" +
"cmot_price: CMOT 最新交易价。\n" +
"low_price: 最低价。\n" +
"cmot_low_price: CMOT 最低价。\n" +
"bbuy_qty: 买入数量。\n" +
"bbuy_price: 买入价格。\n" +
"bsell_qty: 卖出数量。\n" +
"bsell_price: 卖出价格。\n" +
"perchg: 当前涨跌幅。\n" +
"cmot_perchg: CMOT 涨跌幅。\n" +
"pricediff: 当前价格变动。\n" +
"cmot_pricediff: CMOT 价格变动。\n" +
"vol_traded: 成交量。\n" +
"cmot_vol_traded: CMOT 成交量。\n" +
"val_traded: 成交额。\n" +
"52weekhigh: 52周最高价。\n" +
"52weeklow: 52周最低价。\n" +
"value: 市值。\n" +
"list_Info: 是否已上市。\n" +
"h52date: 52周最高价日期。\n" +
"l52date: 52周最低价日期。\n" +
"b52high_adj: 调整后的 52周最高价。\n" +
"b52low_adj: 调整后的 52周最低价。\n" +
"isin: ISIN 编号。\n" +
"prev_close: 前一交易日收盘价。\n" +
"offerqty: 报价数量。\n" +
"message: 返回信息,\"Successful\" 表示成功。\n" +
"fromredis: 标志是否来自 Redis 缓存false 表示不是", response = JSONObject.class),
})
@GetMapping("/api/bToday/stockDetail")
public com.alibaba.fastjson.JSONObject getPriceChartCompanyPullView(
@RequestParam(value = "exchange") String exchange,
@RequestParam(value = "co_code") String coCode
) {
if (StringUtils.isBlank(exchange) || StringUtils.isBlank(coCode) ) {
return new com.alibaba.fastjson.JSONObject();
}
BtodayStock btodayStock = btodayStockService.findBtStockByCoCode(coCode,exchange);
if(btodayStock == null){
return new com.alibaba.fastjson.JSONObject();
}
// 构建请求URL
String apiUrl = buildDetailApiUrl(exchange, coCode);
String forObject = restTemplate.getForObject(apiUrl, String.class);
JSONObject jsonObject = JSON.parseObject(forObject);
jsonObject.put("id",btodayStock.getId());
return jsonObject;
}
private String buildDetailApiUrl(String exchange, String coCode) {
String url = String.format("https://marketapi.intoday.in/widget/stockdetail/pullview?co_code=%s&exchange=%s",coCode,exchange);
return url;
}
private String buildApiUrl(String exchange, String coCode, String format, String durationType, String duration) {
// 构建请求URL的逻辑根据你的实际情况来
// 示例return "https://your-api-endpoint/bToday/kLine?exchange=" + exchange + "&co_code=" + coCode + "&format=" + format + "&durationtype=" + durationType + "&duration=" + duration;
String url = String.format("https://marketapi.intoday.in/widget/pricechart_company/pullview?exchange=%s&co_code=%s&format=%s&durationtype=%s&duration=%s",
exchange, coCode, format, durationType, duration);
return url;
}
}

View File

@@ -1,14 +1,17 @@
package cn.stock.market.web;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import cn.qutaojing.common.PageParam;
import cn.stock.market.domain.basic.entity.SiteNews;
import cn.stock.market.domain.basic.repository.SiteNewsRepository;
import cn.stock.market.infrastructure.db.po.QSiteNewsPO;
import cn.stock.market.web.annotations.EncryptFilter;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
@@ -24,6 +27,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
import com.ag.utils.DateUtils;
import com.ag.utils.Jsons;
import com.ag.utils.param.ParamUtils;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Joiner;
import com.google.common.cache.Cache;
@@ -40,6 +44,9 @@ import cn.stock.market.domain.basic.service.StockService;
import cn.stock.market.dto.model.StockCode;
import cn.stock.market.dto.model.StockVO;
import cn.stock.market.infrastructure.api.EastmoneyApi;
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.qq.QqStockApi;
import cn.stock.market.infrastructure.api.sina.SinaStockApi;
import cn.stock.market.utils.RequestCacheUtils;
@@ -59,6 +66,8 @@ public class StockApiController {
@Autowired
StockService stockService;
@Autowired
SiteNewsRepository newsRepository;
@RequestMapping({"getRawSinaStock.do"})
@ResponseBody
@@ -119,39 +128,80 @@ public class StockApiController {
@ApiOperation(value = "印度股票个股详情", httpMethod = "GET")
@ResponseBody
public ServerResponse getINDStockInfo(@RequestParam("stockCode") String stockCode) {
return this.stockService.getStockInfo(stockCode);
ParamUtils.verify("股票代码", stockCode, ParamUtils.STRING_NOT_EMPTY_VERIFY_AND_CONVERT_VALUE);
IndiaStockVO market = InvestingApis.of().market(StockCode.of(stockCode));
return ServerResponse.createBySuccess(market.toStockVo());
}
//印度股票个股详情
@RequestMapping({"getIndiaIndexInfo.do"})
@ApiOperation(value = "印度--获取指数详情", httpMethod = "GET")
@ResponseBody
public ServerResponse getIndiaIndexInfo(@RequestParam("stockCode") String stockCode) {
ParamUtils.verify("指数代码", stockCode, ParamUtils.STRING_NOT_EMPTY_VERIFY_AND_CONVERT_VALUE);
IndiaStockVO market = InvestingApis.of().market(StockCode.of(stockCode));
return ServerResponse.createBySuccess(market.toStockVo());
}
//印度股票列表 英情
@RequestMapping({"getINDStockList.do"})
@ApiOperation(value = "印度股票列表", httpMethod = "GET")
@ResponseBody
@EncryptFilter(decryptRequest = false)
public ServerResponse getINDStockList(@RequestParam("pageSize") Integer pageSize, @RequestParam("pageNum") Integer pageNum) throws IOException {
return ServerResponse.createBySuccess(InvestingInvokerApis.of().__page(pageNum, pageSize));
}
@RequestMapping({"getTopINDStockList.do"})
@ApiOperation(value = "印度热门股票列表", httpMethod = "GET")
@ResponseBody
public ServerResponse getTopINDStockList(@RequestParam("pageSize") Integer pageSize, @RequestParam("pageNum") Integer pageNum) throws IOException {
return ServerResponse.createBySuccess(InvestingInvokerApis.of().__page_nifty100(pageNum, pageSize));
}
@RequestMapping({"getINDNews.do"})
@ApiOperation(value = "印度新闻列表", httpMethod = "GET")
@ResponseBody
public ServerResponse getINDNews(@RequestParam("pageSize") Integer pageSize, @RequestParam("pageNum") Integer pageNum) {
return ServerResponse.createBySuccess(newsRepository.findAll(PageParam.of(pageNum, pageSize)));
}
//印度股票时线-K线
@RequestMapping({"getINDTimeK.do"})
@ApiOperation(value = "印度股票时线-K线", httpMethod = "GET")
@ApiOperation(value = "印度股票K线", httpMethod = "GET")
@ResponseBody
public ServerResponse getINDTimeK(@RequestParam("stockCode") String stockCode) {
return this.stockService.getTimeK(stockCode);
@ApiImplicitParams({
@ApiImplicitParam(name = "stockCode",value = "股票对应代码",dataType ="String", paramType = "query", required = true),
@ApiImplicitParam(name = "type",value = "min-时分线 day-日线 week-周线 month-月线, 3month-季度, 6month-半年, year-年",dataType ="String", paramType = "query", required = true),
})
public ServerResponse getINDTimeK(@RequestParam("stockCode") String stockCode, @RequestParam("type") String type) throws IOException {
ParamUtils.verify("股票代码", stockCode, ParamUtils.STRING_NOT_EMPTY_VERIFY_AND_CONVERT_VALUE);
ParamUtils.verify("K线类型", stockCode, ParamUtils.STRING_NOT_EMPTY_VERIFY_AND_CONVERT_VALUE);
List<JSONObject> list = InvestingApis.of().kline(StockCode.of(stockCode), type);
return ServerResponse.createBySuccess(list);
}
//印度股票日线-K线
@RequestMapping({"getINDDayK.do"})
@ApiOperation(value = "印度股票日线-K线", httpMethod = "GET")
//印度指数-K线
@RequestMapping({"getIndiaIndexTimeK.do"})
@ApiOperation(value = "印度--获取指数K线", httpMethod = "GET")
@ResponseBody
public ServerResponse getINDDayK(@RequestParam("stockCode") String stockCode) {
return this.stockService.getDayK(stockCode);
}
@ApiImplicitParams({
@ApiImplicitParam(name = "stockCode",value = "指数代码",dataType ="String", paramType = "query", required = true),
@ApiImplicitParam(name = "type",value = "min-时分线 day-日线 week-周线 month-月线, 3month-季度, 6month-半年, year-年",dataType ="String", paramType = "query", required = true),
})
public ServerResponse getIndiaIndexTimeK(@RequestParam("stockCode") String stockCode, @RequestParam("type") String type) throws IOException {
ParamUtils.verify("指数代码", stockCode, ParamUtils.STRING_NOT_EMPTY_VERIFY_AND_CONVERT_VALUE);
ParamUtils.verify("K线类型", stockCode, ParamUtils.STRING_NOT_EMPTY_VERIFY_AND_CONVERT_VALUE);
//印度股票周线-K线
@RequestMapping({"getINDWeekK.do"})
@ApiOperation(value = "印度股票周线-K线", httpMethod = "GET")
@ResponseBody
public ServerResponse getINDWeekK(@RequestParam("stockCode") String stockCode) {
return this.stockService.getWeekK(stockCode);
List<JSONObject> list = InvestingApis.of().kline(StockCode.of(stockCode), type);
return ServerResponse.createBySuccess(list);
}
//印度股票月线-K线
@RequestMapping({"getINDMonthK.do"})
@ApiOperation(value = "印度股票月线-K线", httpMethod = "GET")
@RequestMapping({"getIndiaIndex.do"})
@ApiOperation(value = "印度--获取指定指数信息", httpMethod = "GET")
@ResponseBody
public ServerResponse getINDMonthK(@RequestParam("stockCode") String stockCode) {
return this.stockService.getMonthK(stockCode);
public ServerResponse getIndiaIndex() {
return this.stockService.getIndiaIndex();
}
//根据股票id查询 股票指数、大盘指数信息
@@ -196,7 +246,7 @@ public class StockApiController {
return RequestCacheUtils.cache("getMinK.do", key, (string) -> {
return this.stockService.getMinK(code, time, ma, size);
});
}
@RequestMapping({"getKLine.do"})
@@ -223,7 +273,7 @@ public class StockApiController {
return this.stockService.getDayK_Echarts(code);
});
}
/*查询股票周线*/
@RequestMapping({"getWeekK.do"})
@ApiOperation(value = "查询股票周线", httpMethod = "GET")
@@ -236,7 +286,7 @@ public class StockApiController {
return this.stockService.getWeekK_Echarts(code);
});
}
/*查询股票月线*/
@RequestMapping({"getMonthK.do"})
@ApiOperation(value = "查询股票月线", httpMethod = "GET")
@@ -634,9 +684,16 @@ public class StockApiController {
@ApiOperation(value = "新股待上市接口",httpMethod = "GET", response = ServerResponse.class)
@RequestMapping({"getNewStockList.do"})
@ResponseBody
public
ServerResponse getNewStockList() {
public ServerResponse getNewStockList() {
return this.stockService.getNewStockList();
}
@ApiOperation(value = "印度股票入库",httpMethod = "GET", response = ServerResponse.class)
@RequestMapping({"syncIndiaData.do"})
@ResponseBody
public ServerResponse syncIndiaData() {
return stockService.syncIndiaData();
}
}

View File

@@ -0,0 +1,44 @@
package cn.stock.market.web;
import cn.stock.market.infrastructure.api.TodayApis;
import cn.stock.market.utils.ServerResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@Api(value = "/TodayApiController", tags = "today股票行情")
@RequestMapping({"/api/market/today/"})
public class TodayApiController {
@RequestMapping({"getTopGainers.do"})
@ApiOperation(value = "获取Top Gainers",notes = "exchange传nse或者bse", httpMethod = "GET")
@ResponseBody
public ServerResponse getTopGainers(@RequestParam("exchange") String exchange) {
return ServerResponse.createBySuccess(TodayApis.getTopGainers(exchange));
}
@RequestMapping({"getTopLosers.do"})
@ApiOperation(value = "获取 Top Losers",notes = "exchange传nse或者bse", httpMethod = "GET")
@ResponseBody
public ServerResponse getTopLosers(@RequestParam("exchange") String exchange) {
return ServerResponse.createBySuccess(TodayApis.getTopLosers(exchange));
}
@RequestMapping({"getMostActiveVolume.do"})
@ApiOperation(value = "获取 Most Active Volume",notes = "exchange传nse或者bse", httpMethod = "GET")
@ResponseBody
public ServerResponse getMostActiveVolume(@RequestParam("exchange") String exchange) {
return ServerResponse.createBySuccess(TodayApis.getMostActiveVolume(exchange));
}
@RequestMapping({"getMostActiveValue.do"})
@ApiOperation(value = "获取 Most Active Value",notes = "exchange传nse或者bse",httpMethod = "GET")
@ResponseBody
public ServerResponse getMostActiveValue(@RequestParam("exchange") String exchange) {
return ServerResponse.createBySuccess(TodayApis.getMostActiveValue(exchange));
}
}

View File

@@ -0,0 +1,21 @@
package cn.stock.market.web.annotations;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface EncryptFilter {
/**
* 对入参是否解密
*
* @return
*/
boolean decryptRequest() default true;
/**
* 对出参是否加密
*/
boolean encryptResponse() default true;
}

View File

@@ -6,7 +6,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
@Configuration
@EnableScheduling
@ConditionalOnProperty(prefix = "enable", name = "scheduled", havingValue = "true")
@ConditionalOnProperty(prefix = "enable", name = "scheduled", havingValue = "true", matchIfMissing = true)
public class ControlSchedulingConfiguration {
}

View File

@@ -128,7 +128,7 @@ public class Swagger2Config {
public ApiInfoBuilder commonApiInfoBuilder() {
return new ApiInfoBuilder()
.description("鑫宝 接口文档")
.description("英文股票接口文档")
.termsOfServiceUrl("http://www.xxxx.cn/")
.licenseUrl("http://www.apache.org/licenses/LICENSE-2.0").version("v1.0");
}

View File

@@ -0,0 +1,103 @@
package cn.stock.market.web.handler;
import cn.stock.market.utils.AESUtil;
import cn.stock.market.utils.StreamUtil;
import cn.stock.market.web.annotations.EncryptFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
/**
* 全局请求入参RequestBody处理器
*
*/
@ControllerAdvice
@Slf4j
public class GlobalRequestBodyHandler extends RequestBodyAdviceAdapter {
/**
* 该方法用于判断当前请求是否要执行beforeBodyRead方法
*
* @param methodParameter handler方法的参数对象
* @param targetType handler方法的参数类型
* @param converterType 将会使用到的Http消息转换器类类型
* @return 返回true则会执行beforeBodyRead
*/
@Override
public boolean supports(MethodParameter methodParameter, Type targetType,
Class<? extends HttpMessageConverter<?>> converterType) {
Method method = methodParameter.getMethod();
if (Objects.nonNull(method)) {
EncryptFilter encryptFilter = method.getAnnotation(EncryptFilter.class);
if (Objects.nonNull(encryptFilter)) {
return encryptFilter.decryptRequest();
}
}
return false;
}
/**
* 在Http消息转换器执转换之前执行
*
* @param inputMessage 客户端的请求数据
* @param methodParameter handler方法的参数对象
* @param targetType handler方法的参数类型
* @param converterType 将会使用到的Http消息转换器类类型
* @return 返回 一个自定义的HttpInputMessage
*/
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter methodParameter, Type targetType,
Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
// 读取加密的请求体
InputStream body = inputMessage.getBody();
HttpHeaders headers = inputMessage.getHeaders();
headers.remove("Content-Length");
String s = StreamUtil.getBodyString(body);
log.info("解密前请求body:" + s);
if (StringUtils.isEmpty(s)){
return inputMessage;
}
Method method = methodParameter.getMethod();
if (Objects.isNull(method)) {
return inputMessage;
}
// 解密请求
EncryptFilter encryptFilter = method.getAnnotation(EncryptFilter.class);
if (Objects.nonNull(encryptFilter) && encryptFilter.decryptRequest()) {
// 使用AES解密
String bodyDec = AESUtil.decrypt(s);
log.info("解密后请求body:" + bodyDec);
if (!StringUtils.isEmpty(bodyDec)) {
// 使用解密后的数据,构造新的读取流
InputStream inputStream = new ByteArrayInputStream(bodyDec.getBytes(StandardCharsets.UTF_8));
return new HttpInputMessage() {
@Override
public HttpHeaders getHeaders() {
return inputMessage.getHeaders();
}
@Override
public InputStream getBody() {
return inputStream;
}
};
}
}
return inputMessage;
}
}

View File

@@ -0,0 +1,67 @@
package cn.stock.market.web.handler;
import cn.stock.market.utils.AESUtil;
import cn.stock.market.utils.PropertiesUtil;
import cn.stock.market.web.annotations.EncryptFilter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import java.lang.reflect.Method;
import java.util.Objects;
/**
* 全局响应结果ResponseBody处理器
*
*/
@ControllerAdvice
@Slf4j
public class GlobalResponseBodyHandler implements ResponseBodyAdvice {
private ObjectMapper objectMapper = new ObjectMapper();
public GlobalResponseBodyHandler(){
}
@Override
@SuppressWarnings("NullableProblems") // 避免 IDEA 警告
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
@Override
@SuppressWarnings("NullableProblems") // 避免 IDEA 警告
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response) {
Method method = returnType.getMethod();
if (Objects.isNull(body) || Objects.isNull(method)) {
return body;
}
log.info("处理请求地址:{} 的返回值", request.getURI());
//获取请求数据
String srcData = null;
try {
srcData = objectMapper.writeValueAsString(body);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
log.info("加密前响应body={}", srcData);
EncryptFilter encryptFilter = method.getAnnotation(EncryptFilter.class);
if (Objects.nonNull(encryptFilter) && encryptFilter.encryptResponse()) {
//加密
String returnStr = AESUtil.encrypt(srcData);
log.info("加密后响应body:" + returnStr);
//添加 encrypt 告诉前端数据已加密
return returnStr;
}
return body;
}
}

View File

@@ -3,7 +3,7 @@ spring:
show-sql: true
# Redis配置
redis:
host: 43.128.20.124
host: 43.132.212.180
password: ruTZ9J3gaDhknJ
port: 36379
database: 1
@@ -17,7 +17,7 @@ spring:
datasource:
stock-market:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://124.156.133.209:33306/stock-market?useUnicode=true&characterEncoding=utf-8
url: jdbc:mysql://43.132.212.180:33306/india_stock?useUnicode=true&characterEncoding=utf-8
username: root
password: 33BsUUcnXRYgwt
maxActive: 500

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
This is the JRebel configuration file. It maps the running application to your IDE workspace, enabling JRebel reloading for this project.
Refer to https://manuals.jrebel.com/jrebel/standalone/config.html for more information.
-->
<application generated-by="intellij" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.zeroturnaround.com" xsi:schemaLocation="http://www.zeroturnaround.com http://update.zeroturnaround.com/jrebel/rebel-2_3.xsd">
<id>market</id>
<classpath>
<dir name="/Users/gs/Downloads/works/india_market_java/target/classes">
</dir>
</classpath>
</application>

View File

@@ -113,3 +113,4 @@ website.domain.url=http://www.huijuwang888.com
website.token=0DC8F78384C7AAFF3192A9C60A473FEE7F89C62888689616B98A06910E86B510
news.main.url=http://eminfo.eastmoney.com
aes.key=Jy112211Kj112211

View File

@@ -0,0 +1,57 @@
package rp.lee.jpa;
import java.sql.SQLException;
import javax.annotation.Resource;
import javax.sql.DataSource;
import com.mysql.cj.jdbc.MysqlDataSource;
import rp.lee.jpa.ddd.Cons;
import rp.lee.jpa.ddd.ToolDDD;
/**
*
* title: JpaDDDGen.java
* DDD 脚手架
*
* @author rplees
* @email rplees.i.ly@gmail.com
* @version 1.0
* @created 2023年8月9日 下午5:41:52
*/
public class JpaDDDGen {
@Resource DataSource dataSource;
/**
* 获取数据库连接
* @return
*/
public static DataSource getMySQLDataSource() {
MysqlDataSource mysqlDS = new MysqlDataSource();
mysqlDS.setURL("jdbc:mysql://43.132.212.180:33306/india_stock?useUnicode=true&characterEncoding=utf-8");
mysqlDS.setUser("root");
mysqlDS.setPassword("33BsUUcnXRYgwt");
return mysqlDS;
}
public static void main(String[] args) throws SQLException, Exception {
Cons.BASE_PACKAGE = "cn.stock.%s";
Cons.module = "market";
/**
* 请修改实际上本机的项目路径
*/
String path = "src/main/java";
Cons.CLIENT_FOLDER_PATH = path;
Cons.SERVER_FOLDER_PATH = path;
/**
* cs_statistic - 要生成的数据库表
*/
Cons.tableNameToEntiyMapping.put("stock_ipo", null);
ToolDDD.g(getMySQLDataSource().getConnection());
}
}

View File

@@ -0,0 +1,51 @@
package rp.lee.jpa.ddd;
import java.sql.Connection;
import java.sql.ResultSet;
import javax.lang.model.element.Modifier;
import org.apache.commons.lang.StringUtils;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeSpec.Builder;
public class ApiFeignGen implements IClassGenerate {
@Override
public Builder builder(DDD ddd, Connection conn, ResultSet rs) throws Exception {
Builder builder = TypeSpec.interfaceBuilder(className(ddd))
.addModifiers(Modifier.PUBLIC)
.addJavadoc(String.format("%s \n", className(ddd)))
.addSuperinterface(ddd.api.toClassName())
.addAnnotation(AnnotationSpec
.builder(ClassName.get("org.springframework.cloud.openfeign", "FeignClient"))
.addMember("name", "\"" + ddd.module + "\"")
.addMember("contextId", "\"" + StringUtils.uncapitalize(ddd.entityPrefix) + "\"")
.addMember("configuration", "{ $T.class }", ClassName.get("cn.qutaojing.common.feign", "FeignConfiguration"))
.build())
;
return builder;
}
@Override
public String className(DDD ddd) {
return "IFeign" + ddd.entityPrefix + "Client";
}
@Override
public String folerPath(DDD ddd) {
return Cons.CLIENT_FOLDER_PATH;
}
@Override
public String packagePath(DDD ddd) {
return String.format(Cons.API_FEIGN_PACKAGE, ddd.module);
}
}

View File

@@ -0,0 +1,137 @@
package rp.lee.jpa.ddd;
import java.sql.Connection;
import java.sql.ResultSet;
import java.util.List;
import javax.lang.model.element.Modifier;
import javax.validation.Valid;
import org.apache.commons.lang.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeSpec.Builder;
public class ApiGen implements IClassGenerate {
@Override
public Builder builder(DDD ddd, Connection conn, ResultSet rs) throws Exception {
ClassName springQueryMapClass = ClassName.get("org.springframework.cloud.openfeign", "SpringQueryMap");
Builder builder = TypeSpec.interfaceBuilder(className(ddd))
.addModifiers(Modifier.PUBLIC)
.addJavadoc(String.format("%s \n", className(ddd)))
.addAnnotation(AnnotationSpec.builder(RequestMapping.class).addMember("path", "\"/" + StringUtils.lowerCase(ddd.entityPrefix) + "\"").build())
// 分页构造
.addMethod(MethodSpec.methodBuilder("page").addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.addAnnotation(AnnotationSpec.builder(RequestMapping.class).addMember("path", "\"/page" + "\"").build())
.addParameter(ParameterSpec.builder(ddd.query.toClassName(), "query")
.addAnnotation(springQueryMapClass)
.build())
.addParameter(ParameterSpec.builder(ClassName.get("cn.qutaojing.common", "PageParam"), "p").build())
.returns(ParameterizedTypeName.get(ClassName.get("cn.qutaojing.common", "PageInfo"), ddd.dto.toClassName()))
.build()
)
// 列表构造
.addMethod(MethodSpec.methodBuilder("list").addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.addAnnotation(AnnotationSpec.builder(RequestMapping.class).addMember("path", "\"/list\"").build())
.addParameter(ParameterSpec.builder(ddd.query.toClassName(), "query")
.addAnnotation(springQueryMapClass)
.build())
.returns(ParameterizedTypeName.get(ClassName.get(List.class), ddd.dto.toClassName()))
.build()
)
//create
.addMethod(MethodSpec.methodBuilder("create").addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.addAnnotation(AnnotationSpec.builder(RequestMapping.class).addMember("path", "\"create\"").build())
.addParameter(ParameterSpec.builder(ddd.put.toClassName(), "request").addAnnotation(Valid.class)
.addAnnotation(springQueryMapClass)
.build())
.addParameter(ParameterSpec.builder(BindingResult.class, "bindingResult")
.addAnnotation(AnnotationSpec.builder(RequestParam.class)
.addMember("required", "false")
.addMember("value", "\"bindingResult\"")
.build()).build())
.returns(ddd.dto.toClassName())
.build()
)
//update
.addMethod(MethodSpec.methodBuilder("update").addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.addAnnotation(AnnotationSpec.builder(RequestMapping.class).addMember("path", "\"/{id}/update\"").build())
.addParameter(ParameterSpec.builder(ddd.poPK, "id").addAnnotation(AnnotationSpec.builder(PathVariable.class).addMember("value", "\"id\"").build()).build())
.addParameter(ParameterSpec.builder(ddd.put.toClassName(), "request")
.addAnnotation(springQueryMapClass)
.build())
.returns(ddd.dto.toClassName())
.build()
)
//根据ID获取
.addMethod(MethodSpec.methodBuilder("get").addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.addAnnotation(AnnotationSpec.builder(RequestMapping.class).addMember("path", "\"/{id}/get\"").build())
.addParameter(ParameterSpec.builder(ddd.poPK, "id").addAnnotation(AnnotationSpec.builder(PathVariable.class).addMember("value", "\"id\"").build()).build())
.returns(ddd.dto.toClassName())
.build()
)
//启用
.addMethod(MethodSpec.methodBuilder("enable").addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.addAnnotation(AnnotationSpec.builder(RequestMapping.class).addMember("path", "\"/{id}/enable\"").build())
.addParameter(ParameterSpec.builder(ddd.poPK, "id").addAnnotation(AnnotationSpec.builder(PathVariable.class).addMember("value", "\"id\"").build()).build())
.returns(void.class)
.build()
)
//禁用
.addMethod(MethodSpec.methodBuilder("disable").addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.addAnnotation(AnnotationSpec.builder(RequestMapping.class).addMember("path", "\"/{id}/disable\"").build())
.addParameter(ParameterSpec.builder(ddd.poPK, "id").addAnnotation(AnnotationSpec.builder(PathVariable.class).addMember("value", "\"id\"").build()).build())
.returns(void.class)
.build()
)
//删除
.addMethod(MethodSpec.methodBuilder("remove").addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.addAnnotation(AnnotationSpec.builder(RequestMapping.class).addMember("path", "\"/{id}/remove\"").build())
.addParameter(ParameterSpec.builder(ddd.poPK, "id").addAnnotation(AnnotationSpec.builder(PathVariable.class).addMember("value", "\"id\"").build()).build())
.returns(void.class)
.build()
)
;
return builder;
}
@Override
public String className(DDD ddd) {
return "I" + ddd.entityPrefix + "Client";
}
@Override
public String folerPath(DDD ddd) {
return Cons.CLIENT_FOLDER_PATH;
}
@Override
public String packagePath(DDD ddd) {
return String.format(Cons.API_PACKAGE, ddd.module);
}
}

View File

@@ -0,0 +1,163 @@
package rp.lee.jpa.ddd;
import java.sql.Connection;
import java.sql.ResultSet;
import java.util.List;
import javax.lang.model.element.Modifier;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RestController;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeSpec.Builder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
public class ApiImplGen implements IClassGenerate {
@Override
public Builder builder(DDD ddd, Connection conn, ResultSet rs) throws Exception {
Builder builder = TypeSpec.classBuilder(className(ddd))
.addModifiers(Modifier.PUBLIC)
.addJavadoc(String.format("%s \n", className(ddd)))
.addSuperinterface(ddd.api.toClassName())
.addAnnotation(AnnotationSpec.builder(RestController.class).build())
.addAnnotation(AnnotationSpec.builder(RequiredArgsConstructor.class).addMember("onConstructor", "@__(@$T)", ClassName.get(Autowired.class)).build())
.addAnnotation(AnnotationSpec.builder(Slf4j.class).build())
.addField(FieldSpec.builder(ddd.service.toClassName(), "service").addModifiers(Modifier.FINAL).build())
.addField(FieldSpec.builder(ddd.assembler.toClassName(), "assembler").addModifiers(Modifier.FINAL).build())
.addField(FieldSpec.builder(ddd.factory.toClassName(), "factory").addModifiers(Modifier.FINAL).build())
// 分页构造
.addMethod(MethodSpec.methodBuilder("page")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(AnnotationSpec.builder(Override.class).build())
.addParameter(ParameterSpec.builder(ddd.query.toClassName(), "query").build())
.addParameter(ParameterSpec.builder(ClassName.get("cn.qutaojing.common", "PageParam"), "p").build())
.returns(ParameterizedTypeName.get(ClassName.get("cn.qutaojing.common", "PageInfo"), ddd.dto.toClassName()))
.addStatement("$T<$T> page = service.repository().findAll($T.spec(query), PageParam.of(p))\n"
+ " .map(entity -> assembler.toDTO(entity))",
ClassName.get("org.springframework.data.domain", "Page"),
ddd.dto.toClassName(),ClassName.get("cn.qutaojing.common.jpa", "QueryHelp"))
.addStatement("return PageInfo.with(page)")
.build()
)
// // 列表构造
.addMethod(MethodSpec.methodBuilder("list")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(AnnotationSpec.builder(Override.class).build())
.addParameter(ParameterSpec.builder(ddd.query.toClassName(), "query").build())
.returns(ParameterizedTypeName.get(ClassName.get(List.class), ddd.dto.toClassName()))
.addStatement("List<$T> list = service.repository().findAll($T.spec(query))", ddd.entity.toClassName(), ClassName.get("cn.qutaojing.common.jpa", "QueryHelp"))
.addStatement("return $T.transform(list, entity -> assembler.toDTO(entity))", ClassName.get("com.google.common.collect", "Lists"))
.build()
)
// //create
.addMethod(MethodSpec.methodBuilder("create")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(AnnotationSpec.builder(Override.class).build())
.addParameter(ParameterSpec.builder(ddd.put.toClassName(), "request").build())
.addParameter(ParameterSpec.builder(BindingResult.class, "bindingResult").build())
.returns(ddd.dto.toClassName())
.addStatement("$T.validBindResult(bindingResult)", ClassName.get("com.ag.utils", "AgAssert"))
.addStatement("$T createEntity = factory.entity(request)", ddd.entity.toClassName())
.addStatement("$T entity = service.repository().save(createEntity)", ddd.entity.toClassName())
.addStatement("return assembler.toDTO(entity)")
.build()
)
//
// //update
.addMethod(MethodSpec.methodBuilder("update")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(AnnotationSpec.builder(Override.class).build())
.addParameter(ParameterSpec.builder(ddd.poPK, "id").build())
.addParameter(ParameterSpec.builder(ddd.put.toClassName(), "request").build())
.returns(ddd.dto.toClassName())
.addStatement("$T updateEntity = factory.entity(request)", ddd.entity.toClassName())
.addStatement("$T entity = service.update(id, updateEntity)", ddd.entity.toClassName())
.addStatement("return assembler.toDTO(entity)")
.build()
)
//
// //根据ID获取
.addMethod(MethodSpec.methodBuilder("get")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(AnnotationSpec.builder(Override.class).build())
.addParameter(ParameterSpec.builder(ddd.poPK, "id").build())
.returns(ddd.dto.toClassName())
.addStatement("$T entity = service.repository().findById(id).orElseThrow($T::new)", ddd.entity.toClassName(), ClassName.get("com.ag.exception", "EntityNotFoundException"))
.addStatement("return assembler.toDTO(entity)")
.build()
)
//
// //启用
.addMethod(MethodSpec.methodBuilder("enable")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(AnnotationSpec.builder(Override.class).build())
.addParameter(ParameterSpec.builder(ddd.poPK, "id").build())
.returns(void.class)
.addStatement("service.repository().setStatusEnable(id)")
.build()
)
//
// //禁用
.addMethod(MethodSpec.methodBuilder("disable")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(AnnotationSpec.builder(Override.class).build())
.addParameter(ParameterSpec.builder(ddd.poPK, "id").build())
.returns(void.class)
.addStatement("service.repository().setStatusDisable(id)")
.build()
)
//
// //删除
.addMethod(MethodSpec.methodBuilder("remove")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(AnnotationSpec.builder(Override.class).build())
.addParameter(ParameterSpec.builder(ddd.poPK, "id").build())
.returns(void.class)
.addStatement("log.warn(\"删除{}实体\", id)")
.addStatement("service.repository().deleteById(id)")
.build()
)
;
return builder;
}
@Override
public String className(DDD ddd) {
return ddd.entityPrefix + "ClientImpl";
}
@Override
public String folerPath(DDD ddd) {
return Cons.SERVER_FOLDER_PATH;
}
@Override
public String packagePath(DDD ddd) {
return String.format(Cons.API_IMPL_PACKAGE, ddd.module);
}
}

View File

@@ -0,0 +1,73 @@
package rp.lee.jpa.ddd;
import java.sql.Connection;
import java.sql.ResultSet;
import javax.lang.model.element.Modifier;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeSpec.Builder;
public class AssemblerGen implements IClassGenerate {
@Override
public Builder builder(DDD ddd, Connection conn, ResultSet rs) throws Exception {
ClassName slef = ClassName.get(packagePath(ddd), className(ddd));
Builder builder = TypeSpec.classBuilder(className(ddd))
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Component.class)
.addAnnotation(Lazy.class)
.addMethod(MethodSpec.methodBuilder("toDTO")
.addModifiers(Modifier.PUBLIC)
.addParameter(ddd.entity.toClassName(), "e")
.returns(ddd.dto.toClassName())
.addStatement("$T dto = $T.mapper(e, $T.class)", ddd.dto.toClassName(), ClassName.get("cn.qutaojing.common.utils", "Beans"), ddd.dto.toClassName())
.addStatement("if(dto == null) return dto")
.addStatement("fill(e, dto)")
.addStatement("return dto")
.build()
)
.addMethod(MethodSpec.methodBuilder("fill")
.addModifiers(Modifier.PROTECTED)
.addParameter(ddd.entity.toClassName(), "e")
.addParameter(ddd.dto.toClassName(), "dto")
.addStatement("if(dto == null) return")
.addStatement("return")
.build()
)
.addMethod(MethodSpec.methodBuilder("of")
.addModifiers(Modifier.PUBLIC)
.addModifiers(Modifier.STATIC)
.returns(slef)
.addStatement("return $T.getBean($T.class)", ClassName.get("cn.qutaojing.common.utils", "SpringUtils"), slef)
.build()
)
.addJavadoc(String.format("%s \n", className(ddd)));
return builder;
}
@Override
public String className(DDD ddd) {
return ddd.entityPrefix + "Assembler";
}
@Override
public String folerPath(DDD ddd) {
return Cons.SERVER_FOLDER_PATH;
}
@Override
public String packagePath(DDD ddd) {
return String.format(Cons.ASSEMBLER_PACKAGE, ddd.module, ddd.module);
}
}

View File

@@ -0,0 +1,19 @@
package rp.lee.jpa.ddd;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.TypeSpec.Builder;
import lombok.Data;
@Data
@lombok.Builder
public class ClassVO {
String folderPath;
String packagePath;
String className;
Builder builder;
ClassName toClassName() {
return ClassName.get(packagePath, className);
}
}

View File

@@ -0,0 +1,58 @@
package rp.lee.jpa.ddd;
import java.util.Map;
import com.google.common.collect.Maps;
public class Cons {
public static final boolean SIMPLE = true;
public static final boolean C = true;
/**
* 模块
*/
public static String module = "cs";//项目
public static String entity = "basic"; //领域
/**
* 客户端项目的git路径
*/
public static String CLIENT_FOLDER_PATH = "/Users/rplees/work/git/stock-company/cs_java/src/main/java";
/**
* Server项目的git路径
*/
public static String SERVER_FOLDER_PATH = "/Users/rplees/work/git/stock-company/cs_java/src/main/java";
public static Map<String, String> tableNameToEntiyMapping = Maps.newHashMap();
static {
/**
* 需要导出的数据库表名 -> 导出的 实体命名(不需要加后缀 PO/DTO/Entity)
*/
// tableNameToEntiyMapping.put("cs_statistic", null);
}
public static String BASE_PACKAGE = "cn.stock.%s";
public static String PO_PACKAGE = BASE_PACKAGE + ".infrastructure.db.po";
public static String PO_MONGO_PACKAGE = BASE_PACKAGE + ".infrastructure.mongodb.po";
public static String REPO_PACKAGE = BASE_PACKAGE + ".infrastructure.db.repo";
public static String REPO_MONGO_PACKAGE = BASE_PACKAGE + ".infrastructure.mongodb.repo";
public static String ENTITY_PACKAGE = BASE_PACKAGE + ".domain.%s.entity";
public static String SERVICE_PACKAGE = BASE_PACKAGE + ".domain.%s.service";
public static String REPOSITORY_PACKAGE = BASE_PACKAGE + ".domain.%s.repository";
public static String FACTORY_PACKAGE = BASE_PACKAGE + ".domain.%s.factory";
public static String CONVERT_PACKAGE = BASE_PACKAGE + ".domain.%s.convert";
public static String ASSEMBLER_PACKAGE = BASE_PACKAGE + ".application.assembler";
//client
public static String API_PACKAGE = BASE_PACKAGE + ".client";
public static String API_FEIGN_PACKAGE = BASE_PACKAGE + ".client.impl";
public static String API_IMPL_PACKAGE = BASE_PACKAGE + ".application";
public static String DTO_PACKAGE = BASE_PACKAGE + ".dto";
public static String QUERY_PACKAGE = BASE_PACKAGE + ".vo";
public static String PUT_PACKAGE = BASE_PACKAGE + ".vo";
public static String CREATE_PACKAGE = DTO_PACKAGE + ".command";
public static String MODIFY_PACKAGE = CREATE_PACKAGE;
}

View File

@@ -0,0 +1,92 @@
package rp.lee.jpa.ddd;
import java.sql.Connection;
import java.sql.ResultSet;
import javax.lang.model.element.Modifier;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeSpec.Builder;
public class ConvertGen implements IClassGenerate {
@Override
public Builder builder(DDD ddd, Connection conn, ResultSet rs) throws Exception {
ClassName slef = ClassName.get(packagePath(ddd), className(ddd));
// Builder builder = TypeSpec.interfaceBuilder(className(ddd))
// .addModifiers(Modifier.PUBLIC)
// .addAnnotation(Component.class)
// .addAnnotation(Lazy.class)
// .addAnnotation(AnnotationSpec.builder(ClassName.get("org.mapstruct.Mapper", "Mapper"))
// .addMember("componentModel", "spring")
// .addMember("unmappedTargetPolicy", "ReportingPolicy.IGNORE)")
// .build())
// .addSuperinterface(ParameterizedTypeName.get(ClassName.get("cn.qutaojing.common.domain.convert", "IEntityPOConvert"),
// ddd.entity.toClassName(),
// ddd.po.toClassName()))
//
// .addJavadoc(String.format("%s \n", className(ddd)));
Builder builder = TypeSpec.classBuilder(className(ddd))
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Component.class)
.addAnnotation(Lazy.class)
.superclass(ParameterizedTypeName.get(ClassName.get("cn.qutaojing.common.domain.convert", "SimpleEntityPOConvert"),
ddd.entity.toClassName(),
ddd.po.toClassName()))
// .addSuperinterface(ParameterizedTypeName.get(ClassName.get("cn.qutaojing.common.domain.convert", "IEntityPOConvert"),
// ddd.entity.toClassName(),
// ddd.po.toClassName()))
//
// .addMethod(MethodSpec.methodBuilder("toEntity")
// .addModifiers(Modifier.PUBLIC)
// .addAnnotation(Override.class)
// .addParameter(ddd.po.toClassName(), "po")
// .returns(ddd.entity.toClassName())
// .addStatement("return $T.mapper(po, $T.class)", ClassName.get("cn.qutaojing.common.utils", "Beans"), ddd.entity.toClassName())
// .build()
// )
//
// .addMethod(MethodSpec.methodBuilder("toPo")
// .addModifiers(Modifier.PUBLIC)
// .addAnnotation(Override.class)
// .addParameter(ddd.entity.toClassName(), "entity")
// .returns(ddd.po.toClassName())
// .addStatement("return $T.mapper(entity, $T.class)", ClassName.get("cn.qutaojing.common.utils", "Beans"), ddd.po.toClassName())
// .build()
// )
.addMethod(MethodSpec.methodBuilder("of")
.addModifiers(Modifier.PUBLIC)
.addModifiers(Modifier.STATIC)
.returns(slef)
.addStatement("return $T.getBean($T.class)", ClassName.get("cn.qutaojing.common.utils", "SpringUtils"), slef)
.build()
)
.addJavadoc(String.format("%s \n", className(ddd)));
return builder;
}
@Override
public String className(DDD ddd) {
return ddd.entityPrefix + "Convert";
}
@Override
public String folerPath(DDD ddd) {
return Cons.SERVER_FOLDER_PATH;
}
@Override
public String packagePath(DDD ddd) {
return String.format(Cons.CONVERT_PACKAGE, ddd.module, ddd.e);
}
}

View File

@@ -0,0 +1,87 @@
package rp.lee.jpa.ddd;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.lang.model.element.Modifier;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeSpec.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import rp.lee.jpa.entity.ColumnStyle;
import rp.lee.jpa.entity.Utils;
public class CreateGen implements IClassGenerate {
@Override
public Builder builder(DDD ddd, Connection conn, ResultSet rs) throws Exception {
String tableName = rs.getString("TABLE_NAME");
Builder classBuilder = TypeSpec.classBuilder(className(ddd))
.addModifiers(Modifier.PUBLIC)
.addJavadoc(String.format("%s \n", className(ddd)))
.addJavadoc(rs.getString("REMARKS"))
.addJavadoc("")
.addAnnotation(Data.class)
.addAnnotation(AnnotationSpec.builder(ClassName.get("lombok.experimental", "SuperBuilder")).build())
.addAnnotation(NoArgsConstructor.class)
;
buildFields(ddd, conn, tableName, classBuilder);
return classBuilder;
}
static void buildFields(DDD ddd, Connection conn, String tableName, Builder classBuilder) throws SQLException {
ResultSet rs = null;
try {
DatabaseMetaData metaData = conn.getMetaData();
rs = metaData.getColumns(null, "%", tableName, "%");
while (rs.next()) {
String columnName = rs.getString("COLUMN_NAME");
int dataType = rs.getInt("DATA_TYPE");
String remarks = rs.getString("REMARKS");
String fieldName = Utils.columnNameToFieldName(columnName, ColumnStyle.defaultColumnStyle);
if("createTime".equals(fieldName) || "updateTime".equals(fieldName)) {//忽略
} else {
com.squareup.javapoet.FieldSpec.Builder fieldBuilder = FieldSpec
.builder(Utils.dataTypeToFieldType(columnName, dataType),
fieldName)
.addJavadoc(remarks);
classBuilder.addField(fieldBuilder.build());
}
}
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
}
}
}
}
@Override
public String className(DDD ddd) {
return ddd.entityPrefix + "CreateCommand";
}
@Override
public String folerPath(DDD ddd) {
return Cons.CLIENT_FOLDER_PATH;
}
@Override
public String packagePath(DDD ddd) {
return String.format(Cons.CREATE_PACKAGE, ddd.module);
}
}

View File

@@ -0,0 +1,54 @@
package rp.lee.jpa.ddd;
import java.lang.reflect.*;
import java.util.List;
import com.google.common.collect.Lists;
public class DDD {
public DDD(String m, String e) {
this.module = m;
this.e = e;
}
String module;
String e;
Type poPK;
String poPKKey;
String entityPrefix;
ClassVO po; //ok
ClassVO entity; //ok
ClassVO dto;//ok
ClassVO assembler;//ok
ClassVO convert;//ok
ClassVO factory;//ok
ClassVO repository;//ok
ClassVO service;//ok
ClassVO repo;//ok
ClassVO query;//ok
ClassVO put;//ok
ClassVO create;//ok
ClassVO modify;//ok
ClassVO api;//ok
ClassVO apiFeign;//ok
ClassVO apiImplGen;//ok
public List<ClassVO> list() {
if(Cons.SIMPLE) {
return Lists.newArrayList(po, entity, dto,create,modify, convert, factory,assembler, repository, service, repo, query, put);
}
if(Cons.C) {
return Lists.newArrayList(po, entity, dto, create,modify, convert, factory,assembler, repository, service, repo, query, put, api, apiFeign, apiImplGen);
}
return Lists.newArrayList(po, entity, dto, convert, factory,assembler, repository, service, repo, query, put, api, apiFeign, apiImplGen);
}
public List<ClassVO> mongoList() {
return Lists.newArrayList(entity, dto,create,modify, convert, factory,assembler, repository, service, repo, query, put, api, apiFeign, apiImplGen);
}
}

View File

@@ -0,0 +1,60 @@
package rp.lee.jpa.ddd;
import java.sql.Connection;
import java.sql.ResultSet;
import javax.lang.model.element.Modifier;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeSpec.Builder;
public class DTOGen implements IClassGenerate {
@Override
public Builder builder(DDD ddd, Connection conn, ResultSet rs) throws Exception {
// String tableName = rs.getString("TABLE_NAME");
// Builder classBuilder = TypeSpec.classBuilder(className(ddd))
// .addModifiers(Modifier.PUBLIC)
// .addJavadoc(String.format("%s \n", className(ddd)))
// .addJavadoc(rs.getString("REMARKS"))
// .addJavadoc("")
// .addAnnotation(Data.class)
// .addAnnotation(lombok.Builder.class)
// .addAnnotation(NoArgsConstructor.class)
// .addAnnotation(AllArgsConstructor.class)
// ;
//
// buildFields(ddd, conn, tableName, classBuilder);
// return classBuilder;
Builder builder = TypeSpec.classBuilder(className(ddd))
.addModifiers(Modifier.PUBLIC)
.addAnnotation(lombok.Data.class)
.addAnnotation(lombok.NoArgsConstructor.class)
.addAnnotation(AnnotationSpec.builder(ClassName.get("lombok.experimental", "SuperBuilder")).build())
.superclass(ddd.po.toClassName())
.addAnnotation(AnnotationSpec.builder(ClassName.get("lombok", "EqualsAndHashCode"))
.addMember("callSuper", "false")
.build())
.addJavadoc(String.format("%s \n", className(ddd)))
;
return builder;
}
@Override
public String className(DDD ddd) {
return ddd.entityPrefix + "DTO";
}
@Override
public String folerPath(DDD ddd) {
return Cons.CLIENT_FOLDER_PATH;
}
@Override
public String packagePath(DDD ddd) {
return String.format(Cons.DTO_PACKAGE, ddd.module);
}
}

View File

@@ -0,0 +1,62 @@
package rp.lee.jpa.ddd;
import java.sql.Connection;
import java.sql.ResultSet;
import javax.lang.model.element.Modifier;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeSpec.Builder;
public class EntityGen implements IClassGenerate {
@Override
public Builder builder(DDD ddd, Connection conn, ResultSet rs) throws Exception {
Builder builder = TypeSpec.classBuilder(className(ddd))
.addModifiers(Modifier.PUBLIC)
.addAnnotation(lombok.Data.class)
.addAnnotation(lombok.NoArgsConstructor.class)
.addAnnotation(AnnotationSpec.builder(ClassName.get("lombok.experimental", "SuperBuilder")).build())
.superclass(ddd.po.toClassName())
.addAnnotation(AnnotationSpec.builder(ClassName.get("lombok", "EqualsAndHashCode"))
.addMember("callSuper", "false")
.build())
.addJavadoc(String.format("%s \n", className(ddd)))
//public <E extends FrontClassifyCreateCommand> void update(E cmd) {
// Beans.copyPropertiesIgnoreNull(cmd, this);
// }
;
if(Cons.C) {
builder.addMethod(MethodSpec.methodBuilder("update")
.addModifiers(Modifier.PUBLIC)
.returns(void.class)
.addParameter(ParameterSpec.builder(ddd.create.toClassName(), "cmd").build())
// .addStatement("$T.copyPropertiesIgnoreNull(cmd, this)", ClassName.get("cn.qutaojing.common.utils", "Beans"))
.addStatement("$T.copyProperties(cmd, this)", ClassName.get("cn.qutaojing.common.utils", "Beans"))
.build()
);
}
return builder;
}
@Override
public String className(DDD ddd) {
return ddd.entityPrefix; // + "Entity";
}
@Override
public String folerPath(DDD ddd) {
return Cons.SERVER_FOLDER_PATH;
}
@Override
public String packagePath(DDD ddd) {
return String.format(Cons.ENTITY_PACKAGE, ddd.module, ddd.e);
}
}

View File

@@ -0,0 +1,74 @@
package rp.lee.jpa.ddd;
import java.sql.Connection;
import java.sql.ResultSet;
import javax.lang.model.element.Modifier;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeSpec.Builder;
public class FactoryGen implements IClassGenerate {
@Override
public Builder builder(DDD ddd, Connection conn, ResultSet rs) throws Exception {
ClassName slef = ClassName.get(packagePath(ddd), className(ddd));
Builder builder = TypeSpec.classBuilder(className(ddd))
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Component.class)
.addAnnotation(Lazy.class)
.addMethod(MethodSpec.methodBuilder("of")
.addModifiers(Modifier.PUBLIC)
.addModifiers(Modifier.STATIC)
.returns(slef)
.addStatement("return $T.getBean($T.class)", ClassName.get("cn.qutaojing.common.utils", "SpringUtils"), slef)
.build()
)
// .addMethod(MethodSpec.methodBuilder("entity")
// .addModifiers(Modifier.PUBLIC)
// .addParameter(ddd.put.toClassName(), "request")
// .returns(ddd.entity.toClassName())
// .addStatement("return $T.mapper(request, $T.class)", ClassName.get("cn.qutaojing.common.utils", "Beans"), ddd.entity.toClassName())
// .build()
// )
.addJavadoc(String.format("%s \n", className(ddd)));
if(Cons.C) {
builder.addMethod(MethodSpec.methodBuilder("from")
.addModifiers(Modifier.PUBLIC)
.returns(ddd.entity.toClassName())
.addParameter(ParameterSpec.builder(ddd.create.toClassName(), "cmd").build())
.addStatement("$T e = $T.builder().build()", ddd.entity.toClassName(), ddd.entity.toClassName())
.addStatement("e.update(cmd)")
.addStatement("return e")
.build()
);
}
return builder;
}
@Override
public String className(DDD ddd) {
return ddd.entityPrefix + "Factory";
}
@Override
public String folerPath(DDD ddd) {
return Cons.SERVER_FOLDER_PATH;
}
@Override
public String packagePath(DDD ddd) {
return String.format(Cons.FACTORY_PACKAGE, ddd.module, ddd.e);
}
}

View File

@@ -0,0 +1,21 @@
package rp.lee.jpa.ddd;
import java.sql.Connection;
import java.sql.ResultSet;
import com.ag.utils.DateUtils;
import com.squareup.javapoet.TypeSpec.Builder;
public interface IClassGenerate {
Builder builder(DDD ddd, Connection conn, ResultSet rs) throws Exception;
String className(DDD ddd);
String folerPath(DDD ddd);
String packagePath(DDD ddd);
default void addAuthor(Builder builder) {
builder
.addJavadoc("\n")
.addJavadoc(String.format("@author %s \n", "rplees"))
.addJavadoc(String.format("@email %s \n", "rplees.i.ly@gmail.com"))
.addJavadoc(String.format("@created %s \n", DateUtils.nowDate("yyyy/MM/dd")));
}
}

View File

@@ -0,0 +1,56 @@
package rp.lee.jpa.ddd;
import java.sql.Connection;
import java.sql.ResultSet;
import javax.lang.model.element.Modifier;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeSpec.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
public class ModifyGen implements IClassGenerate {
@Override
public Builder builder(DDD ddd, Connection conn, ResultSet rs) throws Exception {
Builder classBuilder = TypeSpec.classBuilder(className(ddd))
.addModifiers(Modifier.PUBLIC)
.addJavadoc(String.format("%s \n", className(ddd)))
.addJavadoc(rs.getString("REMARKS"))
.addJavadoc("")
.addAnnotation(Data.class)
.addAnnotation(AnnotationSpec.builder(ClassName.get("lombok.experimental", "SuperBuilder")).build())
.addAnnotation(NoArgsConstructor.class)
.addAnnotation(AnnotationSpec.builder(ClassName.get("lombok", "EqualsAndHashCode"))
.addMember("callSuper", "false")
.build())
.superclass(ddd.create.toClassName())
;
com.squareup.javapoet.FieldSpec.Builder fieldBuilder = FieldSpec
.builder(Integer.class,
"id");
classBuilder.addField(fieldBuilder.build());
return classBuilder;
}
@Override
public String className(DDD ddd) {
return ddd.entityPrefix + "ModifyCommand";
}
@Override
public String folerPath(DDD ddd) {
return Cons.CLIENT_FOLDER_PATH;
}
@Override
public String packagePath(DDD ddd) {
return String.format(Cons.MODIFY_PACKAGE, ddd.module);
}
}

View File

@@ -0,0 +1,158 @@
package rp.lee.jpa.ddd;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.lang.model.element.Modifier;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.apache.commons.lang.StringUtils;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.UpdateTimestamp;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeSpec.Builder;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import rp.lee.jpa.entity.ColumnStyle;
import rp.lee.jpa.entity.Utils;
public class POGen implements IClassGenerate {
@Override
public Builder builder(DDD ddd, Connection conn, ResultSet rs) throws Exception {
String primaryKey = ""; //TODO:目前之支持一个主键
String tableName = "";
Builder classBuilder = TypeSpec.classBuilder(className(ddd))
.addModifiers(Modifier.PUBLIC)
.addJavadoc(String.format("%s \n", className(ddd)))
// .addJavadoc(rs.getString("REMARKS"))
.addJavadoc("")
.addAnnotation(AnnotationSpec.builder(ClassName.get("lombok.experimental", "SuperBuilder")).build())
.addAnnotation(Data.class)
.addAnnotation(NoArgsConstructor.class)
.addAnnotation(AllArgsConstructor.class);
if(conn != null) {
tableName = rs.getString("TABLE_NAME");
DatabaseMetaData metaData = conn.getMetaData();
ResultSet primaryKeyResultSet = metaData.getPrimaryKeys(conn.getCatalog(),null, tableName);
try {
while(primaryKeyResultSet.next()){
primaryKey = primaryKeyResultSet.getString("COLUMN_NAME");
}
} finally {
try {
primaryKeyResultSet.close();
} catch(Exception e) {}
}
if(StringUtils.isBlank(primaryKey)) {//没有主键的不生成
System.err.println(String.format("表[%s]没有主键, 将跳过", tableName));
return null;
}
classBuilder.addJavadoc(rs.getString("REMARKS"))
.addAnnotation(AnnotationSpec.builder(Entity.class).build())
.addAnnotation(AnnotationSpec.builder(DynamicInsert.class).build())
.addAnnotation(AnnotationSpec.builder(DynamicUpdate.class).build())
.addAnnotation(AnnotationSpec.builder(Table.class)
.addMember("name", "\"" + tableName + "\"").build());
} else {
primaryKey = "id";
}
buildFields(ddd, conn, tableName, primaryKey, classBuilder);
return classBuilder;
}
static void buildFields(DDD ddd, Connection conn, String tableName, String primaryKey, Builder classBuilder) throws SQLException {
if(conn == null) {
ddd.poPK = Long.class;
ddd.poPKKey = primaryKey;
} else {
ResultSet rs = null;
try {
DatabaseMetaData metaData = conn.getMetaData();
rs = metaData.getColumns(null, "%", tableName, "%");
while (rs.next()) {
String columnName = rs.getString("COLUMN_NAME");
String filedName = Utils.columnNameToFieldName(columnName, ColumnStyle.defaultColumnStyle);
int dataType = rs.getInt("DATA_TYPE");
String remarks = rs.getString("REMARKS");
String IS_AUTOINCREMENT = rs.getString("IS_AUTOINCREMENT");
com.squareup.javapoet.FieldSpec.Builder fieldBuilder = FieldSpec
.builder(Utils.dataTypeToFieldType(columnName, dataType), filedName)
.addJavadoc(remarks);
if(StringUtils.equals(primaryKey, columnName)) {
fieldBuilder.addAnnotation(Id.class);
//主键类型
ddd.poPK = Utils.dataTypeToFieldType(filedName, dataType);
ddd.poPKKey = filedName;
}
if("create_time".equalsIgnoreCase(columnName) || "create_at".equalsIgnoreCase(columnName)) {
fieldBuilder.addAnnotation(CreationTimestamp.class);
fieldBuilder.addAnnotation(AnnotationSpec.builder(Column.class).addMember("updatable", "false").build());
}
if("update_time".equalsIgnoreCase(columnName) || "update_at".equalsIgnoreCase(columnName)) {
fieldBuilder.addAnnotation(UpdateTimestamp.class);
}
if("YES".equals(IS_AUTOINCREMENT)) {
AnnotationSpec generatedValue = AnnotationSpec.builder(ClassName.get("javax.persistence", "GeneratedValue"))
.addMember("strategy", "javax.persistence.GenerationType.IDENTITY")
.build();
fieldBuilder.addAnnotation(generatedValue);
}
classBuilder.addField(fieldBuilder.build());
/**
* 参考资料 https://www.cnblogs.com/lbangel/p/3487796.html
*/
}
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
}
}
}
}
}
@Override
public String className(DDD ddd) {
return ddd.entityPrefix + "PO";
}
@Override
public String folerPath(DDD ddd) {
return Cons.SERVER_FOLDER_PATH;
}
@Override
public String packagePath(DDD ddd) {
return String.format(Cons.PO_PACKAGE, ddd.module);
}
}

View File

@@ -0,0 +1,60 @@
package rp.lee.jpa.ddd;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.lang.model.element.Modifier;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeSpec.Builder;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
public class POMongoGen implements IClassGenerate {
@Override
public Builder builder(DDD ddd, Connection conn, ResultSet rs) throws Exception {
String primaryKey = ""; //TODO:目前之支持一个主键
String tableName = "";
Builder classBuilder = TypeSpec.classBuilder(className(ddd))
.addModifiers(Modifier.PUBLIC)
.addJavadoc(String.format("%s \n", className(ddd)))
// .addJavadoc(rs.getString("REMARKS"))
.addJavadoc("")
.addAnnotation(AnnotationSpec.builder(ClassName.get("lombok.experimental", "SuperBuilder")).build())
.addAnnotation(Data.class)
.addAnnotation(NoArgsConstructor.class)
.addAnnotation(AllArgsConstructor.class);
primaryKey = "id";
buildFields(ddd, conn, tableName, primaryKey, classBuilder);
return classBuilder;
}
static void buildFields(DDD ddd, Connection conn, String tableName, String primaryKey, Builder classBuilder) throws SQLException {
ddd.poPK = Long.class;
ddd.poPKKey = primaryKey;
}
@Override
public String className(DDD ddd) {
return ddd.entityPrefix + "PO";
}
@Override
public String folerPath(DDD ddd) {
return Cons.SERVER_FOLDER_PATH;
}
@Override
public String packagePath(DDD ddd) {
return String.format(Cons.PO_MONGO_PACKAGE, ddd.module);
}
}

View File

@@ -0,0 +1,87 @@
package rp.lee.jpa.ddd;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.lang.model.element.Modifier;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeSpec.Builder;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import rp.lee.jpa.entity.ColumnStyle;
import rp.lee.jpa.entity.Utils;
public class PutGen implements IClassGenerate {
@Override
public Builder builder(DDD ddd, Connection conn, ResultSet rs) throws Exception {
String tableName = rs.getString("TABLE_NAME");
Builder classBuilder = TypeSpec.classBuilder(className(ddd))
.addModifiers(Modifier.PUBLIC)
.addJavadoc(String.format("%s \n", className(ddd)))
.addJavadoc(rs.getString("REMARKS"))
.addJavadoc("")
.addAnnotation(Data.class)
.addAnnotation(lombok.Builder.class)
.addAnnotation(NoArgsConstructor.class)
.addAnnotation(AllArgsConstructor.class)
;
buildFields(ddd, conn, tableName, classBuilder);
return classBuilder;
}
static void buildFields(DDD ddd, Connection conn, String tableName, Builder classBuilder) throws SQLException {
ResultSet rs = null;
try {
DatabaseMetaData metaData = conn.getMetaData();
rs = metaData.getColumns(null, "%", tableName, "%");
while (rs.next()) {
String columnName = rs.getString("COLUMN_NAME");
int dataType = rs.getInt("DATA_TYPE");
String remarks = rs.getString("REMARKS");
String fieldName = Utils.columnNameToFieldName(columnName, ColumnStyle.defaultColumnStyle);
if("createTime".equals(fieldName) || "updateTime".equals(fieldName)) {//忽略
} else {
com.squareup.javapoet.FieldSpec.Builder fieldBuilder = FieldSpec
.builder(Utils.dataTypeToFieldType(columnName, dataType),
fieldName)
.addJavadoc(remarks);
classBuilder.addField(fieldBuilder.build());
}
}
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
}
}
}
}
@Override
public String className(DDD ddd) {
return ddd.entityPrefix + "PutRequest";
}
@Override
public String folerPath(DDD ddd) {
return Cons.CLIENT_FOLDER_PATH;
}
@Override
public String packagePath(DDD ddd) {
return String.format(Cons.PUT_PACKAGE, ddd.module);
}
}

View File

@@ -0,0 +1,110 @@
package rp.lee.jpa.ddd;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.lang.model.element.Modifier;
import org.apache.commons.lang.StringUtils;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeSpec.Builder;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import rp.lee.jpa.entity.ColumnStyle;
import rp.lee.jpa.entity.Utils;
public class QueryGen implements IClassGenerate {
@Override
public Builder builder(DDD ddd, Connection conn, ResultSet rs) throws Exception {
String tableName = rs.getString("TABLE_NAME");
Builder classBuilder = TypeSpec.classBuilder(className(ddd))
.addModifiers(Modifier.PUBLIC)
.addJavadoc(String.format("%s \n", className(ddd)))
.addJavadoc(rs.getString("REMARKS"))
.addJavadoc("")
.addAnnotation(Data.class)
.addAnnotation(lombok.Builder.class)
.addAnnotation(NoArgsConstructor.class)
.addAnnotation(AllArgsConstructor.class)
;
buildFields(ddd, conn, tableName, classBuilder);
return classBuilder;
}
static void buildFields(DDD ddd, Connection conn, String tableName, Builder classBuilder) throws SQLException {
ResultSet rs = null;
try {
DatabaseMetaData metaData = conn.getMetaData();
rs = metaData.getColumns(null, "%", tableName, "%");
while (rs.next()) {
String columnName = rs.getString("COLUMN_NAME");
int dataType = rs.getInt("DATA_TYPE");
String remarks = rs.getString("REMARKS");
String fieldName = Utils.columnNameToFieldName(columnName, ColumnStyle.defaultColumnStyle);
if("createTime".equals(fieldName)) {
com.squareup.javapoet.FieldSpec.Builder fieldBuilder = FieldSpec
.builder(Utils.dataTypeToFieldType(columnName, dataType), "start" + StringUtils.capitalize(fieldName))
.addJavadoc(remarks);
fieldBuilder.addAnnotation(AnnotationSpec.builder(ClassName.get("cn.qutaojing.common.jpa", "QueryCriteria"))
.addMember("type", "$T.GREATER_THAN", ClassName.get("cn.qutaojing.common.jpa.QueryCriteria", "Type"))
.addMember("propName", "\"" + fieldName + "\"")
.build());
com.squareup.javapoet.FieldSpec.Builder fieldBuilder2 = FieldSpec
.builder(Utils.dataTypeToFieldType(columnName, dataType), "end" + StringUtils.capitalize(fieldName))
.addJavadoc(remarks);
fieldBuilder2.addAnnotation(AnnotationSpec.builder(ClassName.get("cn.qutaojing.common.jpa", "QueryCriteria"))
.addMember("type", "$T.LESS_THAN", ClassName.get("cn.qutaojing.common.jpa.QueryCriteria", "Type"))
.addMember("propName", "\"" + fieldName + "\"")
.build());
classBuilder.addField(fieldBuilder.build());
classBuilder.addField(fieldBuilder2.build());
} else if("updateTime".equals(fieldName)) {//忽略
} else {
com.squareup.javapoet.FieldSpec.Builder fieldBuilder = FieldSpec
.builder(Utils.dataTypeToFieldType(columnName, dataType), fieldName)
.addJavadoc(remarks);
fieldBuilder.addAnnotation(AnnotationSpec.builder(ClassName.get("cn.qutaojing.common.jpa", "QueryCriteria"))
.addMember("type", "$T.EQUAL", ClassName.get("cn.qutaojing.common.jpa.QueryCriteria", "Type")).build());
classBuilder.addField(fieldBuilder.build());
}
}
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
}
}
}
}
@Override
public String className(DDD ddd) {
return ddd.entityPrefix + "Query";
}
@Override
public String folerPath(DDD ddd) {
return Cons.CLIENT_FOLDER_PATH;
}
@Override
public String packagePath(DDD ddd) {
return String.format(Cons.QUERY_PACKAGE, ddd.module);
}
}

View File

@@ -0,0 +1,47 @@
package rp.lee.jpa.ddd;
import java.sql.Connection;
import java.sql.ResultSet;
import javax.lang.model.element.Modifier;
import com.rp.spring.jpa.GenericJpaRepository;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeSpec.Builder;
public class RepoGen implements IClassGenerate {
@Override
public Builder builder(DDD ddd, Connection conn, ResultSet rs) throws Exception {
//生成DAO
Builder daoClassBuilder = TypeSpec.interfaceBuilder(className(ddd))
.addModifiers(Modifier.PUBLIC)
.addSuperinterface(ParameterizedTypeName.get(ClassName.get(GenericJpaRepository.class),
ddd.po.toClassName(),
TypeName.get(ddd.poPK)))
.addJavadoc(String.format("%s \n", className(ddd)))
;
return daoClassBuilder;
}
@Override
public String className(DDD ddd) {
return ddd.entityPrefix + "Repo";
}
@Override
public String folerPath(DDD ddd) {
return Cons.SERVER_FOLDER_PATH;
}
@Override
public String packagePath(DDD ddd) {
return String.format(Cons.REPO_PACKAGE, ddd.module);
}
}

View File

@@ -0,0 +1,46 @@
package rp.lee.jpa.ddd;
import java.sql.Connection;
import java.sql.ResultSet;
import javax.lang.model.element.Modifier;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeSpec.Builder;
public class RepoMongoGen implements IClassGenerate {
@Override
public Builder builder(DDD ddd, Connection conn, ResultSet rs) throws Exception {
ClassName className = ClassName.get("cn.qutaojing.data.analyse.infrastructure.mongodb.core", "GenericMongoRepository");
//生成DAO
Builder daoClassBuilder = TypeSpec.interfaceBuilder(className(ddd))
.addModifiers(Modifier.PUBLIC)
.addSuperinterface(ParameterizedTypeName.get(className,
ddd.po.toClassName(),
TypeName.get(ddd.poPK)))
.addJavadoc(String.format("%s \n", className(ddd)))
;
return daoClassBuilder;
}
@Override
public String className(DDD ddd) {
return ddd.entityPrefix + "Repo";
}
@Override
public String folerPath(DDD ddd) {
return Cons.SERVER_FOLDER_PATH;
}
@Override
public String packagePath(DDD ddd) {
return String.format(Cons.REPO_MONGO_PACKAGE, ddd.module);
}
}

View File

@@ -0,0 +1,104 @@
package rp.lee.jpa.ddd;
import java.sql.Connection;
import java.sql.ResultSet;
import javax.lang.model.element.Modifier;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import com.rp.spring.jpa.GenericJpaRepository;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeSpec.Builder;
import com.squareup.javapoet.TypeVariableName;
import lombok.RequiredArgsConstructor;
public class RepositoryGen implements IClassGenerate {
@Override
public Builder builder(DDD ddd, Connection conn, ResultSet rs) throws Exception {
ClassName slef = ClassName.get(packagePath(ddd), className(ddd));
Builder builder = TypeSpec.classBuilder(className(ddd))
.addModifiers(Modifier.PUBLIC)
.addAnnotation(org.springframework.stereotype.Repository.class)
.addAnnotation(AnnotationSpec.builder(RequiredArgsConstructor.class).addMember("onConstructor", "@__(@$T)", ClassName.get(Autowired.class)).build())
.superclass(ParameterizedTypeName.get(ClassName.get("cn.qutaojing.common.domain.respostory", "SimplePoConvertEntityRepository"),
ddd.entity.toClassName(),
ddd.po.toClassName(),
TypeName.get(ddd.poPK)))
.addJavadoc(String.format("%s \n", className(ddd)));
if(StringUtils.isNotBlank(ddd.poPKKey)) { //有主键
// builder.addMethod(MethodSpec.methodBuilder("save")
// .addModifiers(Modifier.PUBLIC)
// .addAnnotation(AnnotationSpec.builder(Override.class).build())
// .addParameter(ParameterSpec.builder(ddd.entity.toClassName(), "entity").build())
// .returns(void.class)
//
// .addStatement("$T po = repo().save(convert().toPo(entity));", ddd.po.toClassName())
// .addStatement(String.format("entity.set%s(po.get%s())", StringUtils.capitalize(ddd.poPKKey), StringUtils.capitalize(ddd.poPKKey)))
// .build()
// );
}
builder.addField(FieldSpec.builder(ddd.repo.toClassName(), "repo").addModifiers(Modifier.FINAL).build())
.addMethod(MethodSpec.methodBuilder("repo")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(AnnotationSpec.builder(Override.class).build())
.returns(ParameterizedTypeName.get(ClassName.get(GenericJpaRepository.class),
ddd.po.toClassName(),
TypeName.get(ddd.poPK)))
.addStatement("return $T", TypeVariableName.get("repo"))
.build()
)
.addField(FieldSpec.builder(ddd.convert.toClassName(), "convert").addModifiers(Modifier.FINAL).build())
.addMethod(MethodSpec.methodBuilder("convert")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(AnnotationSpec.builder(Override.class).build())
.returns(
ParameterizedTypeName.get(ClassName.get("cn.qutaojing.common.domain.convert", "IEntityPOConvert"),
ddd.entity.toClassName(), ddd.po.toClassName()
)
)
.addStatement("return $T", TypeVariableName.get("convert"))
.build()
)
.addMethod(MethodSpec.methodBuilder("of")
.addModifiers(Modifier.PUBLIC)
.addModifiers(Modifier.STATIC)
.returns(slef)
.addStatement("return $T.getBean($T.class)", ClassName.get("cn.qutaojing.common.utils", "SpringUtils"), slef)
.build()
)
;
return builder;
}
@Override
public String className(DDD ddd) {
return ddd.entityPrefix + "Repository";
}
@Override
public String folerPath(DDD ddd) {
return Cons.SERVER_FOLDER_PATH;
}
@Override
public String packagePath(DDD ddd) {
return String.format(Cons.REPOSITORY_PACKAGE, ddd.module, ddd.e);
}
}

View File

@@ -0,0 +1,97 @@
package rp.lee.jpa.ddd;
import java.sql.Connection;
import java.sql.ResultSet;
import javax.lang.model.element.Modifier;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import com.rp.spring.jpa.GenericJpaRepository;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeSpec.Builder;
import com.squareup.javapoet.TypeVariableName;
import lombok.RequiredArgsConstructor;
public class RepositoryMongoGen implements IClassGenerate {
@Override
public Builder builder(DDD ddd, Connection conn, ResultSet rs) throws Exception {
ClassName className = ClassName.get("cn.qutaojing.data.analyse.infrastructure.mongodb.core", "GenericMongoRepository");
Builder builder = TypeSpec.classBuilder(className(ddd))
.addModifiers(Modifier.PUBLIC)
.addAnnotation(org.springframework.stereotype.Repository.class)
.addAnnotation(AnnotationSpec.builder(RequiredArgsConstructor.class).addMember("onConstructor", "@__(@$T)", ClassName.get(Autowired.class)).build())
.superclass(ParameterizedTypeName.get(ClassName.get("cn.qutaojing.dataanalyse.infrastructure.mongodb.core", "SimplePoConvertEntityMongoRepository"),
ddd.entity.toClassName(),
ddd.po.toClassName(),
TypeName.get(ddd.poPK)))
.addJavadoc(String.format("%s \n", className(ddd)));
if(StringUtils.isNotBlank(ddd.poPKKey)) { //有主键
// builder.addMethod(MethodSpec.methodBuilder("save")
// .addModifiers(Modifier.PUBLIC)
// .addAnnotation(AnnotationSpec.builder(Override.class).build())
// .addParameter(ParameterSpec.builder(ddd.entity.toClassName(), "entity").build())
// .returns(void.class)
//
// .addStatement("$T po = repo().save(convert().toPo(entity));", ddd.po.toClassName())
// .addStatement(String.format("entity.set%s(po.get%s())", StringUtils.capitalize(ddd.poPKKey), StringUtils.capitalize(ddd.poPKKey)))
// .build()
// );
}
builder.addField(FieldSpec.builder(ddd.repo.toClassName(), "repo").addModifiers(Modifier.FINAL).build())
.addMethod(MethodSpec.methodBuilder("repo")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(AnnotationSpec.builder(Override.class).build())
.returns(ParameterizedTypeName.get(className,
ddd.po.toClassName(),
TypeName.get(ddd.poPK)))
.addStatement("return $T", TypeVariableName.get("repo"))
.build()
)
.addField(FieldSpec.builder(ddd.convert.toClassName(), "convert").addModifiers(Modifier.FINAL).build())
.addMethod(MethodSpec.methodBuilder("convert")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(AnnotationSpec.builder(Override.class).build())
.returns(
ParameterizedTypeName.get(ClassName.get("cn.qutaojing.common.domain.convert", "IEntityPOConvert"),
ddd.entity.toClassName(), ddd.po.toClassName()
)
)
.addStatement("return $T", TypeVariableName.get("convert"))
.build()
)
;
return builder;
}
@Override
public String className(DDD ddd) {
return ddd.entityPrefix + "Repository";
}
@Override
public String folerPath(DDD ddd) {
return Cons.SERVER_FOLDER_PATH;
}
@Override
public String packagePath(DDD ddd) {
return String.format(Cons.REPOSITORY_PACKAGE, ddd.module, ddd.e);
}
}

View File

@@ -0,0 +1,82 @@
package rp.lee.jpa.ddd;
import java.sql.Connection;
import java.sql.ResultSet;
import javax.lang.model.element.Modifier;
import org.springframework.beans.factory.annotation.Autowired;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeSpec.Builder;
import com.squareup.javapoet.TypeVariableName;
import lombok.RequiredArgsConstructor;
public class ServiceGen implements IClassGenerate {
@Override
public Builder builder(DDD ddd, Connection conn, ResultSet rs) throws Exception {
ClassName slef = ClassName.get(packagePath(ddd), className(ddd));
Builder serviceClassBuilder = TypeSpec.classBuilder(className(ddd))
.addModifiers(Modifier.PUBLIC)
.addAnnotation(org.springframework.stereotype.Service.class)
.addAnnotation(AnnotationSpec.builder(RequiredArgsConstructor.class).addMember("onConstructor", "@__(@$T)", ClassName.get(Autowired.class)).build())
// .addAnnotation(Transactional.class)
.addJavadoc(String.format("%s \n", className(ddd)))
.addField(FieldSpec.builder(ddd.repository.toClassName(), "repository").addModifiers(Modifier.FINAL).build())
.addField(FieldSpec.builder(ddd.factory.toClassName(), "factory").addModifiers(Modifier.FINAL).build())
.addMethod(MethodSpec.methodBuilder("repository")
.addModifiers(Modifier.PUBLIC)
.returns(ddd.repository.toClassName())
.addStatement("return $T", TypeVariableName.get("repository"))
.build()
)
.addMethod(MethodSpec.methodBuilder("of")
.addModifiers(Modifier.PUBLIC)
.addModifiers(Modifier.STATIC)
.returns(slef)
.addStatement("return $T.getBean($T.class)", ClassName.get("cn.qutaojing.common.utils", "SpringUtils"), slef)
.build()
)
// .addMethod(MethodSpec.methodBuilder("update")
// .addModifiers(Modifier.PUBLIC)
// .addParameter(ParameterSpec.builder(ddd.poPK, "id").build())
// .addParameter(ParameterSpec.builder(ddd.entity.toClassName(), "updateEntity").build())
// .returns(ddd.entity.toClassName())
// .addStatement("$T entity = repository().findById(id).orElseThrow($T::new)", ddd.entity.toClassName(), ClassName.get("com.ag.exception", "EntityNotFoundException"))
// .addStatement("$T.copyPropertiesIgnoreNull(updateEntity, entity)", ClassName.get("cn.qutaojing.common.utils", "Beans"))
// .addStatement("return repository().save(entity)")
//
// .build()
// )
;
return serviceClassBuilder;
}
@Override
public String className(DDD ddd) {
return ddd.entityPrefix + "Service";
}
@Override
public String folerPath(DDD ddd) {
return Cons.SERVER_FOLDER_PATH;
}
@Override
public String packagePath(DDD ddd) {
return String.format(Cons.SERVICE_PACKAGE, ddd.module, ddd.e);
}
}

View File

@@ -0,0 +1,98 @@
package rp.lee.jpa.ddd;
import java.nio.file.Paths;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.function.Consumer;
import org.apache.commons.lang.StringUtils;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec.Builder;
import rp.lee.jpa.entity.Utils;
public class ToolDDD {
public static void g(Connection conn) throws Exception {
ResultSet rs = null;
try {
String catalog = conn.getCatalog();
DatabaseMetaData metaData = conn.getMetaData();
rs = metaData.getTables(catalog, null, null, new String[] { "TABLE" });
while (rs.next()) {
String tableName = rs.getString("TABLE_NAME");
boolean pass = Cons.tableNameToEntiyMapping.keySet().contains(tableName);
if(pass) {
buildDDD(conn, rs, Cons.module, Cons.entity);
}
}
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
}
}
}
}
private static void buildDDD(Connection conn, ResultSet rs, String module, String e) throws Exception {
DDD ddd = new DDD(module, e);
String tableName = rs.getString("TABLE_NAME");
String entity = Cons.tableNameToEntiyMapping.get(tableName);
if(StringUtils.isBlank(entity)) {
entity = Utils.tableNameToEntityName(tableName);
}
ddd.entityPrefix = entity;
make(conn, rs, ddd, new POGen(), vo -> ddd.po = vo );
make(conn, rs, ddd, new CreateGen(), vo -> ddd.create = vo );
make(conn, rs, ddd, new ModifyGen(), vo -> ddd.modify = vo );
make(conn, rs, ddd, new EntityGen(), vo -> ddd.entity = vo );
make(conn, rs, ddd, new DTOGen(), vo -> ddd.dto = vo);
make(conn, rs, ddd, new ConvertGen(), vo -> ddd.convert = vo);
make(conn, rs, ddd, new AssemblerGen(), vo -> ddd.assembler = vo);
make(conn, rs, ddd, new FactoryGen(), vo -> ddd.factory = vo);
make(conn, rs, ddd, new RepoGen(), vo -> ddd.repo = vo);
make(conn, rs, ddd, new RepositoryGen(), vo -> ddd.repository = vo);
make(conn, rs, ddd, new ServiceGen(), vo -> ddd.service = vo);
// make(conn, rs, ddd, new ApiGen(), vo -> ddd.api = vo);
// make(conn, rs, ddd, new ApiFeignGen(), vo -> ddd.apiFeign = vo);
// make(conn, rs, ddd, new ApiImplGen(), vo -> ddd.apiImplGen = vo);
// make(conn, rs, ddd, new PutGen(), vo -> ddd.put = vo);
// make(conn, rs, ddd, new QueryGen(), vo -> ddd.query = vo);
List<ClassVO> list = ddd.list();
for (ClassVO classVO : list) {
if(classVO == null) continue;
JavaFile javaFile = JavaFile.builder(classVO.packagePath, classVO.builder.build())
.build();
javaFile.writeTo(System.out);
javaFile.writeTo(Paths.get(classVO.folderPath));
}
}
private static ClassVO make(Connection conn, ResultSet rs, DDD ddd, IClassGenerate ig, Consumer<ClassVO> c) throws Exception {
Builder builder = ig.builder(ddd, conn, rs);
ig.addAuthor(builder);
ClassVO vo = ClassVO.builder()
.builder(builder)
.className(ig.className(ddd))
.folderPath(ig.folerPath(ddd))
.packagePath(ig.packagePath(ddd))
.build();
c.accept(vo);
return vo;
}
}

View File

@@ -0,0 +1,73 @@
package rp.lee.jpa.ddd;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import org.apache.commons.lang.StringUtils;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec.Builder;
import rp.lee.jpa.entity.Utils;
public class ToolDDDMongo {
public static void main(String[] args) throws Exception {
g();
}
public static void g() throws Exception {
for(Map.Entry<String, String> entry : Cons.tableNameToEntiyMapping.entrySet()) {
String entity = entry.getValue();
if(StringUtils.isBlank(entity)) {
entity = Utils.tableNameToEntityName(entry.getKey());
}
buildDDD(entity,Cons.module, Cons.entity);
}
Cons.tableNameToEntiyMapping.keySet();
}
private static void buildDDD(String entity, String module, String e) throws Exception {
DDD ddd = new DDD(module, e);
ddd.entityPrefix = entity;
make(ddd, new POMongoGen(), vo -> ddd.po = vo );
make(ddd, new EntityGen(), vo -> ddd.entity = vo );
make(ddd, new DTOGen(), vo -> ddd.dto = vo);
make(ddd, new ConvertGen(), vo -> ddd.convert = vo);
make(ddd, new AssemblerGen(), vo -> ddd.assembler = vo);
make(ddd, new FactoryGen(), vo -> ddd.factory = vo);
make(ddd, new RepoMongoGen(), vo -> ddd.repo = vo);
make(ddd, new RepositoryMongoGen(), vo -> ddd.repository = vo);
make(ddd, new ServiceGen(), vo -> ddd.service = vo);
List<ClassVO> list = ddd.mongoList();
for (ClassVO classVO : list) {
if(classVO == null) continue;
JavaFile javaFile = JavaFile.builder(classVO.packagePath, classVO.builder.build())
.build();
System.out.println("路径:::" + Paths.get(classVO.folderPath) + "/" + classVO.packagePath);
javaFile.writeTo(System.out);
javaFile.writeTo(Paths.get(classVO.folderPath));
}
}
private static ClassVO make(DDD ddd, IClassGenerate ig, Consumer<ClassVO> c) throws Exception {
Builder builder = ig.builder(ddd, null, null);
ig.addAuthor(builder);
ClassVO vo = ClassVO.builder()
.builder(builder)
.className(ig.className(ddd))
.folderPath(ig.folerPath(ddd))
.packagePath(ig.packagePath(ddd))
.build();
c.accept(vo);
return vo;
}
}

View File

@@ -0,0 +1,10 @@
package rp.lee.jpa.entity;
public enum ColumnStyle {
/**原值*/
normal,
/**下划线转驼峰*/
lowercaseTocamelhump;
public static ColumnStyle defaultColumnStyle = lowercaseTocamelhump;
}

View File

@@ -0,0 +1,60 @@
package rp.lee.jpa.entity;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.sql.Types;
import java.util.Date;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
public class Utils {
public static String tableNameToEntityName(String tableName) {
String[] split = StringUtils.split(tableName, '_');
StringBuffer buffer = new StringBuffer();
for (String string : split) {
buffer.append(StringUtils.capitalize(string));
}
return buffer.toString();
}
public static String columnNameToFieldName(String columnName, ColumnStyle columnStyle) {
if(ColumnStyle.normal == columnStyle) {
return columnName;
} else if(ColumnStyle.lowercaseTocamelhump == columnStyle) {
columnName = StringUtils.lowerCase(columnName);
//user_id_string ==> userIdString
String[] split = StringUtils.split(columnName, '_');
if(split.length <= 1) return columnName;
StringBuffer buffer = new StringBuffer(split[0]);
for (int i = 1; i < split.length; i++) {
buffer.append(StringUtils.capitalize(split[i]));
}
return buffer.toString();
}
//other
return columnName;
}
public static Type dataTypeToFieldType(String columnName, int dataType) {
if (ArrayUtils.contains(new int[] { Types.TINYINT, Types.SMALLINT, Types.INTEGER }, dataType)) {// int.class
return Integer.class;
} else if (ArrayUtils.contains(new int[] { Types.FLOAT, Types.DOUBLE, Types.NUMERIC, },
dataType)) {// double.class
return Double.class;
} else if (ArrayUtils.contains(new int[] {Types.DECIMAL },
dataType)) {// double.class
return BigDecimal.class;
} else if (ArrayUtils.contains(new int[] { Types.BIGINT }, dataType)) {
return Long.class;
} else if (ArrayUtils.contains(new int[] { Types.DATE, Types.TIME, Types.TIMESTAMP }, dataType)) {
return Date.class;
} else {
return String.class;
}
}
}