diff --git a/domain/pom.xml b/domain/pom.xml new file mode 100755 index 0000000..f7442eb --- /dev/null +++ b/domain/pom.xml @@ -0,0 +1,58 @@ + + + 4.0.0 + + com.xiang + xservice-scirpt + 1.0-SNAPSHOT + + + domain + + + 8 + 8 + UTF-8 + + + + + + com.xiang + facade + 1.0-SNAPSHOT + + + + com.aliyun + alidns20150109 + 3.4.7 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + 2.3.0.RELEASE + + exec + + com.xiang.DomainApplication + ZIP + + + + + repackage + + + + + + + + \ No newline at end of file diff --git a/domain/src/main/java/com/xiang/DomainApplication.java b/domain/src/main/java/com/xiang/DomainApplication.java new file mode 100755 index 0000000..b6351bc --- /dev/null +++ b/domain/src/main/java/com/xiang/DomainApplication.java @@ -0,0 +1,17 @@ +package com.xiang; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; + +/** + * @Author: xiang + * @Date: 2025-06-10 16:43 + */ +@SpringBootApplication +@EnableScheduling +public class DomainApplication { + public static void main(String[] args) { + SpringApplication.run(DomainApplication.class, args); + } +} \ No newline at end of file diff --git a/domain/src/main/java/com/xiang/common/Result.java b/domain/src/main/java/com/xiang/common/Result.java new file mode 100755 index 0000000..304b435 --- /dev/null +++ b/domain/src/main/java/com/xiang/common/Result.java @@ -0,0 +1,51 @@ +package com.xiang.common; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Collections; +import java.util.List; + +/** + * @Author: xiang + * @Date: 2025-05-09 14:09 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Result { + + private String code; + + private String message; + + private List data; + + public static Result success(String message) { + return new Result("200", message, null); + } + + + public static Result success(String message, List data) { + return new Result("200", message, data); + } + public static Result success(String message, T data) { + return new Result("200", message, Collections.singletonList(data)); + } + + public static Result error(String message) { + return new Result("500", message, null); + } + + public static Result error(String message, T data) { + return new Result("500", message, Collections.singletonList(data)); + } + public static Result error(String message, List data) { + return new Result("500", message, data); + } + + public static Result error(String code, String message) { + return new Result(code, message, null); + } +} diff --git a/domain/src/main/java/com/xiang/controller/DynamicDomainController.java b/domain/src/main/java/com/xiang/controller/DynamicDomainController.java new file mode 100755 index 0000000..323e939 --- /dev/null +++ b/domain/src/main/java/com/xiang/controller/DynamicDomainController.java @@ -0,0 +1,54 @@ +package com.xiang.controller; + +import com.xiang.common.Result; +import com.xiang.service.DomainService; +import com.xiang.utils.IpUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.io.IOException; +import java.time.LocalDateTime; + +/** + * 域名动态解析 + * + * @Author: xiang + * @Date: 2025-06-10 16:44 + */ +@RestController +@RequestMapping("/system/domain") +@Slf4j +@RequiredArgsConstructor +public class DynamicDomainController { + + private final DomainService domainService; + + @GetMapping("/getIp") + public Result getPublicIp() { + String publicIp; + try { + publicIp = IpUtils.getPublicIp(); + } catch (IOException e) { + log.error("获取公网IP失败, time:{}", LocalDateTime.now(), e); + return Result.error("获取公网IP失败"); + } + return Result.success("获取公网IP成功", publicIp); + } + + @PostMapping("/ddns") + public Result dynamicDomainAnalysis() { + try { + String publicIp = IpUtils.getPublicIp(); + log.info("获取公网IP成功,time:{}, ip:{}", LocalDateTime.now(), publicIp); + domainService.dynamicDomainAnalysis(publicIp); + return Result.success("获取公网IP成功"); + } catch (Exception e) { + log.error("获取公网IP失败, time:{}", LocalDateTime.now(), e); + return Result.error("获取公网IP失败"); + } + } +} diff --git a/domain/src/main/java/com/xiang/entity/resp/PublicIpResp.java b/domain/src/main/java/com/xiang/entity/resp/PublicIpResp.java new file mode 100755 index 0000000..0f36fa2 --- /dev/null +++ b/domain/src/main/java/com/xiang/entity/resp/PublicIpResp.java @@ -0,0 +1,22 @@ +package com.xiang.entity.resp; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @Author: xiang + * @Date: 2025-06-11 15:55 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class PublicIpResp { + private String code; + + private String message; + + private List data; +} diff --git a/domain/src/main/java/com/xiang/schedule/DynamicDomainSchedule.java b/domain/src/main/java/com/xiang/schedule/DynamicDomainSchedule.java new file mode 100755 index 0000000..c706f62 --- /dev/null +++ b/domain/src/main/java/com/xiang/schedule/DynamicDomainSchedule.java @@ -0,0 +1,38 @@ +package com.xiang.schedule; + +import com.xiang.service.DomainServiceImpl; +import com.xiang.utils.IpUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +/** + * @Author: xiang + * @Date: 2025-06-10 17:21 + */ +@Component +@RequiredArgsConstructor +@Slf4j +public class DynamicDomainSchedule { + + private final DomainServiceImpl domainService; + + @Scheduled(cron = "0 0/5 * * * ? ") + public void dynamicDomainSchedule() { + String publicIp = ""; + try { + publicIp = IpUtils.getPublicIp(); + } catch (Exception e) { + log.error("获取公网ip失败,", e); + } + if (StringUtils.isNotBlank(publicIp)) { + try { + domainService.dynamicDomainAnalysis(publicIp); + } catch (Exception e) { + log.error("动态解析公网ip失败, ip:{}", publicIp, e); + } + } + } +} diff --git a/domain/src/main/java/com/xiang/service/DomainService.java b/domain/src/main/java/com/xiang/service/DomainService.java new file mode 100755 index 0000000..ec3eb90 --- /dev/null +++ b/domain/src/main/java/com/xiang/service/DomainService.java @@ -0,0 +1,14 @@ +package com.xiang.service; + +/** + * @Author: xiang + * @Date: 2025-06-10 16:48 + */ +public interface DomainService { + + /** + * 动态域名解析 + * @param publicIp 动态ip + */ + void dynamicDomainAnalysis(String publicIp) throws Exception; +} diff --git a/domain/src/main/java/com/xiang/service/DomainServiceImpl.java b/domain/src/main/java/com/xiang/service/DomainServiceImpl.java new file mode 100755 index 0000000..ddaa4c5 --- /dev/null +++ b/domain/src/main/java/com/xiang/service/DomainServiceImpl.java @@ -0,0 +1,101 @@ +package com.xiang.service; + + +import com.aliyun.alidns20150109.Client; +import com.aliyun.alidns20150109.models.AddDomainRecordRequest; +import com.aliyun.alidns20150109.models.DescribeSubDomainRecordsRequest; +import com.aliyun.alidns20150109.models.DescribeSubDomainRecordsResponse; +import com.aliyun.alidns20150109.models.DescribeSubDomainRecordsResponseBody; +import com.aliyun.alidns20150109.models.UpdateDomainRecordRequest; +import com.aliyun.teaopenapi.models.Config; +import com.xiang.dingTalk.service.DingTalkService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @Author: xiang + * @Date: 2025-06-10 16:48 + */ +@Service +@Slf4j +@RequiredArgsConstructor +public class DomainServiceImpl implements DomainService { + + private static final String ACCESS_KEY_ID = "LTAI5tDMjaVF8Bbqcpp4dmvP"; + private static final String ACCESS_KEY_SECRET = "nkmnaNjWQy5984C5kjyS0oDmdMKGQd"; + /** + * 根域名 + */ + private static final String DOMAIN_NAME = "xiangtech.xyz"; + /** + * 主机记录,例如 home.example.com + */ + @Value("${aliyun.dns.RR}") + private String rr; + private static final String TYPE = "A"; + + private final DingTalkService dingTalkService; + @Value("${DingTalk.chatId}") + private String chatId; + + @Override + public void dynamicDomainAnalysis(String publicIp) throws Exception { + Client client = createClient(); + + // 查询记录 + DescribeSubDomainRecordsRequest query = new DescribeSubDomainRecordsRequest() + .setSubDomain(rr + "." + DOMAIN_NAME) + .setType(TYPE); + DescribeSubDomainRecordsResponse response = client.describeSubDomainRecords(query); + List records = + response.getBody().getDomainRecords().getRecord(); + + if (records.isEmpty()) { + log.info("未找到记录,添加记录..., ip:{}", publicIp); + addDnsRecord(client, publicIp); + dingTalkService.sendChatMessage(chatId, "动态解析公网ip成功,域名:" + rr + "." + DOMAIN_NAME + ", 新ip:" + publicIp); + } else { + String recordId = records.get(0).getRecordId(); + String currentValue = records.get(0).getValue(); + if (!publicIp.equals(currentValue)) { + log.info("IP变更,更新记录...,ip:{}", publicIp); + updateDnsRecord(client, recordId, publicIp); + dingTalkService.sendChatMessage(chatId, "动态解析公网ip成功,域名:" + rr + "." + DOMAIN_NAME + ", 新ip:" + publicIp); + } else { + log.info("ip未变更,无需修改,ip:{}", publicIp); + } + } + } + + private Client createClient() throws Exception { + Config config = new Config() + .setAccessKeyId(ACCESS_KEY_ID) + .setAccessKeySecret(ACCESS_KEY_SECRET) + .setEndpoint("alidns.cn-hangzhou.aliyuncs.com"); + return new Client(config); + } + + private void updateDnsRecord(Client client, String recordId, String newIp) throws Exception { + UpdateDomainRecordRequest request = new UpdateDomainRecordRequest() + .setRecordId(recordId) + .setRR(rr) + .setType(TYPE) + .setValue(newIp); + client.updateDomainRecord(request); + log.info("更新成功: ,newIP:{}", newIp); + } + + private void addDnsRecord(Client client, String ip) throws Exception { + AddDomainRecordRequest request = new AddDomainRecordRequest() + .setDomainName(DOMAIN_NAME) + .setRR(rr) + .setType(TYPE) + .setValue(ip); + client.addDomainRecord(request); + log.info("添加成功: ip:{}", ip); + } +} diff --git a/domain/src/main/java/com/xiang/utils/HttpUtils.java b/domain/src/main/java/com/xiang/utils/HttpUtils.java new file mode 100755 index 0000000..3023740 --- /dev/null +++ b/domain/src/main/java/com/xiang/utils/HttpUtils.java @@ -0,0 +1,121 @@ +package com.xiang.utils; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.MapUtils; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; + +import java.io.Closeable; +import java.io.IOException; +import java.util.Map; +import java.util.Set; + +/** + * @Author: xiang + * @Date: 2025-05-08 14:39 + */ +@Slf4j +public class HttpUtils { + + private final static int socketTimeOut = 60 * 1000; + private final static int connectTimeout = 60 * 1000; + private final static int connectionRequestTimeout = 15 * 1000; + private final static int defaultMaxPerRoute = 500; + private final static int maxTotal = 2000; + + public static String doPost(String url, Map header, String jsonParams) { + RequestConfig requestConfig = RequestConfig.custom() + // 设置连接超时时间 + .setConnectTimeout(connectTimeout) + // 设置Socket超时时间 + .setSocketTimeout(socketTimeOut) + .setConnectionRequestTimeout(connectionRequestTimeout) + .build(); + //创建httpClient对象 + CloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(requestConfig).build(); + CloseableHttpResponse response = null; + String result = ""; + try { + // 创建http请求 + HttpPost httpPost = new HttpPost(url); + httpPost.addHeader("Content-Type", "application/json"); + // 创建请求内容 + StringEntity entity = new StringEntity(jsonParams, "utf-8"); + entity.setContentType("application/json"); + httpPost.setEntity(entity); + // 设置请求头 + if (null != header && !header.isEmpty()) { + Set> entries = header.entrySet(); + for (Map.Entry e : entries) { + httpPost.setHeader(e.getKey(), e.getValue()); + } + } + response = httpClient.execute(httpPost); + result = EntityUtils.toString(response.getEntity(), "utf-8"); + } catch (Exception e) { + log.error("doPost异常", e); + } finally { + //关闭资源 + closeResource(response, httpClient); + } + return result; + } + + public static String doGet(String url, Map header, Map param) { + RequestConfig requestConfig = RequestConfig.custom() + // 设置连接超时时间 + .setConnectTimeout(connectTimeout) + // 设置Socket超时时间 + .setSocketTimeout(socketTimeOut) + .setConnectionRequestTimeout(connectionRequestTimeout) + .build(); + CloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(requestConfig).build(); + CloseableHttpResponse response; + String result = ""; + try { + String request = ""; + if (MapUtils.isNotEmpty(param)) { + StringBuilder req = new StringBuilder("?"); + for (Map.Entry entry : param.entrySet()) { + req.append(entry.getKey()).append("=").append(entry.getValue()).append("&"); + } + request = req.substring(0, req.length() - 1); + } + + HttpGet httpGet = new HttpGet(url + request); + httpGet.addHeader("Content-Type", "application/json"); + if (MapUtils.isNotEmpty(header)) { + for (Map.Entry entry : header.entrySet()) { + httpGet.setHeader(entry.getKey(), entry.getValue()); + } + } + log.info("doGet请求:请求地址:{}", url + request); + response = httpClient.execute(httpGet); + result = EntityUtils.toString(response.getEntity(), "utf-8"); + } catch (Exception e) { + log.error("doGet异常:", e); + } + return result; + } + + /** + * @Description 关闭资源 + */ + private static void closeResource(Closeable... resources) { + try { + for (Closeable resource : resources) { + if (resource != null) { + resource.close(); + } + } + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/domain/src/main/java/com/xiang/utils/IpUtils.java b/domain/src/main/java/com/xiang/utils/IpUtils.java new file mode 100755 index 0000000..d5febc5 --- /dev/null +++ b/domain/src/main/java/com/xiang/utils/IpUtils.java @@ -0,0 +1,22 @@ +package com.xiang.utils; + +import com.google.common.collect.Maps; + +import java.io.IOException; +import java.util.Map; + +/** + * @Author: xiang + * @Date: 2025-06-10 16:50 + */ +public class IpUtils { + + private final static String PUBLIC_IP_URL = "https://api-ipv4.ip.sb/ip"; + + public static String getPublicIp() throws IOException { + + Map header = Maps.newHashMap(); + header.put("User-Agent", "Mozilla/5.0"); + return HttpUtils.doGet(PUBLIC_IP_URL, header, null).trim(); + } +} diff --git a/domain/src/main/resources/application-local.yml b/domain/src/main/resources/application-local.yml new file mode 100755 index 0000000..e2ad775 --- /dev/null +++ b/domain/src/main/resources/application-local.yml @@ -0,0 +1,10 @@ +spring: + datasource: + url: jdbc:mysql:///xservice-script?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowMultiQueries=true + username: root + password: 123456 + driver-class-name: com.mysql.cj.jdbc.Driver + +aliyun: + dns: + RR: test21 \ No newline at end of file diff --git a/domain/src/main/resources/application-nas.yml b/domain/src/main/resources/application-nas.yml new file mode 100755 index 0000000..23b4044 --- /dev/null +++ b/domain/src/main/resources/application-nas.yml @@ -0,0 +1,10 @@ +spring: + datasource: + url: jdbc:mysql://172.28.159.213:3306/xservice-script?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowMultiQueries=true + username: root + password: 123456 + driver-class-name: com.mysql.cj.jdbc.Driver + +aliyun: + dns: + RR: client \ No newline at end of file diff --git a/domain/src/main/resources/application-prod.yml b/domain/src/main/resources/application-prod.yml new file mode 100755 index 0000000..7a478f3 --- /dev/null +++ b/domain/src/main/resources/application-prod.yml @@ -0,0 +1,10 @@ +spring: + datasource: + url: jdbc:mysql://172.28.159.213:3306/xservice-script?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowMultiQueries=true + username: root + password: 123456 + driver-class-name: com.mysql.cj.jdbc.Driver + +aliyun: + dns: + RR: general \ No newline at end of file diff --git a/domain/src/main/resources/application.yml b/domain/src/main/resources/application.yml new file mode 100755 index 0000000..8732c39 --- /dev/null +++ b/domain/src/main/resources/application.yml @@ -0,0 +1,18 @@ +mybatis: + mapper-locations: + - classpath*:mapper/*.xml + configuration: + map-underscore-to-camel-case: true + +DingTalk: + # 钉钉消息用户,用逗号隔开 + userList: "450841600726084717" + # 钉钉消息群ID,需要调用/chat/create api创建群返回 + chatId: "chatd16d8daeea33b36b73588c676d508096" + +server: + port: 8080 + +spring: + profiles: + active: local \ No newline at end of file diff --git a/domain/src/main/resources/logback-spring.xml b/domain/src/main/resources/logback-spring.xml new file mode 100755 index 0000000..d222df7 --- /dev/null +++ b/domain/src/main/resources/logback-spring.xml @@ -0,0 +1,102 @@ + + + + + + ${APP_NAME} + + + + + + + + + + + + + + %boldGreen(%contextName): %boldCyan(%d{yyyy-MM-dd HH:mm:ss:SSS}) %highlight([%c]) %boldMagenta([%t]) %boldCyan([%L]) %highlight([traceId:%X{traceId:-},spanId:%X{spanId:-},localIp:%X{localIp:-}]) %boldGreen([%p]) - %msg%n + + + UTF-8 + + + + + + + + ${LOG_HOME}/debug-%d{yyyy-MM-dd}.log + + ${LOG_MAX_HISTORY} + + + + %contextName: %d{yyyy-MM-dd HH:mm:ss.SSS} [%c][%t][%L][%p] [traceId:%X{traceId:-},spanId:%X{spanId:-},localIp:%X{localIp:-}] - %msg%n + UTF-8 + + + + debug + ACCEPT + DENY + + + + + + + + ${LOG_HOME}/info-%d{yyyy-MM-dd}.log + + ${LOG_MAX_HISTORY} + + + + %contextName: %d{yyyy-MM-dd HH:mm:ss.SSS} [%c][%t][%L][%p] [traceId:%X{traceId:-},spanId:%X{spanId:-},localIp:%X{localIp:-}] - %msg%n + UTF-8 + + + + + info + ACCEPT + DENY + + + + + + + + ${LOG_HOME}/error-%d{yyyy-MM-dd}.log + + ${LOG_MAX_HISTORY} + + + + %contextName: %d{yyyy-MM-dd HH:mm:ss.SSS} [%c][%t][%L][%p] [traceId:%X{traceId:-},spanId:%X{spanId:-},localIp:%X{localIp:-}] - %msg%n + UTF-8 + + + + error + ACCEPT + DENY + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/script/src/main/java/com/xiang/schedule/xb/FundInfoQueryJob.java b/script/src/main/java/com/xiang/schedule/xb/FundInfoQueryJob.java index d80843d..844adf1 100644 --- a/script/src/main/java/com/xiang/schedule/xb/FundInfoQueryJob.java +++ b/script/src/main/java/com/xiang/schedule/xb/FundInfoQueryJob.java @@ -244,6 +244,7 @@ public class FundInfoQueryJob { if (Objects.equals(type, 1)) { code = Arrays.stream(codeArr.split(", ")).collect(Collectors.toList()); } + return Lists.newArrayList(); } else { code = lists.stream().map(XbFundList::getCode).collect(Collectors.toList()); }