|
|
@@ -0,0 +1,252 @@
|
|
|
+package top.lvzhiqiang;
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSONArray;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.poi.xssf.usermodel.XSSFRow;
|
|
|
+import org.apache.poi.xssf.usermodel.XSSFSheet;
|
|
|
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|
|
+import org.jsoup.Connection;
|
|
|
+import org.junit.Test;
|
|
|
+import org.junit.runner.RunWith;
|
|
|
+import org.springframework.boot.test.context.SpringBootTest;
|
|
|
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
|
|
+import top.lvzhiqiang.config.InitRunner;
|
|
|
+import top.lvzhiqiang.mapper.CoinMapper;
|
|
|
+import top.lvzhiqiang.util.DateUtils;
|
|
|
+import top.lvzhiqiang.util.JsoupUtil;
|
|
|
+import top.lvzhiqiang.util.StringUtils;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.InputStream;
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.math.RoundingMode;
|
|
|
+import java.net.Proxy;
|
|
|
+import java.nio.file.Files;
|
|
|
+import java.nio.file.Paths;
|
|
|
+import java.time.LocalDate;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.LinkedHashMap;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 单元测试类
|
|
|
+ *
|
|
|
+ * @author lvzhiqiang
|
|
|
+ * @since 13:45 2024/8/23
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@RunWith(SpringJUnit4ClassRunner.class)
|
|
|
+@SpringBootTest(properties = {
|
|
|
+ "spring.profiles.active=dev",
|
|
|
+ "logging.level.top.lvzhiqiang=DEBUG"
|
|
|
+}
|
|
|
+)
|
|
|
+public class TestCoinExport {
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private CoinMapper coinMapper;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 世界500强币种排名导出
|
|
|
+ */
|
|
|
+ @Test
|
|
|
+ public void testCoinExport1() {
|
|
|
+ /*PageHelper.startPage(1, 500, true);
|
|
|
+
|
|
|
+ Map<String, Object> params = new HashMap<>();
|
|
|
+ params.put("filterField","active");
|
|
|
+ params.put("sort","asc");
|
|
|
+ params.put("sortField","cmc_rank");
|
|
|
+
|
|
|
+ List<CoinCmcMap> cmcMapList = coinMapper.findCmcMapList(params);*/
|
|
|
+
|
|
|
+ InputStream is = null;
|
|
|
+ XSSFWorkbook wb = null;
|
|
|
+ try {
|
|
|
+ String templatePath = "/Users/l1024v/Downloads/coinRank.xlsx";
|
|
|
+ String outputPath = "/Users/l1024v/Downloads/coinRank_" + LocalDate.now().format(DateUtils.dateFormatter2) + ".xlsx";
|
|
|
+ is = Files.newInputStream(Paths.get(templatePath));
|
|
|
+ wb = new XSSFWorkbook(is);
|
|
|
+
|
|
|
+ XSSFSheet sheet = wb.getSheetAt(0);
|
|
|
+ int index = 1;
|
|
|
+
|
|
|
+
|
|
|
+ int MAX_NUMBER = 100;
|
|
|
+ int sortNum = 1;
|
|
|
+ for (int i = 1; i <= 5; i++) {
|
|
|
+ String coingeckoCoinsMarketsUrl = InitRunner.dicCodeMap.get("coingecko_coins_markets_url").getCodeValue();
|
|
|
+ Map<String, String> headerMap = new HashMap<>();
|
|
|
+ headerMap.put("Accept", "application/json");
|
|
|
+ headerMap.put("Accept-Encoding", "deflate,gzip");
|
|
|
+
|
|
|
+ Map<String, String> paramMap = new LinkedHashMap<>();
|
|
|
+ paramMap.put("vs_currency", "usd");
|
|
|
+ paramMap.put("page", String.valueOf(i));
|
|
|
+ paramMap.put("per_page", String.valueOf(MAX_NUMBER));
|
|
|
+ paramMap.put("order", "market_cap_desc");
|
|
|
+ Connection.Response response = null;
|
|
|
+
|
|
|
+ response = JsoupUtil.requestBody(coingeckoCoinsMarketsUrl, JsoupUtil.HTTP_GET, Proxy.NO_PROXY, headerMap, paramMap);
|
|
|
+ JSONArray result = JSONArray.parseArray(response.body());
|
|
|
+
|
|
|
+ for (int j = 0; j < result.size(); j++) {
|
|
|
+ JSONObject marketData = result.getJSONObject(j);
|
|
|
+
|
|
|
+ XSSFRow row = sheet.createRow(sortNum + 1);
|
|
|
+ int column = 0;
|
|
|
+
|
|
|
+ row.createCell(column++).setCellValue(sortNum++);
|
|
|
+
|
|
|
+ // 名称
|
|
|
+ if (marketData.containsKey("name") && null != marketData.get("name")) {
|
|
|
+ row.createCell(column++).setCellValue(marketData.getString("name"));
|
|
|
+ } else {
|
|
|
+ row.createCell(column++).setCellValue("");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 符号
|
|
|
+ if (marketData.containsKey("symbol") && null != marketData.get("symbol")) {
|
|
|
+ row.createCell(column++).setCellValue(marketData.getString("symbol"));
|
|
|
+ } else {
|
|
|
+ row.createCell(column++).setCellValue("");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 市值排名
|
|
|
+ if (marketData.containsKey("market_cap_rank") && null != marketData.get("market_cap_rank")) {
|
|
|
+ row.createCell(column++).setCellValue(marketData.getString("market_cap_rank"));
|
|
|
+ } else {
|
|
|
+ row.createCell(column++).setCellValue("");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 流通市值
|
|
|
+ if (marketData.containsKey("market_cap") && null != marketData.get("market_cap")) {
|
|
|
+ row.createCell(column++).setCellValue(convertHumanReadable(marketData.getString("market_cap")));
|
|
|
+ } else {
|
|
|
+ row.createCell(column++).setCellValue("");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 市场价格
|
|
|
+ if (marketData.containsKey("current_price") && null != marketData.get("current_price")) {
|
|
|
+ row.createCell(column++).setCellValue(marketData.getString("current_price"));
|
|
|
+ } else {
|
|
|
+ row.createCell(column++).setCellValue("");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 流通率
|
|
|
+ if (marketData.containsKey("circulating_supply") && null != marketData.get("circulating_supply")
|
|
|
+ && marketData.containsKey("total_supply") && null != marketData.get("total_supply")) {
|
|
|
+ String circulatingRate = new BigDecimal(marketData.getString("circulating_supply")).divide(new BigDecimal(marketData.getString("total_supply")), 3, RoundingMode.HALF_UP).multiply(new BigDecimal("100")).toPlainString();
|
|
|
+ row.createCell(column++).setCellValue(new BigDecimal(circulatingRate).setScale(1, RoundingMode.HALF_UP).toPlainString());
|
|
|
+ } else {
|
|
|
+ row.createCell(column++).setCellValue("");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 流通供应量
|
|
|
+ if (marketData.containsKey("circulating_supply") && null != marketData.get("circulating_supply")) {
|
|
|
+ row.createCell(column++).setCellValue(convertHumanReadable(marketData.getString("circulating_supply")));
|
|
|
+ } else {
|
|
|
+ row.createCell(column++).setCellValue("");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 总供应量
|
|
|
+ if (marketData.containsKey("total_supply") && null != marketData.get("total_supply")) {
|
|
|
+ row.createCell(column++).setCellValue(convertHumanReadable(marketData.getString("total_supply")));
|
|
|
+ } else {
|
|
|
+ row.createCell(column++).setCellValue("");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 最大供应量
|
|
|
+ if (marketData.containsKey("max_supply") && null != marketData.get("max_supply")) {
|
|
|
+ row.createCell(column++).setCellValue(convertHumanReadable(marketData.getString("max_supply")));
|
|
|
+ } else {
|
|
|
+ row.createCell(column++).setCellValue("");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 完全稀释的价值
|
|
|
+ if (marketData.containsKey("fully_diluted_valuation") && null != marketData.get("fully_diluted_valuation")) {
|
|
|
+ row.createCell(column++).setCellValue(convertHumanReadable(marketData.getString("fully_diluted_valuation")));
|
|
|
+ } else {
|
|
|
+ row.createCell(column++).setCellValue("");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 历史最高价格
|
|
|
+ if (marketData.containsKey("ath") && null != marketData.get("ath")) {
|
|
|
+ row.createCell(column++).setCellValue(marketData.getString("ath"));
|
|
|
+ } else {
|
|
|
+ row.createCell(column++).setCellValue("");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 历史最高日期
|
|
|
+ if (marketData.containsKey("ath_date") && null != marketData.get("ath_date")) {
|
|
|
+ row.createCell(column++).setCellValue(marketData.getString("ath_date").substring(0, 10));
|
|
|
+ } else {
|
|
|
+ row.createCell(column++).setCellValue("");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 历史最低价格
|
|
|
+ if (marketData.containsKey("atl") && null != marketData.get("atl")) {
|
|
|
+ row.createCell(column++).setCellValue(marketData.getString("atl"));
|
|
|
+ } else {
|
|
|
+ row.createCell(column++).setCellValue("");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 历史最低日期
|
|
|
+ if (marketData.containsKey("atl_date") && null != marketData.get("atl_date")) {
|
|
|
+ row.createCell(column++).setCellValue(marketData.getString("atl_date").substring(0, 10));
|
|
|
+ } else {
|
|
|
+ row.createCell(column++).setCellValue("");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 发行日期
|
|
|
+ // 类别
|
|
|
+ // TODO 需要调用另外的接口https://api.coingecko.com/api/v3/coins/bitcoin?tickers=false
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ Thread.sleep(2000L);
|
|
|
+ } catch (InterruptedException e) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ wb.write(Files.newOutputStream(Paths.get(outputPath)));
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ throw new RuntimeException("error");
|
|
|
+ } finally {
|
|
|
+ if (wb != null) {
|
|
|
+ try {
|
|
|
+ wb.close();
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (is != null) {
|
|
|
+ try {
|
|
|
+ is.close();
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public String convertHumanReadable(String number) {
|
|
|
+ if (StringUtils.isEmpty(number)) {
|
|
|
+ return "--";
|
|
|
+ }
|
|
|
+
|
|
|
+ BigDecimal bigDecimal10000 = new BigDecimal("10000");
|
|
|
+ BigDecimal divide = new BigDecimal(number).divide(bigDecimal10000, 8, RoundingMode.HALF_UP);
|
|
|
+ if (divide.compareTo(bigDecimal10000) <= 0) {
|
|
|
+ return divide.setScale(2, RoundingMode.HALF_UP) + "万";
|
|
|
+ } else {
|
|
|
+ return divide.divide(bigDecimal10000, 2, RoundingMode.HALF_UP) + "亿";
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|