17 Commits

Author SHA1 Message Date
Xiang
03f98fbe1e fix:返回值 2026-02-11 15:41:59 +08:00
Xiang
67e67a911e Merge remote-tracking branch 'origin/master'
# Conflicts:
#	script/src/main/java/com/xiang/xservice/application/script/xb/schedule/xb/FundCountJob.java
#	script/src/main/java/com/xiang/xservice/application/script/xb/schedule/xb/FundInfoQueryJob.java
#	script/src/main/java/com/xiang/xservice/application/script/xb/schedule/xb/FundMsgReportJob.java
2026-02-11 09:00:57 +08:00
Xiang
d62d788e81 fix:清理代码 2026-02-11 09:00:12 +08:00
xiang
c506a850c3 feat:基金定时任务 2026-02-07 20:12:45 +08:00
xiang
e22bc012c9 fix:顶顶消息修复 2026-01-30 23:22:48 +08:00
xiang
b598d67281 fix:pom版本修改 2026-01-30 22:54:39 +08:00
xiang
d4c3cf4870 perf:优化代码 2026-01-30 22:53:16 +08:00
xiang
bc4b0c9753 perf:优化代码 2026-01-30 22:51:17 +08:00
xiang
26474073e5 perf:优化代码 2026-01-30 22:50:35 +08:00
xiang
3d50ec5985 perf:页面优化 2026-01-30 22:41:56 +08:00
xiang
1ab0e94cfa perf:页面优化 2026-01-30 22:39:43 +08:00
xiang
2f087553eb feat:代码生成脚本 2026-01-30 22:36:27 +08:00
xiang
59b3dd6320 feat:代码生成脚本 2026-01-30 21:41:20 +08:00
Xiang
217dc6879d fix:glados签到脚本 2026-01-23 09:58:46 +08:00
Xiang
12728d5c84 fix:glados签到球服 2026-01-23 09:35:38 +08:00
Xiang
8928c076c5 fix:glados域名修复 2026-01-23 09:06:17 +08:00
xiang
ec6723070f feat:清理代码 2026-01-15 23:34:26 +08:00
185 changed files with 8727 additions and 2616 deletions

108
pom.xml
View File

@@ -27,35 +27,119 @@
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/com.github.jsqlparser/jsqlparser -->
<dependency>
<groupId>com.xiang</groupId>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>5.3</version>
</dependency>
<!-- JUnit 5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<!-- Mockito for JUnit 5 -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Boot Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 添加 Undertow依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<!-- FastJson2中FastJsonHttpMessageConverter找不到类问题 by https://zhengkai.blog.csdn.net/-->
<!-- https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.60</version>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2-extension</artifactId>
<version>2.0.60</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2-extension-spring6 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2-extension-spring6</artifactId>
<version>2.0.59</version>
</dependency>
<!-- 支持 @ConfigurationProperties 注解 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- freemarker -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/jakarta.xml.bind/jakarta.xml.bind-api -->
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.4</version>
</dependency>
<dependency>
<groupId>com.xiang.starter</groupId>
<artifactId>xmc-mysql-starter</artifactId>
<version>1.0-SNAPSHOT</version>
<version>1.0</version>
</dependency>
<dependency>
<groupId>com.xiang</groupId>
<groupId>com.xiang.starter</groupId>
<artifactId>xmc-cache-starter</artifactId>
<version>1.0-SNAPSHOT</version>
<version>1.0</version>
</dependency>
<dependency>
<groupId>com.xiang</groupId>
<groupId>com.xiang.starter</groupId>
<artifactId>xmc-common</artifactId>
<version>1.0-SNAPSHOT</version>
<version>1.1</version>
</dependency>
<dependency>
<groupId>com.xiang</groupId>
<groupId>com.xiang.starter</groupId>
<artifactId>xmc-message-starter</artifactId>
<version>1.0-SNAPSHOT</version>
<version>1.0</version>
</dependency>
<dependency>
<groupId>com.xiang</groupId>
<groupId>com.xiang.starter</groupId>
<artifactId>xmc-http-starter</artifactId>
<version>1.0-SNAPSHOT</version>
<version>2.0</version>
</dependency>
<dependency>
<groupId>com.xiang</groupId>
<groupId>com.xiang.starter</groupId>
<artifactId>xmc-logger-starter</artifactId>
<version>1.0-SNAPSHOT</version>
<version>1.1</version>
</dependency>
<dependency>
<groupId>com.xiang</groupId>

View File

@@ -17,7 +17,6 @@ import org.springframework.scheduling.annotation.EnableScheduling;
"com.xiang.xservice.application.script.glados.repository",
"com.xiang.xservice.application.script.xb.repository",
"com.xiang.xservice.common.mapper",
"com.xiang.xservice.application.script.jntyzx.mapper"
})
@ConfigurationPropertiesScan(basePackages = {
"com.xiang.xservice.config"

View File

@@ -31,13 +31,13 @@ public class IndexController {
@GetMapping("/index")
public Result<String> index() {
String msg = "已激活环境:" + env + "web端口启用" + port + "使用datasource:" + url;
return Result.success(msg);
return Result.data(msg);
}
@GetMapping("/redisTest")
private Result<String> redisTest() {
redisTemplate.opsForValue().set("2222", "231");
return Result.success("redis获取到key为test的值为" + redisTemplate.opsForValue().get("2222"));
return Result.data("redis获取到key为test的值为" + redisTemplate.opsForValue().get("2222"));
}
}

View File

@@ -0,0 +1,33 @@
package com.xiang.xservice.application.generator.controller;
import com.xiang.xservice.application.generator.entity.domain.ParamInfo;
import com.xiang.xservice.application.generator.service.CodeGenService;
import com.xiang.xservice.basic.common.resp.Result;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
/**
* 代码生成控制器
*
* @author zhengkai.blog.csdn.net
*/
@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/system/generator/code")
public class CodeGenController {
private final CodeGenService codeGenService;
@PostMapping("/generate")
public Result<Map<String, String>> generateCode(@RequestBody ParamInfo paramInfo) throws Exception {
return codeGenService.generateCode(paramInfo);
}
}

View File

@@ -0,0 +1,29 @@
package com.xiang.xservice.application.generator.controller;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* 页面控制器
*
* @author zhengkai.blog.csdn.net
*/
@RequiredArgsConstructor
@Controller
@RequestMapping("/generator")
public class PageController {
@GetMapping("/")
public ModelAndView defaultPage() {
return new ModelAndView("newui2");
}
@GetMapping("/index")
public ModelAndView indexPage() {
return new ModelAndView("newui2");
}
}

View File

@@ -0,0 +1,30 @@
package com.xiang.xservice.application.generator.controller;
import com.xiang.xservice.application.generator.entity.domain.TemplateList;
import com.xiang.xservice.application.generator.service.TemplateService;
import com.xiang.xservice.basic.common.resp.Result;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 模板管理控制器
*
* @author zhengkai.blog.csdn.net
*/
@RequiredArgsConstructor
@RestController
@RequestMapping("system/generator/template")
public class TemplateController {
private final TemplateService templateService;
@PostMapping("/all")
public Result<List<TemplateList>> getAllTemplates() throws Exception {
return Result.data(templateService.getAllTemplates());
}
}

View File

@@ -0,0 +1,150 @@
package com.xiang.xservice.application.generator.entity;
import lombok.AllArgsConstructor;
/**
* String 包装类
* <p>
* 忽略大小写
**考虑增加这个类是, 如果在 StringUtils 中加工具方法, 使用起来代码非常冗长且不方便
*/
@AllArgsConstructor
public class NonCaseString implements CharSequence {
private String value;
public static NonCaseString of(String str) {
assert str != null;
return new NonCaseString(str);
}
/**
* {@link String#indexOf(String)} 增强, 忽略大小写
*/
public int indexOf(String m) {
String text = this.value;
if (text == null || m == null || text.length() < m.length()) {
return -1;
}
return text.toLowerCase().indexOf(m.toLowerCase());
}
/**
* {@link String#lastIndexOf(String)} 增强, 忽略大小写
*/
public int lastIndexOf(String m) {
String text = this.value;
if (text == null || m == null || text.length() < m.length()) {
return -1;
}
return text.toLowerCase().lastIndexOf(m.toLowerCase());
}
/**
* 是否包含, 大小写不敏感
* <pre
* "abcxyz" 包含 "abc" => true
* "abcxyz" 包含 "ABC" => true
* "abcxyz" 包含 "aBC" => true
* </pre>
*
* @param m 被包含字符串
*/
public boolean contains(String m) {
String text = this.value;
if (text.length() < m.length()) {
return false;
}
return text.toLowerCase().contains(m.toLowerCase());
}
/**
* 任意一个包含返回true
* <pre>
* containsAny("abcdef", "a", "b)
* 等价
* "abcdef".contains("a") || "abcdef".contains("b")
* </pre>
*
* @param matchers 多个要判断的被包含项
*/
public boolean containsAny(String... matchers) {
for (String matcher : matchers) {
if (contains(matcher)) {
return true;
}
}
return false;
}
/**
* 所有都包含才返回true
*
* @param matchers 多个要判断的被包含项
*/
public boolean containsAllIgnoreCase(String... matchers) {
for (String matcher : matchers) {
if (contains(matcher) == false) {
return false;
}
}
return true;
}
public NonCaseString trim() {
return NonCaseString.of(this.value.trim());
}
public NonCaseString replace(char oldChar, char newChar) {
return NonCaseString.of(this.value.replace(oldChar, newChar));
}
public NonCaseString replaceAll(String regex, String replacement) {
return NonCaseString.of(this.value.replaceAll(regex, replacement));
}
public NonCaseString substring(int beginIndex) {
return NonCaseString.of(this.value.substring(beginIndex));
}
public NonCaseString substring(int beginIndex, int endIndex) {
return NonCaseString.of(this.value.substring(beginIndex, endIndex));
}
public boolean isNotEmpty() {
return !this.value.isEmpty();
}
@Override
public int length() {
return this.value.length();
}
@Override
public char charAt(int index) {
return this.value.charAt(index);
}
@Override
public CharSequence subSequence(int start, int end) {
return this.value.subSequence(start, end);
}
public String[] split(String regex) {
return this.value.split(regex);
}
/**
* @return 原始字符串
*/
public String get() {
return this.value;
}
@Override
public String toString() {
return this.value;
}
}

View File

@@ -0,0 +1,21 @@
package com.xiang.xservice.application.generator.entity.domain;
import lombok.Data;
import java.util.List;
/**
* 类信息
*
* @author xiang
*/
@Data
public class ClassInfo {
private String tableName;
private String originTableName;
private String className;
private String classComment;
private List<FieldInfo> fieldList;
}

View File

@@ -0,0 +1,19 @@
package com.xiang.xservice.application.generator.entity.domain;
import lombok.Data;
/**
* 字段信息
*
* @author xiang
*/
@Data
public class FieldInfo {
private String columnName;
private String fieldName;
private String fieldClass;
private String swaggerClass;
private String fieldComment;
}

View File

@@ -0,0 +1,25 @@
package com.xiang.xservice.application.generator.entity.domain;
import lombok.Data;
import java.util.Map;
/**
* 请求参数信息
*
* @author xiang
*/
@Data
public class ParamInfo {
private String tableSql;
private Map<String, Object> options;
@Data
public static class NameCaseType {
public static final String CAMEL_CASE = "CamelCase";
public static final String UNDER_SCORE_CASE = "UnderScoreCase";
public static final String UPPER_UNDER_SCORE_CASE = "UpperUnderScoreCase";
}
}

View File

@@ -0,0 +1,13 @@
package com.xiang.xservice.application.generator.entity.domain;
import lombok.Data;
@Data
public class Template {
private String id;
private String name;
private String description;
}

View File

@@ -0,0 +1,11 @@
package com.xiang.xservice.application.generator.entity.domain;
import lombok.Data;
import java.util.List;
@Data
public class TemplateList {
private String group;
private List<Template> templates;
}

View File

@@ -0,0 +1,60 @@
package com.xiang.xservice.application.generator.enums;
import lombok.Getter;
/**
* 解析类型枚举
*/
@Getter
public enum ParserTypeEnum {
/**
* SQL解析类型
*/
SQL("sql", "默认SQL解析"),
JSON("json", "JSON解析"),
INSERT_SQL("insert-sql", "INSERT SQL解析"),
SQL_REGEX("sql-regex", "正则表达式SQL解析"),
SELECT_SQL("select-sql", "SELECT SQL解析"),
CREATE_SQL("create-sql", "CREATE SQL解析");
private final String value;
private final String description;
ParserTypeEnum(String value, String description) {
this.value = value;
this.description = description;
}
public static ParserTypeEnum fromValue(String value) {
if (value == null || value.trim().isEmpty()) {
return SQL;
}
String trimmedValue = value.trim();
// 首先尝试精确匹配枚举值
for (ParserTypeEnum type : ParserTypeEnum.values()) {
if (type.getValue().equals(trimmedValue)) {
return type;
}
}
// 如果精确匹配失败,尝试忽略大小写匹配
for (ParserTypeEnum type : ParserTypeEnum.values()) {
if (type.getValue().equalsIgnoreCase(trimmedValue)) {
return type;
}
}
// 尝试匹配枚举名称
for (ParserTypeEnum type : ParserTypeEnum.values()) {
if (type.name().equalsIgnoreCase(trimmedValue)) {
return type;
}
}
// 默认返回SQL类型
return SQL;
}
}

View File

@@ -0,0 +1,33 @@
package com.xiang.xservice.application.generator.service;
import com.xiang.xservice.application.generator.entity.domain.ParamInfo;
import com.xiang.xservice.basic.common.resp.Result;
import java.util.Map;
/**
* 代码生成服务接口
*
* @author zhengkai.blog.csdn.net
*/
public interface CodeGenService {
/**
* 生成代码
*
* @param paramInfo 参数信息
* @return 生成的代码映射
* @throws Exception 生成过程中的异常
*/
Result<Map<String, String>> generateCode(ParamInfo paramInfo) throws Exception;
/**
* 根据参数获取结果
*
* @param params 参数映射
* @return 结果映射
* @throws Exception 处理过程中的异常
*/
Map<String, String> getResultByParams(Map<String, Object> params) throws Exception;
}

View File

@@ -0,0 +1,22 @@
package com.xiang.xservice.application.generator.service;
import com.xiang.xservice.application.generator.entity.domain.TemplateList;
import java.io.IOException;
import java.util.List;
/**
* 模板服务接口
*
* @author zhengkai.blog.csdn.net
*/
public interface TemplateService {
/**
* 获取所有模板配置
*
* @return 模板配置字符串
* @throws IOException IO异常
*/
List<TemplateList> getAllTemplates() throws IOException;
}

View File

@@ -0,0 +1,120 @@
package com.xiang.xservice.application.generator.service.impl;
import com.xiang.xservice.application.generator.entity.domain.ClassInfo;
import com.xiang.xservice.application.generator.entity.domain.ParamInfo;
import com.xiang.xservice.application.generator.entity.domain.TemplateList;
import com.xiang.xservice.application.generator.enums.ParserTypeEnum;
import com.xiang.xservice.application.generator.service.CodeGenService;
import com.xiang.xservice.application.generator.service.TemplateService;
import com.xiang.xservice.application.generator.service.parser.JsonParserService;
import com.xiang.xservice.application.generator.service.parser.SqlParserService;
import com.xiang.xservice.application.generator.util.FreemarkerUtil;
import com.xiang.xservice.application.generator.util.MapUtil;
import com.xiang.xservice.basic.common.resp.Result;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 代码生成服务实现类
*
* @author xiang
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class CodeGenServiceImpl implements CodeGenService {
private final TemplateService templateService;
private final SqlParserService sqlParserService;
private final JsonParserService jsonParserService;
@Override
public Result<Map<String, String>> generateCode(ParamInfo paramInfo) throws Exception {
if (paramInfo.getTableSql() == null || paramInfo.getTableSql().isEmpty()) {
return Result.error("表结构信息为空");
}
try {
// 1. Parse Table Structure 表结构解析
ClassInfo classInfo = parseTableStructure(paramInfo);
// 2. Set the params 设置表格参数
paramInfo.getOptions().put("classInfo", classInfo);
paramInfo.getOptions().put("tableName", classInfo == null ? System.currentTimeMillis() + "" : classInfo.getTableName());
// 3. generate the code by freemarker templates with parameters .
// Freemarker根据参数和模板生成代码
Map<String, String> result = getResultByParams(paramInfo.getOptions());
return Result.data(result);
} catch (Exception e) {
log.error("代码生成失败", e);
return Result.error("代码生成失败: " + e.getMessage());
}
}
@Override
public Map<String, String> getResultByParams(Map<String, Object> params) throws Exception {
Map<String, String> result = new HashMap<>(32);
result.put("tableName", MapUtil.getString(params, "tableName"));
// 处理模板生成逻辑
// 解析模板配置并生成代码
List<TemplateList> parentTemplates = templateService.getAllTemplates();
for (TemplateList parentTemplateObj : parentTemplates) {
List<com.xiang.xservice.application.generator.entity.domain.Template> childTemplates = parentTemplateObj.getTemplates();
if (childTemplates != null) {
for (int x = 0; x < childTemplates.size(); x++) {
com.xiang.xservice.application.generator.entity.domain.Template childTemplate = childTemplates.get(x);
String templatePath = parentTemplateObj.getGroup() + "/" + childTemplate.getName() + ".ftl";
String generatedCode = FreemarkerUtil.processString(templatePath, params);
result.put(childTemplate.getName(), generatedCode);
}
}
}
return result;
}
/**
* 根据不同的解析类型解析表结构
*
* @param paramInfo 参数信息
* @return 类信息
* @throws Exception 解析异常
*/
private ClassInfo parseTableStructure(ParamInfo paramInfo) throws Exception {
String dataType = MapUtil.getString(paramInfo.getOptions(), "dataType");
ParserTypeEnum parserType = ParserTypeEnum.fromValue(dataType);
// 添加调试信息
log.debug("解析数据类型: {}, 解析结果: {}", dataType, parserType);
switch (parserType) {
case SQL:
// 默认模式parse DDL table structure from sql
return sqlParserService.processTableIntoClassInfo(paramInfo);
case JSON:
// JSON模式parse field from json string
return jsonParserService.processJsonToClassInfo(paramInfo);
case INSERT_SQL:
// INSERT SQL模式parse field from insert sql
return sqlParserService.processInsertSqlToClassInfo(paramInfo);
case SQL_REGEX:
// 正则表达式模式非完善版本parse sql by regex
return sqlParserService.processTableToClassInfoByRegex(paramInfo);
case SELECT_SQL:
// SelectSqlBySQLPraser模式:parse select sql by JSqlParser
return sqlParserService.generateSelectSqlBySQLPraser(paramInfo);
case CREATE_SQL:
// CreateSqlBySQLPraser模式:parse create sql by JSqlParser
return sqlParserService.generateCreateSqlBySQLPraser(paramInfo);
default:
// 默认模式parse DDL table structure from sql
return sqlParserService.processTableIntoClassInfo(paramInfo);
}
}
}

View File

@@ -0,0 +1,37 @@
package com.xiang.xservice.application.generator.service.impl;
import com.alibaba.fastjson2.JSONArray;
import com.xiang.xservice.application.generator.entity.domain.TemplateList;
import com.xiang.xservice.application.generator.service.TemplateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.util.StreamUtils;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;
/**
* 模板服务实现类
*
* @author zhengkai.blog.csdn.net
*/
@Slf4j
@Service
public class TemplateServiceImpl implements TemplateService {
private String templateConfig = null;
@Override
public List<TemplateList> getAllTemplates() throws IOException {
if (templateConfig == null) {
ClassPathResource resource = new ClassPathResource("template.json");
try (InputStream inputStream = resource.getInputStream()) {
templateConfig = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
}
}
return JSONArray.parseArray(templateConfig, TemplateList.class);
}
}

View File

@@ -0,0 +1,89 @@
package com.xiang.xservice.application.generator.service.impl.parser;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.xiang.xservice.application.generator.entity.domain.ClassInfo;
import com.xiang.xservice.application.generator.entity.domain.FieldInfo;
import com.xiang.xservice.application.generator.entity.domain.ParamInfo;
import com.xiang.xservice.application.generator.service.parser.JsonParserService;
import com.xiang.xservice.basic.exception.BusinessException;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
* JSON解析服务实现类
*
* @author zhengkai.blog.csdn.net
*/
@Service
public class JsonParserServiceImpl implements JsonParserService {
@Override
public ClassInfo processJsonToClassInfo(ParamInfo paramInfo) {
ClassInfo codeJavaInfo = new ClassInfo();
codeJavaInfo.setTableName("JsonDto");
codeJavaInfo.setClassName("JsonDto");
codeJavaInfo.setClassComment("JsonDto");
//support children json if forget to add '{' in front of json
if (paramInfo.getTableSql().trim().startsWith("\"")) {
paramInfo.setTableSql("{" + paramInfo.getTableSql());
}
try {
if (paramInfo.getTableSql().trim().startsWith("{")) {
JSONObject jsonObject = JSONObject.parseObject(paramInfo.getTableSql().trim());
//parse FieldList by JSONObject
codeJavaInfo.setFieldList(processJsonObjectToFieldList(jsonObject));
} else if (paramInfo.getTableSql().trim().startsWith("[")) {
JSONArray jsonArray = JSONArray.parseArray(paramInfo.getTableSql().trim());
//parse FieldList by JSONObject
codeJavaInfo.setFieldList(processJsonObjectToFieldList(jsonArray.getJSONObject(0)));
}
} catch (Exception e) {
// JSON解析失败抛出自定义异常
throw new BusinessException("JSON格式不正确: " + e.getMessage());
}
return codeJavaInfo;
}
public List<FieldInfo> processJsonObjectToFieldList(JSONObject jsonObject) {
// field List
List<FieldInfo> fieldList = new ArrayList<FieldInfo>();
for (String jsonField : jsonObject.keySet()) {
FieldInfo fieldInfo = new FieldInfo();
fieldInfo.setFieldName(jsonField);
fieldInfo.setColumnName(jsonField);
fieldInfo.setFieldClass(String.class.getSimpleName());
fieldInfo.setFieldComment("father:" + jsonField);
fieldList.add(fieldInfo);
if (jsonObject.get(jsonField) instanceof JSONArray) {
JSONArray jsonArray = jsonObject.getJSONArray(jsonField);
for (Object arrayObject : jsonArray) {
FieldInfo fieldInfo2 = new FieldInfo();
fieldInfo2.setFieldName(arrayObject.toString());
fieldInfo2.setColumnName(arrayObject.toString());
fieldInfo2.setFieldClass(String.class.getSimpleName());
fieldInfo2.setFieldComment("children:" + arrayObject.toString());
fieldList.add(fieldInfo2);
}
} else if (jsonObject.get(jsonField) instanceof JSONObject) {
JSONObject subJsonObject = jsonObject.getJSONObject(jsonField);
for (String arrayObject : subJsonObject.keySet()) {
FieldInfo fieldInfo2 = new FieldInfo();
fieldInfo2.setFieldName(arrayObject.toString());
fieldInfo2.setColumnName(arrayObject.toString());
fieldInfo2.setFieldClass(String.class.getSimpleName());
fieldInfo2.setFieldComment("children:" + arrayObject.toString());
fieldList.add(fieldInfo2);
}
}
}
if (fieldList.size() < 1) {
throw new BusinessException("JSON解析失败");
}
return fieldList;
}
}

View File

@@ -0,0 +1,545 @@
package com.xiang.xservice.application.generator.service.impl.parser;
import com.alibaba.fastjson2.JSON;
import com.xiang.xservice.application.generator.entity.domain.ClassInfo;
import com.xiang.xservice.application.generator.entity.domain.FieldInfo;
import com.xiang.xservice.application.generator.entity.domain.ParamInfo;
import com.xiang.xservice.application.generator.service.parser.SqlParserService;
import com.xiang.xservice.application.generator.util.MapUtil;
import com.xiang.xservice.application.generator.util.StringUtilsPlus;
import com.xiang.xservice.application.generator.util.Mysql2JavaTypeUtil;
import com.xiang.xservice.basic.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.parser.CCJSqlParserManager;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.create.table.ColumnDefinition;
import net.sf.jsqlparser.statement.create.table.CreateTable;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SelectItem;
import net.sf.jsqlparser.util.TablesNamesFinder;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* SQL解析服务实现类
*
* @author zhengkai.blog.csdn.net
*/
@Slf4j
@Service
public class SqlParserServiceImpl implements SqlParserService {
@Override
public ClassInfo generateSelectSqlBySQLPraser(ParamInfo paramInfo) throws Exception {
ClassInfo classInfo = new ClassInfo();
String processedSql = paramInfo.getTableSql().trim()
.replaceAll("'", "`") // 将单引号替换为反引号
.replaceAll("\"", "`") // 将双引号替换为反引号
.replaceAll("", ","); // 将中文逗号替换为英文逗号
Statement statement = null;
CCJSqlParserManager parserManager = new CCJSqlParserManager();
statement = parserManager.parse(new StringReader(processedSql));
TablesNamesFinder tablesNamesFinder = new TablesNamesFinder(); // 创建表名发现者对象
List<String> tableNameList = tablesNamesFinder.getTableList(statement); // 获取到表名列表
//一般这里应该只解析到一个表名,除非多个表名,取第一个
if (!CollectionUtils.isEmpty(tableNameList)) {
String tableName = tableNameList.get(0).trim();
classInfo.setTableName(tableName);
classInfo.setOriginTableName(tableName);
String className = StringUtilsPlus.upperCaseFirst(StringUtilsPlus.underlineToCamelCase(tableName)).replaceAll("`", "");
if (className.contains("_")) {
className = className.replaceAll("_", "");
}
classInfo.setClassName(className);
classInfo.setClassComment(paramInfo.getTableSql());
}
//解析查询元素
Select select = null;
select = (Select) CCJSqlParserUtil.parse(paramInfo.getTableSql());
PlainSelect plainSelect = (PlainSelect) select.getSelectBody();
List<SelectItem<?>> selectItems = plainSelect.getSelectItems();
// field List
List<FieldInfo> fieldList = new ArrayList<FieldInfo>();
selectItems.forEach(t->{
FieldInfo fieldInfo = new FieldInfo();
String fieldName = ((Column)t.getExpression()).getColumnName().replaceAll("`", "");
String aliasName = t.getAlias() != null ? t.getAlias().getName() : ((Column)t.getExpression()).getColumnName();
//存储原始字段名
fieldInfo.setFieldComment(aliasName);fieldInfo.setColumnName(aliasName);
//处理字段名是t.xxx的情况
fieldName=fieldName.contains(".")?fieldName.substring(fieldName.indexOf(".")+1):fieldName;
//转换前
fieldInfo.setColumnName(fieldName);
fieldName = switch ((String) paramInfo.getOptions().get("nameCaseType")) {
case ParamInfo.NameCaseType.CAMEL_CASE ->
// 2024-1-27 L&J 适配任意(maybe)原始风格转小写驼峰
StringUtilsPlus.toLowerCamel(aliasName);
case ParamInfo.NameCaseType.UNDER_SCORE_CASE -> StringUtilsPlus.toUnderline(aliasName, false);
case ParamInfo.NameCaseType.UPPER_UNDER_SCORE_CASE ->
StringUtilsPlus.toUnderline(aliasName.toUpperCase(), true);
default -> aliasName;
};
//转换后
fieldInfo.setFieldName(fieldName);
//无法推测类型所有都set为String
fieldInfo.setFieldClass("String");
fieldList.add(fieldInfo);
});
classInfo.setFieldList(fieldList);
log.info("classInfo:{}", JSON.toJSONString(classInfo));
return classInfo;
}
@Override
public ClassInfo generateCreateSqlBySQLPraser(ParamInfo paramInfo) throws Exception {
ClassInfo classInfo = new ClassInfo();
Statement statement = null;
// 对SQL进行预处理以提高解析成功率
String processedSql = paramInfo.getTableSql().trim()
.replaceAll("'", "`") // 将单引号替换为反引号
.replaceAll("\"", "`") // 将双引号替换为反引号
.replaceAll("", ","); // 将中文逗号替换为英文逗号
try {
statement = CCJSqlParserUtil.parse(processedSql);
}catch (Exception e) {
e.printStackTrace();
throw new BusinessException("SQL语法错误:"+e.getMessage());
}
// 确保是CREATE TABLE语句
if (!(statement instanceof CreateTable createTable)) {
throw new BusinessException("检测到SQL语句不是DLL CREATE TABLE语句");
}
// 提取表名
String tableName = createTable.getTable().getName().replaceAll("`", "");
classInfo.setTableName(tableName);
String className = StringUtilsPlus.upperCaseFirst(StringUtilsPlus.underlineToCamelCase(tableName));
if (className.contains("_")) {
className = className.replaceAll("_", "");
}
classInfo.setClassName(className);
classInfo.setOriginTableName(tableName);
classInfo.setClassComment(paramInfo.getTableSql());
// 提取字段信息
List<FieldInfo> fieldList = new ArrayList<FieldInfo>();
List<ColumnDefinition> columnDefinitions = createTable.getColumnDefinitions();
if (columnDefinitions != null) {
for (ColumnDefinition columnDefinition : columnDefinitions) {
FieldInfo fieldInfo = new FieldInfo();
String columnName = columnDefinition.getColumnName().replaceAll("`", "");
fieldInfo.setColumnName(columnName);
fieldInfo.setFieldComment(columnDefinition.toString());
// 根据命名规则转换字段名
String fieldName = switch ((String) paramInfo.getOptions().get("nameCaseType")) {
case ParamInfo.NameCaseType.CAMEL_CASE -> StringUtilsPlus.toLowerCamel(columnName);
case ParamInfo.NameCaseType.UNDER_SCORE_CASE -> StringUtilsPlus.toUnderline(columnName, false);
case ParamInfo.NameCaseType.UPPER_UNDER_SCORE_CASE ->
StringUtilsPlus.toUnderline(columnName.toUpperCase(), true);
default -> columnName;
};
fieldInfo.setFieldName(fieldName);
// 设置字段类型为String因为无法准确推测类型
fieldInfo.setFieldClass("String");
fieldList.add(fieldInfo);
}
}
classInfo.setFieldList(fieldList);
log.info("classInfo:{}", JSON.toJSONString(classInfo));
return classInfo;
}
@Override
public ClassInfo processTableIntoClassInfo(ParamInfo paramInfo) throws Exception {
//process the param
String tableSql = paramInfo.getTableSql();
String nameCaseType = MapUtil.getString(paramInfo.getOptions(),"nameCaseType");
String isPackageType = MapUtil.getString(paramInfo.getOptions(),"isPackageType");
//更新空值处理
if (StringUtils.isBlank(tableSql)) {
throw new Exception("Table structure can not be empty. 表结构不能为空。");
}
//deal with special character
tableSql = tableSql.trim()
.replaceAll("'", "`")
.replaceAll("\"", "`")
.replaceAll("", ",")
// 这里全部转小写, 会让驼峰风格的字段名丢失驼峰信息(真有驼峰sql字段名的呢(* ̄︶ ̄)); 下文使用工具方法处理包含等
// .toLowerCase()
;
//deal with java string copy \n"
tableSql = tableSql.trim().replaceAll("\\\\n`", "").replaceAll("\\+", "").replaceAll("``", "`").replaceAll("\\\\", "");
// table Name
String tableName = null;
int tableKwIx = tableSql.indexOf("TABLE"); // 包含判断和位置一次搞定
if (tableKwIx > -1 && tableSql.contains("(")) {
tableName = tableSql.substring(tableKwIx + 5, tableSql.indexOf("("));
} else {
throw new Exception("Table structure incorrect.表结构不正确。");
}
//新增处理create table if not exists members情况
if (tableName.contains("if not exists")) {
tableName = tableName.replaceAll("if not exists", "");
}
if (tableName.contains("`")) {
tableName = tableName.substring(tableName.indexOf("`") + 1, tableName.lastIndexOf("`"));
} else {
//空格开头的,需要替换掉\n\t空格
tableName = tableName.replaceAll(" ", "").replaceAll("\n", "").replaceAll("\t", "");
}
//优化对byeas`.`ct_bd_customerdiscount这种命名的支持
if (tableName.contains("`.`")) {
tableName = tableName.substring(tableName.indexOf("`.`") + 3);
} else if (tableName.contains(".")) {
//优化对likeu.members这种命名的支持
tableName = tableName.substring(tableName.indexOf(".") + 1);
}
String originTableName = tableName;
//ignore prefix
if(tableName!=null && StringUtils.isNotBlank(MapUtil.getString(paramInfo.getOptions(),"ignorePrefix"))){
tableName = tableName.replaceAll(MapUtil.getString(paramInfo.getOptions(),"ignorePrefix"),"");
}
// class Name
String className = StringUtilsPlus.upperCaseFirst(StringUtilsPlus.underlineToCamelCase(tableName));
if (className.contains("_")) {
className = className.replaceAll("_", "");
}
// class Comment
String classComment = null;
//mysql是comment=,pgsql/oracle是comment on table,
//2020-05-25 优化表备注的获取逻辑
if (tableSql.toLowerCase().contains("comment=") || tableSql.toLowerCase().contains("comment on table")) {
int ix = tableSql.toLowerCase().lastIndexOf("comment=");
String classCommentTmp = (ix > -1) ?
tableSql.substring(ix + 8).trim() :
tableSql.substring(tableSql.toLowerCase().lastIndexOf("comment on table") + 17).trim();
if (classCommentTmp.contains("`")) {
classCommentTmp = classCommentTmp.substring(classCommentTmp.indexOf("`") + 1);
classCommentTmp = classCommentTmp.substring(0, classCommentTmp.indexOf("`"));
classComment = classCommentTmp;
} else {
//非常规的没法分析
classComment = className;
}
} else {
//修复表备注为空问题
classComment = tableName;
}
//如果备注跟;混在一起,需要替换掉
classComment = classComment.replaceAll(";", "");
// field List
List<FieldInfo> fieldList = new ArrayList<FieldInfo>();
// 正常( ) 内的一定是字段相关的定义。
String fieldListTmp = tableSql.substring(tableSql.indexOf("(") + 1, tableSql.lastIndexOf(")")).trim();
// 匹配 comment替换备注里的小逗号, 防止不小心被当成切割符号切割
String commentPattenStr1 = "comment `(.*?)\\`";
Matcher matcher1 = Pattern.compile(commentPattenStr1).matcher(fieldListTmp.toLowerCase());
while (matcher1.find()) {
String commentTmp = matcher1.group();
//2018-9-27 zhengk 不替换只处理支持COMMENT评论里面多种注释
//commentTmp = commentTmp.replaceAll("\\ comment `|\\`", " "); // "\\{|\\}"
if (commentTmp.contains(",")) {
String commentTmpFinal = commentTmp.replaceAll(",", "");
fieldListTmp = fieldListTmp.replace(matcher1.group(), commentTmpFinal);
}
}
//2018-10-18 zhengkai 新增支持double(10, 2)等类型中有英文逗号的特殊情况
String commentPattenStr2 = "\\`(.*?)\\`";
Matcher matcher2 = Pattern.compile(commentPattenStr2).matcher(fieldListTmp);
while (matcher2.find()) {
String commentTmp2 = matcher2.group();
if (commentTmp2.contains(",")) {
String commentTmpFinal = commentTmp2.replaceAll(",", "").replaceAll("\\(", "").replaceAll("\\)", "");
fieldListTmp = fieldListTmp.replace(matcher2.group(), commentTmpFinal);
}
}
//2018-10-18 zhengkai 新增支持double(10, 2)等类型中有英文逗号的特殊情况
String commentPattenStr3 = "\\((.*?)\\)";
Matcher matcher3 = Pattern.compile(commentPattenStr3).matcher(fieldListTmp);
while (matcher3.find()) {
String commentTmp3 = matcher3.group();
if (commentTmp3.contains(",")) {
String commentTmpFinal = commentTmp3.replaceAll(",", "");
fieldListTmp = fieldListTmp.replace(matcher3.group(), commentTmpFinal);
}
}
String[] fieldLineList = fieldListTmp.split(",");
if (fieldLineList.length > 0) {
int i = 0;
//i为了解决primary key关键字出现的地方出现在前3行一般和id有关
for (String columnLine0 : fieldLineList) {
i++;
String columnLine = columnLine0.replaceAll("\n", "").replaceAll("\t", "").trim();
// `userid` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
// 2018-9-18 zhengk 修改为contains提升匹配率和匹配不按照规矩出牌的语句
// 2018-11-8 zhengkai 修复tornadoorz反馈的KEY FK_permission_id (permission_id),KEY FK_role_id (role_id)情况
// 2019-2-22 zhengkai 要在条件中使用复杂的表达式
// 2019-4-29 zhengkai 优化对普通和特殊storage关键字的判断感谢@AhHeadFloating的反馈
// 2020-10-20 zhengkai 优化对fulltext/index关键字的处理感谢@WEGFan的反馈
// 2025-12-07 zhengkai 修复对primary key的处理
boolean notSpecialFlag = (
!columnLine.contains("key ")
&& !columnLine.toLowerCase().contains("constraint")
&& !columnLine.toLowerCase().contains(" using ")
&& !columnLine.toLowerCase().contains("unique ")
&& !columnLine.toLowerCase().contains("fulltext ")
&& !columnLine.toLowerCase().contains("index ")
&& !columnLine.toLowerCase().contains("pctincrease")
&& !columnLine.toLowerCase().contains("buffer_pool")
&& !columnLine.toLowerCase().contains("tablespace")
&& !(columnLine.toLowerCase().contains("primary ") && columnLine.indexOf("storage") + 3 > columnLine.indexOf("("))
&& !(columnLine.toLowerCase().contains("primary ") && i > 3)
&& !columnLine.toLowerCase().contains("primary key")
);
if (notSpecialFlag) {
//如果是oracle的number(x,x),可能出现最后分割残留的,x),这里做排除处理
if (columnLine.length() < 5) {
continue;
}
//2018-9-16 zhengkai 支持'符号以及空格的oracle语句// userid` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
String columnName = "";
columnLine = columnLine.replaceAll("`", " ").replaceAll("\"", " ").replaceAll("'", "").replaceAll(" ", " ").trim();
//如果遇到username varchar(65) default '' not null,这种情况,判断第一个空格是否比第一个引号前
try {
columnName = columnLine.substring(0, columnLine.indexOf(" "));
} catch (StringIndexOutOfBoundsException e) {
System.out.println("err happened: " + columnLine);
throw e;
}
// field Name
// 2019-09-08 yj 添加是否下划线转换为驼峰的判断
// 2023-8-27 L&J 支持原始列名任意命名风格, 不依赖用户是否输入下划线
String fieldName = null;
if (ParamInfo.NameCaseType.CAMEL_CASE.equals(nameCaseType)) {
// 2024-1-27 L&J 适配任意(maybe)原始风格转小写驼峰
fieldName = StringUtilsPlus.toLowerCamel(columnName);
} else if (ParamInfo.NameCaseType.UNDER_SCORE_CASE.equals(nameCaseType)) {
fieldName = StringUtilsPlus.toUnderline(columnName, false);
} else if (ParamInfo.NameCaseType.UPPER_UNDER_SCORE_CASE.equals(nameCaseType)) {
fieldName = StringUtilsPlus.toUnderline(columnName.toUpperCase(), true);
} else {
fieldName = columnName;
}
// 修复Oracle字段名不带引号的情况
if (columnLine.contains("`")) {
columnLine = columnLine.substring(columnLine.indexOf("`") + 1).trim();
}
//2025-03-16 修复由于类型大写导致无法转换的问题
String mysqlType = columnLine.split("\\s+")[1].toLowerCase();
if(mysqlType.contains("(")){
mysqlType = mysqlType.substring(0, mysqlType.indexOf("("));
}
//swagger class
String swaggerClass = "string" ;
if(Mysql2JavaTypeUtil.getMysqlSwaggerTypeMap().containsKey(mysqlType)){
swaggerClass = Mysql2JavaTypeUtil.getMysqlSwaggerTypeMap().get(mysqlType);
}
// field class
// int(11) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
String fieldClass = "String";
//2018-9-16 zhengk 补充char/clob/blob/json等类型如果类型未知默认为String
//2018-11-22 lshz0088 处理字段类型的时候不严谨columnLine.contains(" int") 类似这种的,可在前后适当加一些空格之类的加以区分,否则当我的字段包含这些字符的时候,产生类型判断问题。
//2020-05-03 MOSHOW.K.ZHENG 优化对所有类型的处理
//2020-10-20 zhengkai 新增包装类型的转换选择
if(Mysql2JavaTypeUtil.getMysqlJavaTypeMap().containsKey(mysqlType)){
fieldClass = Mysql2JavaTypeUtil.getMysqlJavaTypeMap().get(mysqlType);
}
// field commentMySQL的一般位于field行而pgsql和oralce多位于后面。
String fieldComment = null;
if (tableSql.toLowerCase().contains("comment on column") && (tableSql.toLowerCase().contains("." + columnName + " is ") || tableSql.toLowerCase().contains(".`" + columnName + "` is"))) {
//新增对pgsql/oracle的字段备注支持
//COMMENT ON COLUMN public.check_info.check_name IS '检查者名称';
//2018-11-22 lshz0088 正则表达式的点号前面应该加上两个反斜杠,否则会认为是任意字符
//2019-4-29 zhengkai 优化对oracle注释comment on column的支持@liukex
tableSql = tableSql.toLowerCase().replaceAll(".`" + columnName + "` is", "." + columnName + " is");
Matcher columnCommentMatcher = Pattern.compile("\\." + columnName + " is `").matcher(tableSql.toLowerCase());
fieldComment = columnName;
while (columnCommentMatcher.find()) {
String columnCommentTmp = columnCommentMatcher.group();
//System.out.println(columnCommentTmp);
fieldComment = tableSql.substring(tableSql.indexOf(columnCommentTmp) + columnCommentTmp.length()).trim();
fieldComment = fieldComment.substring(0, fieldComment.indexOf("`")).trim();
}
} else if (columnLine.toLowerCase().contains(" comment")) {
//20200518 zhengkai 修复包含comment关键字的问题
String commentTmp = columnLine.toLowerCase().substring(columnLine.toLowerCase().lastIndexOf("comment") + 7).trim();
// '用户ID',
if (commentTmp.contains("`") || commentTmp.indexOf("`") != commentTmp.lastIndexOf("`")) {
commentTmp = commentTmp.substring(commentTmp.indexOf("`") + 1, commentTmp.lastIndexOf("`"));
}
//解决最后一句是评论,无主键且连着)的问题:album_id int(3) default '1' null comment '相册id0 代表头像 1代表照片墙')
if (commentTmp.contains(")")) {
commentTmp = commentTmp.substring(0, commentTmp.lastIndexOf(")") + 1);
}
fieldComment = commentTmp;
} else if (columnLine.contains("--")) {
// 支持Oracle风格的注释--
fieldComment = columnLine.substring(columnLine.indexOf("--") + 2).trim();
} else {
//修复comment不存在导致报错的问题
fieldComment = columnName;
}
FieldInfo fieldInfo = new FieldInfo();
//
fieldInfo.setColumnName(columnName);
fieldInfo.setFieldName(fieldName);
fieldInfo.setFieldClass(fieldClass);
fieldInfo.setSwaggerClass(swaggerClass);
fieldInfo.setFieldComment(fieldComment);
fieldList.add(fieldInfo);
}
}
}
if (fieldList.isEmpty()) {
throw new Exception("表结构分析失败请检查语句或者提交issue给我");
}
//build Class Info
ClassInfo codeJavaInfo = new ClassInfo();
codeJavaInfo.setTableName(tableName);
codeJavaInfo.setClassName(className);
codeJavaInfo.setClassComment(classComment);
codeJavaInfo.setFieldList(fieldList);
codeJavaInfo.setOriginTableName(originTableName);
return codeJavaInfo;
}
@Override
public ClassInfo processTableToClassInfoByRegex(ParamInfo paramInfo) {
// field List
List<FieldInfo> fieldList = new ArrayList<FieldInfo>();
//return classInfo
ClassInfo codeJavaInfo = new ClassInfo();
//匹配整个ddl将ddl分为表名列sql部分表注释
String DDL_PATTEN_STR = "\\s*create\\s+table\\s+(?<tableName>\\S+)[^\\(]*\\((?<columnsSQL>[\\s\\S]+)\\)[^\\)]+?(comment\\s*(=|on\\s+table)\\s*'(?<tableComment>.*?)'\\s*;?)?$";
Pattern DDL_PATTERN = Pattern.compile(DDL_PATTEN_STR, Pattern.CASE_INSENSITIVE);
//匹配列sql部分分别解析每一列的列名 类型 和列注释
String COL_PATTERN_STR = "\\s*(?<fieldName>\\S+)\\s+(?<fieldType>\\w+)\\s*(?:\\([\\s\\d,]+\\))?((?!comment).)*(comment\\s*'(?<fieldComment>.*?)')?\\s*(,|$)";
Pattern COL_PATTERN = Pattern.compile(COL_PATTERN_STR, Pattern.CASE_INSENSITIVE);
Matcher matcher = Pattern.compile(DDL_PATTEN_STR).matcher(paramInfo.getTableSql().trim());
if (matcher.find()) {
String tableName = matcher.group("tableName");
String tableComment = matcher.group("tableComment");
codeJavaInfo.setTableName(tableName.replaceAll("'", ""));
codeJavaInfo.setClassName(tableName.replaceAll("'", ""));
codeJavaInfo.setClassComment(tableComment.replaceAll("'", ""));
String columnsSQL = matcher.group("columnsSQL");
if (columnsSQL != null && columnsSQL.length() > 0) {
Matcher colMatcher = COL_PATTERN.matcher(columnsSQL);
while (colMatcher.find()) {
String fieldName = colMatcher.group("fieldName");
String fieldType = colMatcher.group("fieldType");
String fieldComment = colMatcher.group("fieldComment");
if (!"key".equalsIgnoreCase(fieldType)) {
FieldInfo fieldInfo = new FieldInfo();
fieldInfo.setFieldName(fieldName.replaceAll("'", ""));
fieldInfo.setColumnName(fieldName.replaceAll("'", ""));
fieldInfo.setFieldClass(fieldType.replaceAll("'", ""));
fieldInfo.setFieldComment(fieldComment.replaceAll("'", ""));
fieldList.add(fieldInfo);
}
}
}
codeJavaInfo.setFieldList(fieldList);
}
return codeJavaInfo;
}
@Override
public ClassInfo processInsertSqlToClassInfo(ParamInfo paramInfo) {
// field List
List<FieldInfo> fieldList = new ArrayList<FieldInfo>();
//return classInfo
ClassInfo codeJavaInfo = new ClassInfo();
//get origin sql
String fieldSqlStr = paramInfo.getTableSql().toLowerCase().trim();
fieldSqlStr = fieldSqlStr.replaceAll(" ", " ").replaceAll("\\\\n`", "")
.replaceAll("\\+", "").replaceAll("``", "`").replaceAll("\\\\", "");
String valueStr = fieldSqlStr.substring(fieldSqlStr.lastIndexOf("values") + 6).replaceAll(" ", "").replaceAll("\\(", "").replaceAll("\\)", "");
//get the string between insert into and values
fieldSqlStr = fieldSqlStr.substring(0, fieldSqlStr.lastIndexOf("values"));
System.out.println(fieldSqlStr);
String insertSqlPattenStr = "insert into (?<tableName>.*) \\((?<columnsSQL>.*)\\)";
//String DDL_PATTEN_STR="\\s*create\\s+table\\s+(?<tableName>\\S+)[^\\(]*\\((?<columnsSQL>[\\s\\S]+)\\)[^\\)]+?(comment\\s*(=|on\\s+table)\\s*'(?<tableComment>.*?)'\\s*;?)?$";
Matcher matcher1 = Pattern.compile(insertSqlPattenStr).matcher(fieldSqlStr);
while (matcher1.find()) {
String tableName = matcher1.group("tableName");
//System.out.println("tableName:"+tableName);
codeJavaInfo.setClassName(tableName);
codeJavaInfo.setTableName(tableName);
String columnsSQL = matcher1.group("columnsSQL");
//System.out.println("columnsSQL:"+columnsSQL);
List<String> valueList = new ArrayList<>();
//add values as comment
String[] values = valueStr.split(",");
for (String column : values) {
valueList.add(column);
}
AtomicInteger n = new AtomicInteger(0);
//add column to fleldList
String[] columns = columnsSQL.replaceAll(" ", "").split(",");
for (String column : columns) {
FieldInfo fieldInfo2 = new FieldInfo();
fieldInfo2.setFieldName(column);
fieldInfo2.setColumnName(column);
fieldInfo2.setFieldClass(String.class.getSimpleName());
if (n.get() < valueList.size()) {
fieldInfo2.setFieldComment(column + " , eg." + valueList.get(n.get()));
}
fieldList.add(fieldInfo2);
n.getAndIncrement();
}
}
if (fieldList.size() < 1) {
throw new RuntimeException("INSERT SQL解析失败");
}
codeJavaInfo.setFieldList(fieldList);
return codeJavaInfo;
}
}

View File

@@ -0,0 +1,21 @@
package com.xiang.xservice.application.generator.service.parser;
import com.xiang.xservice.application.generator.entity.domain.ClassInfo;
import com.xiang.xservice.application.generator.entity.domain.ParamInfo;
/**
* JSON解析服务接口
*
* @author zhengkai.blog.csdn.net
*/
public interface JsonParserService {
/**
* 解析JSON生成类信息
*
* @param paramInfo 参数信息
* @return 类信息
*/
ClassInfo processJsonToClassInfo(ParamInfo paramInfo);
}

View File

@@ -0,0 +1,56 @@
package com.xiang.xservice.application.generator.service.parser;
import com.xiang.xservice.application.generator.entity.domain.ClassInfo;
import com.xiang.xservice.application.generator.entity.domain.ParamInfo;
/**
* SQL解析服务接口
*
* @author zhengkai.blog.csdn.net
*/
public interface SqlParserService {
/**
* 解析Select-SQL生成类信息(JSQLPraser版本)
*
* @param paramInfo 参数信息
* @return 类信息
* @throws Exception 解析异常
*/
ClassInfo generateSelectSqlBySQLPraser(ParamInfo paramInfo) throws Exception;
/**
* 解析Create-SQL生成类信息(JSQLPraser版本)
*
* @param paramInfo 参数信息
* @return 类信息
* @throws Exception 解析异常
*/
ClassInfo generateCreateSqlBySQLPraser(ParamInfo paramInfo) throws Exception;
/**
* 解析DDL-SQL生成类信息
*
* @param paramInfo 参数信息
* @return 类信息
* @throws Exception 解析异常
*/
ClassInfo processTableIntoClassInfo(ParamInfo paramInfo) throws Exception;
/**
* 解析DDL SQL生成类信息-正则表达式版本
*
* @param paramInfo 参数信息
* @return 类信息
*/
ClassInfo processTableToClassInfoByRegex(ParamInfo paramInfo);
/**
* 解析INSERT-SQL生成类信息-正则表达式版本
*
* @param paramInfo 参数信息
* @return 类信息
*/
ClassInfo processInsertSqlToClassInfo(ParamInfo paramInfo);
}

View File

@@ -0,0 +1,84 @@
package com.xiang.xservice.application.generator.util;
import freemarker.cache.ClassTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Locale;
import java.util.Map;
/**
* freemarker tool
*
* @author xiang
*/
@Slf4j
@Component
public class FreemarkerUtil {
/**
* 传入需要转义的字符串进行转义
*/
public static String escapeString(String originStr) {
return originStr.replaceAll("", "\\#").replaceAll("", "\\$");
}
/**
* freemarker config
*/
private static final Configuration freemarkerConfig = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
static {
try {
freemarkerConfig.setClassForTemplateLoading(FreemarkerUtil.class, "/templates/code-generator");
freemarkerConfig.setTemplateLoader(new ClassTemplateLoader(FreemarkerUtil.class, "/templates/code-generator"));
freemarkerConfig.setNumberFormat("#");
freemarkerConfig.setClassicCompatible(true);
freemarkerConfig.setDefaultEncoding("UTF-8");
freemarkerConfig.setLocale(Locale.CHINA);
freemarkerConfig.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
/**
* process Template Into String
*
* @param template
* @param model
* @return
* @throws IOException
* @throws TemplateException
*/
public static String processTemplateIntoString(Template template, Object model)
throws IOException, TemplateException {
StringWriter result = new StringWriter();
template.process(model, result);
return result.toString();
}
/**
* process String
*
* @param templateName
* @param params
* @return
* @throws IOException
* @throws TemplateException
*/
public static String processString(String templateName, Map<String, Object> params)
throws IOException, TemplateException {
Template template = freemarkerConfig.getTemplate(templateName);
return escapeString(processTemplateIntoString(template, params));
}
}

View File

@@ -0,0 +1,19 @@
package com.xiang.xservice.application.generator.util;
import joptsimple.internal.Strings;
import java.util.Map;
public class MapUtil {
public static String getString(Map<String, Object> map, String key) {
if (map != null && map.containsKey(key)) {
try {
return map.get(key).toString();
} catch (Exception e) {
return Strings.EMPTY;
}
}
return Strings.EMPTY;
}
}

View File

@@ -0,0 +1,60 @@
package com.xiang.xservice.application.generator.util;
import java.util.HashMap;
public final class Mysql2JavaTypeUtil {
public static final HashMap<String, String> mysqlJavaTypeMap = new HashMap<String, String>();
public static final HashMap<String, String> mysqlSwaggerTypeMap = new HashMap<String, String>();
static {
mysqlJavaTypeMap.put("bigint", "Long");
mysqlJavaTypeMap.put("int", "Integer");
mysqlJavaTypeMap.put("tinyint", "Integer");
mysqlJavaTypeMap.put("smallint", "Integer");
mysqlJavaTypeMap.put("mediumint", "Integer");
mysqlJavaTypeMap.put("integer", "Integer");
//小数
mysqlJavaTypeMap.put("float", "Float");
mysqlJavaTypeMap.put("double", "Double");
mysqlJavaTypeMap.put("decimal", "Double");
//bool
mysqlJavaTypeMap.put("bit", "Boolean");
//字符串
mysqlJavaTypeMap.put("char", "String");
mysqlJavaTypeMap.put("varchar", "String");
mysqlJavaTypeMap.put("varchar2", "String"); // Oracle类型
mysqlJavaTypeMap.put("tinytext", "String");
mysqlJavaTypeMap.put("text", "String");
mysqlJavaTypeMap.put("mediumtext", "String");
mysqlJavaTypeMap.put("longtext", "String");
//日期
mysqlJavaTypeMap.put("date", "Date");
mysqlJavaTypeMap.put("datetime", "Date");
mysqlJavaTypeMap.put("timestamp", "Date");
// 数字类型 - Oracle增强
mysqlJavaTypeMap.put("number", "BigDecimal"); // Oracle的NUMBER类型默认映射为BigDecimal支持精度
mysqlSwaggerTypeMap.put("bigint", "integer");
mysqlSwaggerTypeMap.put("int", "integer");
mysqlSwaggerTypeMap.put("tinyint", "integer");
mysqlSwaggerTypeMap.put("smallint", "integer");
mysqlSwaggerTypeMap.put("mediumint", "integer");
mysqlSwaggerTypeMap.put("integer", "integer");
mysqlSwaggerTypeMap.put("boolean", "boolean");
mysqlSwaggerTypeMap.put("float", "number");
mysqlSwaggerTypeMap.put("double", "number");
mysqlSwaggerTypeMap.put("decimal", "number");
// Oracle类型
mysqlSwaggerTypeMap.put("varchar2", "string");
mysqlSwaggerTypeMap.put("number", "number");
}
public static HashMap<String, String> getMysqlJavaTypeMap() {
return mysqlJavaTypeMap;
}
public static HashMap<String, String> getMysqlSwaggerTypeMap() {
return mysqlSwaggerTypeMap;
}
}

View File

@@ -0,0 +1,125 @@
package com.xiang.xservice.application.generator.util;
import org.apache.commons.lang3.StringUtils;
public class StringUtilsPlus {
/**
* 首字母大写
*
* @param str 字符串
*
* @return 首字母大写
*/
public static String upperCaseFirst(String str) {
if (str == null || str.trim().isEmpty()) {
return str;
}
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
/**
* 首字母小写
*
* @param str 字符串
*
* @return 首字母小写
*/
public static String lowerCaseFirst(String str) {
return (str != null && str.length() > 1) ? str.substring(0, 1).toLowerCase() + str.substring(1) : "";
}
/**
* 下划线,转换为驼峰式
*
* @param underscoreName 下划线字符串
*
* @return 驼峰式
*/
public static String underlineToCamelCase(String underscoreName) {
StringBuilder result = new StringBuilder();
if (StringUtils.isNotBlank(underscoreName)) {
boolean flag = false;
for (int i = 0; i < underscoreName.length(); i++) {
char ch = underscoreName.charAt(i);
if ('_' == ch) {
flag = true;
} else {
if (flag) {
result.append(Character.toUpperCase(ch));
flag = false;
} else {
result.append(ch);
}
}
}
}
return result.toString();
}
/**
* 转 user_name 风格
*/
public static String toUnderline(String str, boolean upperCase) {
if (str == null || str.trim().isEmpty()) {
return str;
}
StringBuilder result = new StringBuilder();
boolean preIsUnderscore = false;
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
if (ch == '_') {
preIsUnderscore = true;
} else if (ch == '-') {
ch = '_';
preIsUnderscore = true; // -A -> _a
} else if (ch >= 'A' && ch <= 'Z') {
// A -> _a
if (!preIsUnderscore && i > 0) { // _A -> _a
result.append("_");
}
preIsUnderscore = false;
} else {
preIsUnderscore = false;
}
result.append(upperCase ? Character.toUpperCase(ch) : Character.toLowerCase(ch));
}
return result.toString();
}
/**
* 任何字符串 转驼峰
* @param str 任何字符串
*/
public static String toLowerCamel(String str) {
if (str == null || str.trim().isEmpty()) {
return str;
}
StringBuilder result = new StringBuilder();
char pre = '\0';
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
if (ch == '-' || ch == '—' || ch == '_') {
ch = '_';
pre = ch;
continue;
}
char ch2 = ch;
if (pre == '_') {
ch2 = Character.toUpperCase(ch);
pre = ch2;
} else if (pre >= 'A' && pre <= 'Z') {
pre = ch;
ch2 = Character.toLowerCase(ch);
} else {
pre = ch;
}
result.append(ch2);
}
return lowerCaseFirst(result.toString());
}
}

View File

@@ -37,7 +37,7 @@ public class DynamicDomainController {
log.error("获取公网IP失败 time:{}", LocalDateTime.now(), e);
return Result.error("获取公网IP失败");
}
return Result.success("获取公网IP成功", publicIp);
return Result.data(publicIp);
}
@PostMapping("/ddns")
@@ -46,7 +46,7 @@ public class DynamicDomainController {
String publicIp = IpUtils.getPublicIp();
log.info("获取公网IP成功time:{}, ip:{}", LocalDateTime.now(), publicIp);
IDomainService.dynamicDomainAnalysis(publicIp);
return Result.success("获取公网IP成功");
return Result.data("获取公网IP成功");
} catch (Exception e) {
log.error("获取公网IP失败 time:{}", LocalDateTime.now(), e);
return Result.error("获取公网IP失败");

View File

@@ -1,33 +0,0 @@
package com.xiang.xservice.application.script.domain.service;
import com.xiang.xmc.service.message.dingTalk.service.DingTalkService;
import com.xiang.xservice.config.DingTalkRobotScriptConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @Author: xiang
* @Date: 2025-08-07 10:30
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class DingTalkScriptDomainService {
private final DingTalkService dingTalkService;
private final DingTalkRobotScriptConfig dingTalkRobotScriptConfig;
/**
* 发送脚本消息
* @param msg 消息
*/
public void sendScriptMsg(String msg) {
try {
dingTalkService.sendRobotMessage(dingTalkRobotScriptConfig.getSecret(), dingTalkRobotScriptConfig.getToken(),
dingTalkRobotScriptConfig.getUsers(), msg);
} catch (Exception e) {
log.error("信息发送异常, 信息:{}", msg, e);
}
}
}

View File

@@ -9,6 +9,7 @@ import com.aliyun.alidns20150109.models.DescribeSubDomainRecordsResponseBody;
import com.aliyun.alidns20150109.models.UpdateDomainRecordRequest;
import com.aliyun.teaopenapi.models.Config;
import com.xiang.xservice.application.script.domain.config.AliyunDnsPropertyConfig;
import com.xiang.xservice.common.service.dingTalk.ScriptDingTalkFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -36,7 +37,7 @@ public class IDomainServiceImpl implements IDomainService {
private final AliyunDnsPropertyConfig aliyunDnsPropertyConfig;
private static final String TYPE = "A";
private final DingTalkScriptDomainService dingTalkService;
private final ScriptDingTalkFactory dingTalkService;
@Override
public void dynamicDomainAnalysis(String publicIp) throws Exception {
Client client = createClient();
@@ -53,14 +54,14 @@ public class IDomainServiceImpl implements IDomainService {
if (records.isEmpty()) {
log.info("未找到记录,添加记录..., ip:{}", publicIp);
addDnsRecord(client, publicIp, rr);
dingTalkService.sendScriptMsg("动态解析公网ip成功域名" + rr + "." + DOMAIN_NAME + ", 新ip:" + publicIp);
dingTalkService.sendMsg("动态解析公网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, rr);
dingTalkService.sendScriptMsg("动态解析公网ip成功域名" + rr + "." + DOMAIN_NAME + ", 新ip:" + publicIp);
dingTalkService.sendMsg("动态解析公网ip成功域名" + rr + "." + DOMAIN_NAME + ", 新ip:" + publicIp);
} else {
log.info("ip未变更无需修改ip:{}", publicIp);
}

View File

@@ -23,7 +23,6 @@ import com.xiang.xservice.application.script.fwd.mapper.FwdAudienceConfigMapper;
import com.xiang.xservice.application.script.fwd.mapper.FwdPerformConfigMapper;
import com.xiang.xservice.application.script.fwd.mapper.FwdPerformProjectInfoMapper;
import com.xiang.xservice.application.script.fwd.mapper.FwdUserConfigMapper;
import com.xiang.xservice.application.script.fwd.service.DingTalkScriptFWDService;
import com.xiang.xservice.application.script.fwd.service.IPerformService;
import com.xiang.xservice.application.script.fwd.service.IPerformServiceHttp;
import com.xiang.xservice.application.script.fwd.utils.TimeSyncUtils;
@@ -31,6 +30,7 @@ import com.xiang.xservice.basic.utils.DateUtils;
import com.xiang.xservice.basic.utils.PrimaryKeyUtils;
import com.xiang.xservice.common.entity.SysConfigDO;
import com.xiang.xservice.common.mapper.SysConfigMapper;
import com.xiang.xservice.common.service.dingTalk.ScriptDingTalkFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
@@ -66,7 +66,7 @@ public class FwdImportantMsgJob {
private final FwdPerformProjectInfoMapper performProjectInfoMapper;
private final FwdPerformConfigMapper performConfigMapper;
private final DynamicTaskScheduler dynamicTaskScheduler;
private final DingTalkScriptFWDService dingTalkScriptFWDService;
private final ScriptDingTalkFactory dingTalkScriptFWDService;
private final FwdUserConfigMapper fwdUserConfigMapper;
private final FwdAudienceConfigMapper fwdAudienceConfigMapper;
private final IPerformService iPerformService;
@@ -149,7 +149,7 @@ public class FwdImportantMsgJob {
}
}
msg.append("请注意进行数据库配置的更改!");
dingTalkScriptFWDService.sendScriptMsg(msg.toString());
dingTalkScriptFWDService.sendMsg(msg.toString());
log.info("【芬玩岛】演唱会预售定时任务结束time:{}", System.currentTimeMillis());
}
@@ -249,7 +249,7 @@ public class FwdImportantMsgJob {
}
}
});
dingTalkScriptFWDService.sendScriptMsg(msg.toString());
dingTalkScriptFWDService.sendMsg(msg.toString());
}
private void savaTask(FPerformProjectInfo data, long taskId, Map<String, Object> params) {

View File

@@ -102,6 +102,6 @@ public class FwdDataController {
}
}
}
return Result.success("success");
return Result.data("success");
}
}

View File

@@ -36,37 +36,37 @@ public class FwdOuterController {
@GetMapping("/getShowProjects")
public Result<ProjectsResp> getShowProjects() {
ProjectsResp showProjectsFromHttp = performServiceHttp.getShowProjectsFromHttp(new BaseRequest());
return Result.success("查询成功!", showProjectsFromHttp);
return Result.data(showProjectsFromHttp);
}
@GetMapping("/getProjectInfo/{id}")
public Result<Perform> getProjectInfo(@PathVariable("id") Long id) {
String token = fwdUserConfigMapper.getAvailableUser().get(0).getToken();
Perform performsByProjectIdFromHttp = performServiceHttp.getPerformsByProjectIdFromHttp(id, token);
return Result.success("查询成功!", performsByProjectIdFromHttp);
return Result.data(performsByProjectIdFromHttp);
}
@GetMapping("/getPerformsByProjectIdFromHttp/{id}")
public Result<Perform> getPerformsByProjectIdFromHttp(@PathVariable("id") Long id) {
String token = fwdUserConfigMapper.getAvailableUser().get(0).getToken();
Perform performsByProjectIdFromHttp = performServiceHttp.getPerformsByProjectIdFromHttp(id, token);
return Result.success("查询成功!", performsByProjectIdFromHttp);
return Result.data(performsByProjectIdFromHttp);
}
@PostMapping("/createOrder")
public Result<String> createOrder(Long projectId) throws Exception {
String token = fwdUserConfigMapper.getAvailableUser().get(0).getToken();
if (performService.createProjectOrder(projectId, FREQUENT_IDS, token)) {
return Result.success("下单成功!");
return Result.data("下单成功!");
}
return Result.error("下单失败!");
}
@GetMapping("/getSeatPlanStatus")
public Result<SeatPlanStatus> getSeatPlanStatu (@RequestParam List<Long> ids) {
public Result<List<SeatPlanStatus>> getSeatPlanStatu (@RequestParam List<Long> ids) {
String token = fwdUserConfigMapper.getAvailableUser().get(0).getToken();
List<SeatPlanStatus> seatPlanStatusFromHttp = performServiceHttp.getSeatPlanStatusFromHttp(ids, token);
return Result.success("查询成功!", seatPlanStatusFromHttp);
return Result.data(seatPlanStatusFromHttp);
}
}

View File

@@ -1,9 +1,9 @@
package com.xiang.xservice.application.script.fwd.server;
import com.alibaba.fastjson.JSON;
import com.xiang.xservice.basic.common.resp.Result;
import com.xiang.xservice.application.script.fwd.service.DingTalkScriptFWDService;
import com.xiang.xservice.application.script.fwd.service.IPerformService;
import com.xiang.xservice.basic.common.resp.Result;
import com.xiang.xservice.common.service.dingTalk.ScriptDingTalkFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
@@ -24,7 +24,7 @@ import java.util.Map;
public class FwdUserController {
private final IPerformService performService;
private final DingTalkScriptFWDService dingTalkService;
private final ScriptDingTalkFactory dingTalkService;
@GetMapping("/token")
public Result<Void> updateUserTokenFromHttpProxy(@RequestParam Map<String, String> params) {
@@ -35,7 +35,7 @@ public class FwdUserController {
if (b) {
String msg = "用户:" + name + "的token更新成功";
try {
dingTalkService.sendScriptMsg(msg);
dingTalkService.sendMsg(msg);
} catch (Exception e) {
log.error("消息发送失败", e);
return Result.error("消息发送失败");

View File

@@ -1,32 +0,0 @@
package com.xiang.xservice.application.script.fwd.service;
import com.xiang.xmc.service.message.dingTalk.service.DingTalkService;
import com.xiang.xservice.config.DingTalkRobotScriptConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @Author: xiang
* @Date: 2025-08-07 10:30
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class DingTalkScriptFWDService {
private final DingTalkService dingTalkService;
private final DingTalkRobotScriptConfig dingTalkRobotConfig;
/**
* 发送脚本消息
* @param msg 消息
*/
public void sendScriptMsg(String msg) {
try {
dingTalkService.sendRobotMessage(dingTalkRobotConfig.getSecret(), dingTalkRobotConfig.getToken(), dingTalkRobotConfig.getUsers(), msg);
} catch (Exception e) {
log.error("信息发送异常, 信息:{}", msg, e);
}
}
}

View File

@@ -13,10 +13,10 @@ import com.xiang.xservice.application.script.fwd.mapper.FwdPerformConfigMapper;
import com.xiang.xservice.application.script.fwd.mapper.FwdPerformProjectInfoMapper;
import com.xiang.xservice.application.script.fwd.mapper.FwdPerformSeatInfoMapper;
import com.xiang.xservice.application.script.fwd.mapper.FwdUserConfigMapper;
import com.xiang.xservice.application.script.fwd.service.DingTalkScriptFWDService;
import com.xiang.xservice.application.script.fwd.service.IPerformService;
import com.xiang.xservice.application.script.fwd.service.IPerformServiceHttp;
import com.xiang.xservice.basic.config.MyThreadFactory;
import com.xiang.xservice.common.service.dingTalk.ScriptDingTalkFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
@@ -51,7 +51,7 @@ public class PerformServiceImpl implements IPerformService {
private final FwdPerformProjectInfoMapper fwdPerformProjectInfoMapper;
private final FwdPerformConfigMapper fwdPerformConfigMapper;
private final IPerformServiceHttp performServiceHttp;
private final DingTalkScriptFWDService dingTalkService;
private final ScriptDingTalkFactory dingTalkService;
private final FwdUserConfigMapper fwdUserConfigMapper;
private final HttpRequestHelper httpRequestHelper;
private final ExecutorService es =
@@ -121,12 +121,12 @@ public class PerformServiceImpl implements IPerformService {
if (Objects.nonNull(projectOrder)) {
log.info("下单成功,订单信息:{}", JSONObject.toJSONString(projectOrder));
String msg = "【芬玩岛】下单成功✅✅✅,演出名称:" + performByProjectId.getProjectName() + "请在5分钟内完成付款订单号" + projectOrder.getOrderNo();
dingTalkService.sendScriptMsg(msg);
dingTalkService.sendMsg(msg);
return Boolean.TRUE;
}
}
}
dingTalkService.sendScriptMsg("【芬玩岛】下单失败❌❌❌,演出名称:" + performByProjectId.getProjectName());
dingTalkService.sendMsg("【芬玩岛】下单失败❌❌❌,演出名称:" + performByProjectId.getProjectName());
return Boolean.FALSE;
}

View File

@@ -8,5 +8,5 @@ public class GladosConstants {
public static final String GLADOS_COOKIE = "SL_G_WPT_TO=en; SL_GWPT_Show_Hide_tmp=1; SL_wptGlobTipTmp=1; koa:sess=eyJ1c2VySWQiOjU1OTg1MywiX2V4cGlyZSI6MTc3MjYwNDkyNjI4OCwiX21heEFnZSI6MjU5MjAwMDAwMDB9; koa:sess.sig=OdaqjpLkIp19lXn0lFuOsHX7vEM";
public static final String GLADOS_CHECK_IN_BODY = "{\"token\":\"glados.one\"}";
public static final String GLADOS_CHECK_IN_BODY = "{\"token\":\"glados.cloud\"}";
}

View File

@@ -5,7 +5,7 @@ public class URLConstants {
/**
* glados 主域名
*/
public static final String GLADOS_URL_PREFIX = "https://www.glados.one";
public static final String GLADOS_URL_PREFIX = "https://glados.cloud";
/**
* 签到

View File

@@ -1,11 +1,9 @@
package com.xiang.xservice.application.script.glados.controller;
import com.xiang.xservice.basic.common.resp.Result;
import com.xiang.xservice.application.script.glados.entity.req.GladosCheckInReq;
import com.xiang.xservice.application.script.glados.service.GLaDOSService;
import com.xiang.xservice.basic.common.resp.Result;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -21,9 +19,10 @@ public class GLaDOSController {
private final GLaDOSService glaDOSService;
@PostMapping("/checkIn")
public Result<String> checkIn(@RequestBody GladosCheckInReq request) {
return Result.success(glaDOSService.checkIn());
@GetMapping("/checkIn")
public Result<Void> checkIn() {
glaDOSService.checkInV2();
return Result.success();
}
}

View File

@@ -0,0 +1,20 @@
package com.xiang.xservice.application.script.glados.entity.resp;
import lombok.Data;
/**
* @Author: xiang
* @Date: 2026-01-23 09:21
*/
@Data
public class CheckInResp {
private Long id;
private Long userId;
private Long time;
private String asset;
private String business;
private String change;
private String balance;
private String detail;
}

View File

@@ -22,6 +22,6 @@ public class GladosCheckInJob {
@Scheduled(cron = "0 0 7 1/1 * ?")
public void checkInJon() {
log.info("[job] Glados Check In Job start, time:{}", LocalDateTime.now());
glaDOSService.checkIn();
glaDOSService.checkInV2();
}
}

View File

@@ -1,33 +0,0 @@
package com.xiang.xservice.application.script.glados.service;
import com.xiang.xmc.service.message.dingTalk.service.DingTalkService;
import com.xiang.xservice.config.DingTalkRobotScriptConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @Author: xiang
* @Date: 2025-08-07 10:30
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class DingTalkScriptGladosService {
private final DingTalkService dingTalkService;
private final DingTalkRobotScriptConfig dingTalkRobotScriptConfig;
/**
* 发送脚本消息
* @param msg 消息
*/
public void sendScriptMsg(String msg) {
try {
dingTalkService.sendRobotMessage(dingTalkRobotScriptConfig.getSecret(), dingTalkRobotScriptConfig.getToken(),
dingTalkRobotScriptConfig.getUsers(), msg);
} catch (Exception e) {
log.error("信息发送异常, 信息:{}", msg, e);
}
}
}

View File

@@ -10,4 +10,9 @@ public interface GLaDOSService {
* 签到
*/
String checkIn();
/**
* 签到
*/
void checkInV2();
}

View File

@@ -1,14 +1,19 @@
package com.xiang.xservice.application.script.glados.service;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.google.common.collect.Maps;
import com.xiang.xmc.service.http.helper.BaseHttpHelp;
import com.xiang.xmc.service.http.helper.HttpHelperFactory;
import com.xiang.xservice.application.script.glados.common.GladosConstants;
import com.xiang.xservice.application.script.glados.common.URLConstants;
import com.xiang.xservice.application.script.glados.entity.GladosRunLog;
import com.xiang.xservice.application.script.glados.entity.resp.CheckInResp;
import com.xiang.xservice.application.script.glados.entity.resp.GLaDOSResponse;
import com.xiang.xservice.application.script.glados.repository.GladosMapper;
import com.xiang.xservice.application.script.xb.entity.pojo.User;
import com.xiang.xservice.basic.utils.HttpUtils;
import com.xiang.xservice.common.service.dingTalk.ScriptDingTalkFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -31,7 +36,9 @@ public class GLaDOSServiceImpl implements GLaDOSService{
private final GladosMapper gladosMapper;
private final DingTalkScriptGladosService dingTalkService;
private final ScriptDingTalkFactory dingTalkService;
private final BaseHttpHelp httpHelp = HttpHelperFactory.createSimpleHttp();
/**
* 签到
@@ -63,6 +70,91 @@ public class GLaDOSServiceImpl implements GLaDOSService{
return sb.toString();
}
@Override
public void checkInV2() {
List<User> users = gladosMapper.listAllUser();
if (CollectionUtils.isEmpty(users)) {
return;
}
for (User user : users) {
try {
for (int i = 0; i < 3; i++) {
if (checkInV2(user)) {
break;
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
log.error("线程暂停10s失败");
}
}
} catch (Exception e) {
log.error("签到失败,", e);
}
}
}
public boolean checkInV2(User user) {
Map<String, String> header = Maps.newHashMap();
header.put("Cookie", user.getCookie());
String response = null;
try {
response = httpHelp.doPost(URLConstants.GLADOS_CHECK_IN_URL, header, GladosConstants.GLADOS_CHECK_IN_BODY);
} catch (Exception e) {
log.error("http请求异常:{}", user.getEmail());
return false;
}
if (org.apache.commons.lang3.StringUtils.isBlank(response)) {
return false;
}
GLaDOSResponse<CheckInResp> gLaDOSResponse = JSONObject.parseObject(response, new TypeReference<GLaDOSResponse<CheckInResp>>() {
});
if (Objects.isNull(gLaDOSResponse)) {
return false;
}
if (0 == gLaDOSResponse.getCode()) {
// 成功请求
if (Objects.nonNull(gLaDOSResponse.getPoints()) && 0 != gLaDOSResponse.getPoints()) {
// 签到成功
dingTalkService.sendMsg("[时间:" + LocalDateTime.now() + "] 用户: " +
user.getEmail() + "签到成功,获得积分:" + gLaDOSResponse.getPoints());
GladosRunLog build = GladosRunLog.builder().time(LocalDateTime.now()).status(1).code(Integer.valueOf(gLaDOSResponse.getCode().toString())).response(response).user(user.getEmail()).userId(user.getId()).build();
gladosMapper.insertScriptRunLog(build);
return Boolean.TRUE;
}
}
if (gLaDOSResponse.getMessage().contains("Repeats")) {
if (!CollectionUtils.isEmpty(gLaDOSResponse.getList())) {
dingTalkService.sendMsg("用户:" + user.getEmail() + "当前已签到。结果:" + gLaDOSResponse.getList().get(0));
GladosRunLog build = GladosRunLog.builder().time(LocalDateTime.now()).status(1).code(Integer.valueOf(gLaDOSResponse.getCode().toString())).response(response).user(user.getEmail()).userId(user.getId()).build();
gladosMapper.insertScriptRunLog(build);
return true;
}
}
if (-2 == gLaDOSResponse.getCode()) {
log.warn("签到失败,用户:{}, cookie过期:{}", user.getEmail(), gLaDOSResponse.getMessage());
String message = "[时间:" + LocalDateTime.now() + "] 用户: " + user.getEmail() + ",签到消息: " + gLaDOSResponse.getMessage() + "手动请求http://general.xiangtech.xyz:30026/system/glados/checkIn";
try {
dingTalkService.sendMsg(message);
return true;
} catch (Exception e) {
log.error("发送钉钉消息失败", e);
}
}
// 请求异常
dingTalkService.sendMsg("用户:" + user.getEmail() + "请求异常,响应结果:" + gLaDOSResponse.getMessage());
GladosRunLog build = GladosRunLog.builder().time(LocalDateTime.now()).status(0).code(Integer.valueOf(gLaDOSResponse.getCode().toString())).response(response).user(user.getEmail()).userId(user.getId()).build();
gladosMapper.insertScriptRunLog(build);
return false;
}
private boolean checkIn(User user, StringBuffer sb) {
Map<String, String> header = Maps.newHashMap();
@@ -83,11 +175,12 @@ public class GLaDOSServiceImpl implements GLaDOSService{
log.info("http do post success, response:{}", response);
// 成功签到记录
if (0 == gLaDOSResponse.getCode() && Objects.nonNull(gLaDOSResponse.getPoints())) {
if (0 == gLaDOSResponse.getCode()) {
if (Objects.nonNull(gLaDOSResponse.getPoints())) {
log.info("签到成功, 签到积分:{}, 签到消息:{}", gLaDOSResponse.getPoints(), gLaDOSResponse.getMessage());
sb.append(user.getEmail()).append("签到成功,获得积分:").append(gLaDOSResponse.getPoints()).append("\n");
try {
dingTalkService.sendScriptMsg("[时间:" + LocalDateTime.now() + "] 用户: " +
dingTalkService.sendMsg("[时间:" + LocalDateTime.now() + "] 用户: " +
user.getEmail() + "签到成功,获得积分:" + gLaDOSResponse.getPoints());
} catch (Exception e) {
log.error("发送钉钉消息失败", e);
@@ -95,6 +188,13 @@ public class GLaDOSServiceImpl implements GLaDOSService{
GladosRunLog build = GladosRunLog.builder().time(LocalDateTime.now()).status(1).code(Integer.valueOf(gLaDOSResponse.getCode().toString())).response(response).user(user.getEmail()).userId(user.getId()).build();
gladosMapper.insertScriptRunLog(build);
return Boolean.TRUE;
} else {
log.info("签到异常, 签到消息:{}", gLaDOSResponse.getMessage());
sb.append(user.getEmail()).append("签到异常,消息:").append(gLaDOSResponse.getMessage());
GladosRunLog build = GladosRunLog.builder().time(LocalDateTime.now()).status(0).code(Integer.valueOf(gLaDOSResponse.getCode().toString())).response(response).user(user.getEmail()).userId(user.getId()).build();
gladosMapper.insertScriptRunLog(build);
return Boolean.FALSE;
}
}
// 重复签到,表示当日签到成功
@@ -102,7 +202,7 @@ public class GLaDOSServiceImpl implements GLaDOSService{
log.warn("签到失败,重复签到,用户:{}, 签到消息:{}", user.getEmail(), gLaDOSResponse.getMessage());
sb.append(user).append("签到失败,重复签到,用户:").append(user).append(",签到消息:").append(gLaDOSResponse.getMessage());
try {
dingTalkService.sendScriptMsg("[时间:" + LocalDateTime.now() + "] 用户: " +
dingTalkService.sendMsg("[时间:" + LocalDateTime.now() + "] 用户: " +
user.getEmail() + "当天已经签到成功!获得积分" + gLaDOSResponse.getList().get(0));
} catch (Exception e) {
log.error("发送钉钉消息失败", e);
@@ -117,7 +217,7 @@ public class GLaDOSServiceImpl implements GLaDOSService{
log.warn("签到失败,用户:{}, cookie过期:{}", user.getEmail(), gLaDOSResponse.getMessage());
String message = "[时间:" + LocalDateTime.now() + "] 用户: " + user.getEmail() + ",签到消息: " + gLaDOSResponse.getMessage();
try {
dingTalkService.sendScriptMsg(message);
dingTalkService.sendMsg(message);
} catch (Exception e) {
log.error("发送钉钉消息失败", e);
}
@@ -134,7 +234,7 @@ public class GLaDOSServiceImpl implements GLaDOSService{
} else {
try {
String mes = "[时间:" + LocalDateTime.now() + "] 用户: " + user.getEmail() + ",签到异常,请求结果为空。";
dingTalkService.sendScriptMsg(mes);
dingTalkService.sendMsg(mes);
} catch (Exception e) {
log.error("发送钉钉消息失败", e);
}

View File

@@ -1,15 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.constants;
/**
* @Author: xiang
* @Date: 2025-12-16 10:43
*/
public class RedisKeyConstant {
public static final String JNTYZX_ORDER_CREATE_KEY = "jntyzx:order:create:orderId:";
public static final String JNTUZX_ORDER_PEEK_KEY = "jntyzx:order:peek:user:";
public static final String JNTYZX_VENUE_MSG_628_KEY = "jntyzx:venue:msg:628";
public static final String JNTYZX_VENUE_MSG_8210_KEY = "jntyzx:venue:msg:8210";
}

View File

@@ -1,35 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.constants;
/**
* @Author: xiang
* @Date: 2025-12-15 13:46
*/
public class UrlConstant {
/**
* 江南体育中心基础URL
*/
private final static String GNTYZX_BASE_URL = "https://jntyzx.cn:8443";
/**
* 查询当天的场地信息
*/
public final static String QUERY_TODAY_SUBSCRIBE_URL = GNTYZX_BASE_URL + "/GYM-JN/multi/Subscribe/getSubscribeByToday";
public final static String QUERY_TOMORROW_SUBSCRIBE_URL = GNTYZX_BASE_URL + "/GYM-JN/multi/Subscribe/getSubscribeByTomorrow";
/**
* 订阅场地
*/
public final static String ADD_SUBSCRIBE = GNTYZX_BASE_URL + "/GYM-JN/multi/Subscribe/addSubscribe";
/**
* 订单信息
*/
public final static String ORDER_INFO = GNTYZX_BASE_URL + "/GYM-JN/multi/busiOrder/queryOrderInfo";
/**
* 心跳监测接口
*/
public final static String HEALTH_DECLARATION = GNTYZX_BASE_URL + "/GYM-JN//busi/healthDeclaration/addUserPrivacy";
}

View File

@@ -1,37 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.controller;
import com.xiang.xservice.application.script.jntyzx.service.DingTalkScriptVenueService;
import com.xiang.xservice.application.script.jntyzx.service.IUserTokenInfoService;
import com.xiang.xservice.basic.common.resp.Result;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author: xiang
* @Date: 2025-12-18 09:08
*/
@RestController
@RequestMapping("/open/jntyzx/token/")
@RequiredArgsConstructor
public class TokenFreshController {
private final IUserTokenInfoService userTokenInfoService;
private final DingTalkScriptVenueService dingTalkScriptVenueService;
@GetMapping("/freshToken")
public Result<Void> freshToken() {
boolean token = userTokenInfoService.flushToken();
return Result.success();
}
@GetMapping("/freshTokenOnline")
public Result<Void> freshTokenOnline(@RequestParam("token") String token, @RequestParam("name") String name) {
if (userTokenInfoService.updateTokenByName(name, token)) {
dingTalkScriptVenueService.sendScriptMsg(name + "token更新成功");
}
return Result.success();
}
}

View File

@@ -1,71 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.controller;
import com.xiang.xservice.application.script.jntyzx.entity.pojo.VenueInfoDO;
import com.xiang.xservice.application.script.jntyzx.entity.resp.query.SitePositionList;
import com.xiang.xservice.application.script.jntyzx.service.DingTalkScriptVenueService;
import com.xiang.xservice.application.script.jntyzx.service.IJntyzxHttpService;
import com.xiang.xservice.application.script.jntyzx.service.IUserTokenInfoService;
import com.xiang.xservice.application.script.jntyzx.service.IVenueService;
import com.xiang.xservice.application.script.jntyzx.utils.VenueInfoUtils;
import com.xiang.xservice.basic.common.resp.Result;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @Author: xiang
* @Date: 2025-12-15 14:28
*/
@RestController
@RequiredArgsConstructor
public class VenueController {
private final IVenueService venueService;
private final IJntyzxHttpService jntyzxHttpService;
private final IUserTokenInfoService userTokenInfoService;
private final DingTalkScriptVenueService dingTalkScriptVenueService;
private final static String STATIC_TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3NjU3ODQ1NjMsInVzZXJuYW1lIjoid3hfb3Blbl9pZF9vMjFNWDR5N3doWENHanZVVEdQNkNUejJIYkQ4In0.QBzNQNvJZQPZZnzmbU8K5Liz0piHwercrDIq3kirUJk";
@PostMapping("/queryVenue")
public Result<Void> queryVenue() {
venueService.queryVenueService();
return Result.success();
}
@PostMapping("/getTomorrowVenue")
public Result<SitePositionList> getTomorrowVenue() {
List<SitePositionList> sitePositionLists = venueService.queryTomorrowVenue();
return Result.success(sitePositionLists);
}
@PostMapping("/addSubscribe")
public Result<Void> addSubscribe() {
List<VenueInfoDO> venueInfoDOS = venueService.queryCanBuyVenue();
if (CollectionUtils.isEmpty(venueInfoDOS)) {
return Result.error("暂无可订购的数据");
}
Map<String, List<VenueInfoDO>> map = venueInfoDOS.stream().filter(VenueInfoUtils::get1221VenueInfo4Mor).collect(Collectors.groupingBy(VenueInfoDO::getPlaceName));
String token = userTokenInfoService.getToken("Xiang");
if (StringUtils.isBlank(token)) {
return Result.error("暂无可订购的用户");
}
map.keySet().parallelStream().forEach(placeName -> {
List<VenueInfoDO> venueInfoDOList = map.get(placeName);
Boolean order = jntyzxHttpService.createOrder(venueInfoDOList, token);
if (order) {
dingTalkScriptVenueService.sendScriptMsg("场地:" + placeName + "下单成功,请付款!时间:" + LocalDateTime.now());
}
});
return Result.success();
}
}

View File

@@ -1,34 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.entity.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Author: xiang
* @Date: 2025-12-15 13:55
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class VenueListDTO {
/**
* 时间
*/
private String date;
/**
* 时间
*/
private String sjName;
/**
* 场地名称
*/
private String placeName;
/**
* 联系人
*/
private String contacts;
}

View File

@@ -1,55 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.entity.pojo;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* @Author: xiang
* @Date: 2025-12-16 10:57
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("jntyzx_order_create_info")
public class OrderInfoDO {
private Long id;
/**
* 订单id
*/
private String orderId;
/**
* 参数
*/
private String params;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 订单创建人
*/
private String username;
/**
* 场地号
*/
private String placeName;
/**
* 所属日期
*/
private LocalDate date;
/**
* 订单状态 0:待付款1:已付款)
*/
private Integer orderStatus;
}

View File

@@ -1,37 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.entity.pojo;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Author: xiang
* @Date: 2025-12-16 09:18
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("jntyzx_user_token_info")
public class UserTokenInfoDO {
private Long id;
/**
* 用户名
*/
private String name;
/**
* token
*/
private String token;
/**
* wx openid
*/
private String openId;
/**
* 状态(0:禁用 1:启用)
*/
private Integer status;
}

View File

@@ -1,72 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.entity.pojo;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* @Author: xiang
* @Date: 2025-12-15 15:48
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("jntyzx_venue_info")
public class VenueInfoDO {
private Long id;
/**
* 场地名称
*/
private String placeName;
/**
* 所属日期
*/
private LocalDate date;
/**
* 场地信息三方主键
*/
private Long placeMainId;
/**
* 场地id
*/
private Integer placeId;
/**
*
*/
private Integer scheduleId;
/**
* 时间范围
*/
private String sjName;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 联系人
*/
private String contacts;
/**
* 状态
*/
private Integer type;
private BigDecimal money;
private String className;
private String classCode;
private String appointments;
private String cTypeCode;
}

View File

@@ -1,23 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.entity.req;
import com.alibaba.fastjson2.JSONObject;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @Author: xiang
* @Date: 2025-12-15 16:34
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SubscribeRequest {
private JSONObject jsonObject;
private List<SubscribeVo> subscribeVos;
private String bookTime;
private Integer paymentMethod;
private String svCiphertext;
}

View File

@@ -1,60 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.entity.req;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/**
* @Author: xiang
* @Date: 2025-12-15 16:35
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SubscribeVo {
private int id;
private String ballCourtId;
private String sjName;
private String scheduleId;
private String placeName;
private int placeId;
private String type;
private String className;
private String classCode;
private BigDecimal money;
private String contacts;
private String contactNumber;
private String memberNumber;
private String appointments;
private String operator;
private String endTime;
private String beginTime;
private int specOneTimes;
private String ctypeCode;
private int isWhole;
private String orderId;
private int votesnum;
}

View File

@@ -1,20 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.entity.resp;
import lombok.Data;
/**
* @Author: xiang
* @Date: 2025-05-14 14:38
*/
@Data
public class JntyzxResponse<T> {
private Boolean success;
private String message;
private Integer code;
private T result;
private Long timestamp;
}

View File

@@ -1,18 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.entity.resp;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Author: xiang
* @Date: 2025-12-16 10:36
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OrderCreateResp {
private String id;
private String countDownNum;
}

View File

@@ -1,16 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.entity.resp.query;
import lombok.Data;
import java.util.List;
/**
* @Author: xiang
* @Date: 2025-05-14 14:37
*/
@Data
public class QueryVenueResponse {
private List<TimeList> timeList;
private List<VenueList> venue;
}

View File

@@ -1,56 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.entity.resp.query;
import lombok.Data;
import java.math.BigDecimal;
/**
* @Author: xiang
* @Date: 2025-05-14 14:45
*/
@Data
public class SitePositionList {
private Long id;
private String ballCourtId;
private String sjName;
private String scheduleId;
private String placeName;
private Integer placeId;
private Integer type;
private String className;
private String classCode;
private BigDecimal money;
private String contacts;
private String contactNumber;
private String memberNumber;
private String appointments;
private String operator;
private String endTime;
private String beginTime;
private Integer specOneTimes;
private String ctypeCode;
private String isWhole;
private Long orderId;
private Integer votesnum;
}

View File

@@ -1,32 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.entity.resp.query;
import lombok.Data;
/**
* @Author: xiang
* @Date: 2025-05-14 14:39
*/
@Data
public class TimeList {
private Long id;
private String name;
private String beginTime;
private String endTime;
private String type;
private String isenable;
private String operator;
private String createtime;
private String remarks;
private String default01;
private String default02;
private String default03;
private String votesnum;
}

View File

@@ -1,20 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.entity.resp.query;
import lombok.Data;
import java.util.List;
/**
* @Author: xiang
* @Date: 2025-05-14 14:39
*/
@Data
public class VenueList {
private Integer placeId;
private String placeName;
private List<SitePositionList> sitePosition;
}

View File

@@ -1,17 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.manage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xiang.xservice.application.script.jntyzx.entity.pojo.OrderInfoDO;
import java.util.List;
/**
* @Author: xiang
* @Date: 2025-12-16 10:59
*/
public interface IOrderCreateInfoManage extends IService<OrderInfoDO> {
List<OrderInfoDO> queryNoPayOrder();
}

View File

@@ -1,16 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.manage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xiang.xservice.application.script.jntyzx.entity.pojo.UserTokenInfoDO;
import java.util.List;
/**
* @Author: xiang
* @Date: 2025-12-16 09:19
*/
public interface IUserTokenInfoManage extends IService<UserTokenInfoDO> {
List<UserTokenInfoDO> listUser();
UserTokenInfoDO getByName(String name);
}

View File

@@ -1,18 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.manage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xiang.xservice.application.script.jntyzx.entity.pojo.VenueInfoDO;
import java.time.LocalDate;
import java.util.List;
/**
* @Author: xiang
* @Date: 2025-12-15 15:50
*/
public interface IVenueInfoManage extends IService<VenueInfoDO> {
List<VenueInfoDO> queryByDate(LocalDate date);
List<VenueInfoDO> queryByType(LocalDate date, Integer type);
}

View File

@@ -1,26 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.manage;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiang.xservice.application.script.jntyzx.entity.pojo.OrderInfoDO;
import com.xiang.xservice.application.script.jntyzx.mapper.JntyzxOrderCreateInfoMapper;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @Author: xiang
* @Date: 2025-12-16 10:59
*/
@Service
public class OrderCreateInfoManageImpl extends ServiceImpl<JntyzxOrderCreateInfoMapper, OrderInfoDO> implements IOrderCreateInfoManage {
@Override
public List<OrderInfoDO> queryNoPayOrder() {
LambdaQueryWrapper<OrderInfoDO> lambdaQueryWrapper = Wrappers.lambdaQuery();
lambdaQueryWrapper.eq(OrderInfoDO::getOrderStatus, 0);
return baseMapper.selectList(lambdaQueryWrapper);
}
}

View File

@@ -1,32 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.manage;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiang.xservice.application.script.jntyzx.entity.pojo.UserTokenInfoDO;
import com.xiang.xservice.application.script.jntyzx.mapper.JntyzxUserTokenInfoMapper;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @Author: xiang
* @Date: 2025-12-16 09:19
*/
@Service
public class UserTokenInfoManageImpl extends ServiceImpl<JntyzxUserTokenInfoMapper, UserTokenInfoDO> implements IUserTokenInfoManage {
@Override
public List<UserTokenInfoDO> listUser() {
LambdaQueryWrapper<UserTokenInfoDO> lambdaQueryWrapper = Wrappers.lambdaQuery();
lambdaQueryWrapper.eq(UserTokenInfoDO::getStatus, 1);
return baseMapper.selectList(lambdaQueryWrapper);
}
@Override
public UserTokenInfoDO getByName(String name) {
LambdaQueryWrapper<UserTokenInfoDO> lambdaQueryWrapper = Wrappers.lambdaQuery();
lambdaQueryWrapper.eq(UserTokenInfoDO::getStatus, 1);
lambdaQueryWrapper.eq(UserTokenInfoDO::getName, name);
return baseMapper.selectOne(lambdaQueryWrapper);
}
}

View File

@@ -1,33 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.manage;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiang.xservice.application.script.jntyzx.entity.pojo.VenueInfoDO;
import com.xiang.xservice.application.script.jntyzx.mapper.JntyzxVenueInfoMapper;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.util.List;
/**
* @Author: xiang
* @Date: 2025-12-15 15:51
*/
@Service
public class VenueInfoManageImpl extends ServiceImpl<JntyzxVenueInfoMapper, VenueInfoDO> implements IVenueInfoManage {
public List<VenueInfoDO> queryByDate(LocalDate date) {
LambdaQueryWrapper<VenueInfoDO> lqw = Wrappers.lambdaQuery();
lqw.eq(VenueInfoDO::getDate, date);
return baseMapper.selectList(lqw);
}
@Override
public List<VenueInfoDO> queryByType(LocalDate date, Integer type) {
LambdaQueryWrapper<VenueInfoDO> lqw = Wrappers.lambdaQuery();
lqw.eq(VenueInfoDO::getDate, date);
lqw.eq(VenueInfoDO::getType, type);
return baseMapper.selectList(lqw);
}
}

View File

@@ -1,15 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xiang.xservice.application.script.jntyzx.entity.pojo.OrderInfoDO;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
/**
* @Author: xiang
* @Date: 2025-12-16 10:58
*/
@Mapper
@Repository
public interface JntyzxOrderCreateInfoMapper extends BaseMapper<OrderInfoDO> {
}

View File

@@ -1,15 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xiang.xservice.application.script.jntyzx.entity.pojo.UserTokenInfoDO;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
/**
* @Author: xiang
* @Date: 2025-12-16 09:18
*/
@Mapper
@Repository
public interface JntyzxUserTokenInfoMapper extends BaseMapper<UserTokenInfoDO> {
}

View File

@@ -1,15 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xiang.xservice.application.script.jntyzx.entity.pojo.VenueInfoDO;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
/**
* @Author: xiang
* @Date: 2025-12-15 15:48
*/
@Mapper
@Repository
public interface JntyzxVenueInfoMapper extends BaseMapper<VenueInfoDO> {
}

View File

@@ -1,21 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.schedule;
import com.xiang.xservice.application.script.jntyzx.service.IUserTokenInfoService;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* @Author: xiang
* @Date: 2025-12-16 09:15
*/
@Component
@RequiredArgsConstructor
public class JtTokenHealthSchedule {
private final IUserTokenInfoService userTokenInfoService;
@Scheduled(cron = "0 30 0/2 * * ?")
public void flushToken() {
userTokenInfoService.flushToken();
}
}

View File

@@ -1,129 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.schedule;
import com.xiang.xmc.service.cache.service.IRedisService;
import com.xiang.xservice.application.script.jntyzx.constants.RedisKeyConstant;
import com.xiang.xservice.application.script.jntyzx.entity.pojo.VenueInfoDO;
import com.xiang.xservice.application.script.jntyzx.service.DingTalkScriptVenueService;
import com.xiang.xservice.application.script.jntyzx.service.IJntyzxHttpService;
import com.xiang.xservice.application.script.jntyzx.service.IUserTokenInfoService;
import com.xiang.xservice.application.script.jntyzx.service.IVenueService;
import com.xiang.xservice.application.script.jntyzx.utils.VenueInfoUtils;
import com.xiang.xservice.basic.utils.DateUtils;
import com.xiang.xservice.common.entity.SysConfigDO;
import com.xiang.xservice.common.service.ISysConfigService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @Author: xiang
* @Date: 2025-12-15 16:12
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class VenuePeekSchedule {
private final IVenueService venueService;
private final IJntyzxHttpService jntyzxHttpService;
private final ISysConfigService sysConfigService;
private final IUserTokenInfoService userTokenInfoService;
private final DingTalkScriptVenueService dingTalkScriptVenueService;
private final IRedisService redisService;
@Scheduled(cron = "5 0/1 * * * ?")
public void peek8210() {
log.info("8-10捡漏定时任务启动");
SysConfigDO config = sysConfigService.getByName("jntyzx.venue.peek.switch");
boolean peekSwitch;
if (Objects.isNull(config)) {
peekSwitch = false;
} else {
if (StringUtils.equals(config.getValue(), "true")) {
peekSwitch = true;
} else {
peekSwitch = false;
}
}
if (peekSwitch) {
List<VenueInfoDO> venueInfoDOS = venueService.queryCanBuyVenue();
if (CollectionUtils.isEmpty(venueInfoDOS)) {
return;
}
Map<String, List<VenueInfoDO>> map = venueInfoDOS.stream()
.filter(VenueInfoUtils::get8210VenueInfo)
.collect(Collectors.groupingBy(VenueInfoDO::getPlaceName));
String token = userTokenInfoService.getToken("Xiang");
if (StringUtils.isBlank(token)) {
return;
}
String key = RedisKeyConstant.JNTUZX_ORDER_PEEK_KEY + "Xiang" + DateUtils.getDateFromDate(LocalDate.now(), "yyyyMMdd");
String redisResp = (String) redisService.get(key);
if (StringUtils.equals(redisResp, "true")) {
log.info("当前已捡漏,勿重复捡漏");
return;
}
map.keySet().parallelStream().forEach(placeName -> {
List<VenueInfoDO> venueInfoDOList = map.get(placeName);
Boolean order = jntyzxHttpService.createOrder(venueInfoDOList, token);
if (order) {
dingTalkScriptVenueService.sendScriptMsg("场地:" + placeName + "下单成功,请付款!时间:" + LocalDateTime.now());
redisService.set(key, "true");
}
});
}
}
@Scheduled(cron = "5 0/1 * * * ?")
public void peek628() {
log.info("6-8捡漏定时任务启动");
SysConfigDO config = sysConfigService.getByName("jntyzx.venue.peek.switch");
boolean peekSwitch;
if (Objects.isNull(config)) {
peekSwitch = false;
} else {
if (StringUtils.equals(config.getValue(), "true")) {
peekSwitch = true;
} else {
peekSwitch = false;
}
}
if (peekSwitch) {
List<VenueInfoDO> venueInfoDOS = venueService.queryCanBuyVenue();
if (CollectionUtils.isEmpty(venueInfoDOS)) {
return;
}
Map<String, List<VenueInfoDO>> map = venueInfoDOS.stream()
.filter(VenueInfoUtils::get628VenueInfo)
.collect(Collectors.groupingBy(VenueInfoDO::getPlaceName));
String token = userTokenInfoService.getToken("Xiang");
if (StringUtils.isBlank(token)) {
return;
}
String key = RedisKeyConstant.JNTUZX_ORDER_PEEK_KEY + "Xiang" + DateUtils.getDateFromDate(LocalDate.now(), "yyyyMMdd");
String redisResp = (String) redisService.get(key);
if (StringUtils.equals(redisResp, "true")) {
log.info("当前已捡漏,勿重复捡漏");
return;
}
map.keySet().parallelStream().forEach(placeName -> {
List<VenueInfoDO> venueInfoDOList = map.get(placeName);
Boolean order = jntyzxHttpService.createOrder(venueInfoDOList, token);
if (order) {
dingTalkScriptVenueService.sendScriptMsg("场地:" + placeName + "下单成功,请付款!时间:" + LocalDateTime.now());
redisService.set(key, "true");
}
});
}
}
}

View File

@@ -1,237 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.schedule;
import com.google.common.collect.Maps;
import com.xiang.xmc.service.cache.service.IRedisService;
import com.xiang.xservice.application.script.jntyzx.constants.RedisKeyConstant;
import com.xiang.xservice.application.script.jntyzx.entity.pojo.VenueInfoDO;
import com.xiang.xservice.application.script.jntyzx.entity.resp.query.SitePositionList;
import com.xiang.xservice.application.script.jntyzx.service.DingTalkScriptVenueService;
import com.xiang.xservice.application.script.jntyzx.service.IVenueService;
import com.xiang.xservice.common.entity.SysConfigDO;
import com.xiang.xservice.common.service.ISysConfigService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
* @Author: xiang
* @Date: 2025-12-15 15:02
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class VenueQuerySchedule {
private final IVenueService venueService;
private final DingTalkScriptVenueService dingTalkScriptVenueService;
private final ISysConfigService sysConfigService;
private final IRedisService redisService;
@Scheduled(cron = "0 30 8 * * ?")
public void venueQueryTask() {
log.info("每日8:30拉取江体小程序数据定时任务");
List<SitePositionList> sitePositionLists = venueService.queryTomorrowVenue();
// 6-8场地
Map<String, List<SitePositionList>> map1 = Maps.newLinkedHashMap();
// 8-10场地
Map<String, List<SitePositionList>> map2 = Maps.newLinkedHashMap();
sitePositionLists.stream()
.filter(item -> StringUtils.equals(item.getSjName(), "18:00-19:00") || StringUtils.equals(item.getSjName(), "19:00-20:00")
|| StringUtils.equals(item.getSjName(), "20:00-21:00") || StringUtils.equals(item.getSjName(), "21:00-22:00"))
.forEach(item -> {
if (StringUtils.equals(item.getSjName(), "18:00-19:00")) {
putIntoMap(item, map1);
}
if (StringUtils.equals(item.getSjName(), "19:00-20:00")) {
putIntoMap(item, map1);
}
if (StringUtils.equals(item.getSjName(), "20:00-21:00")) {
putIntoMap(item, map2);
}
if (StringUtils.equals(item.getSjName(), "21:00-22:00")) {
putIntoMap(item, map2);
}
});
if (MapUtils.isNotEmpty(map1)) {
StringBuffer sb1 = new StringBuffer("查询江体小程序场地信息【18:00-20:00】\n");
buildMsg2(map1, sb1);
String s = (String) redisService.get(RedisKeyConstant.JNTYZX_VENUE_MSG_628_KEY);
if (StringUtils.isBlank(s)) {
dingTalkScriptVenueService.sendScriptMsg(sb1.toString());
redisService.set(RedisKeyConstant.JNTYZX_VENUE_MSG_628_KEY, "true", 30, TimeUnit.MINUTES);
}
}
if (MapUtils.isNotEmpty(map2)) {
StringBuffer sb2 = new StringBuffer("查询江体小程序场地信息【20:00-22:00】\n");
buildMsg2(map2, sb2);
String s = (String) redisService.get(RedisKeyConstant.JNTYZX_VENUE_MSG_8210_KEY);
if (StringUtils.isBlank(s)) {
dingTalkScriptVenueService.sendScriptMsg(sb2.toString());
redisService.set(RedisKeyConstant.JNTYZX_VENUE_MSG_8210_KEY, "true", 30, TimeUnit.MINUTES);
}
}
}
@Scheduled(cron = "0 0/1 9-10 * * ?")
public void venueQueryTask49210() {
log.info("每日9-10点时刻拉取江体小程序数据定时任务");
venueService.queryVenueService();
}
@Scheduled(cron = "0 0/10 10-12 * * ?")
public void venueQueryTask4Free() {
log.info("每日空闲时刻10-12点拉取江体小程序数据定时任务");
venueService.queryVenueService();
}
@Scheduled(cron = "1 0/5 12-17 * * ?")
public void venueQueryTask4Normal() {
log.info("每日正常时刻12-17点拉取江体小程序数据定时任务");
venueService.queryVenueService();
}
@Scheduled(cron = "2 0/2 17-20 * * ?")
public void venueQueryTask4Urgency() {
log.info("每日紧急时刻17-20点拉取江体小程序数据定时任务");
venueService.queryVenueService();
}
@Scheduled(cron = "0 0 17 * * ?")
public void todayVenueInfo() {
log.info("每日拉取江体小程序数据定时任务");
List<VenueInfoDO> venueInfoDOS = venueService.queryToday6210VenueInfo();
if (CollectionUtils.isEmpty(venueInfoDOS)) {
return;
}
// 6-8场地
Map<String, List<VenueInfoDO>> map1 = Maps.newLinkedHashMap();
// 8-10场地
Map<String, List<VenueInfoDO>> map2 = Maps.newLinkedHashMap();
venueInfoDOS.forEach(item -> {
if (StringUtils.equals(item.getSjName(), "18:00-19:00")) {
putIntoMap(item, map1);
}
if (StringUtils.equals(item.getSjName(), "19:00-20:00")) {
putIntoMap(item, map1);
}
if (StringUtils.equals(item.getSjName(), "20:00-21:00")) {
putIntoMap(item, map2);
}
if (StringUtils.equals(item.getSjName(), "21:00-22:00")) {
putIntoMap(item, map2);
}
});
if (MapUtils.isNotEmpty(map1)) {
StringBuffer sb1 = new StringBuffer("查询江体小程序场地信息【18:00-20:00】\n");
buildMsg(map1, sb1);
dingTalkScriptVenueService.sendScriptMsg(sb1.toString());
}
if (MapUtils.isNotEmpty(map1)) {
StringBuffer sb2 = new StringBuffer("查询江体小程序场地信息【20:00-22:00】\n");
buildMsg(map2, sb2);
dingTalkScriptVenueService.sendScriptMsg(sb2.toString());
}
}
@Scheduled(cron = "0 0/1 9-20 * * ?")
public void venueCanBuyMsg() {
List<VenueInfoDO> venueInfoDOS = venueService.queryCanBuyVenue();
if (CollectionUtils.isEmpty(venueInfoDOS)) {
return;
}
SysConfigDO config = sysConfigService.getByName("jntyzx.order.create.xiaoguan.switch");
boolean orderSwitch;
if (Objects.nonNull(config)) {
String value = config.getValue();
if (StringUtils.equals(value, "true")) {
orderSwitch = true;
} else {
orderSwitch = false;
}
} else {
orderSwitch = false;
}
// 6-8场地
Map<String, List<VenueInfoDO>> map1 = Maps.newLinkedHashMap();
// 8-10场地
Map<String, List<VenueInfoDO>> map2 = Maps.newLinkedHashMap();
venueInfoDOS.stream()
.filter(item -> StringUtils.equals(item.getSjName(), "18:00-19:00") || StringUtils.equals(item.getSjName(), "19:00-20:00")
|| StringUtils.equals(item.getSjName(), "20:00-21:00") || StringUtils.equals(item.getSjName(), "21:00-22:00"))
.filter(item -> {
if (!orderSwitch) {
return !item.getPlaceName().contains("小馆");
}
return false;
})
.forEach(item -> {
if (StringUtils.equals(item.getSjName(), "18:00-19:00")) {
putIntoMap(item, map1);
}
if (StringUtils.equals(item.getSjName(), "19:00-20:00")) {
putIntoMap(item, map1);
}
if (StringUtils.equals(item.getSjName(), "20:00-21:00")) {
putIntoMap(item, map2);
}
if (StringUtils.equals(item.getSjName(), "21:00-22:00")) {
putIntoMap(item, map2);
}
});
if (MapUtils.isNotEmpty(map1) && LocalTime.now().isBefore(LocalTime.of(18, 0, 0))) {
StringBuffer sb1 = new StringBuffer("查询江体小程序场地信息【18:00-20:00】\n");
buildMsg(map1, sb1);
dingTalkScriptVenueService.sendScriptMsg(sb1.toString());
}
if (MapUtils.isNotEmpty(map2) && LocalTime.now().isBefore(LocalTime.of(20, 0, 0))) {
StringBuffer sb2 = new StringBuffer("查询江体小程序场地信息【20:00-22:00】\n");
buildMsg(map2, sb2);
dingTalkScriptVenueService.sendScriptMsg(sb2.toString());
}
}
private static void buildMsg(Map<String, List<VenueInfoDO>> map1, StringBuffer sb1) {
map1.forEach((k, v) -> {
VenueInfoDO sitePositionList1 = v.get(0);
VenueInfoDO sitePositionList2 = v.get(1);
String contacts = sitePositionList1.getContacts();
if (!StringUtils.equals(sitePositionList1.getContacts(), sitePositionList2.getContacts())) {
contacts = sitePositionList1.getContacts() + "" + sitePositionList2.getContacts();
}
sb1.append(k).append("场地,订购人:").append(contacts).append("\n");
});
}
private static void buildMsg2(Map<String, List<SitePositionList>> map1, StringBuffer sb1) {
map1.forEach((k, v) -> {
SitePositionList sitePositionList1 = v.get(0);
SitePositionList sitePositionList2 = v.get(1);
String contacts = sitePositionList1.getContacts();
if (!StringUtils.equals(sitePositionList1.getContacts(), sitePositionList2.getContacts())) {
contacts = sitePositionList1.getContacts() + "" + sitePositionList2.getContacts();
}
sb1.append(k).append("场地,订购人:").append(contacts).append("\n");
});
}
private static void putIntoMap(VenueInfoDO item, Map<String, List<VenueInfoDO>> map1) {
map1.computeIfAbsent(item.getPlaceName(),
k -> new ArrayList<>()
).add(item);
}
private static void putIntoMap(SitePositionList item, Map<String, List<SitePositionList>> map1) {
map1.computeIfAbsent(item.getPlaceName(),
k -> new ArrayList<>()
).add(item);
}
}

View File

@@ -1,68 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.schedule;
import com.xiang.xmc.service.cache.service.IRedisService;
import com.xiang.xservice.application.script.jntyzx.constants.RedisKeyConstant;
import com.xiang.xservice.application.script.jntyzx.entity.pojo.OrderInfoDO;
import com.xiang.xservice.application.script.jntyzx.entity.pojo.VenueInfoDO;
import com.xiang.xservice.application.script.jntyzx.service.DingTalkScriptVenueService;
import com.xiang.xservice.application.script.jntyzx.service.IJntyzxHttpService;
import com.xiang.xservice.application.script.jntyzx.service.IJtOrderService;
import com.xiang.xservice.application.script.jntyzx.service.IUserTokenInfoService;
import com.xiang.xservice.application.script.jntyzx.service.IVenueService;
import com.xiang.xservice.application.script.jntyzx.utils.VenueInfoUtils;
import com.xiang.xservice.basic.utils.DateUtils;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @Author: xiang
* @Date: 2025-12-16 14:26
*/
@Component
@RequiredArgsConstructor
public class VenueSubscribeSchedule {
private final IVenueService venueService;
private final IJntyzxHttpService jntyzxHttpService;
private final IUserTokenInfoService userTokenInfoService;
private final DingTalkScriptVenueService dingTalkScriptVenueService;
private final IJtOrderService orderService;
private final IRedisService redisService;
@Scheduled(cron = "0 0 9 * * ?")
public void subscribe() {
List<VenueInfoDO> venueInfoDOS = venueService.queryCanBuyVenue();
if (CollectionUtils.isEmpty(venueInfoDOS)) {
return;
}
Map<String, List<VenueInfoDO>> map = venueInfoDOS.stream().filter(VenueInfoUtils::get1221VenueInfo4Mor).collect(Collectors.groupingBy(VenueInfoDO::getPlaceName));
String token = userTokenInfoService.getToken("Xiang");
if (StringUtils.isBlank(token)) {
return;
}
String key = RedisKeyConstant.JNTUZX_ORDER_PEEK_KEY + "Xiang" + DateUtils.getDateFromDate(LocalDate.now(), "yyyyMMdd");
map.keySet().parallelStream().forEach(placeName -> {
List<VenueInfoDO> venueInfoDOList = map.get(placeName);
Boolean order = jntyzxHttpService.createOrder(venueInfoDOList, token);
if (order) {
dingTalkScriptVenueService.sendScriptMsg("场地:" + placeName + "下单成功,请付款!时间:" + LocalDateTime.now());
redisService.set(key, "true");
}
});
}
@Scheduled(cron = "0 0/2 * * * ?")
public void checkPay() {
List<OrderInfoDO> orderInfoDOS = orderService.queryNoPayOrder();
if (CollectionUtils.isEmpty(orderInfoDOS)) {
return;
}
}
}

View File

@@ -1,33 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.service;
import com.xiang.xmc.service.message.dingTalk.service.DingTalkService;
import com.xiang.xservice.config.DingTalkRobotVenueConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @Author: xiang
* @Date: 2025-08-07 10:30
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class DingTalkScriptVenueService {
private final DingTalkService dingTalkService;
private final DingTalkRobotVenueConfig dingTalkRobotVenueConfig;
/**
* 发送脚本消息
* @param msg 消息
*/
public void sendScriptMsg(String msg) {
try {
dingTalkService.sendRobotMessage(dingTalkRobotVenueConfig.getSecret(), dingTalkRobotVenueConfig.getToken(),
dingTalkRobotVenueConfig.getUsers(), msg);
} catch (Exception e) {
log.error("信息发送异常, 信息:{}", msg, e);
}
}
}

View File

@@ -1,35 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.service;
import com.xiang.xservice.application.script.jntyzx.entity.pojo.VenueInfoDO;
import com.xiang.xservice.application.script.jntyzx.entity.resp.JntyzxResponse;
import com.xiang.xservice.application.script.jntyzx.entity.resp.query.SitePositionList;
import java.util.List;
/**
* @Author: xiang
* @Date: 2025-12-15 14:47
*/
public interface IJntyzxHttpService {
/**
* 查询今日可用场地
*/
List<SitePositionList> queryAvailable(String isWeekend, String token);
List<SitePositionList> queryAvailableTomorrow(String isWeekend, String token);
/**
* 订单创建
* @return
*/
Boolean createOrder(List<VenueInfoDO> venueInfos, String token);
/**
* 心跳监测
* @param token token
* @param openId openid
* @return
*/
JntyzxResponse healthDeclaration(String token, String openId);
}

View File

@@ -1,14 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.service;
import com.xiang.xservice.application.script.jntyzx.entity.pojo.OrderInfoDO;
import java.util.List;
/**
* @Author: xiang
* @Date: 2025-12-16 16:17
*/
public interface IJtOrderService {
List<OrderInfoDO> queryNoPayOrder();
}

View File

@@ -1,14 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.service;
/**
* @Author: xiang
* @Date: 2025-12-16 09:22
*/
public interface IUserTokenInfoService {
String getToken(String name);
boolean flushSingleToken(String name);
boolean flushToken();
boolean updateTokenByName(String name, String token);
}

View File

@@ -1,18 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.service;
import com.xiang.xservice.application.script.jntyzx.entity.pojo.VenueInfoDO;
import com.xiang.xservice.application.script.jntyzx.entity.resp.query.SitePositionList;
import java.util.List;
/**
* @Author: xiang
* @Date: 2025-12-15 16:07
*/
public interface IVenueService {
List<SitePositionList> queryVenueService();
List<SitePositionList> queryTomorrowVenue();
List<VenueInfoDO> queryCanBuyVenue();
List<VenueInfoDO> queryToday6210VenueInfo();
}

View File

@@ -1,242 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.service;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.xiang.xmc.service.cache.service.IRedisService;
import com.xiang.xmc.service.http.helper.HttpHelper;
import com.xiang.xservice.application.script.jntyzx.constants.RedisKeyConstant;
import com.xiang.xservice.application.script.jntyzx.constants.UrlConstant;
import com.xiang.xservice.application.script.jntyzx.entity.pojo.OrderInfoDO;
import com.xiang.xservice.application.script.jntyzx.entity.pojo.VenueInfoDO;
import com.xiang.xservice.application.script.jntyzx.entity.req.SubscribeRequest;
import com.xiang.xservice.application.script.jntyzx.entity.req.SubscribeVo;
import com.xiang.xservice.application.script.jntyzx.entity.resp.JntyzxResponse;
import com.xiang.xservice.application.script.jntyzx.entity.resp.OrderCreateResp;
import com.xiang.xservice.application.script.jntyzx.entity.resp.query.SitePositionList;
import com.xiang.xservice.application.script.jntyzx.entity.resp.query.VenueList;
import com.xiang.xservice.application.script.jntyzx.manage.IOrderCreateInfoManage;
import com.xiang.xservice.basic.utils.Base64;
import com.xiang.xservice.basic.utils.JsonUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* @Author: xiang
* @Date: 2025-05-14 14:07
*/
@Service
@RequiredArgsConstructor
@Slf4j
public class JntyzxHttpServiceImpl implements IJntyzxHttpService {
private final IRedisService redisService;
private final IOrderCreateInfoManage orderCreateInfoManage;
@Override
public List<SitePositionList> queryAvailable(String isWeekend, String token) {
String url = UrlConstant.QUERY_TODAY_SUBSCRIBE_URL;
return querySitePositionInfo(isWeekend, token, url);
}
@NotNull
private static List<SitePositionList> querySitePositionInfo(String isWeekend, String token, String url) {
Map<String, String> header = Maps.newHashMap();
header.put("X-Access-Token", token);
String resp = null;
Map<String, String> params = Maps.newHashMap();
params.put("gid", "03");
params.put("isWeekend", isWeekend);
try {
resp = HttpHelper.doGet(url, header, params);
} catch (Exception e) {
log.error("[doGet] 江南体育中心查询当天场地 请求失败, url:{}", url);
return Lists.newArrayList();
}
if (StringUtils.isEmpty(resp)) {
log.warn("[查询场地] 江南体育中心查询当天场地 请求结果为空, url:{}, resp:{}", url, resp);
return Lists.newArrayList();
}
JSONObject jsonObject = JSON.parseObject(resp);
if (Objects.isNull(jsonObject)) {
return Lists.newArrayList();
}
String resultStr = JSON.toJSONString(jsonObject.get("result"));
if (StringUtils.isBlank(resultStr)) {
return Lists.newArrayList();
}
JSONObject result = JSON.parseObject(resultStr);
if (Objects.isNull(result)) {
return Lists.newArrayList();
}
String venueStr = JSON.toJSONString(result.get("venue"));
if (StringUtils.isBlank(venueStr)) {
return Lists.newArrayList();
}
List<VenueList> venueLists = JSON.parseArray(venueStr, VenueList.class);
if (CollectionUtils.isEmpty(venueLists)) {
return Lists.newArrayList();
}
List<SitePositionList> res = Lists.newArrayList();
for (VenueList venueList : venueLists) {
List<SitePositionList> sitePositionList = venueList.getSitePosition();
if (CollectionUtils.isEmpty(sitePositionList)) {
continue;
}
res.addAll(sitePositionList);
}
return res;
}
@Override
public List<SitePositionList> queryAvailableTomorrow(String isWeekend, String token) {
String url = UrlConstant.QUERY_TOMORROW_SUBSCRIBE_URL;
return querySitePositionInfo(isWeekend, token, url);
}
@Override
public Boolean createOrder(List<VenueInfoDO> venueInfos, String token) {
List<SubscribeVo> vos = Lists.newArrayList();
for (VenueInfoDO venueInfo : venueInfos) {
SubscribeVo subscribeVo = new SubscribeVo();
subscribeVo.setId(0);
subscribeVo.setBallCourtId("03");
subscribeVo.setSjName(venueInfo.getSjName());
subscribeVo.setScheduleId(String.valueOf(venueInfo.getScheduleId()));
subscribeVo.setPlaceName(venueInfo.getPlaceName());
subscribeVo.setPlaceId(venueInfo.getPlaceId());
subscribeVo.setType("0");
subscribeVo.setClassName(venueInfo.getClassName());
subscribeVo.setClassCode(venueInfo.getClassCode());
subscribeVo.setMoney(venueInfo.getMoney().setScale(0));
subscribeVo.setContacts("0");
subscribeVo.setContactNumber(null);
subscribeVo.setMemberNumber(null);
subscribeVo.setAppointments(venueInfo.getAppointments());
subscribeVo.setOperator(null);
subscribeVo.setEndTime(null);
subscribeVo.setBeginTime(null);
subscribeVo.setSpecOneTimes(3);
subscribeVo.setCtypeCode(venueInfo.getCTypeCode());
subscribeVo.setIsWhole(0);
subscribeVo.setOrderId(null);
subscribeVo.setVotesnum(1);
vos.add(subscribeVo);
}
JSONObject jsonObject = buildParamJsonObj();
SubscribeRequest subscribeRequest = new SubscribeRequest();
subscribeRequest.setSubscribeVos(vos);
subscribeRequest.setBookTime(venueInfos.get(0).getAppointments());
subscribeRequest.setPaymentMethod(1);
subscribeRequest.setSvCiphertext(sonAddSalt(JsonUtils.toJsonString(vos)));
subscribeRequest.setJsonObject(jsonObject);
Map<String, String> params = Maps.newHashMap();
params.put("X-Access-Token", token);
String resp = HttpHelper.doPost(UrlConstant.ADD_SUBSCRIBE, params, JsonUtils.toJsonString(subscribeRequest));
if (StringUtils.isBlank(resp)) {
log.info("请求结果为空");
return false;
}
JntyzxResponse<OrderCreateResp> response = JSON.parseObject(resp, new TypeReference<JntyzxResponse<OrderCreateResp>>() {
});
if (Objects.isNull(response)) {
log.info("请求结果为空");
return false;
}
if (response.getSuccess()) {
OrderCreateResp createResp = response.getResult();
if (Objects.nonNull(createResp)) {
String orderId = createResp.getId();
redisService.set(RedisKeyConstant.JNTYZX_ORDER_CREATE_KEY + orderId, String.valueOf(System.currentTimeMillis()));
OrderInfoDO orderInfoDO = new OrderInfoDO();
orderInfoDO.setOrderId(orderId);
orderInfoDO.setParams(JsonUtils.toJsonString(subscribeRequest));
orderInfoDO.setCreateTime(LocalDateTime.now());
orderInfoDO.setUsername(token);
orderInfoDO.setPlaceName(vos.get(0).getPlaceName());
orderInfoDO.setDate(LocalDate.now());
orderInfoDO.setOrderStatus(0);
orderCreateInfoManage.save(orderInfoDO);
return true;
}
}
return false;
}
@Override
public JntyzxResponse healthDeclaration(String token, String openId) {
Map<String, String> headers = Maps.newHashMap();
headers.put("X-Access-Token", token);
Map<String, String> params = Maps.newHashMap();
params.put("openId", openId);
String respStr = HttpHelper.doGet(UrlConstant.HEALTH_DECLARATION, headers, params);
if (StringUtils.isBlank(respStr)) {
return null;
}
return JSON.parseObject(respStr, JntyzxResponse.class);
}
private static JSONObject buildParamJsonObj() {
JSONObject jsonObject = new JSONObject();
jsonObject.put("id", "1702581215097257986");
jsonObject.put("createBy", null);
jsonObject.put("createTime", "2023-09-15 15:12:48");
jsonObject.put("updateBy", null);
jsonObject.put("updateTime", null);
jsonObject.put("sysOrgCode", null);
jsonObject.put("openId", "o21MX4y7whXCGjvUTGP6CTz2HbD8");
jsonObject.put("nickName", "1");
jsonObject.put("unionId", null);
jsonObject.put("avatarUrl", "https://thirdwx.qlogo.cn/mmopen/vi_32/POgEwh4mIHO4nibH0KlMECNjjGxQUq24ZEaGT4poC6icRiccVGKSyXwibcPq4BWmiaIGuG1icwxaQX6grC9VemZoJ8rg/132");
jsonObject.put("remarks", null);
jsonObject.put("default01", null);
jsonObject.put("default02", null);
jsonObject.put("default03", null);
jsonObject.put("default04", null);
jsonObject.put("default05", null);
return jsonObject;
}
private static int[] getMonthAndDay() {
LocalDate currentDate = LocalDate.now();
int month = currentDate.getMonthValue();
int day = currentDate.getDayOfMonth();
return new int[]{month, day};
}
private String sonAddSalt(String json) {
String svCiphertext = "";
String suiji = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
String token1 = String.valueOf(suiji.charAt((int) (Math.random() * (double) suiji.length())));
String token2 = String.valueOf(suiji.charAt((int) (Math.random() * (double) suiji.length())));
svCiphertext = Base64.encode(json.getBytes(StandardCharsets.UTF_8));
int[] monthAndDay = getMonthAndDay();
int month = monthAndDay[0];
int day = monthAndDay[1];
if (month == 1) {
svCiphertext = (svCiphertext = token1 + svCiphertext).substring(0, day - 1) + token2 + svCiphertext.substring(day - 1);
} else if (day == 1) {
svCiphertext = token2 + svCiphertext.substring(0, month - 1) + token1 + svCiphertext.substring(month - 1);
} else {
svCiphertext = (svCiphertext = svCiphertext.substring(0, month - 1) + token1 + svCiphertext.substring(month - 1)).substring(0, day - 1) + token2 + svCiphertext.substring(day - 1);
}
return svCiphertext;
}
}

View File

@@ -1,23 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.service;
import com.xiang.xservice.application.script.jntyzx.entity.pojo.OrderInfoDO;
import com.xiang.xservice.application.script.jntyzx.manage.IOrderCreateInfoManage;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @Author: xiang
* @Date: 2025-12-16 16:17
*/
@Service
@RequiredArgsConstructor
public class OrderInfoServiceImpl implements IJtOrderService {
private final IOrderCreateInfoManage orderCreateInfoManage;
@Override
public List<OrderInfoDO> queryNoPayOrder() {
return orderCreateInfoManage.queryNoPayOrder();
}
}

View File

@@ -1,83 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.service;
import com.xiang.xservice.application.script.jntyzx.entity.pojo.UserTokenInfoDO;
import com.xiang.xservice.application.script.jntyzx.entity.resp.JntyzxResponse;
import com.xiang.xservice.application.script.jntyzx.manage.IUserTokenInfoManage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Objects;
/**
* @Author: xiang
* @Date: 2025-12-16 09:22
*/
@Service
@Slf4j
@RequiredArgsConstructor
public class UserTokenInfoServiceImpl implements IUserTokenInfoService {
private final IUserTokenInfoManage userTokenInfoManage;
private final IJntyzxHttpService jntyzxHttpService;
private final DingTalkScriptVenueService dingTalkScriptVenueService;
@Override
public String getToken(String name) {
UserTokenInfoDO userTokenInfoDO = userTokenInfoManage.getByName(name);
if (Objects.isNull(userTokenInfoDO)) {
return null;
}
return userTokenInfoDO.getToken();
}
@Override
public boolean flushSingleToken(String name) {
UserTokenInfoDO userTokenInfoDO = userTokenInfoManage.getByName(name);
if (Objects.isNull(userTokenInfoDO)) {
log.info("用户信息不存在,无需进行监测!");
return false;
}
return healthDeclaration(userTokenInfoDO);
}
@Override
public boolean flushToken() {
List<UserTokenInfoDO> userTokenInfoDOS = userTokenInfoManage.listUser();
if (CollectionUtils.isEmpty(userTokenInfoDOS)) {
log.info("【心跳监测】查询用户信息为空,无需操作");
return true;
}
userTokenInfoDOS.parallelStream().forEach(this::healthDeclaration);
return true;
}
@Override
public boolean updateTokenByName(String name, String token) {
UserTokenInfoDO userTokenInfoDO = userTokenInfoManage.getByName(name);
if (Objects.isNull(userTokenInfoDO)) {
return false;
}
userTokenInfoDO.setToken(token);
return userTokenInfoManage.updateById(userTokenInfoDO);
}
private boolean healthDeclaration(UserTokenInfoDO userTokenInfoDO) {
JntyzxResponse jntyzxResponse = jntyzxHttpService.healthDeclaration(userTokenInfoDO.getToken(), userTokenInfoDO.getOpenId());
if (Objects.isNull(jntyzxResponse)) {
log.info("用户名:{}心跳监测失败!", userTokenInfoDO.getName());
}
boolean flag = StringUtils.contains(jntyzxResponse.getMessage(), "已存在");
if (flag) {
log.info("用户名:{}心跳成功✅✅✅✅✅✅", userTokenInfoDO.getName());
} else {
dingTalkScriptVenueService.sendScriptMsg("用户名:" + userTokenInfoDO.getName() + "心跳失败,消息:" + jntyzxResponse.getMessage());
}
return flag;
}
}

View File

@@ -1,133 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.service;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.xiang.xservice.application.script.jntyzx.entity.pojo.VenueInfoDO;
import com.xiang.xservice.application.script.jntyzx.entity.resp.query.SitePositionList;
import com.xiang.xservice.application.script.jntyzx.manage.IVenueInfoManage;
import com.xiang.xservice.application.script.jntyzx.utils.VenueInfoUtils;
import com.xiang.xservice.basic.utils.DateUtils;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @Author: xiang
* @Date: 2025-12-15 16:08
*/
@Service
@RequiredArgsConstructor
public class VenueServiceImpl implements IVenueService {
// private final static String STATIC_TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3NjU4NTI4MjYsInVzZXJuYW1lIjoid3hfb3Blbl9pZF9vMjFNWDR5N3doWENHanZVVEdQNkNUejJIYkQ4In0.pI1tK1imZdKZWXdHRxseqq87_IarHhiRt-hUdBq8hkg";
private final IJntyzxHttpService jntyzxHttpService;
private final IVenueInfoManage venueInfoManage;
private final IUserTokenInfoService userTokenInfoService;
@Override
public List<SitePositionList> queryVenueService() {
String token = userTokenInfoService.getToken("Xiang");
if (StringUtils.isBlank(token)) {
return Lists.newArrayList();
}
List<SitePositionList> sitePositionLists = jntyzxHttpService.queryAvailable("1", token);
if (CollectionUtils.isEmpty(sitePositionLists)) {
return Lists.newArrayList();
}
updateDatabase(sitePositionLists, true);
return sitePositionLists;
}
@Override
public List<SitePositionList> queryTomorrowVenue() {
String token = userTokenInfoService.getToken("Xiang");
if (StringUtils.isBlank(token)) {
return Lists.newArrayList();
}
List<SitePositionList> sitePositionLists = jntyzxHttpService.queryAvailableTomorrow("1", token);
if (CollectionUtils.isEmpty(sitePositionLists)) {
return Lists.newArrayList();
}
updateDatabase(sitePositionLists, false);
return sitePositionLists;
}
@Override
public List<VenueInfoDO> queryCanBuyVenue() {
return venueInfoManage.queryByType(LocalDate.now(), 0);
}
@Override
public List<VenueInfoDO> queryToday6210VenueInfo() {
List<VenueInfoDO> venueInfoDOS = venueInfoManage.queryByDate(LocalDate.now());
return venueInfoDOS.stream().filter(item -> VenueInfoUtils.get628VenueInfo(item) || VenueInfoUtils.get8210VenueInfo(item)).toList();
}
private void updateDatabase(List<SitePositionList> list, boolean isToday) {
List<VenueInfoDO> venueInfoDOS = Lists.newArrayList();
if (isToday) {
venueInfoDOS.addAll(venueInfoManage.queryByDate(LocalDate.now()));
} else {
venueInfoDOS.addAll(venueInfoManage.queryByDate(LocalDate.now().plusDays(1)));
}
Map<Integer, List<VenueInfoDO>> map = Maps.newHashMap();
if (CollectionUtils.isNotEmpty(venueInfoDOS)) {
map.putAll(venueInfoDOS.stream().filter(Objects::nonNull)
.collect(Collectors.groupingBy(VenueInfoDO::getPlaceId)));
}
List<VenueInfoDO> insertList = Lists.newArrayList();
for (SitePositionList sitePositionList : list) {
if (map.containsKey(sitePositionList.getPlaceId())) {
List<VenueInfoDO> venueInfoDOList = map.get(sitePositionList.getPlaceId());
Map<String, VenueInfoDO> sjMap = venueInfoDOList.stream().collect(Collectors.toMap(VenueInfoDO::getSjName, Function.identity(), (a, b) -> a));
if (sjMap.containsKey(sitePositionList.getSjName())) {
VenueInfoDO venueInfoDO = sjMap.get(sitePositionList.getSjName());
if (!StringUtils.equals(venueInfoDO.getContacts(), sitePositionList.getContacts())
|| !Objects.equals(venueInfoDO.getType(), sitePositionList.getType())
|| !Objects.equals(venueInfoDO.getPlaceMainId(), sitePositionList.getId())) {
venueInfoDO.setContacts(sitePositionList.getContacts());
venueInfoDO.setType(sitePositionList.getType());
venueInfoDO.setPlaceMainId(sitePositionList.getId());
venueInfoManage.updateById(venueInfoDO);
}
} else {
addIntoInsert(sitePositionList, insertList);
}
} else {
addIntoInsert(sitePositionList, insertList);
}
}
if (CollectionUtils.isNotEmpty(insertList)) {
venueInfoManage.saveBatch(insertList);
}
}
private static void addIntoInsert(SitePositionList sitePositionList, List<VenueInfoDO> insertList) {
VenueInfoDO venueInfoDO = new VenueInfoDO();
venueInfoDO.setPlaceName(sitePositionList.getPlaceName());
venueInfoDO.setDate(DateUtils.getDateFromStr(sitePositionList.getAppointments()));
venueInfoDO.setPlaceMainId(sitePositionList.getId());
venueInfoDO.setPlaceId(sitePositionList.getPlaceId());
venueInfoDO.setScheduleId(Integer.valueOf(sitePositionList.getScheduleId()));
venueInfoDO.setSjName(sitePositionList.getSjName());
venueInfoDO.setCreateTime(LocalDateTime.now());
venueInfoDO.setContacts(sitePositionList.getContacts());
venueInfoDO.setType(sitePositionList.getType());
venueInfoDO.setMoney(sitePositionList.getMoney());
venueInfoDO.setClassName(sitePositionList.getClassName());
venueInfoDO.setClassCode(sitePositionList.getClassCode());
venueInfoDO.setAppointments(sitePositionList.getAppointments());
venueInfoDO.setCTypeCode(sitePositionList.getCtypeCode());
insertList.add(venueInfoDO);
}
}

View File

@@ -1,25 +0,0 @@
package com.xiang.xservice.application.script.jntyzx.utils;
import com.xiang.xservice.application.script.jntyzx.entity.pojo.VenueInfoDO;
import org.apache.commons.lang3.StringUtils;
/**
* @Author: xiang
* @Date: 2025-12-16 09:55
*/
public class VenueInfoUtils {
public static boolean get123VenueInfo4Mor(VenueInfoDO venueInfoDO) {
return StringUtils.equals(venueInfoDO.getSjName(), "13:00-14:00") || StringUtils.equals(venueInfoDO.getSjName(), "14:00-15:00");
}
public static boolean get1221VenueInfo4Mor(VenueInfoDO venueInfoDO) {
return StringUtils.equals(venueInfoDO.getSjName(), "12:00-13:00") || StringUtils.equals(venueInfoDO.getSjName(), "13:00-14:00");
}
public static boolean get628VenueInfo(VenueInfoDO venueInfoDO) {
return StringUtils.equals(venueInfoDO.getSjName(), "18:00-19:00") || StringUtils.equals(venueInfoDO.getSjName(), "19:00-20:00");
}
public static boolean get8210VenueInfo(VenueInfoDO venueInfoDO) {
return StringUtils.equals(venueInfoDO.getSjName(), "20:00-21:00") || StringUtils.equals(venueInfoDO.getSjName(), "21:00-22:00");
}
}

View File

@@ -1,7 +1,5 @@
package com.xiang.xservice.application.script.xb.controller;
import com.google.common.collect.Lists;
import com.xiang.xservice.basic.common.resp.Result;
import com.xiang.xservice.application.script.xb.entity.pojo.xb.XbFundList;
import com.xiang.xservice.application.script.xb.entity.request.xb.fund.QueryFundInfoReq;
import com.xiang.xservice.application.script.xb.entity.request.xb.fund.QueryFundListReq;
@@ -9,6 +7,7 @@ import com.xiang.xservice.application.script.xb.entity.request.xb.fund.QueryXbFu
import com.xiang.xservice.application.script.xb.entity.response.xbyj.fund.FundInfo;
import com.xiang.xservice.application.script.xb.entity.response.xbyj.fund.FundList;
import com.xiang.xservice.application.script.xb.service.FundService;
import com.xiang.xservice.basic.common.resp.Result;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.web.bind.annotation.PostMapping;
@@ -31,28 +30,28 @@ public class XBController {
private final FundService fundService;
@PostMapping("/queryFundList")
public Result<XbFundList> queryFundList(@RequestBody QueryXbFundListReq req) {
public Result<List<XbFundList>> queryFundList(@RequestBody QueryXbFundListReq req) {
List<XbFundList> result = fundService.queryFundList(req.getType());
if (CollectionUtils.isEmpty(result)) {
return Result.error("基金列表信息为空!");
}
return Result.success("success", result);
return Result.data(result);
}
@PostMapping("/queryList")
public Result<FundList> queryList(@RequestBody QueryFundListReq req) {
public Result<List<FundList>> queryList(@RequestBody QueryFundListReq req) {
List<FundList> result = fundService.queryTodayList(req.getDate(), req.getDataResources(), req.getDataSourceSwitch(), req.getCodeArr());
if (CollectionUtils.isEmpty(result)) {
return Result.error("基金列表信息为空!");
}
return Result.success("success", result);
return Result.data(result);
}
@PostMapping("/queryFundInfo")
public Result<FundInfo> queryFundInfo(@RequestBody QueryFundInfoReq req) {
FundInfo fundInfo = fundService.queryFundInfo(req.getCode());
if (Objects.nonNull(fundInfo)) {
return Result.success("success", Lists.newArrayList(fundInfo));
return Result.data(fundInfo);
}
return Result.error("查询基金信息为空!");
}

View File

@@ -1,105 +0,0 @@
package com.xiang.xservice.application.script.xb.schedule.xb;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.collect.Lists;
import com.xiang.xservice.basic.utils.DateUtils;
import com.xiang.xservice.application.script.xb.entity.pojo.xb.XbFundCount;
import com.xiang.xservice.application.script.xb.entity.pojo.xb.XbFundList;
import com.xiang.xservice.application.script.xb.entity.response.xbyj.fund.FundList;
import com.xiang.xservice.application.script.xb.service.DingTalkRobotService;
import com.xiang.xservice.application.script.xb.service.FundService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @Author: xiang
* @Date: 2025-05-21 13:59
*/
@Component
@RequiredArgsConstructor
@Slf4j
@RestController
public class FundCountJob {
private final FundService fundService;
private final DingTalkRobotService dingTalkService;
@Scheduled(cron = "0 0 22 * * ?")
public void countFundJob() {
// 周六周日过滤
if (Objects.equals(LocalDateTime.now().getDayOfWeek(), DayOfWeek.SATURDAY) ||
Objects.equals(LocalDateTime.now().getDayOfWeek(), DayOfWeek.SUNDAY)) {
return;
}
log.info("==========================[基金统计] 基金统计定时任务启动!==========================");
List<XbFundList> lists = fundService.queryFundList();
if (CollectionUtils.isEmpty(lists)) {
return;
}
List<XbFundCount> counts = Lists.newCopyOnWriteArrayList();
String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
lists.parallelStream().forEach(xbFundList -> {
List<FundList> fund = fundService.queryTodayList(date, "2", Boolean.TRUE, Collections.singletonList(xbFundList.getCode()));
if (CollectionUtils.isNotEmpty(fund)) {
XbFundCount xbFundCount = new XbFundCount();
xbFundCount.setLId(xbFundList.getId());
xbFundCount.setCode(xbFundList.getCode());
xbFundCount.setName(xbFundList.getName());
xbFundCount.setChange(fund.get(0).getChange().multiply(new BigDecimal("100")).setScale(2, RoundingMode.HALF_UP));
xbFundCount.setUpdateTime(LocalDateTime.now());
counts.add(xbFundCount);
}
});
if (CollectionUtils.isNotEmpty(counts)) {
log.info("[基金统计] 基金统计记录,需要插入的数据:{}", JSONObject.toJSONString(counts));
fundService.addCounts(counts);
}
log.info("==========================[基金统计] 基金统计定时任务结束!==========================");
}
@Scheduled(cron = "0 40 14 * * ? ")
public void countFundInWeek() throws Exception {
if (DateUtils.validWeekTime()) return;
log.info("==========================[基金统计] 基金本周涨跌幅消息发送定时任务启动!==========================");
List<XbFundCount> xbFundCounts = fundService.queryFundCountInWeek();
if (CollectionUtils.isEmpty(xbFundCounts)) {
return;
}
StringBuilder sb = new StringBuilder();
Map<String, List<XbFundCount>> map = xbFundCounts.stream().collect(Collectors.groupingBy(XbFundCount::getCode));
map.forEach((k, v) -> {
List<XbFundCount> fundCounts = map.get(k);
if (CollectionUtils.isEmpty(fundCounts)) {
return;
}
List<BigDecimal> decimals = fundCounts.stream().map(XbFundCount::getChange).collect(Collectors.toList());
BigDecimal sum = BigDecimal.ZERO;
for (BigDecimal decimal : decimals) {
sum = sum.add(decimal);
}
BigDecimal avg = sum.divide(BigDecimal.valueOf(decimals.size()), 2, RoundingMode.HALF_UP);
sb.append("").append(fundCounts.get(0).getName()).append("】本周平均涨跌幅为:").append(avg).append("\n");
});
if (StringUtils.isNotBlank(sb)) {
dingTalkService.sendXbMsg(sb.toString());
}
log.info("==========================[基金统计] 基金本周涨跌幅消息发送定时任务结束!==========================");
}
}

View File

@@ -1,180 +0,0 @@
package com.xiang.xservice.application.script.xb.schedule.xb;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.collect.Lists;
import com.xiang.xmc.service.cache.service.IRedisService;
import com.xiang.xmc.service.message.dingTalk.service.DingTalkService;
import com.xiang.xservice.application.script.xb.entity.pojo.xb.FundMessage;
import com.xiang.xservice.application.script.xb.entity.pojo.xb.XbFundList;
import com.xiang.xservice.application.script.xb.entity.response.xbyj.fund.FundInfo;
import com.xiang.xservice.application.script.xb.entity.response.xbyj.fund.FundList;
import com.xiang.xservice.application.script.xb.repository.XBFundMapper;
import com.xiang.xservice.application.script.xb.service.FundService;
import com.xiang.xservice.basic.config.MyThreadFactory;
import com.xiang.xservice.basic.utils.DateUtils;
import com.xiang.xservice.common.entity.DayResult;
import com.xiang.xservice.common.enums.RedisConstant;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* @Author: xiang
* @Date: 2025-05-14 17:15
*/
@Component
@RequiredArgsConstructor
@Slf4j
public class FundInfoQueryJob {
private final FundService fundService;
private final DingTalkService dingTalkService;
private final XBFundMapper xbFundMapper;
private final IRedisService redisService;
private final ExecutorService es =
new ThreadPoolExecutor(
10,
20,
1000,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(),
new MyThreadFactory("xb-query-thread", Boolean.TRUE),
new ThreadPoolExecutor.AbortPolicy());
@Value("${xiaobei.codeArr}")
private String codeArr;
@Value("${dingtalk.chatId}")
private String chatId;
/**
* 基金涨跌幅5分钟超过2%重点通知
*/
@Scheduled(cron = "0 0/5 9,10,11,13,14,15 * * ? ")
public void queryFundEmergencyJob() throws Exception {
// 周六周日过滤
if (DateUtils.validWeekTime()) return;
LocalDate now = LocalDate.now();
com.alibaba.fastjson.JSONObject dayResult = (com.alibaba.fastjson.JSONObject) redisService.hGet(RedisConstant.DAY_INFO_PREFIX_KEY + RedisConstant.getDate4Key(), DateUtils.getDateFromDate(now));
com.xiang.xservice.common.utils.DateUtils dateUtils = new com.xiang.xservice.common.utils.DateUtils(redisService);
if (dateUtils.validHoliday(JSON.toJavaObject(dayResult, DayResult.class))) return;
List<com.xiang.xservice.application.script.xb.entity.pojo.xb.FundInfo> fundInfos = xbFundMapper.queryListIn2Min();
if (CollectionUtils.isEmpty(fundInfos)) {
return;
}
Map<String, List<com.xiang.xservice.application.script.xb.entity.pojo.xb.FundInfo>> map = fundInfos.stream().collect(Collectors.groupingBy(com.xiang.xservice.application.script.xb.entity.pojo.xb.FundInfo::getCode));
StringBuffer sb = new StringBuffer();
map.entrySet().parallelStream().forEach(entry -> {
List<com.xiang.xservice.application.script.xb.entity.pojo.xb.FundInfo> infos = entry.getValue();
BigDecimal sum = new BigDecimal("0");
for (int i = 0; i < infos.size() - 1; i++) {
BigDecimal subtract = new BigDecimal(infos.get(i + 1).getChange()).subtract(new BigDecimal(infos.get(i).getChange()));
sum = sum.add(subtract);
}
BigDecimal avg = sum.divide(new BigDecimal(String.valueOf(infos.size())), 2, RoundingMode.HALF_UP);
if (avg.abs().compareTo(new BigDecimal("2")) > 0) {
sb.append("基金").append(entry.getValue().get(0).getName()).append("5分钟的平均涨跌幅超过2%,涨跌幅达到").append(avg).append("\n");
}
});
if (StringUtils.isNotBlank(sb)) {
dingTalkService.sendChatMessage(chatId, sb.toString());
}
}
/**
* 基金每分钟涨幅记录
*/
@Scheduled(cron = "0 0/1 9,10,11,13,14 * * ?")
public void queryFundInfoInMinJob() {
// 周六周日过滤
if (Objects.equals(LocalDateTime.now().getDayOfWeek(), DayOfWeek.SATURDAY) ||
Objects.equals(LocalDateTime.now().getDayOfWeek(), DayOfWeek.SUNDAY)) {
return;
}
List<FundMessage> fundMessageList = queryFund(null);
if (CollectionUtils.isEmpty(fundMessageList)) {
return;
}
List<CompletableFuture> futures = Lists.newArrayList();
List<com.xiang.xservice.application.script.xb.entity.pojo.xb.FundInfo> fundInfoList = Lists.newCopyOnWriteArrayList();
fundMessageList.parallelStream().forEach(fundMessage -> {
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
FundInfo fundInfo = fundService.queryFundInfo(fundMessage.getCode());
com.xiang.xservice.application.script.xb.entity.pojo.xb.FundInfo info = com.xiang.xservice.application.script.xb.entity.pojo.xb.FundInfo.builder()
.code(fundMessage.getCode())
.name(fundInfo.getName())
.change(fundMessage.getChange().multiply(new BigDecimal("100")).setScale(2, RoundingMode.HALF_UP).toString())
.updateTime(getTimeFromStr(fundMessage.getDate(), fundMessage.getUpdate()))
.build();
fundInfoList.add(info);
}, es);
futures.add(future);
});
CompletableFuture[] futureArr = futures
.toArray(futures.toArray(new CompletableFuture[0]));
CompletableFuture.allOf(futureArr).join();
if (CollectionUtils.isNotEmpty(fundInfoList)) {
log.info("[基金查询] 每分钟基金涨跌幅查询记录,需要插入的数据:{}", JSONObject.toJSONString(fundInfoList));
xbFundMapper.batchSave(fundInfoList);
}
}
private List<FundMessage> queryFund(Integer type) {
String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
List<String> code = Lists.newArrayList();
List<XbFundList> lists = xbFundMapper.queryFundList(type);
if (CollectionUtils.isEmpty(lists)) {
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());
}
List<FundList> fundLists = fundService.queryTodayList(date, "2", Boolean.TRUE, code);
if (CollectionUtils.isEmpty(fundLists)) {
return Lists.newArrayList();
}
List<FundMessage> result = Lists.newCopyOnWriteArrayList();
fundLists.parallelStream().forEach(fundList -> {
FundInfo fundInfo = fundService.queryFundInfo(fundList.getCode());
if (Objects.nonNull(fundInfo)) {
FundMessage fund = FundMessage.builder().name(fundInfo.getName()).date(fundList.getDate())
.code(fundList.getCode()).change(fundList.getChange()).update(fundList.getUpdate()).build();
result.add(fund);
}
});
return result;
}
private LocalDateTime getTimeFromStr(String date, String time) {
String dateTimeStr = date + " " + time;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return LocalDateTime.parse(dateTimeStr, formatter);
}
}

View File

@@ -1,144 +0,0 @@
package com.xiang.xservice.application.script.xb.schedule.xb;
import com.alibaba.fastjson.JSON;
import com.xiang.xservice.application.script.xb.entity.pojo.xb.XbFundList;
import com.xiang.xservice.application.script.xb.entity.response.xbyj.fund.FundList;
import com.xiang.xservice.application.script.xb.service.DingTalkRobotService;
import com.xiang.xservice.application.script.xb.service.FundService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @Author: xiang
* @Date: 2025-07-31 18:10
*/
@Component
@Slf4j
@RestController
@RequiredArgsConstructor
public class FundMsgReportJob {
private final FundService fundService;
private final DingTalkRobotService dingTalkService;
private static final Integer TYPE_A = 1;
private static final Integer TYPE_M = 3;
private static final Integer TYPE_G = 2;
@Scheduled(cron = "0 1,31 9,10,11,13,14 * * ?")
@PostMapping("/asdasda")
public void fundReport4A() {
log.info("===========A股基金变化通知===========");
// 周六周日过滤
if (Objects.equals(LocalDateTime.now().getDayOfWeek(), DayOfWeek.SATURDAY) ||
Objects.equals(LocalDateTime.now().getDayOfWeek(), DayOfWeek.SUNDAY)) {
log.info("当前时间为:{}", LocalDateTime.now());
return;
}
List<XbFundList> fundLists = fundService.queryFundList(TYPE_A);
if (CollectionUtils.isEmpty(fundLists)) {
log.info("查询配置的A股信息为空");
return;
}
Map<String, XbFundList> fundMap = fundLists.stream().collect(Collectors.toMap(XbFundList::getCode, Function.identity(), (a, b) -> a));
String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
List<FundList> funds = fundService.queryTodayList(date, "2", Boolean.TRUE, new ArrayList<>(fundMap.keySet()));
if (CollectionUtils.isEmpty(funds)) {
log.info("http请求查询基金信息为空");
return;
}
log.info("http查询基金信息:{}", JSON.toJSONString(funds));
StringBuilder msg = new StringBuilder(date).append("===》A股基金变化通知:\n");
buildMsg(funds, fundMap, msg);
dingTalkService.sendXbMsg(msg.toString());
}
@Scheduled(cron = "0 1,31 9,10,11,13,14,15 * * ?")
public void fundReport4G() {
log.info("===========港股基金变化通知!===========");
// 周六周日过滤
if (Objects.equals(LocalDateTime.now().getDayOfWeek(), DayOfWeek.SATURDAY) ||
Objects.equals(LocalDateTime.now().getDayOfWeek(), DayOfWeek.SUNDAY)) {
log.info("当前时间为:{}", LocalDateTime.now());
return;
}
List<XbFundList> fundLists = fundService.queryFundList(TYPE_G);
if (CollectionUtils.isEmpty(fundLists)) {
log.info("查询配置的港股信息为空");
return;
}
Map<String, XbFundList> fundMap = fundLists.stream().collect(Collectors.toMap(XbFundList::getCode, Function.identity(), (a, b) -> a));
String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
List<FundList> funds = fundService.queryTodayList(date, "2", Boolean.TRUE, new ArrayList<>(fundMap.keySet()));
if (CollectionUtils.isEmpty(funds)) {
log.info("http请求查询基金信息为空");
return;
}
log.info("http查询港股基金信息:{}", JSON.toJSONString(funds));
StringBuilder msg = new StringBuilder(date).append("===》港股基金变化通知:\n");
buildMsg(funds, fundMap, msg);
dingTalkService.sendXbMsg(msg.toString());
}
@Scheduled(cron = "0 0 9 * * ?")
public void fundReport4M() {
log.info("===========美股基金变化通知!===========");
// 周六周日过滤
if (Objects.equals(LocalDateTime.now().getDayOfWeek(), DayOfWeek.SATURDAY) ||
Objects.equals(LocalDateTime.now().getDayOfWeek(), DayOfWeek.SUNDAY)) {
log.info("当前时间为:{}", LocalDateTime.now());
return;
}
List<XbFundList> fundLists = fundService.queryFundList(TYPE_M);
if (CollectionUtils.isEmpty(fundLists)) {
log.info("查询配置的美股信息为空");
return;
}
Map<String, XbFundList> fundMap = fundLists.stream().collect(Collectors.toMap(XbFundList::getCode, Function.identity(), (a, b) -> a));
String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
List<FundList> funds = fundService.queryTodayList(date, "2", Boolean.TRUE, new ArrayList<>(fundMap.keySet()));
if (CollectionUtils.isEmpty(funds)) {
log.info("http请求查询基金信息为空");
return;
}
log.info("http查询美股基金信息:{}", JSON.toJSONString(funds));
StringBuilder msg = new StringBuilder(date).append("===》美股基金变化通知:\n");
buildMsg(funds, fundMap, msg);
dingTalkService.sendXbMsg(msg.toString());
}
private static void buildMsg(List<FundList> funds, Map<String, XbFundList> fundMap, StringBuilder msg) {
funds = funds.stream().sorted(Comparator.comparing(FundList::getChange).reversed())
.collect(Collectors.toList());
for (FundList fund : funds) {
if (fundMap.containsKey(fund.getCode())) {
XbFundList fundList = fundMap.get(fund.getCode());
msg.append("基金名称:")
.append(fundList.getName())
.append("涨跌幅:")
.append(fund.getChange()
.multiply(new BigDecimal("100"))
.setScale(2, RoundingMode.HALF_UP))
.append("\n");
}
}
}
}

View File

@@ -1,31 +0,0 @@
package com.xiang.xservice.application.script.xb.service;
import com.xiang.xmc.service.message.dingTalk.service.DingTalkService;
import com.xiang.xservice.config.DingTalkRobotXbConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @Author: xiang
* @Date: 2025-08-07 11:02
*/
@Service
@RequiredArgsConstructor
@Slf4j
public class DingTalkRobotService {
private final DingTalkService dingTalkService;
private final DingTalkRobotXbConfig dingTalkRobotConfig;
/**
* 发送脚本消息
* @param msg 消息
*/
public void sendXbMsg(String msg) {
try {
dingTalkService.sendRobotMessage(dingTalkRobotConfig.getSecret(), dingTalkRobotConfig.getToken(), dingTalkRobotConfig.getUsers(), msg);
} catch (Exception e) {
log.error("信息发送异常, 信息:{}", msg, e);
}
}
}

View File

@@ -0,0 +1,21 @@
package com.xiang.xservice.common.enums;
import com.xiang.xmc.service.message.dingTalk.enums.BaseDingTalkBizType;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* @Author: xiang
* @Date: 2026-01-04 16:13
*/
@Getter
@RequiredArgsConstructor
public enum DingTalkBizTypeEnum implements BaseDingTalkBizType {
JT("venue", "江南体育中心"),
XB("xb", "股票基金变化通知"),
SCRIPT("script", "脚本运行通知群")
;
private final String bizName;
private final String desc;
}

View File

@@ -1,72 +0,0 @@
package com.xiang.xservice.common.schedule;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.xiang.xmc.service.cache.service.IRedisService;
import com.xiang.xservice.basic.utils.DateUtils;
import com.xiang.xservice.basic.utils.HttpUtils;
import com.xiang.xservice.common.entity.DayResult;
import com.xiang.xservice.common.enums.RedisConstant;
import com.xiang.xservice.common.enums.UrlConstant;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDate;
import java.time.YearMonth;
import java.util.HashMap;
import java.util.Objects;
/**
* @Author: xiang
* @Date: 2025-10-04 10:09
*/
@Component
@RequiredArgsConstructor
@RestController
public class HolidayQueryJob {
private final IRedisService redisService;
private static final String API_KEY = "d20db0ca13e151ca7323d849d8efc6db";
@Scheduled(cron = "0 0 0 1 1/1 ?")
@PostMapping("/queryHolidayInfoJob")
public void queryHolidayInfoJob() {
YearMonth now = YearMonth.now(); // 当前年月
LocalDate start = now.atDay(1);
LocalDate end = now.atEndOfMonth();
for (LocalDate d = start; !d.isAfter(end); d = d.plusDays(1)) {
try {
String date = DateUtils.getDateFromDate(d);
HashMap<String, String> paramMap = Maps.newHashMap();
paramMap.put("key", API_KEY);
paramMap.put("date", date);
paramMap.put("detail", "");
HashMap<String, String> headers = Maps.newHashMap();
headers.put("Content-Type", "application/x-www-form-urlencoded");
String resp = HttpUtils.doGet(UrlConstant.HOLIDAY_QUERY_URL, headers, paramMap);
if (StringUtils.isNotBlank(resp)) {
JSONObject jsonObject = JSON.parseObject(resp);
String reason = (String) jsonObject.get("reason");
if (!StringUtils.equals(reason, "success")) {
continue;
}
JSONObject result = jsonObject.getJSONObject("result");
DayResult dayResult = JSON.toJavaObject(result, DayResult.class);
if (Objects.isNull(dayResult)) {
continue;
}
redisService.hSet(RedisConstant.DAY_INFO_PREFIX_KEY + RedisConstant.getDate4Key(), date, result);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

View File

@@ -0,0 +1,23 @@
package com.xiang.xservice.common.service.dingTalk;
import com.xiang.xmc.service.message.dingTalk.config.DingTalkRobotProperties;
import com.xiang.xmc.service.message.dingTalk.service.AbstractDingTalkFactory;
import com.xiang.xmc.service.message.dingTalk.service.DingTalkSender;
import com.xiang.xservice.common.enums.DingTalkBizTypeEnum;
import org.springframework.stereotype.Service;
/**
* @Author: xiang
* @Date: 2026-01-04 16:19
*/
@Service
public class JtDingTalkFactory extends AbstractDingTalkFactory {
public JtDingTalkFactory(DingTalkRobotProperties dingTalkRobotProperties, DingTalkSender dingTalkSender) {
super(dingTalkRobotProperties, dingTalkSender);
}
@Override
public void sendMsg(String msg) {
getClient(DingTalkBizTypeEnum.JT).sendDingTalkMsg(msg);
}
}

View File

@@ -0,0 +1,19 @@
package com.xiang.xservice.common.service.dingTalk;
import com.xiang.xmc.service.message.dingTalk.config.DingTalkRobotProperties;
import com.xiang.xmc.service.message.dingTalk.service.AbstractDingTalkFactory;
import com.xiang.xmc.service.message.dingTalk.service.DingTalkSender;
import com.xiang.xservice.common.enums.DingTalkBizTypeEnum;
import org.springframework.stereotype.Service;
@Service
public class ScriptDingTalkFactory extends AbstractDingTalkFactory {
public ScriptDingTalkFactory(DingTalkRobotProperties dingTalkRobotProperties, DingTalkSender dingTalkSender) {
super(dingTalkRobotProperties, dingTalkSender);
}
@Override
public void sendMsg(String msg) {
getClient(DingTalkBizTypeEnum.SCRIPT).sendDingTalkMsg(msg);
}
}

View File

@@ -0,0 +1,19 @@
package com.xiang.xservice.common.service.dingTalk;
import com.xiang.xmc.service.message.dingTalk.config.DingTalkRobotProperties;
import com.xiang.xmc.service.message.dingTalk.service.AbstractDingTalkFactory;
import com.xiang.xmc.service.message.dingTalk.service.DingTalkSender;
import com.xiang.xservice.common.enums.DingTalkBizTypeEnum;
import org.springframework.stereotype.Service;
@Service
public class StockDingTalkFactory extends AbstractDingTalkFactory {
public StockDingTalkFactory(DingTalkRobotProperties dingTalkRobotProperties, DingTalkSender dingTalkSender) {
super(dingTalkRobotProperties, dingTalkSender);
}
@Override
public void sendMsg(String msg) {
getClient(DingTalkBizTypeEnum.XB).sendDingTalkMsg(msg);
}
}

View File

@@ -0,0 +1,14 @@
package com.xiang.xservice.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/statics/**").addResourceLocations("classpath:/statics/");
}
}

View File

@@ -29,6 +29,21 @@ spring:
max-idle: 8
min-idle: 0
max-wait: 1000
freemarker:
request-context-attribute: request
suffix: .html
content-type: text/html
enabled: true
cache: false
charset: UTF-8
allow-request-override: false
expose-request-attributes: true
expose-session-attributes: true
expose-spring-macro-helpers: true
settings:
number_format: 0.##
default_encoding: UTF-8
aliyun:
dns:
@@ -36,23 +51,23 @@ aliyun:
- local
dingtalk:
# 钉钉消息用户,用逗号隔开
userList: "450841600726084717"
# 钉钉消息群ID需要调用/chat/create api创建群返回
chatId: "chatd16d8daeea33b36b73588c676d508096"
robot:
properties:
venue:
name: 江南体育中心通知群
token: 6a218646972c684c75832b0229ea93a234778af537d7469ce96bef290faf530e
secret: SEC9018755ba86d3e5c1ed2fbfa1d6953d84bb2a6c8ebe7ed4e318457bfed5e0465
users:
- 450841600726084717
script:
name: 脚本运行通知群
token: 797be7f32062e31dec1d567f8b490a5649a5366083618e236c7a1263df1f4af3
secret: SEC9aca642c0c29c9da261462869c464d34623247583d98fc82343a0a4464abbe91
users:
- 450841600726084717
xb:
name: 股票基金变化通知群
token: ad21ead99f0fdc63aa00d6732b7b0888c17590f7612c68297edfcb71844d1437
secret: SECc09d8aad6635f1a4cbadb7c0ab365523c46299f138438cd885e445e0f5f4d730
users:
- 450841600726084717
venue:
token: 6a218646972c684c75832b0229ea93a234778af537d7469ce96bef290faf530e
secret: SEC9018755ba86d3e5c1ed2fbfa1d6953d84bb2a6c8ebe7ed4e318457bfed5e0465
users:
- 450841600726084717

View File

@@ -29,6 +29,20 @@ spring:
max-idle: 8
min-idle: 0
max-wait: 1000
freemarker:
request-context-attribute: request
suffix: .html
content-type: text/html
enabled: true
cache: false
charset: UTF-8
allow-request-override: false
expose-request-attributes: true
expose-session-attributes: true
expose-spring-macro-helpers: true
settings:
number_format: 0.##
default_encoding: UTF-8
aliyun:
dns:
@@ -38,23 +52,23 @@ aliyun:
- nexus
dingtalk:
# 钉钉消息用户,用逗号隔开
userList: "450841600726084717"
# 钉钉消息群ID需要调用/chat/create api创建群返回
chatId: "chatd16d8daeea33b36b73588c676d508096"
robot:
properties:
venue:
name: 江南体育中心通知群
token: 6a218646972c684c75832b0229ea93a234778af537d7469ce96bef290faf530e
secret: SEC9018755ba86d3e5c1ed2fbfa1d6953d84bb2a6c8ebe7ed4e318457bfed5e0465
users:
- 450841600726084717
script:
name: 脚本运行通知群
token: 4709b708d961846e0aee523c5abc3b67e8fa424ee292501d85efd4e504f15a8b
secret: SEC768ed578c0fb31a9aec84b1c1db4f195f5aca203985bbb9d549e23e41c8874d1
users:
- 450841600726084717
xb:
name: 股票基金变化通知群
token: 340a9d39a5b0b6a52ba2262f9c27179cf50e3c8cfe6883ca082649d306038f41
secret: SECe10ade3058880b84df5c6f46ab072c11f4ac2a5ef9f134d684705c2a3b004de2
users:
- 450841600726084717
venue:
token: 6a218646972c684c75832b0229ea93a234778af537d7469ce96bef290faf530e
secret: SEC9018755ba86d3e5c1ed2fbfa1d6953d84bb2a6c8ebe7ed4e318457bfed5e0465
users:
- 450841600726084717

View File

@@ -29,6 +29,20 @@ spring:
max-idle: 8
min-idle: 0
max-wait: 1000
freemarker:
request-context-attribute: request
suffix: .html
content-type: text/html
enabled: true
cache: false
charset: UTF-8
allow-request-override: false
expose-request-attributes: true
expose-session-attributes: true
expose-spring-macro-helpers: true
settings:
number_format: 0.##
default_encoding: UTF-8
aliyun:
dns:
@@ -36,17 +50,22 @@ aliyun:
- test
dingtalk:
# 钉钉消息用户,用逗号隔开
userList: "450841600726084717"
# 钉钉消息群ID需要调用/chat/create api创建群返回
chatId: "chatd16d8daeea33b36b73588c676d508096"
robot:
properties:
venue:
name: 江南体育中心通知群
token: 6a218646972c684c75832b0229ea93a234778af537d7469ce96bef290faf530e
secret: SEC9018755ba86d3e5c1ed2fbfa1d6953d84bb2a6c8ebe7ed4e318457bfed5e0465
users:
- 450841600726084717
script:
name: 脚本运行通知群
token: 797be7f32062e31dec1d567f8b490a5649a5366083618e236c7a1263df1f4af3
secret: SEC9aca642c0c29c9da261462869c464d34623247583d98fc82343a0a4464abbe91
users:
- 450841600726084717
xb:
name: 股票基金变化通知群
token: ad21ead99f0fdc63aa00d6732b7b0888c17590f7612c68297edfcb71844d1437
secret: SECc09d8aad6635f1a4cbadb7c0ab365523c46299f138438cd885e445e0f5f4d730
users:

View File

@@ -21,6 +21,9 @@ spring:
name: xservice-script-center
main:
allow-bean-definition-overriding: true
autoconfigure:
exclude:
- com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration
http:
maxAttempts: 10

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 434 KiB

Some files were not shown because too many files have changed in this diff Show More