初始化

This commit is contained in:
yuejiajun 2025-09-28 09:54:54 +08:00
commit b356735d72
126 changed files with 93861 additions and 0 deletions

284
pom.xml Normal file
View File

@ -0,0 +1,284 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 项目基本信息 -->
<groupId>com.example</groupId>
<artifactId>xml-to-txt-service</artifactId>
<version>1.0.0-SNAPSHOT</version>
<!-- 父项目 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!-- 属性配置 -->
<properties>
<!-- 基本属性 -->
<java.version>21</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- 依赖版本管理 -->
<commins-fileupload.version>1.6.0</commins-fileupload.version>
<mybatis-flex.version>1.9.3</mybatis-flex.version>
<swagger.version>2.2.0</swagger.version>
<h2.version>2.2.224</h2.version>
<sqlite.version>3.45.1.0</sqlite.version>
<lombok.version>1.18.30</lombok.version>
<hutool.version>5.8.27</hutool.version>
<json.version>20231013</json.version>
<fastjson2.version>2.0.49</fastjson2.version>
<knife4j.version>4.5.0</knife4j.version>
<bean-searcher.version>4.3.0</bean-searcher.version>
<mapstruct-plus.version>1.4.0</mapstruct-plus.version>
<easy-trans.version>3.0.5</easy-trans.version>
<modelmapper.version>2.3.9</modelmapper.version>
<tika.version>2.8.0</tika.version>
<jinjia2.version>2.8.1</jinjia2.version>
<velocity.version>1.7</velocity.version>
</properties>
<!-- 依赖管理 - 强制规范 -->
<dependencies>
<!-- 项目基本依赖 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- 文件上传 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${commins-fileupload.version}</version>
</dependency>
<!-- 代码简化与基础工具箱 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>${jackson-bom.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-bom.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2-extension</artifactId>
<version>${fastjson2.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>${json.version}</version>
</dependency>
<!-- API文档 -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
</dependency>
<!-- 数据库相关依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>${sqlite.version}</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
</dependency>
<!-- ORM框架 -->
<dependency>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-spring-boot3-starter</artifactId>
<version>${mybatis-flex.version}</version>
</dependency>
<dependency>
<groupId>cn.zhxu</groupId>
<artifactId>bean-searcher-boot-starter</artifactId>
<version>${bean-searcher.version}</version>
</dependency>
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>${modelmapper.version}</version>
</dependency>
<!-- 翻译工具 -->
<dependency>
<groupId>com.fhs-opensource</groupId>
<artifactId>easy-trans-spring-boot-starter</artifactId>
<version>${easy-trans.version}</version>
</dependency>
<dependency>
<groupId>com.fhs-opensource</groupId>
<artifactId>easy-trans-mybatis-flex-extend</artifactId>
<version>${easy-trans.version}</version>
</dependency>
<!-- 文件编码工具 -->
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
<version>${tika.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-parsers-standard-package</artifactId>
<version>${tika.version}</version>
</dependency>
<!-- 模板JinJia2 -->
<dependency>
<groupId>com.hubspot.jinjava</groupId>
<artifactId>jinjava</artifactId>
<version>${jinjia2.version}</version>
</dependency>
<!-- 模板freemarker -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- 模板thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- 模板velocity -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>${velocity.version}</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-tools</artifactId>
<version>2.0</version>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/**/*.j2</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
<repositories>
<repository>
<id>aliyun</id>
<name>aliyun</name>
<url>https://maven.aliyun.com/repository/public</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>aliyun</id>
<name>aliyun</name>
<url>https://maven.aliyun.com/repository/public</url>
</pluginRepository>
</pluginRepositories>
</project>

View File

@ -0,0 +1,52 @@
package com.example.demo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.modelmapper.ModelMapper;
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.info.Info;
import io.swagger.v3.oas.annotations.info.License;
/**
* XML解析器应用程序主类
* Spring Boot应用程序的入口点
*
* @author system
* @since 1.0.0
*/
@SpringBootApplication
@MapperScan("com.example.demo.parser.mapper") // 扫描Mapper接口
@OpenAPIDefinition(
info = @Info(
title = "XML解析器API文档",
description = "XML文件解析并转化为TXT服务项目的API接口文档",
version = "1.0",
license = @License(
name = "Apache 2.0",
url = "http://www.apache.org/licenses/LICENSE-2.0.html"
)
)
)
public class Application {
/**
* 应用程序入口方法
*
* @param args 命令行参数
*/
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
/**
* 配置ModelMapper用于DTOEntity和VO之间的转换
*
* @return ModelMapper实例
*/
@Bean
public ModelMapper modelMapper() {
return new ModelMapper();
}
}

View File

@ -0,0 +1,160 @@
package com.example.demo.common.config;
import com.example.demo.common.constant.GlobalConstants;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
* 缓存配置类
* 配置H2内存缓存用于缓存解析规则和映射规则等数据
*
* @author system
* @version 1.0
*/
@Configuration
@EnableCaching
public class CacheConfig {
/**
* 配置缓存管理器
* 使用ConcurrentMapCacheManager作为缓存管理器提供基于内存的缓存实现
*
* @return ConcurrentMapCacheManager实例
*/
@Bean
public ConcurrentMapCacheManager cacheManager() {
ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();
// 预定义的缓存名称
cacheManager.setCacheNames(Arrays.asList(
GlobalConstants.Cache.CACHE_KEY_PARSE_RULE,
GlobalConstants.Cache.CACHE_KEY_MAPPER_RULE,
"system_config",
"user_session"
));
// 设置默认缓存配置
cacheManager.setAllowNullValues(false);
return cacheManager;
}
/**
* 创建一个简单的缓存包装器支持过期时间
*
* @param <K> 缓存键类型
* @param <V> 缓存值类型
* @return 带过期时间的缓存
*/
@Bean
public <K, V> CacheWrapper<K, V> cacheWrapper() {
return new CacheWrapper<>();
}
/**
* 带过期时间的缓存包装器
*
* @param <K> 缓存键类型
* @param <V> 缓存值类型
*/
public static class CacheWrapper<K, V> {
private final ConcurrentHashMap<K, CacheEntry<V>> cache = new ConcurrentHashMap<>();
/**
* 存储值到缓存使用默认过期时间
*
* @param key 缓存键
* @param value 缓存值
*/
public void put(K key, V value) {
put(key, value, GlobalConstants.Cache.DEFAULT_CACHE_EXPIRE);
}
/**
* 存储值到缓存指定过期时间
*
* @param key 缓存键
* @param value 缓存值
* @param expireTime 过期时间
*/
public void put(K key, V value, long expireTime) {
long expireAt = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(expireTime);
cache.put(key, new CacheEntry<>(value, expireAt));
}
/**
* 从缓存中获取值
*
* @param key 缓存键
* @return 缓存值如果不存在或已过期则返回null
*/
public V get(K key) {
CacheEntry<V> entry = cache.get(key);
if (entry == null) {
return null;
}
// 检查是否过期
if (System.currentTimeMillis() > entry.getExpireAt()) {
cache.remove(key);
return null;
}
return entry.getValue();
}
/**
* 从缓存中删除值
*
* @param key 缓存键
*/
public void remove(K key) {
cache.remove(key);
}
/**
* 清空缓存
*/
public void clear() {
cache.clear();
}
/**
* 获取缓存大小
*
* @return 缓存中的条目数量
*/
public int size() {
return cache.size();
}
/**
* 缓存条目内部类
*
* @param <T> 条目值类型
*/
private static class CacheEntry<T> {
private final T value;
private final long expireAt;
public CacheEntry(T value, long expireAt) {
this.value = value;
this.expireAt = expireAt;
}
public T getValue() {
return value;
}
public long getExpireAt() {
return expireAt;
}
}
}
}

View File

@ -0,0 +1,49 @@
//package com.example.demo.common.config;
//
//import lombok.RequiredArgsConstructor;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.boot.CommandLineRunner;
//import org.springframework.core.io.ClassPathResource;
//import org.springframework.jdbc.datasource.init.ScriptUtils;
//import org.springframework.stereotype.Component;
//
//import javax.sql.DataSource;
//import java.sql.Connection;
//
///**
// * 数据库初始化配置
// * 应用启动时自动执行数据库脚本
// *
// * @author system
// * @version 1.0
// */
//@Slf4j
//@Component
//@RequiredArgsConstructor
//public class DatabaseInitializer implements CommandLineRunner {
//
// private final DataSource dataSource;
//
// /**
// * 应用启动时执行数据库初始化
// *
// * @param args 命令行参数
// * @throws Exception 异常
// */
// @Override
// public void run(String... args) throws Exception {
// log.info("开始初始化数据库...");
//
// try (Connection connection = dataSource.getConnection()) {
// // 执行数据库初始化脚本
// ClassPathResource schemaResource = new ClassPathResource("schema.sql");
// ScriptUtils.executeSqlScript(connection, schemaResource);
//
// log.info("数据库初始化完成");
// } catch (Exception e) {
// log.error("数据库初始化失败: {}", e.getMessage(), e);
// throw new RuntimeException("数据库初始化失败", e);
// }
// log.info("应用启动成功....");
// }
//}

View File

@ -0,0 +1,70 @@
package com.example.demo.common.config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.datasource.init.DataSourceInitializer;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import javax.sql.DataSource;
/**
* H2数据源配置类
* 配置缓存数据库H2的数据源和初始化
*
* @author system
* @since 1.0.0
*/
@Configuration
public class H2DataSourceConfig {
private final static String baseURL = "script/h2/";
/**
* 配置H2数据源属性
*
* @return DataSourceProperties H2数据源属性
*/
@Bean
@ConfigurationProperties("spring.datasource.h2")
public DataSourceProperties h2DataSourceProperties() {
return new DataSourceProperties();
}
/**
* 创建H2数据源
*
* @return DataSource H2数据源
*/
@Bean
@ConfigurationProperties("spring.datasource.h2.hikari")
public DataSource h2DataSource() {
return h2DataSourceProperties().initializeDataSourceBuilder().build();
}
/**
* H2数据库初始化器
* 仅在spring.sql.init.h2.enabled=true时启用
*
* @return DataSourceInitializer 数据库初始化器
*/
@Bean
@ConditionalOnProperty(prefix = "spring.sql.init.h2", name = "enabled", havingValue = "true")
public DataSourceInitializer h2DataSourceInitializer() {
DataSourceInitializer initializer = new DataSourceInitializer();
initializer.setDataSource(h2DataSource());
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
// 先执行cache-schema.sql创建缓存表结构
populator.addScript(new ClassPathResource(baseURL + "h2-schema.sql"));
// 再执行cache-data.sql插入缓存数据
populator.addScript(new ClassPathResource(baseURL + "h2-data.sql"));
populator.setContinueOnError(true);
initializer.setDatabasePopulator(populator);
return initializer;
}
}

View File

@ -0,0 +1,73 @@
package com.example.demo.common.config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.datasource.init.DataSourceInitializer;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import javax.sql.DataSource;
/**
* SQLite数据源配置类
* 配置主数据库SQLite的数据源和初始化
*
* @author system
* @since 1.0.0
*/
@Configuration
public class SqliteDataSourceConfig {
private final static String baseURL = "script/sqlite/";
/**
* 配置SQLite数据源属性
*
* @return DataSourceProperties SQLite数据源属性
*/
@Bean
@Primary
@ConfigurationProperties("spring.datasource.sqlite")
public DataSourceProperties sqliteDataSourceProperties() {
return new DataSourceProperties();
}
/**
* 创建SQLite数据源
*
* @return DataSource SQLite数据源
*/
@Bean
@Primary
@ConfigurationProperties("spring.datasource.sqlite.hikari")
public DataSource sqliteDataSource() {
return sqliteDataSourceProperties().initializeDataSourceBuilder().build();
}
/**
* SQLite数据库初始化器
* 仅在spring.sql.init.sqlite.enabled=true时启用
*
* @return DataSourceInitializer 数据库初始化器
*/
@Bean
@ConditionalOnProperty(prefix = "spring.sql.init.sqlite", name = "enabled", havingValue = "true")
public DataSourceInitializer sqliteDataSourceInitializer() {
DataSourceInitializer initializer = new DataSourceInitializer();
initializer.setDataSource(sqliteDataSource());
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
// 先执行schema.sql创建表结构
populator.addScript(new ClassPathResource(baseURL + "sqlite-schema.sql"));
// 再执行data.sql插入数据
populator.addScript(new ClassPathResource(baseURL + "sqlite-data.sql"));
populator.setContinueOnError(true);
initializer.setDatabasePopulator(populator);
return initializer;
}
}

View File

@ -0,0 +1,77 @@
package com.example.demo.common.config.orm;
import org.springframework.context.annotation.Configuration;
/**
* Bean Searcher配置类
* 配置Bean Searcher框架用于高级查询功能
*
* @author system
* @version 1.0
*/
@Configuration
public class BeanSearcherConfig {
/**
* 由于Bean Searcher框架会自动配置这里仅做占位配置
* 实际项目中可根据需要添加自定义配置
*/
// 注意实际使用时需要引入正确的Bean Searcher依赖并使用正确的包名
// 例如import cn.beansearcher.config.SearcherConfig;
// import cn.beansearcher.interceptor.InterceptorChain;
/*
@Bean
public SearcherConfig searcherConfig(InterceptorChain interceptorChain) {
SearcherConfig config = new SearcherConfig();
// 配置默认的页码从1开始
config.setDefaultPage(1);
// 配置默认的每页记录数
config.setDefaultSize(10);
// 配置最大每页记录数
config.setMaxSize(1000);
// 配置是否允许多表查询
config.setAllowMultiTable(true);
// 配置是否允许模糊查询
config.setAllowLike(true);
// 配置模糊查询的默认模式LEFT, RIGHT, BOTH
config.setDefaultLikeMode("BOTH");
// 配置是否允许排序
config.setAllowOrderby(true);
// 配置拦截器链
config.setInterceptorChain(interceptorChain);
// 配置是否显示SQL日志
config.setShowSql(true);
// 配置是否格式化SQL日志
config.setFormatSql(true);
// 配置是否显示参数
config.setShowParams(true);
// 配置是否显示执行时间
config.setShowExecuteTime(true);
return config;
}
@Bean
public InterceptorChain interceptorChain() {
InterceptorChain chain = new InterceptorChain();
// 这里可以添加自定义拦截器
// chain.addInterceptor(new MyInterceptor());
return chain;
}
*/
}

View File

@ -0,0 +1,37 @@
package com.example.demo.common.config.springdoc;
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.info.Info;
import io.swagger.v3.oas.annotations.info.License;
import io.swagger.v3.oas.annotations.servers.Server;
import org.springframework.context.annotation.Configuration;
/**
* OpenAPI配置类
* 配置Swagger/OpenAPI文档生成
*
* @author system
* @version 1.0
*/
@Configuration
@OpenAPIDefinition(
info = @Info(
title = "XML解析转TXT服务API文档",
description = "提供XML文件解析并转换为TXT文件的服务接口",
version = "1.0.0",
license = @License(
name = "Apache 2.0",
url = "http://www.apache.org/licenses/LICENSE-2.0"
)
),
servers = {
@Server(
url = "/xml-parser",
description = "本地开发环境"
)
}
)
public class OpenApiConfig {
// 这里可以添加更多OpenAPI配置
// 例如安全配置全局参数等
}

View File

@ -0,0 +1,101 @@
package com.example.demo.common.config.tika.config;
import lombok.RequiredArgsConstructor;
import org.apache.tika.Tika;
import org.apache.tika.config.TikaConfig;
import org.apache.tika.detect.Detector;
import org.apache.tika.exception.TikaException;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.parser.Parser;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.xml.sax.SAXException;
import java.io.IOException;
import java.io.InputStream;
/**
* Tika配置类
*
* <p>该类负责配置和初始化Apache Tika组件用于文档内容检测和解析
* 通过加载自定义的tika-config.xml配置文件来定制Tika的行为</p>
*
* <p>使用示例</p>
* <pre>
* {@code
* // 自动注入Tika实例
* @Autowired
* private Tika tika;
*
* // 使用Tika检测文件类型
* String fileType = tika.detect(file);
*
* // 使用Tika解析文件内容
* String content = tika.parseToString(file);
* }
* </pre>
*
* @author system
* @version 1.0
*
* @see Tika
* @see TikaConfig
* @see Detector
* @see Parser
*/
@Configuration
@RequiredArgsConstructor
public class MyTikaConfig {
/**
* Spring资源加载器用于加载类路径下的配置文件
*/
private final ResourceLoader resourceLoader;
/**
* 创建并配置Tika实例
*
* <p>该方法会从类路径下加载tika-config.xml配置文件基于该配置创建TikaConfig
* 然后获取配置中的检测器(Detector)和解析器(Parser)最终构建Tika实例</p>
*
* <p>配置文件的预期位置src/main/resources/tika-config.xml</p>
*
* @return 配置好的Tika实例可用于文件类型检测和内容解析
* @throws TikaException 当Tika配置处理过程中发生错误时抛出
* @throws IOException 当读取配置文件发生I/O错误时抛出
* @throws SAXException 当解析XML配置文件发生错误时抛出
*
* @see TikaConfig
* @see Detector
* @see AutoDetectParser
*
* @example 使用自定义配置的Tika实例
* <pre>
* {@code
* Tika tika = myTikaConfig.tika();
* String mimeType = tika.detect(new File("document.pdf"));
* String content = tika.parseToString(new File("document.pdf"));
* }
* </pre>
*/
@Bean
public Tika tika() throws TikaException, IOException, SAXException {
// 从类路径加载Tika配置文件
Resource resource = resourceLoader.getResource("classpath:tika-config.xml");
InputStream inputStream = resource.getInputStream();
// 基于配置文件创建Tika配置
TikaConfig config = new TikaConfig(inputStream);
// 从配置中获取文件类型检测器
Detector detector = config.getDetector();
// 创建自动检测解析器使用自定义配置
Parser autoDetectParser = new AutoDetectParser(config);
// 构建并返回Tika实例组合检测器和解析器
return new Tika(detector, autoDetectParser);
}
}

View File

@ -0,0 +1,65 @@
package com.example.demo.common.config.tika.handle;
import lombok.extern.slf4j.Slf4j;
import org.apache.tika.detect.AutoDetectReader;
import org.apache.tika.exception.TikaException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
/**
* 文件字符集检测工具类
* <p>
* 该类使用Apache Tika库的AutoDetectReader自动检测输入流的字符集编码
* 主要用于识别文件或数据流的字符集如UTF-8GBKISO-8859-1等
* </p>
*
* @author system
* @version 1.0
*/
@Slf4j
public class FileCharsetCheck {
/**
* 检测输入流的字符集编码
* <p>
* 该方法通过分析输入流的前几个字节来自动识别字符集编码
* 如果检测过程中发生异常将记录错误日志并返回null
* </p>
*
* <p><b>注意</b>该方法会读取输入流的起始部分内容但不会重置流的位置
* 调用者需要自行处理输入流的位置重置或重新创建输入流</p>
*
* <p><b>使用示例</b></p>
* <pre>{@code
* InputStream inputStream = new FileInputStream("example.txt");
* String charset = FileCharsetCheck.check(inputStream);
* if (charset != null) {
* System.out.println("文件编码: " + charset);
* } else {
* System.out.println("编码检测失败");
* }
* }</pre>
*
* @param input 要检测的输入流不能为null
* @return 检测到的字符集名称"UTF-8"如果检测失败则返回null
* @throws IllegalArgumentException 如果输入流为null
*
* @see AutoDetectReader
* @see Charset
*/
public static String check(InputStream input) {
if (input == null) {
throw new IllegalArgumentException("输入流不能为null");
}
try {
Charset charset = new AutoDetectReader(input).getCharset();
return charset.name();
} catch (IOException | TikaException e) {
log.error("解析文件编码异常!", e);
}
return null;
}
}

View File

@ -0,0 +1,119 @@
package com.example.demo.common.config.tika.handle;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.tika.Tika;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
/**
* 文件类型检查工具类
* 使用Apache Tika库检测文件真实类型防止文件类型欺骗攻击
* 通过白名单机制限制可上传的文件类型增强系统安全性
*
* @author system
* @version 1.0
*/
@Slf4j
public class FileTypeCheck {
/**
* 允许的文件类型白名单
* 包含办公文档图片媒体文件数据文件等常见安全文件类型
*/
private static final List<String> WHITE_LIST = new ArrayList<>(16);
static {
/* 办公文件 */
WHITE_LIST.add(FileTypeConst.FILE_TYPE_XLS);
WHITE_LIST.add(FileTypeConst.FILE_TYPE_XLSX);
WHITE_LIST.add(FileTypeConst.FILE_TYPE_DOC);
WHITE_LIST.add(FileTypeConst.FILE_TYPE_DOCX);
WHITE_LIST.add(FileTypeConst.FILE_TYPE_PPT);
WHITE_LIST.add(FileTypeConst.FILE_TYPE_PPTX);
WHITE_LIST.add(FileTypeConst.FILE_TYPE_PDF);
/* 图片 */
WHITE_LIST.add(FileTypeConst.FILE_TYPE_SVG);
WHITE_LIST.add(FileTypeConst.FILE_TYPE_ICO);
WHITE_LIST.add(FileTypeConst.FILE_TYPE_PNG);
WHITE_LIST.add(FileTypeConst.FILE_TYPE_JPEG);
WHITE_LIST.add(FileTypeConst.FILE_TYPE_GIF);
WHITE_LIST.add(FileTypeConst.FILE_TYPE_BMP);
WHITE_LIST.add(FileTypeConst.FILE_TYPE_WEBP);
/* 媒体 */
WHITE_LIST.add(FileTypeConst.FILE_TYPE_MP3);
WHITE_LIST.add(FileTypeConst.FILE_TYPE_MP4);
WHITE_LIST.add(FileTypeConst.FILE_TYPE_WAV);
WHITE_LIST.add(FileTypeConst.FILE_TYPE_AVI);
WHITE_LIST.add(FileTypeConst.FILE_TYPE_MOV);
/* 可执行文件或安装包 */
WHITE_LIST.add(FileTypeConst.FILE_TYPE_EXE);
WHITE_LIST.add(FileTypeConst.FILE_TYPE_MSI);
/* 常用格式化数据文件 */
WHITE_LIST.add(FileTypeConst.FILE_TYPE_TXT);
WHITE_LIST.add(FileTypeConst.FILE_TYPE_JSON);
WHITE_LIST.add(FileTypeConst.FILE_TYPE_XML);
WHITE_LIST.add(FileTypeConst.FILE_TYPE_CSV);
/* 压缩包 */
WHITE_LIST.add(FileTypeConst.FILE_TYPE_7Z);
WHITE_LIST.add(FileTypeConst.FILE_TYPE_RAR);
WHITE_LIST.add(FileTypeConst.FILE_TYPE_ZIP);
}
/**
* 通过文件名和输入流检查文件类型
* 使用Tika库检测文件的真实MIME类型并与白名单进行比对
* 如果文件类型不在白名单中将抛出RuntimeException
*
* @param fileName 文件名用于创建临时文件
* @param inputStream 文件输入流
* @throws RuntimeException 当文件类型不在白名单中时抛出
*/
public static void getFileTypeByFileName(final String fileName, InputStream inputStream) {
Tika defaultTika = new Tika();
String fileType;
// 创建临时文件用于类型检测
final File file = new File(fileName);
try {
// 将输入流复制到临时文件
FileUtils.copyInputStreamToFile(inputStream, file);
// 使用Tika检测文件真实类型
fileType = defaultTika.detect(file);
// 检查文件类型是否在白名单中
if (!WHITE_LIST.contains(fileType)) {
throw new RuntimeException("请上传正确的文件类型!!!");
}
} catch (IOException e) {
log.error("getFileTypeByFileName exception:", e);
} finally {
// 清理临时文件
if (file.exists()) {
file.delete();
}
}
}
/**
* 通过MultipartFile检查文件类型
* 适用于Spring MVC文件上传场景
*
* @param fileName 文件名
* @param mFile Spring MultipartFile对象
*/
public static void getFileTypeByFileName(final String fileName, MultipartFile mFile) {
try {
// 调用重载方法使用MultipartFile的输入流
getFileTypeByFileName(fileName, mFile.getInputStream());
} catch (IOException e) {
log.error("getFileTypeByFileName exception:", e);
}
}
}

View File

@ -0,0 +1,368 @@
package com.example.demo.common.config.tika.handle;
/**
* 文件类型常量类
* <p>
* 该类定义了常见的文件MIME类型常量用于文件上传下载验证等场景
* 所有常量均为标准的MIME类型字符串
* 参考了标准MIME类型定义及常见文件格式:cite[2]:cite[9]
* </p>
*
* @author system
* @version 1.0
*/
public class FileTypeConst {
/* 电子文档与数据文件 */
/**
* Excel 97-2003 工作表格式 (.xls)
*/
public static final String FILE_TYPE_XLS = "application/vnd.ms-excel";
/**
* Excel 2007及以上 工作表格式 (.xlsx)
*/
public static final String FILE_TYPE_XLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
/**
* Word 97-2003 文档格式 (.doc)
*/
public static final String FILE_TYPE_DOC = "application/msword";
/**
* Word 2007及以上 文档格式 (.docx)
*/
public static final String FILE_TYPE_DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
/**
* PowerPoint 97-2003 演示文稿格式 (.ppt)
*/
public static final String FILE_TYPE_PPT = "application/vnd.ms-powerpoint";
/**
* PowerPoint 2007及以上 演示文稿格式 (.pptx)
*/
public static final String FILE_TYPE_PPTX = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
/**
* Adobe PDF 文档格式 (.pdf)
*/
public static final String FILE_TYPE_PDF = "application/pdf";
/**
* JSON 数据格式 (.json)
*/
public static final String FILE_TYPE_JSON = "application/json";
/**
* XML 数据格式 (.xml)
*/
public static final String FILE_TYPE_XML = "application/xml";
/**
* 纯文本文件格式 (.txt)
*/
public static final String FILE_TYPE_TXT = "text/plain";
/**
* CSV 逗号分隔值文件格式 (.csv)
*/
public static final String FILE_TYPE_CSV = "text/csv";
/**
* HTML 网页文件格式 (.html, .htm)
*/
public static final String FILE_TYPE_HTML = "text/html";
/**
* CSS 样式表文件格式 (.css)
*/
public static final String FILE_TYPE_CSS = "text/css";
/* 压缩文件 */
/**
* ZIP 压缩文件格式 (.zip)
*/
public static final String FILE_TYPE_ZIP = "application/zip";
/**
* RAR 压缩文件格式 (.rar)
*/
public static final String FILE_TYPE_RAR = "application/vnd.rar";
/**
* 7-Zip 压缩文件格式 (.7z)
*/
public static final String FILE_TYPE_7Z = "application/x-7z-compressed";
/**
* GZIP 压缩文件格式 (.gz)
*/
public static final String FILE_TYPE_GZ = "application/gzip";
/**
* TAR 归档文件格式 (.tar)
*/
public static final String FILE_TYPE_TAR = "application/x-tar";
/* 可执行文件与安装包 */
/**
* Windows 可执行程序格式 (.exe)
*/
public static final String FILE_TYPE_EXE = "application/x-msdownload";
/**
* Windows 安装包格式 (.msi)
*/
public static final String FILE_TYPE_MSI = "application/x-msi";
/**
* Android 应用安装包格式 (.apk)
*/
public static final String FILE_TYPE_APK = "application/vnd.android.package-archive";
/**
* Debian/Ubuntu 系统安装包格式 (.deb)
*/
public static final String FILE_TYPE_DEB = "application/vnd.debian.binary-package";
/**
* Red Hat/CentOS 系统安装包格式 (.rpm)
*/
public static final String FILE_TYPE_RPM = "application/x-rpm";
/**
* macOS 磁盘映像文件格式 (.dmg)
*/
public static final String FILE_TYPE_DMG = "application/x-apple-diskimage";
/**
* Java 归档文件格式 (.jar)
*/
public static final String FILE_TYPE_JAR = "application/java-archive";
/* 图片与图形文件 */
/**
* JPEG 图像格式 (.jpg, .jpeg)
*/
public static final String FILE_TYPE_JPEG = "image/jpeg";
/**
* PNG 图像格式 (.png)
*/
public static final String FILE_TYPE_PNG = "image/png";
/**
* GIF 图像格式 (.gif)
*/
public static final String FILE_TYPE_GIF = "image/gif";
/**
* BMP 位图格式 (.bmp)
*/
public static final String FILE_TYPE_BMP = "image/bmp";
/**
* WebP 图像格式 (.webp)
*/
public static final String FILE_TYPE_WEBP = "image/webp";
/**
* TIFF 高质量图像格式 (.tiff, .tif)
*/
public static final String FILE_TYPE_TIFF = "image/tiff";
/**
* ICO 图标文件格式 (.ico)
*/
public static final String FILE_TYPE_ICO = "image/x-icon";
/**
* SVG 矢量图形格式 (.svg) - 标准MIME类型为 image/svg+xml:cite[2]
*/
public static final String FILE_TYPE_SVG = "image/svg+xml";
/**
* HEIC/HEIF 高效图像文件格式 (.heic, .heif)
*/
public static final String FILE_TYPE_HEIC = "image/heic";
/* 音频文件 */
/**
* MP3 音频格式 (.mp3)
*/
public static final String FILE_TYPE_MP3 = "audio/mpeg";
/**
* WAV 音频格式 (.wav)
*/
public static final String FILE_TYPE_WAV = "audio/wav";
/**
* AAC 高级音频编码格式 (.aac)
*/
public static final String FILE_TYPE_AAC = "audio/aac";
/**
* OGG 音频格式 (.ogg, .oga)
*/
public static final String FILE_TYPE_OGG_AUDIO = "audio/ogg";
/**
* FLAC 无损音频格式 (.flac)
*/
public static final String FILE_TYPE_FLAC = "audio/flac";
/**
* MIDI 音乐文件格式 (.mid, .midi)
*/
public static final String FILE_TYPE_MIDI = "audio/midi";
/* 视频文件 */
/**
* MP4 视频格式 (.mp4)
*/
public static final String FILE_TYPE_MP4 = "video/mp4";
/**
* AVI 音频视频交错格式 (.avi)
*/
public static final String FILE_TYPE_AVI = "video/x-msvideo";
/**
* MOV QuickTime 视频格式 (.mov)
*/
public static final String FILE_TYPE_MOV = "video/quicktime";
/**
* WebM 开放网络媒体格式 (.webm)
*/
public static final String FILE_TYPE_WEBM = "video/webm";
/**
* MPEG-1/2 视频格式 (.mpeg, .mpg)
*/
public static final String FILE_TYPE_MPEG = "video/mpeg";
/**
* WMV Windows Media 视频格式 (.wmv)
*/
public static final String FILE_TYPE_WMV = "video/x-ms-wmv";
/**
* FLV Flash 视频格式 (.flv)
*/
public static final String FILE_TYPE_FLV = "video/x-flv";
/**
* 3GPP 多媒体容器格式 (.3gp)
*/
public static final String FILE_TYPE_3GP = "video/3gpp";
/* 脚本与源代码文件 */
/**
* JavaScript 文件格式 (.js)
*/
public static final String FILE_TYPE_JS = "application/javascript";
/**
* TypeScript 文件格式 (.ts) - 通常作为文本处理
*/
public static final String FILE_TYPE_TS = "application/typescript";
/**
* Python 脚本文件格式 (.py)
*/
public static final String FILE_TYPE_PY = "text/x-python";
/**
* Java 源代码文件格式 (.java)
*/
public static final String FILE_TYPE_JAVA = "text/x-java-source";
/**
* C/C++ 头文件格式 (.h)
*/
public static final String FILE_TYPE_H = "text/x-c";
/**
* C/C++ 源文件格式 (.c, .cpp)
*/
public static final String FILE_TYPE_C = "text/x-c";
/**
* PHP 脚本文件格式 (.php)
*/
public static final String FILE_TYPE_PHP = "application/x-php";
/**
* Shell 脚本文件格式 (.sh)
*/
public static final String FILE_TYPE_SH = "application/x-sh";
/**
* PowerShell 脚本文件格式 (.ps1)
*/
public static final String FILE_TYPE_PS1 = "application/x-powershell";
/**
* Batch 批处理文件格式 (.bat) - 通常作为文本处理
*/
public static final String FILE_TYPE_BAT = "application/x-msdownload";
/* 字体文件 */
/**
* TrueType 字体格式 (.ttf)
*/
public static final String FILE_TYPE_TTF = "font/ttf";
/**
* OpenType 字体格式 (.otf)
*/
public static final String FILE_TYPE_OTF = "font/otf";
/**
* Web Open Font 格式 (.woff)
*/
public static final String FILE_TYPE_WOFF = "font/woff";
/**
* Web Open Font 格式 2.0 (.woff2)
*/
public static final String FILE_TYPE_WOFF2 = "font/woff2";
/* 其他文件类型 */
/**
* 电子邮件格式 (.eml)
*/
public static final String FILE_TYPE_EML = "message/rfc822";
/**
* iCalendar 日历文件格式 (.ics)
*/
public static final String FILE_TYPE_ICS = "text/calendar";
/**
* SQL 数据库转储文件格式 (.sql)
*/
public static final String FILE_TYPE_SQL = "application/sql";
/**
* 电子书 EPUB 格式 (.epub)
*/
public static final String FILE_TYPE_EPUB = "application/epub+zip";
/**
* 虚拟磁盘文件格式 (.iso)
*/
public static final String FILE_TYPE_ISO = "application/x-iso9660-image";
}

View File

@ -0,0 +1,163 @@
package com.example.demo.common.constant;
/**
* 系统常量类
* 定义系统中使用的各种常量包括错误码文件类型状态码等
*
* @author system
* @version 1.0
*/
public class GlobalConstants {
/** 否 */
public static final String N = "0";
/** 是 */
public static final String Y = "1";
// ==================== 文件相关常量 ==================== //
public static class FileExtensionType {
/**
* XML文件扩展名
*/
public static final String FILE_EXTENSION_XML = ".xml";
/**
* TXT文件扩展名
*/
public static final String FILE_EXTENSION_TXT = ".txt";
}
public static class FileStatus {
/**
* 文件上传状态已上传
*/
public static final String FILE_STATUS_UPLOADED = "uploaded";
/**
* 文件状态已解析
*/
public static final String FILE_STATUS_PARSED = "parsed";
/**
* 文件状态已转换
*/
public static final String FILE_STATUS_CONVERTED = "converted";
}
// ==================== XML解析相关常量 ==================== //
public static class XMLTagType {
/**
* XML标签类型根节点
*/
public static final String XML_TAG_TYPE_ROOT = "root";
/**
* XML标签类型普通节点
*/
public static final String XML_TAG_TYPE_NODE = "node";
/**
* XML标签类型叶子节点
*/
public static final String XML_TAG_TYPE_LEAF = "leaf";
/**
* XML属性label
*/
public static final String XML_ATTR_LABEL = "label";
/**
* XML属性isNull
*/
public static final String XML_ATTR_IS_NULL = "isNull";
/**
* XML属性node
*/
public static final String XML_ATTR_NODE = "node";
}
// ==================== 通用状态常量 ==================== //
public static class Status {
/**
* 未删除状态
*/
public static final String NOT_DELETED = "0";
/**
* 已删除状态
*/
public static final String DELETED = "1";
/**
* 启用状态
*/
public static final String ENABLED = "1";
/**
* 禁用状态
*/
public static final String DISABLED = "0";
}
// ==================== 字符集常量 ==================== //
public static class Charset {
/**
* UTF-8字符集
*/
public static final String CHARSET_UTF8 = "UTF-8";
}
// ==================== 路径常量 ==================== //
public static class Path {
/**
* 路径分隔符
*/
public static final String PATH_SEPARATOR = "/";
/**
* Windows路径分隔符
*/
public static final String WINDOWS_PATH_SEPARATOR = "\\";
}
// ==================== 缓存相关常量 ==================== //
public static class Cache {
/**
* 解析规则缓存键前缀
*/
public static final String CACHE_KEY_PARSE_RULE = "parse_rule:";
/**
* 映射规则缓存键前缀
*/
public static final String CACHE_KEY_MAPPER_RULE = "mapper_rule:";
/**
* 默认缓存过期时间
*/
public static final long DEFAULT_CACHE_EXPIRE = 3600L;
}
}

View File

@ -0,0 +1,58 @@
package com.example.demo.common.domain;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.experimental.SuperBuilder;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 基础数据传输对象
* 所有DTO类的基类用于数据在不同层之间的传递
*
* @author system
* @version 1.0
*/
@Schema(description = "基础数据传输对象")
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class BaseDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
@Schema(description = "ID")
private String id;
/**
* 创建时间
*/
@Schema(description = "创建时间")
private Date createdTime;
/**
* 创建人ID
*/
@Schema(description = "创建人ID")
private String createdId;
/**
* 更新时间
*/
@Schema(description = "更新时间")
private Date updatedTime;
/**
* 更新人ID
*/
@Schema(description = "更新人ID")
private String updatedId;
}

View File

@ -0,0 +1,104 @@
package com.example.demo.common.domain;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.core.keygen.KeyGenerators;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.experimental.SuperBuilder;
import org.springframework.format.annotation.DateTimeFormat;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 基础实体类
* 所有数据库实体类的基类包含通用字段和注解
*
* @author system
* @version 1.0
*/
@Schema(description = "基础实体类")
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class BaseEntity implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
@Id(keyType = KeyType.Generator, value = KeyGenerators.uuid)
@Schema(description = "ID")
private String id;
/**
* 命名空间
*/
@Schema(description = "命名空间")
private String nameSpace;
/**
* 排序字段
*/
@Schema(description = "排序字段")
private String sortName;
/**
* 是否删除0未删除1已删除
*/
@Column(isLogicDelete = true)
@Schema(description = "是否删除")
private String isDelete;
/**
* 乐观锁版本号
*/
@Column(version = true)
@Schema(description = "乐观锁版本号")
private Integer revision;
/**
* 创建时间
*/
@Column(onInsertValue = "now()")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description = "创建时间")
private Date createdTime;
/**
* 创建人ID
*/
@Schema(description = "创建人ID")
private String createdId;
/**
* 更新时间
*/
@Column(onUpdateValue = "now()", onInsertValue = "now()")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description = "更新时间")
private Date updatedTime;
/**
* 更新人ID
*/
@Schema(description = "更新人ID")
private String updatedId;
/**
* 租户ID
*/
@Schema(description = "租户ID")
private String tenantId;
}

View File

@ -0,0 +1,62 @@
package com.example.demo.common.domain;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import cn.zhxu.bs.bean.DbField;
import lombok.experimental.SuperBuilder;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 基础查询数据传输对象
* 所有查询DTO类的基类用于封装查询条件
*
* @author system
* @version 1.0
*/
@Schema(description = "基础查询数据传输对象")
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class BaseQueryDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 模糊查询
*/
@Schema(description = "模糊查询")
private String fuzzy;
/**
* 分页参数当前页码
*/
@Builder.Default
@Schema(description = "当前页码")
private Integer pageNum = 1;
/**
* 分页参数每页条数
*/
@Builder.Default
@Schema(description = "每页条数")
private Integer pageSize = 10;
/**
* 排序字段
*/
@Schema(description = "排序字段")
private String sortField;
/**
* 排序方式asc或desc
*/
@Schema(description = "排序方式")
private String sortOrder;
}

View File

@ -0,0 +1,80 @@
package com.example.demo.common.domain;
import com.mybatisflex.annotation.Column;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.experimental.SuperBuilder;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 基础视图对象
* 所有VO类的基类用于向前端返回数据
*
* @author system
* @version 1.0
*/
@Schema(description = "基础视图对象")
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class BaseVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
@Schema(description = "ID")
private String id;
/**
*
*/
@Schema(description = "key")
private String key;
/**
* 名称
*/
@Schema(description = "name")
private String name;
/**
* 创建时间
*/
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description = "创建时间")
private Date createdTime;
/**
* 创建人ID
*/
@Schema(description = "创建人ID")
private String createdId;
/**
* 更新时间
*/
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description = "更新时间")
private Date updatedTime;
/**
* 更新人ID
*/
@Schema(description = "更新人ID")
private String updatedId;
/**
* 是否删除0未删除1已删除
*/
@Schema(description = "是否删除")
private String isDelete;
}

View File

@ -0,0 +1,76 @@
package com.example.demo.common.exception;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import java.io.Serial;
/**
* 业务异常类
* 用于表示业务逻辑中的异常情况
*
* @author system
* @version 1.0
*/
@Getter
@Setter(value = AccessLevel.PRIVATE)
public class BusinessException extends RuntimeException {
@Serial
private static final long serialVersionUID = 1L;
/**
* 错误码
*/
private int code;
/**
* 构造函数
*
* @param code 错误码
* @param message 错误信息
*/
public BusinessException(int code, String message) {
super(message);
this.code = code;
}
/**
* 构造函数使用默认错误码
*
* @param message 错误信息
*/
public BusinessException(String message) {
super(message);
this.code = 500;
}
/**
* 构造函数包含异常原因
*
* @param code 错误码
* @param message 错误信息
* @param cause 异常原因
*/
public BusinessException(int code, String message, Throwable cause) {
super(message, cause);
this.code = code;
}
/**
* 构造函数包含异常原因使用默认错误码
*
* @param message 错误信息
* @param cause 异常原因
*/
public BusinessException(String message, Throwable cause) {
super(message, cause);
this.code = 500;
}
@Override
public String toString() {
return "BusinessException{code=" + code + ", message='" + getMessage() + "'}";
}
}

View File

@ -0,0 +1,138 @@
package com.example.demo.common.exception.global;
import com.example.demo.common.wrapper.WrapMapper;
import com.example.demo.common.wrapper.Wrapper;
import com.example.demo.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 全局异常处理器
* 统一处理系统异常返回规范的错误响应
*
* @author system
* @version 1.0
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 处理业务异常
*
* @param e 业务异常
* @return 错误响应
*/
@ExceptionHandler(BusinessException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Wrapper<String> handleBusinessException(BusinessException e) {
log.warn("业务异常: {}", e.getMessage(), e);
return WrapMapper.fail(String.valueOf(e.getCode()), e.getMessage());
}
/**
* 处理参数校验异常MethodArgumentNotValidException
*
* @param e 参数校验异常
* @return 错误响应
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Wrapper<String> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
String errorMessage = fieldErrors.stream()
.map(error -> error.getField() + ": " + error.getDefaultMessage())
.collect(Collectors.joining("; "));
log.warn("参数校验异常: {}", errorMessage);
return WrapMapper.fail("PARAM_VALIDATION_ERROR", errorMessage);
}
/**
* 处理参数绑定异常BindException
*
* @param e 参数绑定异常
* @return 错误响应
*/
@ExceptionHandler(BindException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Wrapper<String> handleBindException(BindException e) {
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
String errorMessage = fieldErrors.stream()
.map(error -> error.getField() + ": " + error.getDefaultMessage())
.collect(Collectors.joining("; "));
log.warn("参数绑定异常: {}", errorMessage);
return WrapMapper.fail("PARAM_BINDING_ERROR", errorMessage);
}
/**
* 处理约束违反异常ConstraintViolationException
*
* @param e 约束违反异常
* @return 错误响应
*/
@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Wrapper<String> handleConstraintViolationException(ConstraintViolationException e) {
Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
String errorMessage = violations.stream()
.map(violation -> violation.getPropertyPath() + ": " + violation.getMessage())
.collect(Collectors.joining("; "));
log.warn("约束违反异常: {}", errorMessage);
return WrapMapper.fail("CONSTRAINT_VIOLATION_ERROR", errorMessage);
}
/**
* 处理文件上传大小限制异常
*
* @param e 文件上传大小限制异常
* @return 错误响应
*/
@ExceptionHandler(MaxUploadSizeExceededException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Wrapper<String> handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e) {
log.warn("文件上传大小限制异常: {}", e.getMessage(), e);
return WrapMapper.fail("FILE_UPLOAD_SIZE_LIMIT", "上传文件大小超过限制");
}
/**
* 处理系统异常
*
* @param e 系统异常
* @return 错误响应
*/
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Wrapper<String> handleException(Exception e) {
log.error("系统异常: {}", e.getMessage(), e);
return WrapMapper.fail("SYSTEM_ERROR", "系统内部错误,请联系管理员");
}
/**
* 处理运行时异常
*
* @param e 运行时异常
* @return 错误响应
*/
@ExceptionHandler(RuntimeException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Wrapper<String> handleRuntimeException(RuntimeException e) {
log.error("运行时异常: {}", e.getMessage(), e);
return WrapMapper.fail("RUNTIME_ERROR", "系统运行时错误,请联系管理员");
}
}

View File

@ -0,0 +1,11 @@
package com.example.demo.common.typography;
/**
* 统一 Controller 接口
* 统一定义 Controller 基础接口
*
* @author system
* @version 1.0
*/
public abstract class BaseController {
}

View File

@ -0,0 +1,68 @@
package com.example.demo.common.typography;
import cn.zhxu.bs.SearchResult;
import com.example.demo.common.domain.BaseDTO;
import com.example.demo.common.domain.BaseEntity;
import com.example.demo.common.domain.BaseQueryDTO;
import com.example.demo.common.domain.BaseVO;
import com.mybatisflex.core.service.IService;
import java.util.List;
/**
* 统一 Service 接口
* 统一定义Service基础接口
*
* @author system
* @version 1.0
*/
public interface BaseService<Entity extends BaseEntity, VO extends BaseVO, DTO extends BaseDTO, QueryDTO extends BaseQueryDTO>
extends IService<Entity> {
/**
* 创建
* @param dto DTO
* @return 创建结果
*/
VO create(DTO dto);
/**
* 删除
* @param id ID
*/
void delete(String id);
/**
* 更新
* @param dto DTO
* @return 是否更新成功
*/
Boolean update(DTO dto);
/**
* 分页查询
* @param dto 查询条件
* @return 分页结果
*/
SearchResult<VO> pageList(QueryDTO dto);
/**
* 获取下拉框数据
* @param dto 查询条件
* @return 下拉框数据列表
*/
List<VO> option(QueryDTO dto);
/**
* 获取详情
* @param id ID
* @return 详情
*/
VO detail(String id);
/**
* 刷新缓存
*/
void refreshCache();
}

View File

@ -0,0 +1,208 @@
package com.example.demo.common.typography;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.zhxu.bs.BeanSearcher;
import cn.zhxu.bs.SearchResult;
import cn.zhxu.bs.operator.Contain;
import cn.zhxu.bs.util.MapUtils;
import com.example.demo.common.constant.GlobalConstants;
import com.example.demo.common.domain.BaseDTO;
import com.example.demo.common.domain.BaseEntity;
import com.example.demo.common.domain.BaseQueryDTO;
import com.example.demo.common.domain.BaseVO;
import com.fhs.trans.service.impl.TransService;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Map;
@Service
@RequiredArgsConstructor
public abstract class BaseServiceImpl<
Entity extends BaseEntity,
VO extends BaseVO,
DTO extends BaseDTO,
QueryDTO extends BaseQueryDTO,
Mapper extends BaseMapper<Entity>
>
extends
ServiceImpl<Mapper, Entity>
implements
BaseService<Entity, VO, DTO, QueryDTO>, InitializingBean, DisposableBean {
/** 实际Log出例服务 */
private final Logger log;
/** 实际业务实现类 */
private final String CLASS_NAME;
/** 实际业务实现VO类 */
private final Class<VO> clazzVO;
/** 提供Select服务 */
private final BeanSearcher beanSearcher;
/** 提供数据翻译服务 */
private final TransService transService;
@Transactional(rollbackFor = Exception.class)
@Override
public VO create(DTO dto) {
Entity entity = createEntity();
BeanUtil.copyProperties(dto, entity);
// 新增数据
save(entity);
// 仅返回数据ID
@SuppressWarnings("all")
VO resultVO = (VO) VO.builder().id(entity.getId()).build();
// 其他处理...
return resultVO;
}
@Transactional(rollbackFor = Exception.class)
@Override
public void delete(String id) {
// 使用逻辑删除
removeById(id);
}
@Transactional(rollbackFor = Exception.class)
@Override
public Boolean update(DTO dto) {
Entity entity = createEntity();
BeanUtil.copyProperties(dto, entity);
// 更新数据
return updateById(entity);
}
@Override
public SearchResult<VO> pageList(QueryDTO dto) {
// 组装分页查询参数
Map<String, Object> paramMap = MapUtils.builder()
// 分页查询
.page(dto.getPageNum(), dto.getPageSize())
.limit(dto.getPageNum(), dto.getPageSize())
// 模糊查询
.field(VO::getName, dto.getFuzzy()).op(Contain.class)
// 未删除数据
.field(VO::getIsDelete, GlobalConstants.N)
// 分页排序默认强制按照更新时间倒序单词正序
.orderBy(VO::getUpdatedTime).desc()
.orderBy(VO::getName).asc()
.build();
@SuppressWarnings("all")
SearchResult<VO> vos = beanSearcher.search(this.clazzVO, paramMap);
if(CollUtil.isEmpty(vos.getDataList())) {
return vos;
}
// 批量数据翻译
// transService.transBatch(vos.getDataList());
return vos;
}
@Override
public List option(QueryDTO dto) {
Map<String, Object> paramMap = MapUtils.builder()
.onlySelect(
VO::getId,
VO::getName,
VO::getKey
)
// 下拉框允许模糊筛选
.field(VO::getName, dto.getFuzzy()).op(Contain.class)
// 下拉框只能查询未删除的数据
.field(VO::getIsDelete, GlobalConstants.N)
// 下拉框强制使用单词正序时间倒序
.orderBy(VO::getName).asc()
.orderBy(VO::getCreatedTime).desc()
.build();
List<VO> vos = beanSearcher.searchAll(this.clazzVO, paramMap);
if (CollUtil.isEmpty(vos)) {
return List.of();
}
return vos;
}
@Override
@SuppressWarnings("all")
public VO detail(String id) {
Map<String, Object> paramMap = MapUtils.builder()
.field(VO::getId, id)
.field(VO::getIsDelete, GlobalConstants.N)
.build();
VO wordVO = beanSearcher.searchFirst(this.clazzVO, paramMap);
// 数据翻译
if (ObjectUtil.isNotEmpty(wordVO)) {
// transService.transOne(wordVO);
}
return wordVO;
}
@Override
public void refreshCache() {
// ignore
log.warn("刷新缓存(暂无实现)");
}
@PostConstruct
public void init() {
// ignore
}
@Override
public void destroy() {
// ignore
}
@Override
public void afterPropertiesSet() {
// ignore
}
@PreDestroy
public void preDestroy() {
// ignore
}
/**
* 实例化 entity
* @return 获取新实例化 entity
*/
@SuppressWarnings("all")
protected Entity createEntity() {
return (Entity) Entity.builder().build();
}
/**
* 实例化 entity
* @return 获取新实例化 entity
*/
@SuppressWarnings("all")
protected VO createVO() {
return (VO) VO.builder().build();
}
/**
* 实例化 entity
* @return 获取新实例化 entity
*/
@SuppressWarnings("all")
protected DTO createDTO() {
return (DTO) DTO.builder().build();
}
}

View File

@ -0,0 +1,315 @@
package com.example.demo.common.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* 文件操作工具类
* 提供文件读写复制删除等通用功能
*
* @author system
* @version 1.0
*/
public class FileUtil {
private static final Logger logger = LoggerFactory.getLogger(FileUtil.class);
/**
* 读取文件内容
*
* @param filePath 文件路径
* @return 文件内容
* @throws IOException IO异常
*/
public static String readFileContent(String filePath) throws IOException {
return new String(Files.readAllBytes(Paths.get(filePath)), StandardCharsets.UTF_8);
}
/**
* 写入内容到文件
*
* @param filePath 文件路径
* @param content 文件内容
* @throws IOException IO异常
*/
public static void writeFileContent(String filePath, String content) throws IOException {
// 确保父目录存在
Path path = Paths.get(filePath);
Path parentDir = path.getParent();
if (parentDir != null) {
Files.createDirectories(parentDir);
}
// 写入文件
Files.write(path, content.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
}
/**
* 追加内容到文件
*
* @param filePath 文件路径
* @param content 文件内容
* @throws IOException IO异常
*/
public static void appendFileContent(String filePath, String content) throws IOException {
// 确保父目录存在
Path path = Paths.get(filePath);
Path parentDir = path.getParent();
if (parentDir != null) {
Files.createDirectories(parentDir);
}
// 追加文件
Files.write(path, content.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE, StandardOpenOption.APPEND);
}
/**
* 复制文件
*
* @param sourceFilePath 源文件路径
* @param targetFilePath 目标文件路径
* @throws IOException IO异常
*/
public static void copyFile(String sourceFilePath, String targetFilePath) throws IOException {
Path sourcePath = Paths.get(sourceFilePath);
Path targetPath = Paths.get(targetFilePath);
// 确保目标目录存在
Path targetDir = targetPath.getParent();
if (targetDir != null) {
Files.createDirectories(targetDir);
}
// 复制文件
Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING);
}
/**
* 移动文件
*
* @param sourceFilePath 源文件路径
* @param targetFilePath 目标文件路径
* @throws IOException IO异常
*/
public static void moveFile(String sourceFilePath, String targetFilePath) throws IOException {
Path sourcePath = Paths.get(sourceFilePath);
Path targetPath = Paths.get(targetFilePath);
// 确保目标目录存在
Path targetDir = targetPath.getParent();
if (targetDir != null) {
Files.createDirectories(targetDir);
}
// 移动文件
Files.move(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING);
}
/**
* 删除文件
*
* @param filePath 文件路径
* @return 是否删除成功
* @throws IOException IO异常
*/
public static boolean deleteFile(String filePath) throws IOException {
return Files.deleteIfExists(Paths.get(filePath));
}
/**
* 创建目录
*
* @param dirPath 目录路径
* @return 是否创建成功
* @throws IOException IO异常
*/
public static boolean createDirectory(String dirPath) throws IOException {
Path path = Paths.get(dirPath);
if (Files.exists(path)) {
return Files.isDirectory(path);
}
Files.createDirectories(path);
return true;
}
/**
* 删除目录包括目录下的所有文件
*
* @param dirPath 目录路径
* @return 是否删除成功
* @throws IOException IO异常
*/
public static boolean deleteDirectory(String dirPath) throws IOException {
Path path = Paths.get(dirPath);
if (!Files.exists(path)) {
return true;
}
// 递归删除目录内容
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
return true;
}
/**
* 获取文件大小
*
* @param filePath 文件路径
* @return 文件大小字节
* @throws IOException IO异常
*/
public static long getFileSize(String filePath) throws IOException {
return Files.size(Paths.get(filePath));
}
/**
* 获取文件扩展名
*
* @param fileName 文件名
* @return 文件扩展名小写
*/
public static String getFileExtension(String fileName) {
if (fileName == null || fileName.lastIndexOf('.') == -1) {
return "";
}
return fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase();
}
/**
* 生成唯一文件名
*
* @param originalFileName 原始文件名
* @return 唯一文件名
*/
public static String generateUniqueFileName(String originalFileName) {
String extension = getFileExtension(originalFileName);
String timestamp = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
String uuid = UUID.randomUUID().toString().replaceAll("-|", "");
if (extension.isEmpty()) {
return timestamp + "_" + uuid;
} else {
return timestamp + "_" + uuid + "." + extension;
}
}
/**
* 列出目录下的所有文件
*
* @param dirPath 目录路径
* @return 文件路径列表
* @throws IOException IO异常
*/
public static List<String> listFiles(String dirPath) throws IOException {
List<String> filePaths = new ArrayList<>();
Path path = Paths.get(dirPath);
if (Files.exists(path) && Files.isDirectory(path)) {
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
filePaths.add(file.toString());
return FileVisitResult.CONTINUE;
}
});
}
return filePaths;
}
/**
* 获取文件的MIME类型
*
* @param filePath 文件路径
* @return MIME类型
* @throws IOException IO异常
*/
public static String getMimeType(String filePath) throws IOException {
return Files.probeContentType(Paths.get(filePath));
}
/**
* 检查文件是否存在
*
* @param filePath 文件路径
* @return 是否存在
*/
public static boolean fileExists(String filePath) {
return Files.exists(Paths.get(filePath));
}
/**
* 清理临时文件
*
* @param dirPath 临时目录路径
* @param daysAgo 清理多少天前的文件
* @return 清理的文件数量
* @throws IOException IO异常
*/
public static int cleanTempFiles(String dirPath, int daysAgo) throws IOException {
final int[] deletedCount = {0};
Path path = Paths.get(dirPath);
if (!Files.exists(path) || !Files.isDirectory(path)) {
return deletedCount[0];
}
long cutoffTime = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(daysAgo);
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
try {
// 检查文件的最后修改时间
if (Files.getLastModifiedTime(file).toMillis() < cutoffTime) {
Files.delete(file);
deletedCount[0]++;
}
} catch (IOException e) {
logger.error("删除临时文件失败: {}", file, e);
}
return FileVisitResult.CONTINUE;
}
});
return deletedCount[0];
}
/**
* 创建临时文件
*
* @param prefix 文件前缀
* @param suffix 文件后缀
* @param tempDir 临时目录
* @return 临时文件路径
* @throws IOException IO异常
*/
public static String createTempFile(String prefix, String suffix, String tempDir) throws IOException {
// 确保临时目录存在
createDirectory(tempDir);
// 创建临时文件
File tempFile = File.createTempFile(prefix, suffix, new File(tempDir));
return tempFile.getAbsolutePath();
}
}

View File

@ -0,0 +1,382 @@
package com.example.demo.common.utils;
import cn.hutool.core.util.StrUtil;
import org.w3c.dom.*;
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
/**
* XML解析工具类
* 提供XML文件解析和转换为TXT文件的核心功能
*
* @author system
* @version 1.0
*/
public class XmlParserUtil {
/**
* 解析XML文件并转换为TXT文件
*
* @param xmlFilePath XML文件路径
* @param txtFilePath TXT文件路径
* @throws Exception 解析过程中的异常
*/
public static void parseXmlToTxt(String xmlFilePath, String txtFilePath) throws Exception {
// 读取XML文件并解析
Document document = parseXmlFile(xmlFilePath);
// 创建TXT文件
createTxtFile(document, txtFilePath);
}
/**
* 解析XML文件为Document对象
*
* @param xmlFilePath XML文件路径
* @return Document对象
* @throws Exception 解析异常
*/
public static Document parseXmlFile(String xmlFilePath) throws Exception {
// 确保文件存在
File file = new File(xmlFilePath);
if (!file.exists()) {
throw new FileNotFoundException("XML文件不存在: " + xmlFilePath);
}
// 创建DocumentBuilder并解析文件
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setIgnoringElementContentWhitespace(true);
try (FileInputStream fis = new FileInputStream(file)) {
InputSource is = new InputSource(new InputStreamReader(fis, StandardCharsets.UTF_8));
return factory.newDocumentBuilder().parse(is);
}
}
/**
* 将Document对象转换为TXT文件
*
* @param document XML文档对象
* @param txtFilePath TXT文件路径
* @throws IOException IO异常
*/
public static void createTxtFile(Document document, String txtFilePath) throws IOException {
// 确保输出目录存在
Path outputPath = Paths.get(txtFilePath).getParent();
if (outputPath != null && !Files.exists(outputPath)) {
Files.createDirectories(outputPath);
}
// 写入TXT文件
try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(txtFilePath), StandardCharsets.UTF_8)) {
// 处理根元素
Element rootElement = document.getDocumentElement();
processElement(rootElement, writer, 0);
}
}
/**
* 递归处理XML元素并写入TXT文件
* 将中文XML标签转换为特定的TXT格式
*
* @param element 当前XML元素
* @param writer 输出写入器
* @param indentLevel 缩进级别
* @throws IOException IO异常
*/
private static void processElement(Element element, BufferedWriter writer, int indentLevel) throws IOException {
String tagName = element.getTagName();
String indent = " ".repeat(Math.max(0, indentLevel));
// 根据中文标签名映射到对应的TXT格式
switch (tagName) {
case "任务":
processTaskElement(element, writer, indentLevel);
break;
case "任务信息":
processTaskInfoElement(element, writer, indentLevel);
break;
case "平台":
processPlatformElement(element, writer, indentLevel);
break;
case "行动":
processActionElement(element, writer, indentLevel);
break;
default:
processGenericElement(element, writer, indentLevel);
break;
}
}
/**
* 处理任务元素
*/
private static void processTaskElement(Element element, BufferedWriter writer, int indentLevel) throws IOException {
String indent = " ".repeat(Math.max(0, indentLevel));
// 获取任务行动信息
String taskAction = getElementTextByTagName(element, "任务行动信息");
if (StrUtil.isNotBlank(taskAction)) {
writer.write(indent + "task " + taskAction + " # 任务信息");
writer.newLine();
}
// 处理子元素
processChildElements(element, writer, indentLevel + 1);
writer.write(indent + "end_task");
writer.newLine();
}
/**
* 处理任务信息元素
*/
private static void processTaskInfoElement(Element element, BufferedWriter writer, int indentLevel) throws IOException {
String indent = " ".repeat(Math.max(0, indentLevel));
// 处理指令有效期拆分为开始和结束时间
String instructionPeriod = getElementTextByTagName(element, "指令有效期");
if (StrUtil.isNotBlank(instructionPeriod)) {
String[] timeRange = instructionPeriod.split("~");
if (timeRange.length == 2) {
writer.write(indent + "start_time " + timeRange[0].trim());
writer.newLine();
writer.write(indent + "end_time " + timeRange[1].trim());
writer.newLine();
}
}
// 处理其他子元素
processChildElements(element, writer, indentLevel);
}
/**
* 处理平台元素
*/
private static void processPlatformElement(Element element, BufferedWriter writer, int indentLevel) throws IOException {
String indent = " ".repeat(Math.max(0, indentLevel));
writer.write(indent + "platform # 平台信息");
writer.newLine();
// 处理平台子元素
String platformName = getElementTextByTagName(element, "平台名称");
String machineType = getElementTextByTagName(element, "机型");
String numOfCpus = getElementTextByTagName(element, "架数");
String platformId = getElementTextByTagName(element, "平台识别码");
String country = getElementTextByTagName(element, "国家");
if (StrUtil.isNotBlank(platformName)) {
writer.write(indent + " platform_name " + platformName);
writer.newLine();
}
if (StrUtil.isNotBlank(machineType)) {
writer.write(indent + " machine_type " + machineType);
writer.newLine();
}
if (StrUtil.isNotBlank(numOfCpus)) {
writer.write(indent + " num_of_cpus " + numOfCpus);
writer.newLine();
}
if (StrUtil.isNotBlank(platformId)) {
writer.write(indent + " platform_id " + platformId);
writer.newLine();
}
if (StrUtil.isNotBlank(country)) {
writer.write(indent + " country " + country);
writer.newLine();
}
// 处理行动子元素
processChildElements(element, writer, indentLevel + 1);
writer.write(indent + "end_platform");
writer.newLine();
}
/**
* 处理行动元素
*/
private static void processActionElement(Element element, BufferedWriter writer, int indentLevel) throws IOException {
String indent = " ".repeat(Math.max(0, indentLevel));
writer.write(indent + "action");
writer.newLine();
// 处理行动属性
if (element.hasAttributes()) {
NamedNodeMap attributes = element.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Attr attr = (Attr) attributes.item(i);
if ("label".equals(attr.getName())) {
writer.write(indent + " action_name " + attr.getValue());
writer.newLine();
}
}
}
// 处理航线名称
String routeName = getElementTextByTagName(element, "航线名称");
if (StrUtil.isNotBlank(routeName)) {
writer.write(indent + " route_name " + routeName);
writer.newLine();
}
writer.write(indent + "end_action");
writer.newLine();
}
/**
* 处理通用元素
*/
private static void processGenericElement(Element element, BufferedWriter writer, int indentLevel) throws IOException {
String tagName = element.getTagName();
String indent = " ".repeat(Math.max(0, indentLevel));
// 将中文标签名转换为英文简单映射
String englishTag = convertChineseTagToEnglish(tagName);
if (StrUtil.isNotBlank(englishTag)) {
String textContent = getElementText(element);
if (StrUtil.isNotBlank(textContent)) {
writer.write(indent + englishTag + " " + textContent);
writer.newLine();
}
}
}
/**
* 处理子元素
*/
private static void processChildElements(Element parent, BufferedWriter writer, int indentLevel) throws IOException {
NodeList children = parent.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
if (children.item(i) instanceof Element) {
processElement((Element) children.item(i), writer, indentLevel);
}
}
}
/**
* 根据标签名获取元素文本内容
*/
private static String getElementTextByTagName(Element parent, String tagName) {
NodeList elements = parent.getElementsByTagName(tagName);
if (elements.getLength() > 0) {
Element element = (Element) elements.item(0);
return getElementText(element);
}
return "";
}
/**
* 将中文标签转换为英文标签
*/
private static String convertChineseTagToEnglish(String chineseTag) {
// 简单的中文到英文映射
switch (chineseTag) {
case "指令确认信息": return "confirm_info";
case "覆盖的指令文档": return "document_version";
default: return chineseTag;
}
}
/**
* 从XML字符串解析为Document对象
*
* @param xmlContent XML字符串内容
* @return Document对象
* @throws Exception 解析异常
*/
public static Document parseXmlString(String xmlContent) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
try (InputStream inputStream = new ByteArrayInputStream(xmlContent.getBytes(StandardCharsets.UTF_8))) {
InputSource is = new InputSource(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
return factory.newDocumentBuilder().parse(is);
}
}
/**
* 获取XML元素的文本内容
*
* @param element XML元素
* @return 文本内容
*/
public static String getElementText(Element element) {
if (element == null) {
return "";
}
NodeList childNodes = element.getChildNodes();
StringBuilder textContent = new StringBuilder();
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
if (node.getNodeType() == Node.TEXT_NODE) {
textContent.append(node.getNodeValue());
}
}
return textContent.toString().trim();
}
/**
* 获取指定路径的XML元素
*
* @param document XML文档对象
* @param xpath 元素路径
* @return 元素列表
*/
public static List<Element> getElementsByPath(Document document, String xpath) {
List<Element> elements = new ArrayList<>();
// 简单实现XPath功能实际项目中可使用JAXB或XPath API
String[] pathParts = xpath.split("/");
if (pathParts.length == 0) {
return elements;
}
// 查找根元素
Element currentElement = document.getDocumentElement();
if (!currentElement.getTagName().equals(pathParts[0])) {
return elements;
}
// 递归查找子元素
for (int i = 1; i < pathParts.length; i++) {
currentElement = findChildElement(currentElement, pathParts[i]);
if (currentElement == null) {
return elements;
}
}
elements.add(currentElement);
return elements;
}
/**
* 在父元素中查找指定名称的子元素
*
* @param parent 父元素
* @param tagName 子元素标签名
* @return 子元素
*/
private static Element findChildElement(Element parent, String tagName) {
NodeList childNodes = parent.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE && node.getNodeName().equals(tagName)) {
return (Element) node;
}
}
return null;
}
}

View File

@ -0,0 +1,90 @@
package com.example.demo.common.wrapper;
/**
* 统一响应包装工具类
* 提供静态方法创建Wrapper实例
*
* @author system
* @version 1.0
*/
public class WrapMapper {
/**
* 成功响应无数据
*
* @return 响应结果
*/
public static Wrapper<Object> ok() {
return ok(null, "操作成功");
}
/**
* 成功响应带消息
*
* @param message 响应消息
* @return 响应结果
*/
public static Wrapper<Object> ok(String message) {
return ok(null, message);
}
/**
* 成功响应带数据
*
* @param data 响应数据
* @return 响应结果
*/
public static <T> Wrapper<T> ok(T data) {
return ok(data, "操作成功");
}
/**
* 成功响应带数据和消息
*
* @param data 响应数据
* @param message 响应消息
* @return 响应结果
*/
public static <T> Wrapper<T> ok(T data, String message) {
Wrapper<T> result = new Wrapper<>();
result.setCode("SUCCESS");
result.setMessage(message);
result.setData(data);
result.setTimestamp(System.currentTimeMillis());
return result;
}
/**
* 失败响应默认消息
*
* @return 响应结果
*/
public static <T> Wrapper<T> fail() {
return fail("FAIL", "操作失败");
}
/**
* 失败响应带消息
*
* @param message 响应消息
* @return 响应结果
*/
public static <T> Wrapper<T> fail(String message) {
return fail("FAIL", message);
}
/**
* 失败响应带状态码和消息
*
* @param code 状态码
* @param message 响应消息
* @return 响应结果
*/
public static <T> Wrapper<T> fail(String code, String message) {
Wrapper<T> result = new Wrapper<>();
result.setCode(code);
result.setMessage(message);
result.setTimestamp(System.currentTimeMillis());
return result;
}
}

View File

@ -0,0 +1,61 @@
package com.example.demo.common.wrapper;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 统一响应包装类
* 用于封装所有RESTful API的响应数据
*
* @param <T> 响应数据类型
* @author system
* @version 1.0
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Wrapper<T> implements Serializable {
/**
* 响应状态码
*/
private String code;
/**
* 响应消息
*/
private String message;
/**
* 响应数据
*/
private T data;
/**
* 时间戳
*/
private Long timestamp;
/**
* 判断响应是否成功
*
* @return 是否成功
*/
public boolean isSuccess() {
return "SUCCESS".equals(code);
}
/**
* 判断响应是否失败
*
* @return 是否失败
*/
public boolean isFail() {
return !isSuccess();
}
}

View File

@ -0,0 +1,20 @@
// TODO XML 转成 JSON 注意事项
// 1 XML标签 需要映射到 特定的JSON路径上
// 2 XML标签 映射时允许模糊映射
// 3 XML标签 映射时允许批量映射
// 4 XML标签 映射时允许块映射
// TODO XML 转成 JSON 一定需要解决或者对接统一的问题
// 5 XML标签值 部分内容需要格式化例如 时间
// 6 XML标签值 部分内容需要函数计算例如 经纬度统一转化
// 7 XML标签值 部分内容需要确定统一单位例如 速度单位 m/s
// TODO XML 转成 JSON 可能存在的问题
// 8 XML标签一定存在部分数据是固定数据例如 各种类型枚举
// 9 XML标签属性 内容需要合并
// 10 XML标签 自定义函数问题
// 11 XML标签值存在一部分值需要拆分成多个数据
// 97 增量更新问题例如 推演过程中数据是动态不断更新的这种是需要追加旧数据还是读到什么数据就是什么数据
// 98 允许组合规则条件生效
// 99 对接时需要一个字段一个字段对应

View File

@ -0,0 +1,67 @@
package com.example.demo.draft.demo043;
import com.alibaba.fastjson.JSON;
import com.example.demo.draft.demo043.domain.ConfigDocument;
import com.example.demo.draft.demo043.core.EnhancedTemplateGenerator;
import com.example.demo.draft.demo043.core.Xml2AFSIMTransformation;
import com.example.demo.draft.demo043.util.FormatUtil;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
public class ApplicationTest__01 {
public static void main(String[] args) throws IOException {
List<String> dataList = new ArrayList<>() {{
add("20250923_6b399e.xml");
add("20250923_6ba0d8.xml");
add("20250923_9efa34.xml");
add("20250923_b345dd.xml");
add("20250923_e9dd05.xml");
}};
String prefix = "src/main/resources/data/01-作战部队武器装备/";
String inputTemplateData = prefix + "default.json";
String inputData = prefix + dataList.get(new Random().nextInt(dataList.size()));
String processJSONFile = "output-transformed-cg-003__01.json";
// Step.1
try {
Map<String, String> rules = new HashMap<>();
rules.put("\\.(.*)", "$1");
Xml2AFSIMTransformation converter = new Xml2AFSIMTransformation(rules);
File xmlFile = new File(inputData);
File jsonFile = new File(processJSONFile);
converter.convertXmlToJson(xmlFile, jsonFile, "作战部队武器装备");
System.out.println("XML转JSON并转换完成");
} catch (Exception e) {
e.printStackTrace();
}
// Step.2
String targetContent = Files.readString(Path.of(processJSONFile), StandardCharsets.UTF_8);
List<Object> list = JSON.parseArray(targetContent);
String templateContent = Files.readString(Path.of(inputTemplateData), StandardCharsets.UTF_8);
ConfigDocument document = JSON.parseObject(templateContent, ConfigDocument.class);
String result = JSON.toJSONString(document);
System.out.println(result);
for(Object obj: list) {
Map<String, String> map = JSON.parseObject(JSON.toJSONString(obj), Map.class);
result = FormatUtil.stealBeamsAndReplacePillars(result, map);
}
// Step.3
Map demoData = JSON.parseObject(result, Map.class);
System.out.println("=== 测试动态模板 ===");
String result1 = EnhancedTemplateGenerator.generateCodeWithFormat(demoData, "generator/jinjia2/dynamic-template.j2");
System.out.println(result1);
}
}

View File

@ -0,0 +1,67 @@
package com.example.demo.draft.demo043;
import com.alibaba.fastjson.JSON;
import com.example.demo.draft.demo043.domain.ConfigDocument;
import com.example.demo.draft.demo043.core.EnhancedTemplateGenerator;
import com.example.demo.draft.demo043.core.Xml2AFSIMTransformation;
import com.example.demo.draft.demo043.util.FormatUtil;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
public class ApplicationTest__02 {
public static void main(String[] args) throws IOException {
List<String> dataList = new ArrayList<>() {{
add("20250923_5e813d.xml");
add("20250923_7bbb1d.xml");
add("20250923_7f3eb1.xml");
add("20250923_199d51.xml");
}};
String prefix = "src/main/resources/data/02-单个空中平台任务数据/";
String inputTemplateData = prefix + "default.json";
String inputData = prefix + dataList.get(new Random().nextInt(dataList.size()));
String processJSONFile = "output-transformed-cg-003__02.json";
// Step.1
try {
Map<String, String> rules = new HashMap<>();
rules.put("\\.(.*)", "$1");
rules.put("单个空中平台任务数据.机型名称", "单个空中平台任务数据.平台名称");
Xml2AFSIMTransformation converter = new Xml2AFSIMTransformation(rules);
File xmlFile = new File(inputData);
File jsonFile = new File(processJSONFile);
converter.convertXmlToJson(xmlFile, jsonFile, "单个空中平台任务数据");
System.out.println("XML转JSON并转换完成");
} catch (Exception e) {
e.printStackTrace();
}
// Step.2
String targetContent = Files.readString(Path.of(processJSONFile), StandardCharsets.UTF_8);
List<Object> list = JSON.parseArray(targetContent);
String templateContent = Files.readString(Path.of(inputTemplateData), StandardCharsets.UTF_8);
ConfigDocument document = JSON.parseObject(templateContent, ConfigDocument.class);
String result = JSON.toJSONString(document);
System.out.println(result);
for(Object obj: list) {
Map<String, String> map = JSON.parseObject(JSON.toJSONString(obj), Map.class);
result = FormatUtil.stealBeamsAndReplacePillars(result, map);
}
// Step.3
Map demoData = JSON.parseObject(result, Map.class);
System.out.println("=== 测试动态模板 ===");
String result1 = EnhancedTemplateGenerator.generateCodeWithFormat(demoData, "generator/jinjia2/dynamic-template.j2");
System.out.println(result1);
}
}

View File

@ -0,0 +1,67 @@
package com.example.demo.draft.demo043;
import com.alibaba.fastjson.JSON;
import com.example.demo.draft.demo043.domain.ConfigDocument;
import com.example.demo.draft.demo043.core.EnhancedTemplateGenerator;
import com.example.demo.draft.demo043.core.Xml2AFSIMTransformation;
import com.example.demo.draft.demo043.util.FormatUtil;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
public class ApplicationTest__03 {
public static void main(String[] args) throws IOException {
List<String> dataList = new ArrayList<>() {{
add("20250923_4c32c8.xml");
add("20250923_82c579.xml");
add("20250923_422dc2.xml");
add("20250923_b43a26.xml");
add("20250923_c87aa1.xml");
}};
String prefix = "src/main/resources/data/03-任务航线/";
String inputTemplateData = prefix + "default.json";
String inputData = prefix + dataList.get(new Random().nextInt(dataList.size()));
String processJSONFile = "output-transformed-cg-003__03.json";
// Step.1
try {
Map<String, String> rules = new HashMap<>();
rules.put("\\.(.*)", "$1");
Xml2AFSIMTransformation converter = new Xml2AFSIMTransformation(rules);
File xmlFile = new File(inputData);
File jsonFile = new File(processJSONFile);
converter.convertXmlToJson(xmlFile, jsonFile, "任务航线");
System.out.println("XML转JSON并转换完成");
} catch (Exception e) {
e.printStackTrace();
}
// Step.2
String targetContent = Files.readString(Path.of(processJSONFile), StandardCharsets.UTF_8);
List<Object> list = JSON.parseArray(targetContent);
String templateContent = Files.readString(Path.of(inputTemplateData), StandardCharsets.UTF_8);
ConfigDocument document = JSON.parseObject(templateContent, ConfigDocument.class);
String result = JSON.toJSONString(document);
System.out.println(result);
for(Object obj: list) {
Map<String, String> map = JSON.parseObject(JSON.toJSONString(obj), Map.class);
result = FormatUtil.stealBeamsAndReplacePillars(result, map);
}
// Step.3
Map demoData = JSON.parseObject(result, Map.class);
System.out.println("=== 测试动态模板 ===");
String result1 = EnhancedTemplateGenerator.generateCodeWithFormat(demoData, "generator/jinjia2/dynamic-template.j2");
System.out.println(result1);
}
}

View File

@ -0,0 +1,65 @@
package com.example.demo.draft.demo043;
import com.alibaba.fastjson.JSON;
import com.example.demo.draft.demo043.domain.ConfigDocument;
import com.example.demo.draft.demo043.core.EnhancedTemplateGenerator;
import com.example.demo.draft.demo043.core.Xml2AFSIMTransformation;
import com.example.demo.draft.demo043.util.FormatUtil;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
public class ApplicationTest__04 {
public static void main(String[] args) throws IOException {
List<String> dataList = new ArrayList<>() {{
add("20250923_02d1d0.xml");
add("20250923_5da5e9.xml");
add("20250923_3929b4.xml");
}};
String prefix = "src/main/resources/data/04-空域数据/";
String inputTemplateData = prefix + "default.json";
String inputData = prefix + dataList.get(new Random().nextInt(dataList.size()));
String processJSONFile = "output-transformed-cg-003__04.json";
// Step.1
try {
Map<String, String> rules = new HashMap<>();
rules.put("\\.(.*)", "$1");
Xml2AFSIMTransformation converter = new Xml2AFSIMTransformation(rules);
File xmlFile = new File(inputData);
File jsonFile = new File(processJSONFile);
converter.convertXmlToJson(xmlFile, jsonFile, "空域数据");
System.out.println("XML转JSON并转换完成");
} catch (Exception e) {
e.printStackTrace();
}
// Step.2
String targetContent = Files.readString(Path.of(processJSONFile), StandardCharsets.UTF_8);
List<Object> list = JSON.parseArray(targetContent);
String templateContent = Files.readString(Path.of(inputTemplateData), StandardCharsets.UTF_8);
ConfigDocument document = JSON.parseObject(templateContent, ConfigDocument.class);
String result = JSON.toJSONString(document);
System.out.println(result);
for(Object obj: list) {
Map<String, String> map = JSON.parseObject(JSON.toJSONString(obj), Map.class);
result = FormatUtil.stealBeamsAndReplacePillars(result, map);
}
// Step.3
Map demoData = JSON.parseObject(result, Map.class);
System.out.println("=== 测试动态模板 ===");
String result1 = EnhancedTemplateGenerator.generateCodeWithFormat(demoData, "generator/jinjia2/dynamic-template.j2");
System.out.println(result1);
}
}

View File

@ -0,0 +1,163 @@
package com.example.demo.draft.demo043;
import com.alibaba.fastjson.JSON;
import com.example.demo.draft.demo043.core.EnhancedTemplateGenerator;
import com.example.demo.draft.demo043.domain.ConfigDocument;
import com.example.demo.draft.demo043.domain.ConfigValue;
import com.example.demo.draft.demo043.domain.LevelConfig;
import com.example.demo.draft.demo043.domain.ValueConfig;
import lombok.SneakyThrows;
import java.util.*;
public class ConfigDataCreator__02 {
@SneakyThrows
public static void main(String[] args) {
System.out.println(JSON.toJSONString(createConfigDocument()));
String result1 = EnhancedTemplateGenerator.generateCodeWithFormat(
JSON.parseObject(JSON.toJSONString(createConfigDocument()), Map.class),
"generator/jinjia2/dynamic-template.j2");
System.out.println(result1);
}
private static final String customTemplateCode = "string %s = \"%s\" # %s";
public static ConfigDocument createConfigDocument() {
// 创建最内层的ConfigValue对象
ConfigValue tacanWorkChannelValue = ConfigValue.builder()
.value(String.format(
customTemplateCode,
"tacanWorkChannel",
"单个空中平台任务数据.塔康工作频道",
"塔康工作频道"
))
.unit(null)
.combined(false)
.build();
ConfigValue platformIdCardCodeValue = ConfigValue.builder()
.value(String.format(
customTemplateCode,
"platformIdCardCode",
"单个空中平台任务数据.平台识别码",
"平台识别码"
))
.unit(null)
.combined(false)
.build();
ConfigValue platformIdCardNumberValue = ConfigValue.builder()
.value(String.format(
customTemplateCode,
"platformIdCardNumber",
"单个空中平台任务数据.平台识别号",
"平台识别号"
))
.unit(null)
.combined(false)
.build();
ConfigValue quantity1Value = ConfigValue.builder()
.value("数量1")
.unit(null)
.combined(false)
.build();
ConfigValue quantity2Value = ConfigValue.builder()
.value("数量2")
.unit(null)
.combined(false)
.build();
// 创建ValueConfig对象
ValueConfig tacanWorkChannelConfig = ValueConfig.builder()
.valueName(null)
.values(Collections.singletonList(tacanWorkChannelValue))
.build();
ValueConfig platformIdCardCodeConfig = ValueConfig.builder()
.valueName(null)
.values(Collections.singletonList(platformIdCardCodeValue))
.build();
ValueConfig platformIdCardNumberConfig = ValueConfig.builder()
.valueName(null)
.values(Collections.singletonList(platformIdCardNumberValue))
.build();
ValueConfig quantity1Config = ValueConfig.builder()
.valueName("quantity")
.values(Collections.singletonList(quantity1Value))
.comment(null)
.build();
ValueConfig quantity2Config = ValueConfig.builder()
.valueName("quantity")
.values(Collections.singletonList(quantity2Value))
.comment(null)
.build();
// 创建子LevelConfig对象
LevelConfig commLevel = LevelConfig.builder()
.levelName("comm")
.values(Arrays.asList("xxx", "默认通信链"))
.comment(null)
.conditionType(null)
.valueConfigs(Collections.singletonList(tacanWorkChannelConfig))
.subLevels(List.of())
.build();
LevelConfig auxDataLevel = LevelConfig.builder()
.levelName("aux_data")
.values(Arrays.asList())
.comment(null)
.conditionType(null)
.valueConfigs(Arrays.asList(platformIdCardCodeConfig, platformIdCardNumberConfig))
.subLevels(List.of())
.build();
LevelConfig weapon1Level = LevelConfig.builder()
.levelName("weapon")
.values(Arrays.asList("单个空中平台任务数据.主挂载武器", "类型"))
.comment(null)
.conditionType(null)
.valueConfigs(Collections.singletonList(quantity1Config))
.subLevels(List.of())
.build();
LevelConfig weapon2Level = LevelConfig.builder()
.levelName("weapon")
.values(Arrays.asList("单个空中平台任务数据.次挂载武器", "类型"))
.comment(null)
.conditionType(null)
.valueConfigs(Collections.singletonList(quantity2Config))
.subLevels(List.of())
.build();
// 创建主LevelConfig对象
LevelConfig platformLevel = LevelConfig.builder()
.levelName("platform")
.values(Arrays.asList("单个空中平台任务数据.机型名称", "单个空中平台任务数据.机型"))
.comment(null)
.conditionType(null)
.valueConfigs(Arrays.asList(
ValueConfig.builder().valueName("side").values(Arrays.asList(
ConfigValue.builder().value("red").unit(null).combined(false).build()
)).comment(null).build(),
ValueConfig.builder().valueName("icon").values(Arrays.asList(
ConfigValue.builder().value("weasel").unit(null).combined(false).build()
)).comment(null).build()
))
.subLevels(Arrays.asList(commLevel, auxDataLevel, weapon1Level, weapon2Level))
.build();
// 创建ConfigDocument对象
return ConfigDocument.builder()
.globalComment(null)
.initialIndent(null)
.conditionMap(new HashMap<>())
.levelConfigs(Arrays.asList(platformLevel))
.build();
}
}

View File

@ -0,0 +1,197 @@
package com.example.demo.draft.demo043;
import com.alibaba.fastjson.JSON;
import com.example.demo.draft.demo043.core.EnhancedTemplateGenerator;
import com.example.demo.draft.demo043.domain.ConfigDocument;
import com.example.demo.draft.demo043.domain.ConfigValue;
import com.example.demo.draft.demo043.domain.LevelConfig;
import com.example.demo.draft.demo043.domain.ValueConfig;
import lombok.SneakyThrows;
import java.util.*;
public class ConfigDataCreator__03 {
@SneakyThrows
public static void main(String[] args) {
System.out.println(JSON.toJSONString(createConfigDocument()));
String result1 = EnhancedTemplateGenerator.generateCodeWithFormat(
JSON.parseObject(JSON.toJSONString(createConfigDocument()), Map.class),
"generator/jinjia2/dynamic-template.j2");
System.out.println(result1);
}
private static final String customTemplateCode = "string %s = \"%s\" # %s";
public static ConfigDocument createConfigDocument() {
// 创建最内层的ConfigValue对象 - waypoint层级的值配置
ConfigValue positionValue = ConfigValue.builder()
// .value("39.9242N 116.5074E")
.value("任务航线.航线点坐标")
.unit(null)
.combined(false)
.build();
ConfigValue waypointTypeValue = ConfigValue.builder()
.value("任务航线.航线点类型")
.unit(null)
.combined(false)
.build();
ConfigValue etaValue = ConfigValue.builder()
.value("任务航线.准时到达时间")
.unit(null)
.combined(false)
.build();
ConfigValue turnMethodValue = ConfigValue.builder()
.value("任务航线.转弯方式")
.unit(null)
.combined(false)
.build();
ConfigValue turnDirectionValue = ConfigValue.builder()
.value("任务航线.转向方式")
.unit(null)
.combined(false)
.build();
ConfigValue bankAngleValue = ConfigValue.builder()
.value("任务航线.坡度")
.unit("deg")
.combined(false)
.build();
ConfigValue speedValue = ConfigValue.builder()
.value("任务航线.速度")
.unit("km/h")
.combined(false)
.build();
ConfigValue altitudeValue = ConfigValue.builder()
.value("任务航线.高度")
.unit("m")
.combined(false)
.build();
ConfigValue altitudeTypeValue = ConfigValue.builder()
.value("任务航线.高度属性")
.unit(null)
.combined(false)
.build();
ConfigValue climbRateValue = ConfigValue.builder()
.value("任务航线.升降率")
.unit("m/s")
.combined(false)
.build();
// 创建ValueConfig对象 - waypoint层级的值配置
ValueConfig positionConfig = ValueConfig.builder()
.valueName("position")
.values(Arrays.asList(positionValue))
.comment("航线点坐标")
.build();
ValueConfig waypointTypeConfig = ValueConfig.builder()
.valueName("waypoint_type")
.values(Arrays.asList(waypointTypeValue))
.comment("航线点类型")
.build();
ValueConfig etaConfig = ValueConfig.builder()
.valueName("eta")
.values(Arrays.asList(etaValue))
.comment("准时到达时间")
.build();
ValueConfig turnMethodConfig = ValueConfig.builder()
.valueName("turn_method")
.values(Arrays.asList(turnMethodValue))
.comment("转弯方式")
.build();
ValueConfig turnDirectionConfig = ValueConfig.builder()
.valueName("turn_direction")
.values(Arrays.asList(turnDirectionValue))
.comment("转向方式")
.build();
ValueConfig bankAngleConfig = ValueConfig.builder()
.valueName("bank_angle")
.values(Arrays.asList(bankAngleValue))
.comment("坡度")
.build();
ValueConfig speedConfig = ValueConfig.builder()
.valueName("speed")
.values(Arrays.asList(speedValue))
.comment("速度")
.build();
ValueConfig altitudeConfig = ValueConfig.builder()
.valueName("altitude")
.values(Arrays.asList(altitudeValue))
.comment("高度")
.build();
ValueConfig altitudeTypeConfig = ValueConfig.builder()
.valueName("altitude_type")
.values(Arrays.asList(altitudeTypeValue))
.comment("高度属性")
.build();
ValueConfig climbRateConfig = ValueConfig.builder()
.valueName("climb_rate")
.values(Arrays.asList(climbRateValue))
.comment("升降率")
.build();
// 创建waypoint LevelConfig对象
LevelConfig waypointLevel = LevelConfig.builder()
.levelName("waypoint")
.values(Arrays.asList("任务航线.航线点型号", "任务航线.航线点名称"))
.comment("航线点型号为 任务航线.航线点型号 ,名称为 任务航线.航线点名称")
.conditionType(null)
.valueConfigs(Arrays.asList(
positionConfig, waypointTypeConfig, etaConfig, turnMethodConfig,
turnDirectionConfig, bankAngleConfig, speedConfig, altitudeConfig,
altitudeTypeConfig, climbRateConfig
))
.subLevels(Arrays.asList())
.build();
// 创建route LevelConfig对象
LevelConfig routeLevel = LevelConfig.builder()
.levelName("route")
.values(Arrays.asList())
.comment(null)
.conditionType(null)
.valueConfigs(Arrays.asList())
.subLevels(Arrays.asList(waypointLevel))
.build();
// 创建主LevelConfig对象 - platform
LevelConfig platformLevel = LevelConfig.builder()
.levelName("platform")
.values(Arrays.asList("mission_plane", "AIRCRAFT"))
.comment(null)
.conditionType(null)
.valueConfigs(Arrays.asList(
ValueConfig.builder().valueName("heading").values(Arrays.asList(
ConfigValue.builder().value(0).unit("deg").combined(false).build()
)).comment("初始航向为0度").build()
))
.subLevels(Arrays.asList(routeLevel))
.build();
// 创建ConfigDocument对象
return ConfigDocument.builder()
.globalComment(null)
.initialIndent(null)
.conditionMap(new HashMap<>())
.levelConfigs(Arrays.asList(platformLevel))
.build();
}
}

View File

@ -0,0 +1,318 @@
package com.example.demo.draft.demo043;
import com.alibaba.fastjson.JSON;
import com.example.demo.draft.demo043.core.EnhancedTemplateGenerator;
import com.example.demo.draft.demo043.domain.ConfigDocument;
import com.example.demo.draft.demo043.domain.ConfigValue;
import com.example.demo.draft.demo043.domain.LevelConfig;
import com.example.demo.draft.demo043.domain.ValueConfig;
import lombok.SneakyThrows;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class ConfigDataCreator__04 {
@SneakyThrows
public static void main(String[] args) {
System.out.println(JSON.toJSONString(createConfigDocument()));
String result1 = EnhancedTemplateGenerator.generateCodeWithFormat(
JSON.parseObject(JSON.toJSONString(createConfigDocument()), Map.class),
"generator/jinjia2/dynamic-template.j2");
System.out.println(result1);
}
private static final String customTemplateCode = "string %s = \"%s\" # %s";
public static ConfigDocument createConfigDocument() {
// 创建最内层的ConfigValue对象 - time_window层级
ConfigValue modeValue = ConfigValue.builder()
.value("空域数据.空域生效时间段.日期时间使用模式")
.unit(null)
.combined(false)
.build();
ConfigValue startValue = ConfigValue.builder()
.value("空域数据.空域生效时间段.开始时间")
.unit(null)
.combined(false)
.build();
ConfigValue endValue = ConfigValue.builder()
.value("空域数据.空域生效时间段.结束时间")
.unit(null)
.combined(false)
.build();
ConfigValue endTypeValue = ConfigValue.builder()
.value("空域数据.空域生效时间段.结束时间标识符")
.unit(null)
.combined(false)
.build();
ConfigValue intervalValue = ConfigValue.builder()
.value("空域数据.空域生效时间段.间隔频率")
.unit(null)
.combined(false)
.build();
ConfigValue intervalEndValue = ConfigValue.builder()
.value("空域数据.空域生效时间段.间隔结束时间")
.unit(null)
.combined(false)
.build();
ConfigValue relativeStartValue = ConfigValue.builder()
.value("空域数据.空域生效时间段.相对时开始时间")
.unit(null)
.combined(false)
.build();
ConfigValue relativeEndValue = ConfigValue.builder()
.value("空域数据.空域生效时间段.相对时结束数据")
.unit(null)
.combined(false)
.build();
ConfigValue timeFormatValue = ConfigValue.builder()
.value("空域数据.空域生效时间段.时间类型")
.unit(null)
.combined(false)
.build();
// 创建最内层的ConfigValue对象 - control_point层级
ConfigValue typeValue = ConfigValue.builder()
.value("空域数据.代表空域相关的控制点.控制点类型")
.unit(null)
.combined(false)
.build();
ConfigValue positionValue = ConfigValue.builder()
.value("空域数据.空域几何数据.几何数据信息.纬度N 空域数据.空域几何数据.几何数据信息.经度E")
.unit(null)
.combined(false)
.build();
ConfigValue topAltitudeValue = ConfigValue.builder()
.value("空域数据.代表空域相关的控制点.控制点的顶高")
.unit("m")
.combined(false)
.build();
ConfigValue bottomAltitudeValue = ConfigValue.builder()
.value("空域数据.代表空域相关的控制点.控制点的底高")
.unit("m")
.combined(false)
.build();
ConfigValue visibleValue = ConfigValue.builder()
.value("空域数据.代表空域相关的控制点.是否隐藏控制点")
.unit(null)
.combined(false)
.build();
// 创建最内层的ConfigValue对象 - geometry层级
ConfigValue shapeValue = ConfigValue.builder()
.value("空域数据.空域几何数据.形状类型")
.unit(null)
.combined(false)
.build();
ConfigValue centerValue = ConfigValue.builder()
.value("空域数据.代表空域相关的控制点.控制点的坐标位置纬度N 空域数据.代表空域相关的控制点.控制点的坐标位置经度E")
.unit(null)
.combined(false)
.build();
ConfigValue pointCountValue = ConfigValue.builder()
.value("空域数据.空域几何数据.数据点数目")
.unit(null)
.combined(false)
.build();
// 创建ValueConfig对象 - time_window层级
ValueConfig modeConfig = ValueConfig.builder()
.valueName("mode")
.values(Arrays.asList(modeValue))
.comment("日期时间使用模式")
.build();
ValueConfig startConfig = ValueConfig.builder()
.valueName("start")
.values(Arrays.asList(startValue))
.comment("开始时间")
.build();
ValueConfig endConfig = ValueConfig.builder()
.valueName("end")
.values(Arrays.asList(endValue))
.comment("结束时间")
.build();
ValueConfig endTypeConfig = ValueConfig.builder()
.valueName("end_type")
.values(Arrays.asList(endTypeValue))
.comment("结束时间标识符")
.build();
ValueConfig intervalConfig = ValueConfig.builder()
.valueName("interval")
.values(Arrays.asList(intervalValue))
.comment("间隔频率")
.build();
ValueConfig intervalEndConfig = ValueConfig.builder()
.valueName("interval_end")
.values(Arrays.asList(intervalEndValue))
.comment("间隔结束时间")
.build();
ValueConfig relativeStartConfig = ValueConfig.builder()
.valueName("relative_start")
.values(Arrays.asList(relativeStartValue))
.comment("相对时开始时间")
.build();
ValueConfig relativeEndConfig = ValueConfig.builder()
.valueName("relative_end")
.values(Arrays.asList(relativeEndValue))
.comment("相对时结束数据")
.build();
ValueConfig timeFormatConfig = ValueConfig.builder()
.valueName("time_format")
.values(Arrays.asList(timeFormatValue))
.comment("时间类型")
.build();
// 创建ValueConfig对象 - control_point层级
ValueConfig typeConfig = ValueConfig.builder()
.valueName("type")
.values(Arrays.asList(typeValue))
.comment("控制点类型")
.build();
ValueConfig positionConfig = ValueConfig.builder()
.valueName("position")
.values(Arrays.asList(positionValue))
.comment("控制点坐标(纬度,经度)")
.build();
ValueConfig topAltitudeConfig = ValueConfig.builder()
.valueName("top_altitude")
.values(Arrays.asList(topAltitudeValue))
.comment("控制点顶高")
.build();
ValueConfig bottomAltitudeConfig = ValueConfig.builder()
.valueName("bottom_altitude")
.values(Arrays.asList(bottomAltitudeValue))
.comment("控制点底高")
.build();
ValueConfig visibleConfig = ValueConfig.builder()
.valueName("visible")
.values(Arrays.asList(visibleValue))
.comment("是否隐藏控制点false表示显示")
.build();
// 创建ValueConfig对象 - geometry层级
ValueConfig shapeConfig = ValueConfig.builder()
.valueName("shape")
.values(Arrays.asList(shapeValue))
.comment("形状类型")
.build();
ValueConfig centerConfig = ValueConfig.builder()
.valueName("center")
.values(Arrays.asList(centerValue))
.comment("圆心坐标")
.build();
ValueConfig pointCountConfig = ValueConfig.builder()
.valueName("point_count")
.values(Arrays.asList(pointCountValue))
.comment("数据点数目")
.build();
// 创建子LevelConfig对象 - time_window
LevelConfig timeWindowLevel = LevelConfig.builder()
.levelName("time_window")
.values(Arrays.asList())
.comment("空域生效时间配置")
.conditionType(null)
.valueConfigs(Arrays.asList(
modeConfig, startConfig, endConfig, endTypeConfig, intervalConfig,
intervalEndConfig, relativeStartConfig, relativeEndConfig, timeFormatConfig
))
.subLevels(Arrays.asList())
.build();
// 创建子LevelConfig对象 - control_point
LevelConfig controlPointLevel = LevelConfig.builder()
.levelName("control_point")
.values(Arrays.asList("空域数据.代表空域相关的控制点.控制点ID", "空域数据.代表空域相关的控制点.控制点名称"))
.comment("控制点ID和名称")
.conditionType(null)
.valueConfigs(Arrays.asList(
typeConfig, positionConfig, topAltitudeConfig, bottomAltitudeConfig, visibleConfig
))
.subLevels(Arrays.asList())
.build();
// 创建子LevelConfig对象 - geometry
LevelConfig geometryLevel = LevelConfig.builder()
.levelName("geometry")
.values(Arrays.asList())
.comment("空域几何形状配置")
.conditionType(null)
.valueConfigs(Arrays.asList(
shapeConfig, centerConfig, pointCountConfig
))
.subLevels(Arrays.asList())
.build();
// 创建主LevelConfig对象 - platform
LevelConfig platformLevel = LevelConfig.builder()
.levelName("platform")
.values(Arrays.asList("airspace", "AERIAL_REGION"))
.comment(null)
.conditionType(null)
.valueConfigs(Arrays.asList(
ValueConfig.builder().valueName("id").values(Arrays.asList(
ConfigValue.builder().value("空域数据.空域ID").unit(null).combined(false).build()
)).comment("空域ID").build(),
ValueConfig.builder().valueName("name").values(Arrays.asList(
ConfigValue.builder().value("空域数据.空域名称").unit(null).combined(false).build()
)).comment("空域名称").build(),
ValueConfig.builder().valueName("category").values(Arrays.asList(
ConfigValue.builder().value("空域数据.协调措施所属的大类型").unit(null).combined(false).build()
)).comment("协调措施所属的大类型").build(),
ValueConfig.builder().valueName("subcategory").values(Arrays.asList(
ConfigValue.builder().value("空域数据.空域的具体协调措施类型").unit(null).combined(false).build()
)).comment("空域的具体协调措施类型").build(),
ValueConfig.builder().valueName("status").values(Arrays.asList(
ConfigValue.builder().value("空域数据.空域管控状态").unit(null).combined(false).build()
)).comment("空域管控状态").build(),
ValueConfig.builder().valueName("control_status").values(Arrays.asList(
ConfigValue.builder().value("limit").unit(null).combined(false).build()
)).comment("空域管控状态").build()
))
.subLevels(Arrays.asList(timeWindowLevel, controlPointLevel, geometryLevel))
.build();
// 创建ConfigDocument对象
return ConfigDocument.builder()
.globalComment(null)
.initialIndent(null)
.conditionMap(new HashMap<>())
.levelConfigs(Arrays.asList(platformLevel))
.build();
}
}

View File

@ -0,0 +1,147 @@
## AI提示词用于离线本地AI生成
### 系统角色设定
```
你是一个专业的Java代码生成专家专门负责根据文本配置格式生成对应的Java实体对象构建代码。请严格按照以下规范生成代码。
```
### 任务描述
```
请根据提供的文本配置格式生成对应的Java实体对象构建代码。文本格式遵循 `xxx ... end_xxx` 的层级结构需要转换为ConfigDocument对象。
```
### 输入数据结构说明
```
输入数据采用以下Java实体结构
1. **ConfigDocument** - 配置文档根对象
- globalComment: 全局注释
- initialIndent: 初始缩进
- conditionMap: 条件映射表
- levelConfigs: 层级配置列表
2. **LevelConfig** - 层级配置
- levelName: 层级名称(如 "platform", "aux_data"
- levelLoopIndex: 层级循环索引(用于生成带索引的层级名)
- enableLevel: 是否启用该层级
- values: 层级值列表(如 ["north_cap_1", "STRIKER"]
- comment: 层级注释
- conditionType: 条件类型
- valueConfigs: 值配置列表
- subLevels: 子层级列表
- enableLoop: 是否启用循环
- loopCount: 循环次数
- enumMapping: 枚举映射
- utilFunction: 工具函数配置
3. **ValueConfig** - 值配置
- valueName: 值名称(如 "side", "icon"
- values: 配置值列表
- comment: 值注释
4. **ConfigValue** - 配置值
- value: 实际值
- unit: 单位
- combined: 是否组合值
- regexPattern: 正则表达式模式
- regexReplacement: 正则替换
- enumMapping: 枚举映射
- utilFunction: 工具函数
```
### 输出要求:
#### 代码结构:
```java
public static ConfigDocument createConfigDocument() {
// 按从外到内的顺序创建对象
// 1. 先创建最内层的ConfigValue
// 2. 然后创建ValueConfig包含ConfigValue列表
// 3. 创建LevelConfig包含ValueConfig列表和子层级
// 4. 最后创建ConfigDocument包含LevelConfig列表
ConfigValue batchnumberValue = ConfigValue.builder()
.value("333333665")
.unit(null)
.combined(false)
.build();
// 创建ValueConfig对象
ValueConfig batchnumberConfig = ValueConfig.builder()
.valueName("batchnumber")
.values(Arrays.asList(batchnumberValue))
.comment("批次号")
.build();
ValueConfig sideConfig = ValueConfig.builder()
.valueName("side")
.values(Arrays.asList(ConfigValue.builder().value("red").build()))
.comment("阵营")
.build();
ValueConfig iconConfig = ValueConfig.builder()
.valueName("icon")
.values(Arrays.asList(ConfigValue.builder().value("weasel").build()))
.comment("图标")
.build();
// 创建子LevelConfig对象
LevelConfig auxDataLevel = LevelConfig.builder()
.levelName("aux_data")
.values(Arrays.asList())
.comment("辅助数据")
.valueConfigs(Arrays.asList(batchnumberConfig))
.subLevels(Arrays.asList())
.build();
// 创建主LevelConfig对象
LevelConfig platformLevel = LevelConfig.builder()
.levelName("platform")
.values(Arrays.asList("north_cap_1", "STRIKER"))
.comment("平台配置")
.valueConfigs(Arrays.asList(sideConfig, iconConfig))
.subLevels(Arrays.asList(auxDataLevel))
.build();
// 创建ConfigDocument对象
return ConfigDocument.builder()
// ... 构建逻辑
.build();
}
```
## 转换规则
### 文本格式解析规则:
1. **层级定义**`levelName value1 value2 ... # 注释`
2. **值配置**`valueName value [unit] # 注释`
3. **条件类型**:单独一行,无前缀
4. **子层级**:缩进表示嵌套关系
5. **结束标记**`end_levelName`
### 映射规则:
- 每行开头单词为`levelName` → 创建LevelConfig
- 缩进2空格后的单词为`valueName` → 创建ValueConfig
- `#`后面的内容 → 对应comment字段
- 行中的数值/字符串 → 创建ConfigValue
- 存在=等于符号的,整行内容默认全部为 value → ConfigValue.value字段
- 数值后的单位 → ConfigValue.unit字段
- 条件类型单独一行 → LevelConfig.conditionType
### 处理流程:
1. 解析文本配置,识别层级结构
2. 按从内到外的顺序创建对象:
- 先创建最内层的ConfigValue
- 然后创建包含ConfigValue的ValueConfig
- 再创建包含ValueConfig和子层级的LevelConfig
- 最后创建包含LevelConfig列表的ConfigDocument
3. 保持正确的缩进和嵌套关系
4. 处理注释信息
5. 生成完整的Java构建代码
### 质量要求:
- 生成的代码必须语法正确
- 使用正确的Builder模式
- 保持代码格式整洁
- 正确处理空值和默认值
- 支持中英文混合内容

View File

@ -0,0 +1,55 @@
package com.example.demo.draft.demo043;
import com.alibaba.fastjson2.JSON;
import com.example.demo.draft.demo043.domain.ConfigDocument;
import com.example.demo.draft.demo043.domain.LevelConfig;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.charset.StandardCharsets;
/**
* 测试LevelConfig的loopCount字段修复
*/
public class TestLoopCountFix {
public static void main(String[] args) throws Exception {
// 读取default.json文件
String templateContent = Files.readString(
Path.of("src/main/resources/data/02-单个空中平台任务数据/default.json"),
StandardCharsets.UTF_8
);
System.out.println("=== 原始JSON内容 ===");
System.out.println(templateContent);
// 解析JSON到ConfigDocument对象
ConfigDocument document = JSON.parseObject(templateContent, ConfigDocument.class);
System.out.println("\n=== 解析后的ConfigDocument ===");
System.out.println("levelConfigs数量: " + document.getLevelConfigs().size());
if (!document.getLevelConfigs().isEmpty()) {
LevelConfig platformLevel = document.getLevelConfigs().get(0);
System.out.println("\n=== platform层级配置 ===");
System.out.println("levelName: " + platformLevel.getLevelName());
System.out.println("enableLoop: " + platformLevel.getEnableLoop());
System.out.println("loopCount: " + platformLevel.getLoopCount());
System.out.println("values: " + platformLevel.getValues());
// 验证loopCount是否正确获取
if (platformLevel.getLoopCount() != null) {
System.out.println("✅ SUCCESS: loopCount字段已正确获取值: " + platformLevel.getLoopCount());
} else {
System.out.println("❌ FAILED: loopCount字段仍然为null");
}
if (platformLevel.getEnableLoop() != null && platformLevel.getEnableLoop()) {
System.out.println("✅ SUCCESS: enableLoop字段已正确获取值: " + platformLevel.getEnableLoop());
} else {
System.out.println("❌ FAILED: enableLoop字段获取异常");
}
}
}
}

View File

@ -0,0 +1,338 @@
package com.example.demo.draft.demo043.core;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.example.demo.draft.demo043.domain.ConfigValue;
import com.example.demo.draft.demo043.domain.LevelConfig;
import com.example.demo.draft.demo043.domain.ValueConfig;
import com.example.demo.draft.demo043.util.FormatUtil;
import java.lang.reflect.Method;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 增强的配置处理器
*
* <p>处理配置中的循环正则表达式枚举映射和工具函数调用功能</p>
*
* <p><b>功能说明</b></p>
* <ul>
* <li>层级循环处理</li>
* <li>值正则表达式处理</li>
* <li>枚举映射转换</li>
* <li>工具函数调用</li>
* </ul>
*/
public class EnhancedConfigProcessor {
/**
* 处理层级配置
*
* @param levelConfig 层级配置
* @param context 处理上下文
* @return 处理后的层级配置列表可能包含循环生成的多个配置
*/
public static List<LevelConfig> processLevelConfig(LevelConfig levelConfig, Map<String, Object> context) {
List<LevelConfig> result = new ArrayList<>();
// 检查是否启用循环
if (levelConfig.getEnableLoop() != null && levelConfig.getEnableLoop()) {
int loopCount = 0;
if(StrUtil.isBlank(levelConfig.getLoopCount())) {
levelConfig.setLoopCount("1");
}
try {
loopCount = Integer.parseInt(levelConfig.getLoopCount());
} catch (NumberFormatException e) {
loopCount = 1;
}
// 根据loopCount的最大值确定数字格式化的位数
int maxDigits = String.valueOf(loopCount).length();
// 遍历每个配置项从1开始到loopCount结束包含两端
for (int i = 1; i <= loopCount; i++) {
// 处理单个层级的配置传入当前索引i-1因为processSingleLevelConfig期望从0开始
LevelConfig processedConfig = processSingleLevelConfig(levelConfig, context, i - 1);
String newValue;
if (loopCount >= 2) {
// 当loopCount大于等于2时添加带序号的后缀根据最大位数自动补零
newValue = String.format("%s_%0" + maxDigits + "d", processedConfig.getValues().getFirst(), i);
} else {
// 当loopCount等于1时不添加后缀编号直接使用原始值
newValue = processedConfig.getValues().getFirst();
}
// 获取原始值列表
List<String> values = processedConfig.getValues();
// 检查值列表是否非空
if(CollUtil.isNotEmpty(values)) {
// 移除第一个值通常是要被替换的基础值
values.removeFirst();
// 创建新的值列表包含格式化后的新值然后添加剩余的值
List<String> newValues = new ArrayList<>() {{
add(newValue); // 添加格式化后的新值作为第一个元素
addAll(values); // 添加原始列表中剩余的所有值
}};
// 将新值列表设置回处理后的配置对象
processedConfig.setValues(newValues);
}
// 将处理后的配置添加到结果列表中
result.add(processedConfig);
}
} else {
LevelConfig processedConfig = processSingleLevelConfig(levelConfig, context, 0);
result.add(processedConfig);
}
return result;
}
/**
* 处理单个层级配置
*/
private static LevelConfig processSingleLevelConfig(LevelConfig levelConfig, Map<String, Object> context, int loopIndex) {
LevelConfig result = new LevelConfig();
result.setLevelName(levelConfig.getLevelName());
result.setComment(levelConfig.getComment());
result.setConditionType(levelConfig.getConditionType());
// 处理层级值
if (levelConfig.getValues() != null) {
List<String> processedValues = new ArrayList<>();
for (String value : levelConfig.getValues()) {
String processedValue = processValue(value, levelConfig.getEnumMapping(),
levelConfig.getUtilFunction(), context, loopIndex);
processedValues.add(processedValue);
}
result.setValues(processedValues);
}
// 处理值配置
if (levelConfig.getValueConfigs() != null) {
List<ValueConfig> processedValueConfigs = new ArrayList<>();
for (ValueConfig valueConfig : levelConfig.getValueConfigs()) {
ValueConfig processedValueConfig = processValueConfig(valueConfig, context, loopIndex);
processedValueConfigs.add(processedValueConfig);
}
result.setValueConfigs(processedValueConfigs);
}
// 处理子层级
if (levelConfig.getSubLevels() != null) {
List<LevelConfig> processedSubLevels = new ArrayList<>();
for (LevelConfig subLevel : levelConfig.getSubLevels()) {
List<LevelConfig> processedSubs = processLevelConfig(subLevel, context);
processedSubLevels.addAll(processedSubs);
}
result.setSubLevels(processedSubLevels);
}
return result;
}
/**
* 处理配置值
*
* @param value 原始值
* @param enumMapping 枚举映射配置
* @param utilFunction 工具函数配置
* @param context 处理上下文
* @param loopIndex 循环索引
* @return 处理后的值
*/
public static String processValue(String value, Map<String, String> enumMapping,
Map<String, Object> utilFunction, Map<String, Object> context, int loopIndex) {
if (value == null) return null;
String result = value;
// 1. 应用枚举映射
if (enumMapping != null && enumMapping.containsKey(result)) {
result = enumMapping.get(result);
}
// 2. 应用工具函数
if (utilFunction != null && !utilFunction.isEmpty()) {
result = applyUtilFunction(result, utilFunction, context, loopIndex);
}
return result;
}
/**
* 处理值配置对象
*
* @param valueConfig 值配置对象
* @param context 处理上下文
* @param loopIndex 循环索引
* @return 处理后的值配置对象
*/
public static ValueConfig processValueConfig(ValueConfig valueConfig, Map<String, Object> context, int loopIndex) {
if (valueConfig == null) return null;
ValueConfig result = new ValueConfig();
result.setValueName(valueConfig.getValueName());
result.setComment(valueConfig.getComment());
// 处理配置值列表
if (valueConfig.getValues() != null) {
List<ConfigValue> processedValues = new ArrayList<>();
for (ConfigValue configValue : valueConfig.getValues()) {
ConfigValue processedConfigValue = processConfigValue(configValue, context, loopIndex);
processedValues.add(processedConfigValue);
}
result.setValues(processedValues);
}
return result;
}
/**
* 处理配置值对象
*
* @param configValue 配置值对象
* @param context 处理上下文
* @param loopIndex 循环索引
* @return 处理后的配置值对象
*/
public static ConfigValue processConfigValue(ConfigValue configValue, Map<String, Object> context, int loopIndex) {
if (configValue == null) return null;
ConfigValue result = new ConfigValue();
result.setUnit(configValue.getUnit());
result.setCombined(configValue.isCombined());
Object originalValue = configValue.getValue();
Object processedValue = originalValue;
// 处理字符串值
if (originalValue instanceof String) {
@SuppressWarnings("all")
String strValue = (String) originalValue;
// 1. 应用正则表达式
if (configValue.getRegexPattern() != null && configValue.getRegexReplacement() != null) {
try {
Pattern pattern = Pattern.compile(configValue.getRegexPattern());
Matcher matcher = pattern.matcher(strValue);
strValue = matcher.replaceAll(configValue.getRegexReplacement());
} catch (Exception e) {
// 正则表达式错误保持原值
}
}
// 2. 应用枚举映射
if (configValue.getEnumMapping() != null && configValue.getEnumMapping().containsKey(strValue)) {
strValue = configValue.getEnumMapping().get(strValue);
}
// 3. 应用工具函数
if (configValue.getUtilFunction() != null && !configValue.getUtilFunction().isEmpty()) {
strValue = applyUtilFunction(strValue, configValue.getUtilFunction(), context, loopIndex);
}
processedValue = strValue;
}
result.setValue(processedValue);
return result;
}
/**
* 应用工具函数
*/
@SuppressWarnings("all")
private static String applyUtilFunction(String value, Map<String, Object> utilFunction,
Map<String, Object> context, int loopIndex) {
if (utilFunction == null || utilFunction.isEmpty()) return value;
String result = value;
try {
// 获取函数名称
String functionName = utilFunction.keySet().iterator().next();
Object functionParams = utilFunction.get(functionName);
// 构建参数映射
Map<String, Object> params = new HashMap<>();
if (functionParams instanceof Map) {
params.putAll((Map<String, Object>) functionParams);
}
// 添加上下文和循环索引
params.put("context", context);
params.put("loopIndex", loopIndex);
// 调用工具函数
result = callFormatUtilFunction(functionName, value, params);
} catch (Exception e) {
// 工具函数调用失败保持原值
}
return result;
}
/**
* 调用 FormatUtil 工具函数
*/
private static String callFormatUtilFunction(String functionName, String value, Map<String, Object> params) {
try {
Method method = FormatUtil.class.getMethod(functionName, String.class, Map.class);
Object result = method.invoke(null, value, params);
return result != null ? result.toString() : value;
} catch (Exception e) {
// 方法调用失败尝试其他方式
return callCustomUtilFunction(functionName, value, params);
}
}
/**
* 调用自定义工具函数
*/
private static String callCustomUtilFunction(String functionName, String value, Map<String, Object> params) {
// 这里可以扩展支持其他工具类
// 目前只支持 FormatUtil
return value;
}
/**
* 批量处理层级配置列表
*/
public static List<LevelConfig> processLevelConfigs(List<LevelConfig> levelConfigs, Map<String, Object> context) {
List<LevelConfig> result = new ArrayList<>();
if (levelConfigs != null) {
for (LevelConfig levelConfig : levelConfigs) {
List<LevelConfig> processedConfigs = processLevelConfig(levelConfig, context);
result.addAll(processedConfigs);
}
}
return result;
}
/**
* 批量处理配置值列表
*/
public static List<ConfigValue> processConfigValues(List<ConfigValue> configValues, Map<String, Object> context, int loopIndex) {
List<ConfigValue> result = new ArrayList<>();
if (configValues != null) {
for (ConfigValue configValue : configValues) {
ConfigValue processedValue = processConfigValue(configValue, context, loopIndex);
result.add(processedValue);
}
}
return result;
}
}

View File

@ -0,0 +1,628 @@
package com.example.demo.draft.demo043.core;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.example.demo.draft.demo043.domain.ConfigValue;
import com.example.demo.draft.demo043.domain.LevelConfig;
import com.example.demo.draft.demo043.domain.ValueConfig;
import com.example.demo.draft.demo043.util.FormatUtil;
import com.hubspot.jinjava.Jinjava;
import com.hubspot.jinjava.JinjavaConfig;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 增强的 Jinja2 模板生成器
*
* <p>该类提供了基于 Jinja2 模板引擎的动态代码生成功能支持从文件系统或类路径加载模板文件
* 实现了灵活的模板管理和渲染机制</p>
*
* <h3>主要特性</h3>
* <ul>
* <li>支持从类路径和文件系统加载模板文件</li>
* <li>内置模板缓存机制提高渲染性能</li>
* <li>支持多种数据格式和复杂的嵌套结构</li>
* <li>提供条件判断循环控制等高级模板功能</li>
* <li>灵活的缩进控制和格式化管理</li>
* </ul>
*
* <h3>使用示例</h3>
* <pre>{@code
* // 构建模板数据
* TemplateData data = EnhancedTemplateGenerator.TemplateData.builder()
* .globalComment("示例配置")
* .levelConfigs(Arrays.asList(...))
* .build();
*
* // 使用默认模板生成代码
* String result = EnhancedTemplateGenerator.generateCode(data);
*
* // 使用指定模板文件生成代码
* String result2 = EnhancedTemplateGenerator.generateCode(data, "templates/custom-template.j2");
* }</pre>
*
* @author Template Generator Team
* @version 1.0.0
* @since 2024-01-01
* @see TemplateFileLoader
*/
public class EnhancedTemplateGenerator {
/**
* Jinja2 模板引擎实例
* <p>使用单例模式确保整个应用中只有一个引擎实例提高性能并避免资源浪费</p>
*/
private static final Jinjava JINJAVA;
/**
* 默认模板文件路径
* <p>当不指定模板路径时将使用此路径对应的模板文件</p>
*/
private static final String DEFAULT_TEMPLATE = "generator/jinjia2/dynamic-template.j2";
// 静态初始化块 - 配置 Jinja2 引擎
static {
// 初始化 Jinja2 引擎配置
JinjavaConfig config = JinjavaConfig.newBuilder()
.withTrimBlocks(true) // 启用块修剪去除标签后的换行符
.withLstripBlocks(true) // 启用行修剪去除标签前的空格
.build();
JINJAVA = new Jinjava(config);
}
/**
* 使用指定模板文件生成代码
*
* <p>该方法允许使用自定义的模板文件进行代码生成提供更大的灵活性</p>
*
* <h3>模板路径支持格式</h3>
* <ul>
* <li>类路径资源"templates/my-template.j2"</li>
* <li>类路径前缀"classpath:templates/my-template.j2"</li>
* <li>文件系统路径"file:/path/to/template.j2"</li>
* <li>相对路径"file:./templates/my-template.j2"</li>
* </ul>
*
* @param data 模板数据对象
* @param templatePath 模板文件路径支持类路径和文件系统路径
* @return 渲染后的代码字符串
* @throws IOException 当模板文件不存在或读取失败时抛出
* @throws IllegalArgumentException 当模板路径格式不正确时抛出
*
* @see TemplateFileLoader#loadTemplate(String)
*
* @example
* <pre>{@code
* // 使用类路径模板
* String code1 = generateCode(data, "templates/custom.j2");
*
* // 使用文件系统模板
* String code2 = generateCode(data, "file:/home/user/templates/custom.j2");
* }</pre>
*/
public static String generateCode(Map<String, Object> data, String templatePath) throws IOException {
// 参数校验
if (templatePath == null || templatePath.trim().isEmpty()) {
throw new IllegalArgumentException("模板路径不能为空");
}
if (data == null) {
throw new IllegalArgumentException("模板数据不能为空");
}
// 应用增强配置处理
// FIXME 2025-9-25 13:44:26 增强解析能力异常
@SuppressWarnings("all")
Map<String, Object> processedMap = data;
processedMap = applyEnhancedProcessing(processedMap);
String groupLog = String.format("%s %s %s", "=".repeat(40), "%s","=".repeat(40));
System.out.printf((groupLog) + "%n", "最终Map ↓↓↓");
System.out.println(JSON.toJSONString(processedMap));
System.out.printf((groupLog) + "%n", "最终Map ↑↑↑");
// 加载模板内容
String templateContent = TemplateFileLoader.loadTemplate(templatePath);
// 渲染模板
return renderTemplate(processedMap, templateContent);
}
/**
* 使用增强功能处理模板数据并生成格式化代码
*
* <p>该方法在生成代码前会应用增强的配置处理功能包括</p>
* <ul>
* <li>层级循环处理</li>
* <li>值正则表达式处理</li>
* <li>枚举映射转换</li>
* <li>工具函数调用</li>
* </ul>
*
* @param map 模板数据映射
* @param templatePath 模板文件路径
* @return 处理后的格式化代码
* @throws IOException 当模板文件不存在或读取失败时抛出
*/
public static String generateCodeWithFormat(Map<String, Object> map, String templatePath) throws IOException {
// 生成基础代码
String data = generateCode(map, templatePath);
// 格式化输出
String result = FormatUtil.replaceRepeatedPatterns(data, "\r\n", "", 1, 1);
result = result.replaceAll("( {4,})( {4})end_(\\w+)", "$1end_$3");
// result = result.replaceAll("\r\n( {4})", "\r\n");
// result = result.replaceAll("\r\n( {8})", "\r\n");
return result;
}
/**
* 应用增强配置处理
*
* <p>对模板数据中的层级配置进行增强处理包括循环正则枚举映射和函数调用</p>
*
* @param originalMap 原始模板数据
* @return 处理后的模板数据
*/
public static Map<String, Object> applyEnhancedProcessing(Map<String, Object> originalMap) {
Map<String, Object> processedMap = new HashMap<>(originalMap);
// 检查是否包含层级配置
if (processedMap.containsKey("levelConfigs")) {
Object levelConfigsObj = processedMap.get("levelConfigs");
if (levelConfigsObj instanceof List) {
@SuppressWarnings("unchecked")
List<Object> levelConfigsList = (List<Object>) levelConfigsObj;
// 处理每个层级配置
List<Object> processedLevelConfigs = new ArrayList<>();
Map<String, Object> context = new HashMap<>();
for (Object levelConfigObj : levelConfigsList) {
if (levelConfigObj instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, Object> levelConfigMap = (Map<String, Object>) levelConfigObj;
// 转换为LevelConfig对象进行处理
LevelConfig levelConfig = convertMapToLevelConfig(levelConfigMap);
// 应用增强处理
List<LevelConfig> processedConfigs = EnhancedConfigProcessor.processLevelConfig(levelConfig, context);
// 转换回Map格式
for (LevelConfig processedConfig : processedConfigs) {
Map<String, Object> processedConfigMap = convertLevelConfigToMap(processedConfig);
processedLevelConfigs.add(processedConfigMap);
}
} else {
// 保持原样
processedLevelConfigs.add(levelConfigObj);
}
}
processedMap.put("levelConfigs", processedLevelConfigs);
}
}
return processedMap;
}
/**
* 将Map转换为LevelConfig对象
*/
private static LevelConfig convertMapToLevelConfig(Map<String, Object> map) {
LevelConfig.LevelConfigBuilder builder = LevelConfig.builder();
if (map.containsKey("levelName")) {
builder.levelName((String) map.get("levelName"));
}
if (map.containsKey("values")) {
Object valuesObj = map.get("values");
if (valuesObj instanceof List) {
@SuppressWarnings("unchecked")
List<String> values = (List<String>) valuesObj;
builder.values(values);
}
}
if (map.containsKey("comment")) {
builder.comment((String) map.get("comment"));
}
if (map.containsKey("conditionType")) {
builder.conditionType((String) map.get("conditionType"));
}
if (map.containsKey("enableLoop")) {
builder.enableLoop((Boolean) map.get("enableLoop"));
}
if (map.containsKey("loopCount")) {
Object loopCountObj = map.get("loopCount");
if (loopCountObj instanceof String) {
try {
int loopCountInteger = Integer.parseInt(loopCountObj.toString());
builder.loopCount(String.valueOf(loopCountInteger));
} catch (NumberFormatException e) {
builder.loopCount("1");
}
} else if (loopCountObj instanceof Integer) {
builder.loopCount(String.valueOf(loopCountObj));
}
}
if (map.containsKey("enumMapping")) {
Object enumMappingObj = map.get("enumMapping");
if (enumMappingObj instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, String> enumMapping = (Map<String, String>) enumMappingObj;
builder.enumMapping(enumMapping);
}
}
if (map.containsKey("utilFunction")) {
Object utilFunctionObj = map.get("utilFunction");
if (utilFunctionObj instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, Object> utilFunction = (Map<String, Object>) utilFunctionObj;
builder.utilFunction(utilFunction);
}
}
// 处理valueConfigs
if (map.containsKey("valueConfigs")) {
Object valueConfigsObj = map.get("valueConfigs");
if (valueConfigsObj instanceof List) {
@SuppressWarnings("unchecked")
List<Object> valueConfigsList = (List<Object>) valueConfigsObj;
List<ValueConfig> valueConfigs = new ArrayList<>();
for (Object valueConfigObj : valueConfigsList) {
if (valueConfigObj instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, Object> valueConfigMap = (Map<String, Object>) valueConfigObj;
ValueConfig valueConfig = convertMapToValueConfig(valueConfigMap);
valueConfigs.add(valueConfig);
}
}
builder.valueConfigs(valueConfigs);
}
}
// 处理subLevels
if (map.containsKey("subLevels")) {
Object subLevelsObj = map.get("subLevels");
if (subLevelsObj instanceof List) {
@SuppressWarnings("unchecked")
List<Object> subLevelsList = (List<Object>) subLevelsObj;
List<LevelConfig> subLevels = new ArrayList<>();
for (Object subLevelObj : subLevelsList) {
if (subLevelObj instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, Object> subLevelMap = (Map<String, Object>) subLevelObj;
LevelConfig subLevel = convertMapToLevelConfig(subLevelMap);
subLevels.add(subLevel);
}
}
builder.subLevels(subLevels);
}
}
return builder.build();
}
/**
* 将Map转换为ValueConfig对象
*/
private static ValueConfig convertMapToValueConfig(Map<String, Object> map) {
ValueConfig.ValueConfigBuilder builder = ValueConfig.builder();
if (map.containsKey("valueName")) {
builder.valueName((String) map.get("valueName"));
}
if (map.containsKey("comment")) {
builder.comment((String) map.get("comment"));
}
// 处理values
if (map.containsKey("values")) {
Object valuesObj = map.get("values");
if (valuesObj instanceof List) {
@SuppressWarnings("unchecked")
List<Object> valuesList = (List<Object>) valuesObj;
List<ConfigValue> configValues = new ArrayList<>();
for (Object valueUnitObj : valuesList) {
if (valueUnitObj instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, Object> valueUnitMap = (Map<String, Object>) valueUnitObj;
ConfigValue configValue = convertMapToConfigValue(valueUnitMap);
configValues.add(configValue);
}
}
builder.values(configValues);
}
}
return builder.build();
}
/**
* 将Map转换为ConfigValue对象
*/
private static ConfigValue convertMapToConfigValue(Map<String, Object> map) {
ConfigValue.ConfigValueBuilder builder = ConfigValue.builder();
if (map.containsKey("value")) {
builder.value(map.get("value"));
}
if (map.containsKey("unit")) {
builder.unit((String) map.get("unit"));
}
if (map.containsKey("combined")) {
builder.combined((Boolean) map.get("combined"));
}
if (map.containsKey("regexPattern")) {
builder.regexPattern((String) map.get("regexPattern"));
}
if (map.containsKey("regexReplacement")) {
builder.regexReplacement((String) map.get("regexReplacement"));
}
if (map.containsKey("enumMapping")) {
Object enumMappingObj = map.get("enumMapping");
if (enumMappingObj instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, String> enumMapping = (Map<String, String>) enumMappingObj;
builder.enumMapping(enumMapping);
}
}
if (map.containsKey("utilFunction")) {
Object utilFunctionObj = map.get("utilFunction");
if (utilFunctionObj instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, Object> utilFunction = (Map<String, Object>) utilFunctionObj;
builder.utilFunction(utilFunction);
}
}
return builder.build();
}
/**
* 将LevelConfig对象转换为Map
*/
private static Map<String, Object> convertLevelConfigToMap(LevelConfig levelConfig) {
Map<String, Object> map = new HashMap<>();
if (levelConfig.getLevelName() != null) {
map.put("levelName", levelConfig.getLevelName());
}
if (levelConfig.getValues() != null) {
map.put("values", levelConfig.getValues());
}
if (levelConfig.getComment() != null) {
map.put("comment", levelConfig.getComment());
}
if (levelConfig.getConditionType() != null) {
map.put("conditionType", levelConfig.getConditionType());
}
if (levelConfig.getValueConfigs() != null) {
List<Map<String, Object>> valueConfigsList = new ArrayList<>();
for (ValueConfig valueConfig : levelConfig.getValueConfigs()) {
Map<String, Object> valueConfigMap = convertValueConfigToMap(valueConfig);
valueConfigsList.add(valueConfigMap);
}
map.put("valueConfigs", valueConfigsList);
}
if (levelConfig.getSubLevels() != null) {
List<Map<String, Object>> subLevelsList = new ArrayList<>();
for (LevelConfig subLevel : levelConfig.getSubLevels()) {
Map<String, Object> subLevelMap = convertLevelConfigToMap(subLevel);
subLevelsList.add(subLevelMap);
}
map.put("subLevels", subLevelsList);
}
return map;
}
/**
* 将ValueConfig对象转换为Map
*/
private static Map<String, Object> convertValueConfigToMap(ValueConfig valueConfig) {
Map<String, Object> map = new HashMap<>();
if (valueConfig.getValueName() != null) {
map.put("valueName", valueConfig.getValueName());
}
if (valueConfig.getComment() != null) {
map.put("comment", valueConfig.getComment());
}
if (valueConfig.getValues() != null) {
List<Map<String, Object>> valuesList = new ArrayList<>();
for (ConfigValue configValue : valueConfig.getValues()) {
Map<String, Object> configValueMap = convertConfigValueToMap(configValue);
valuesList.add(configValueMap);
}
map.put("values", valuesList);
}
return map;
}
/**
* 将ConfigValue对象转换为Map
*/
private static Map<String, Object> convertConfigValueToMap(ConfigValue configValue) {
Map<String, Object> map = new HashMap<>();
if (ObjectUtil.isNotNull(configValue.getValue())) {
map.put("value", configValue.getValue());
}
if (ObjectUtil.isNotNull(configValue.getUnit())) {
map.put("unit", configValue.getUnit());
}
if (configValue.isCombined()) {
map.put("combined", true);
}
if (ObjectUtil.isNotNull(configValue.getRegexPattern())) {
map.put("regexPattern", configValue.getRegexPattern());
}
if (ObjectUtil.isNotNull(configValue.getRegexReplacement())) {
map.put("regexReplacement", configValue.getRegexReplacement());
}
if (CollUtil.isNotEmpty(configValue.getEnumMapping())) {
map.put("enumMapping", configValue.getEnumMapping());
}
if (CollUtil.isNotEmpty(configValue.getUtilFunction())) {
map.put("utilFunction", configValue.getUtilFunction());
}
return map;
}
/**
* 执行模板渲染
*
* <p>内部方法负责准备上下文数据并调用 Jinja2 引擎进行渲染</p>
*
* <h3>上下文变量</h3>
* <ul>
* <li>{@code data}: 主要的模板数据对象</li>
* <li>{@code indent}: 缩进字符串根据 indentSpaces 生成</li>
* </ul>
*
* @param data 模板数据
* @param templateContent 模板内容
* @return 渲染结果
* @throws RuntimeException 当模板渲染过程中出现错误时抛出
*/
private static String renderTemplate(Map<String, Object> data, String templateContent) {
// 准备模板上下文
Map<String, Object> context = new HashMap<>();
context.put("data", data);
context.put("indent", " ".repeat((Integer) data.getOrDefault("indent", 4)));
try {
// 执行模板渲染
return JINJAVA.render(templateContent, context);
} catch (Exception e) {
throw new RuntimeException("模板渲染失败: " + e.getMessage(), e);
}
}
/**
* 列出可用的模板文件
*
* <p>该方法会检查预定义的模板文件是否存在并显示每个模板的基本信息</p>
*
* <h3>输出信息</h3>
* <ul>
* <li>模板文件路径</li>
* <li>加载状态 表示成功 表示失败</li>
* <li>模板内容长度字符数</li>
* </ul>
*
* @example
* <pre>{@code
* 可用的模板文件:
* templates/dynamic-template.j2 (856 字符)
* templates/simple-template.j2 (512 字符)
* templates/custom-template.j2 (未找到)
* }</pre>
*/
public static void listAvailableTemplates() {
// 预定义的模板文件列表
String[] templates = {
"generator/jinjia2/dynamic-template.j2"
};
System.out.println("可用的模板文件:");
for (String template : templates) {
try {
// 尝试加载模板文件
String content = TemplateFileLoader.loadTemplate(template);
System.out.println("" + template + " (" + content.length() + " 字符)");
} catch (IOException e) {
System.out.println("" + template + " (未找到)");
}
}
}
/**
* 获取 Jinja2 引擎实例
*
* <p>提供对内部 Jinja2 引擎的访问用于高级定制或扩展功能</p>
*
* <h3>使用注意事项</h3>
* <ul>
* <li>不建议直接修改引擎配置</li>
* <li>主要用于添加自定义过滤器或函数</li>
* <li>修改配置可能会影响其他模板渲染</li>
* </ul>
*
* @return Jinja2 引擎实例
*/
public static Jinjava getJinjavaEngine() {
return JINJAVA;
}
/**
* 获取默认模板路径
*
* @return 默认模板文件路径
*/
public static String getDefaultTemplatePath() {
return DEFAULT_TEMPLATE;
}
/**
* 清空模板缓存
*
* <p>清除所有已缓存的模板内容强制下次加载时重新读取文件</p>
*
* <h3>适用场景</h3>
* <ul>
* <li>模板文件内容已更新</li>
* <li>需要释放内存</li>
* <li>测试缓存机制</li>
* </ul>
*/
public static void clearTemplateCache() {
TemplateFileLoader.clearCache();
}
}

View File

@ -0,0 +1,110 @@
package com.example.demo.draft.demo043.core;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
/**
* 模板文件工具类
* 负责从文件系统或类路径加载模板文件
*/
@Slf4j
public class TemplateFileLoader {
private static final String DEFAULT_TEMPLATE_DIR = "templates/";
private static final String CLASS_PATH_PREFIX = "classpath:";
private static final String FILE_PATH_PREFIX = "file:";
// 模板缓存
private static final Map<String, String> TEMPLATE_CACHE = new HashMap<>();
/**
* 从类路径加载模板文件
*/
public static String loadTemplateFromClasspath(String templatePath) throws IOException {
String cacheKey = CLASS_PATH_PREFIX + templatePath;
if (TEMPLATE_CACHE.containsKey(cacheKey)) {
return TEMPLATE_CACHE.get(cacheKey);
}
try {
// 从类路径加载
String fullPath = templatePath.startsWith("/") ? templatePath : "/" + templatePath;
java.io.InputStream inputStream = TemplateFileLoader.class.getResourceAsStream(fullPath);
if (inputStream == null) {
throw new IOException("模板文件未找到: " + templatePath);
}
String content = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
TEMPLATE_CACHE.put(cacheKey, content);
log.info("从类路径加载模板: {}", templatePath);
return content;
} catch (IOException e) {
log.error("从类路径加载模板失败: {}", templatePath, e);
throw e;
}
}
/**
* 从文件系统加载模板文件
*/
public static String loadTemplateFromFileSystem(String filePath) throws IOException {
String cacheKey = FILE_PATH_PREFIX + filePath;
if (TEMPLATE_CACHE.containsKey(cacheKey)) {
return TEMPLATE_CACHE.get(cacheKey);
}
try {
Path path = Paths.get(filePath);
if (!Files.exists(path)) {
throw new IOException("模板文件不存在: " + filePath);
}
String content = Files.readString(path, StandardCharsets.UTF_8);
TEMPLATE_CACHE.put(cacheKey, content);
log.info("从文件系统加载模板: {}", filePath);
return content;
} catch (IOException e) {
log.error("从文件系统加载模板失败: {}", filePath, e);
throw e;
}
}
/**
* 智能加载模板自动判断路径类型
*/
public static String loadTemplate(String templatePath) throws IOException {
if (templatePath.startsWith(CLASS_PATH_PREFIX)) {
return loadTemplateFromClasspath(templatePath.substring(CLASS_PATH_PREFIX.length()));
} else if (templatePath.startsWith(FILE_PATH_PREFIX)) {
return loadTemplateFromFileSystem(templatePath.substring(FILE_PATH_PREFIX.length()));
} else {
// 默认从类路径加载
return loadTemplateFromClasspath(templatePath);
}
}
/**
* 清除模板缓存
*/
public static void clearCache() {
TEMPLATE_CACHE.clear();
log.info("模板缓存已清除");
}
/**
* 获取缓存中的模板数量
*/
public static int getCacheSize() {
return TEMPLATE_CACHE.size();
}
}

View File

@ -0,0 +1,294 @@
package com.example.demo.draft.demo043.core;
import lombok.extern.slf4j.Slf4j;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.regex.Pattern;
@Slf4j
public class Xml2AFSIMTransformation {
private final Map<Pattern, String> regexRules;
public Xml2AFSIMTransformation(Map<String, String> rules) {
log.info("初始化转换器,规则数量: {}", rules != null ? rules.size() : 0);
// 编译正则表达式规则
regexRules = new HashMap<>();
if (rules != null) {
for (Map.Entry<String, String> entry : rules.entrySet()) {
regexRules.put(Pattern.compile(entry.getKey()), entry.getValue());
}
}
}
/**
* 流式XML转JSON并应用转换规则
*/
public void convertXmlToJson(File xmlFile, File jsonFile, String rootElement) throws Exception {
log.info("开始XML转JSON转换并应用规则");
try (FileInputStream xmlInputStream = new FileInputStream(xmlFile);
FileWriter jsonWriter = new FileWriter(jsonFile)) {
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader reader = factory.createXMLStreamReader(xmlInputStream);
jsonWriter.write("[\n");
boolean firstObject = true;
int objectCount = 0;
// 用于跟踪当前解析状态
Stack<String> elementStack = new Stack<>();
Map<String, Object> currentObject = new HashMap<>();
StringBuilder currentText = new StringBuilder();
String currentElement = null;
while (reader.hasNext()) {
int event = reader.next();
switch (event) {
case XMLStreamReader.START_ELEMENT:
String elementName = reader.getLocalName();
elementStack.push(elementName);
currentElement = elementName;
currentText.setLength(0); // 重置文本内容
log.debug("开始元素: {}, 栈深度: {}", elementName, elementStack.size());
// 如果是根元素开始新对象
if (elementName.equals(rootElement)) {
currentObject.clear();
// 处理根元素的属性
processAttributesForElement(reader, elementStack, currentObject);
} else {
// 处理子元素的属性
processAttributesForElement(reader, elementStack, currentObject);
}
break;
case XMLStreamReader.CHARACTERS:
if (!reader.isWhiteSpace()) {
String text = reader.getText().trim();
if (!text.isEmpty()) {
currentText.append(text);
log.debug("文本内容: {}", text);
}
}
break;
case XMLStreamReader.END_ELEMENT:
String endedElement = elementStack.pop();
String elementContent = currentText.toString().trim();
log.debug("结束元素: {}, 内容: {}, 栈深度: {}",
endedElement, elementContent, elementStack.size());
// 处理元素内容
if (!elementContent.isEmpty()) {
processElementContent(endedElement, elementContent, elementStack, currentObject);
}
// 如果是根元素结束输出当前对象
if (endedElement.equals(rootElement)) {
// 应用转换规则
Map<String, Object> transformedObject = applyRules(currentObject);
String json = convertObjectToJson(transformedObject);
if (json != null && !json.trim().isEmpty()) {
if (!firstObject) {
jsonWriter.write(",\n");
} else {
firstObject = false;
}
jsonWriter.write(json);
objectCount++;
if (objectCount % 100 == 0) {
log.info("已处理 {} 个对象", objectCount);
jsonWriter.flush();
}
}
currentObject.clear();
}
currentText.setLength(0); // 重置文本内容
break;
}
}
jsonWriter.write("\n]");
log.info("转换完成,共处理 {} 个对象", objectCount);
} catch (Exception e) {
log.error("转换失败", e);
throw e;
}
}
/**
* 处理元素的属性
*/
private void processAttributesForElement(XMLStreamReader reader, Stack<String> elementStack,
Map<String, Object> currentObject) {
if (reader.getAttributeCount() > 0) {
for (int i = 0; i < reader.getAttributeCount(); i++) {
String attrName = reader.getAttributeLocalName(i);
String attrValue = reader.getAttributeValue(i);
// 默认处理将属性添加到对象中
String attrKey = elementStack.peek() + "@" + attrName;
currentObject.put(attrKey, attrValue);
}
}
}
/**
* 处理元素文本内容
*/
private void processElementContent(String elementName, String content,
Stack<String> elementStack, Map<String, Object> currentObject) {
// 默认处理将元素内容添加到对象中
// 构建完整的元素路径作为key
String elementKey = String.join(".", elementStack) + "." + elementName;
currentObject.put(elementKey, content);
}
/**
* 将对象转换为JSON字符串
*/
private String convertObjectToJson(Map<String, Object> object) {
if (object.isEmpty()) {
log.warn("空对象,跳过输出");
return null;
}
try {
return mapToJson(object);
} catch (Exception e) {
log.error("对象转JSON失败", e);
return "{}";
}
}
/**
* Map转JSON字符串
*/
private String mapToJson(Map<String, Object> map) {
if (map.isEmpty()) {
return "{}";
}
StringBuilder json = new StringBuilder("{");
boolean first = true;
for (Map.Entry<String, Object> entry : map.entrySet()) {
if (!first) {
json.append(",");
}
first = false;
json.append("\"").append(escapeJson(entry.getKey())).append("\":");
json.append(valueToJson(entry.getValue()));
}
json.append("}");
return json.toString();
}
/**
* 值转JSON
*/
private String valueToJson(Object value) {
if (value == null) {
return "null";
}
if (value instanceof String) {
return "\"" + escapeJson((String) value) + "\"";
}
if (value instanceof Number || value instanceof Boolean) {
return value.toString();
}
if (value instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>) value;
return mapToJson(map);
}
if (value instanceof List<?> list) {
StringBuilder json = new StringBuilder("[");
boolean first = true;
for (Object item : list) {
if (!first) {
json.append(",");
}
first = false;
json.append(valueToJson(item));
}
json.append("]");
return json.toString();
}
return "\"" + escapeJson(value.toString()) + "\"";
}
/**
* JSON特殊字符转义
*/
private String escapeJson(String text) {
if (text == null) return "";
return text.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\b", "\\b")
.replace("\f", "\\f")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t");
}
/**
* 应用正则表达式转换规则到单个对象
*/
private Map<String, Object> applyRules(Map<String, Object> originalMap) {
Map<String, Object> transformedMap = new HashMap<>();
for (Map.Entry<String, Object> entry : originalMap.entrySet()) {
String originalKey = entry.getKey();
Object value = entry.getValue();
String newKey = findAndReplace(originalKey);
// 如果找到匹配的规则则使用新key否则保留原key
if (newKey != null) {
transformedMap.put(newKey, value);
log.debug("转换键: {} -> {}", originalKey, newKey);
} else {
transformedMap.put(originalKey, value);
}
}
return transformedMap;
}
/**
* 查找并替换匹配的正则规则
*/
private String findAndReplace(String originalKey) {
for (Map.Entry<Pattern, String> rule : regexRules.entrySet()) {
if (rule.getKey().matcher(originalKey).matches()) {
return rule.getKey().matcher(originalKey).replaceAll(rule.getValue());
}
}
return null;
}
}

View File

@ -0,0 +1,102 @@
package com.example.demo.draft.demo043.domain;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Map;
/**
* 配置文档根实体
*
* <p>该实体表示完整的配置文档结构包含全局注释条件类型映射和多个层级配置</p>
*
* <h3>数据结构说明</h3>
* <ul>
* <li>{@link #globalComment} - 全局配置说明</li>
* <li>{@link #levelConfigs} - 层级配置列表</li>
* <li>{@link #conditionMap} - 条件判断映射表</li>
* <li>{@link #indentSpaces} - 缩进空格数控制</li>
* <li>{@link #initialIndent} - 初始缩进配置</li>
* </ul>
*
* <p><b>使用建造者模式简化对象创建过程使用示例</b></p>
* <pre>
* {@code
* ConfigDocument config = ConfigDocument.builder()
* .globalComment("系统主配置文件")
* .conditionMap(Map.of("required", "必须配置"))
* .levelConfigs(List.of(systemLevelConfig))
* .build();
* }
* </pre>
*
* @author Generated
* @version 1.0
* @since 2024
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ConfigDocument {
/**
* 全局备注信息
* <p>用于描述整个配置文件的用途版本信息或其他全局性说明</p>
*
* <p>示例</p>
* <pre>{@code
* # 这是全局备注信息
* }</pre>
*/
private String globalComment;
/**
* 初始缩进配置保留字段
* <p>用于格式化输出时的初始缩进空格当前版本通常为空字符串</p>
*
* @default ""
*/
@Builder.Default
private String initialIndent = "";
/**
* 缩进空格数
* <p>控制输出内容的缩进格式默认使用 4 个空格</p>
*
* <p>取值范围正整数建议使用 248 等常用值</p>
*
* @default 4
*/
@Builder.Default
private Integer indentSpaces = 4;
/**
* 条件类型映射表
* <p>定义不同条件类型的描述信息用于说明配置项的必要性级别</p>
*
* <p><b>常见键值</b></p>
* <ul>
* <li>required - 必须配置</li>
* <li>optional - 可选配置</li>
* <li>advanced - 高级选项需要权限</li>
* <li>deprecated - 已弃用不推荐使用</li>
* </ul>
*
* <p>示例</p>
* <pre>{@code
* conditionMap.put("type1", "显示内容1");
* conditionMap.put("type2", "显示内容2");
* }</pre>
*/
private Map<String, String> conditionMap;
/**
* 层级配置列表
* <p>包含系统各个模块的配置信息支持多层级的嵌套结构</p>
*/
private List<LevelConfig> levelConfigs;
}

View File

@ -0,0 +1,97 @@
package com.example.demo.draft.demo043.domain;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Map;
/**
* 配置值实体
*
* <p>表示单个配置值的详细信息支持带单位的数值配置和标志位配置</p>
*
* <p><b>值类型说明</b></p>
* <ul>
* <li>数值类型如超时时间重试次数等</li>
* <li>字符串类型如文件路径模式名称等</li>
* <li>布尔类型如启用/禁用标志</li>
* </ul>
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ConfigValue {
/**
* 配置值
* <p>实际的配置数值类型为Object以支持多种数据类型</p>
*
* <p><b>支持的数据类型</b></p>
* <ul>
* <li>Integer - 整数值如30510</li>
* <li>String - 字符串值"min""max""admin"</li>
* <li>Boolean - 布尔值"true"</li>
* </ul>
*/
private Object value;
/**
* 值单位
* <p>配置值的单位说明"seconds""GB""retries"</p>
*
* <p><b>注意</b>对于无单位的配置值此字段可为空</p>
*/
private String unit;
/**
* 组合标志
* <p>指示该值是否与其他值组合使用</p>
*
* <p><b>取值说明</b></p>
* <ul>
* <li>true - 组合值需要与其他值一起解析</li>
* <li>false - 独立值可单独使用</li>
* </ul>
*/
@Builder.Default
private boolean combined = false;
/**
* 正则表达式模式
* <p>用于对值内容进行正则匹配和替换</p>
*
* <p><b>注意</b>如果设置了此字段将在值处理时应用正则替换</p>
*/
private String regexPattern;
/**
* 正则替换字符串
* <p>用于正则替换的目标字符串</p>
*
* <p><b>格式说明</b>支持正则表达式中的替换组引用如$1$2等</p>
*/
private String regexReplacement;
/**
* 枚举映射配置
* <p>用于将值映射到预定义的枚举值</p>
*
* <p><b>格式说明</b>key为原始值value为映射后的值</p>
*/
private Map<String, String> enumMapping;
/**
* 工具函数调用配置
* <p>指定要调用的工具函数及其参数</p>
*
* <p><b>格式说明</b></p>
* <ul>
* <li>functionName - 函数名称</li>
* <li>parameters - 函数参数列表</li>
* </ul>
*/
private Map<String, Object> utilFunction;
}

View File

@ -0,0 +1,192 @@
package com.example.demo.draft.demo043.domain;
import com.alibaba.fastjson2.JSON;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Map;
/**
* 层级配置实体
*
* <p>表示配置中的一个层级节点可以包含值配置和子层级形成树状结构</p>
*
* <p><b>典型应用场景</b></p>
* <ul>
* <li>系统级配置system</li>
* <li>数据库配置database</li>
* <li>日志配置logging</li>
* </ul>
*
*
* <h3>模板中的表现形式</h3>
* <pre>{@code
* section param1 param2 # 层级备注
* condition_value
* values 100 ms 200 kb
* end_section
* }</pre>
*/
@Data
@Builder
@NoArgsConstructor
public class LevelConfig {
/**
* 层级名称
* <p>标识当前配置层级的唯一名称"system""database"</p>
*
* <p>在模板中作为开始标签和结束标签的标识</p>
* <pre>{@code
* {{ levelName }} ... end_{{ levelName }}
* }</pre>
*/
private String levelName;
/**
* 层级值循环索引号
* <p>标识当前配置层级的索引"1""2"</p>
*
* <p>为空时示例模板</p>
* <pre>{@code
* {{ levelName }} param1 ... end_{{ levelName }}
* }</pre>
*
* <p>不为空时示例模板</p>
* <pre>{@code
* {{ levelName }} param1_01 ... end_{{ levelName }}
* }</pre>
*/
private String levelLoopIndex;
/**
* 是否启用循环
* <p>控制是否对当前层级进行循环处理</p>
*
* <p><b>取值说明</b></p>
* <ul>
* <li>true - 启用循环处理</li>
* <li>false - 不启用循环处理默认</li>
* </ul>
*/
@Builder.Default
private Boolean enableLevel = true;
/**
* 层级值列表
* <p>当前层级的主要配置值如版本号启用状态等</p>
*
* <p>示例</p>
* <pre>{@code
* Arrays.asList("param1", "param2", "param3")
* }</pre>
*/
private List<String> values;
/**
* 层级注释说明
* <p>描述当前层级的用途功能或注意事项</p>
*/
private String comment;
/**
* 条件类型
* <p>引用conditionMap中的键表示该层级的配置必要性</p>
*
* @see ConfigDocument#getConditionMap()
*
* <p>示例模板</p>
* <pre>{@code
* <p>xxx param1 # description</p>
* <p> conditionType</p>
* <p> key1 value1</p>
* <p> key2 value2</p>
* <p> key3 value3</p>
* <p>end_xxx</p>
* }</pre>
*/
private String conditionType;
/**
* 值配置列表
* <p>当前层级下的具体配置项集合</p>
*/
private List<ValueConfig> valueConfigs;
/**
* 子层级列表
* <p>嵌套的子级配置支持无限层级嵌套</p>
*/
private List<LevelConfig> subLevels;
/**
* 是否启用循环
* <p>控制是否对当前层级进行循环处理</p>
*
* <p><b>取值说明</b></p>
* <ul>
* <li>true - 启用循环处理</li>
* <li>false - 不启用循环处理默认</li>
* </ul>
*/
private Boolean enableLoop = false;
/**
* 循环次数
* <p>指定循环处理的次数当启用循环时有效</p>
*
* <p><b>注意</b>如果为null或小于等于0则使用默认循环次数1</p>
*/
private String loopCount;
/**
* 枚举映射配置
* <p>用于将值映射到预定义的枚举值</p>
*
* <p><b>格式说明</b>key为原始值value为映射后的值</p>
*/
private Map<String, String> enumMapping;
/**
* 工具函数调用配置
* <p>指定要调用的工具函数及其参数</p>
*
* <p><b>格式说明</b></p>
* <ul>
* <li>functionName - 函数名称</li>
* <li>parameters - 函数参数列表</li>
* </ul>
*/
private Map<String, Object> utilFunction;
public LevelConfig(
String levelName,
String levelLoopIndex,
Boolean enableLevel,
List<String> values,
String comment,
String conditionType,
List<ValueConfig> valueConfigs,
List<LevelConfig> subLevels,
Boolean enableLoop,
String loopCount,
Map<String, String> enumMapping,
Map<String, Object> utilFunction
) {
this.levelName = levelName;
this.levelLoopIndex = levelLoopIndex;
this.enableLevel = enableLevel;
this.values = values;
this.comment = comment;
this.conditionType = conditionType;
this.valueConfigs = valueConfigs;
this.subLevels = subLevels;
this.enableLoop = enableLoop;
this.loopCount = loopCount;
this.enumMapping = enumMapping;
this.utilFunction = utilFunction;
}
}

View File

@ -0,0 +1,40 @@
package com.example.demo.draft.demo043.domain;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* 值配置实体
*
* <p>表示具体的配置项包含配置名称值列表和注释信息</p>
*
* <p><b>注意</b>values字段可以包含不同类型的配置值支持复杂配置场景</p>
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ValueConfig {
/**
* 值配置名称
* <p>配置项的唯一标识"timeout""memory"</p>
*/
private String valueName;
/**
* 配置值列表
* <p>包含一个或多个配置值对象支持多值配置</p>
*/
private List<ConfigValue> values;
/**
* 值配置注释
* <p>描述该配置项的作用取值范围或特殊说明</p>
*/
private String comment;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,245 @@
//package com.example.demo.parser.controller;
//
//import com.example.demo.common.wrapper.WrapMapper;
//import com.example.demo.common.wrapper.Wrapper;
//import com.example.demo.common.exception.BusinessException;
//import com.example.demo.common.utils.FileUtil;
//import com.example.demo.common.utils.XmlParserUtil;
//import com.example.demo.parser.entity.FileRecordEntity;
//import com.example.demo.parser.model.dto.FileRecordDTO;
//import com.example.demo.parser.model.vo.FileRecordVO;
//import com.example.demo.parser.service.FileRecordService;
//import com.mybatisflex.core.paginate.Page;
//import io.swagger.v3.oas.annotations.Operation;
//import io.swagger.v3.oas.annotations.Parameter;
//import io.swagger.v3.oas.annotations.tags.Tag;
//import lombok.RequiredArgsConstructor;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.beans.factory.annotation.Value;
//import org.springframework.web.bind.annotation.*;
//import org.springframework.web.multipart.MultipartFile;
//
//import java.io.File;
//import java.nio.file.Files;
//import java.nio.file.Path;
//import java.nio.file.Paths;
//import java.time.LocalDateTime;
//import java.util.List;
//import java.util.UUID;
//
///**
// * 文件解析控制器
// * 提供文件上传解析和转换的RESTful API接口
// *
// * @author system
// * @version 1.0
// */
//@Slf4j
//@RestController
//@RequestMapping("/parser/files")
//@RequiredArgsConstructor
//@Tag(name = "文件解析管理", description = "提供XML文件上传、解析和转换的接口")
//public class FileParserController {
//
// private final FileRecordService fileRecordService;
//
// @Value("${xml-parser.file.upload-dir:./upload}")
// private String uploadDir;
//
// @Value("${xml-parser.file.temp-dir:./temp}")
// private String tempDir;
//
// /**
// * 上传XML文件
// *
// * @param file 上传的XML文件
// * @return 操作结果
// */
// @PostMapping("/upload")
// @Operation(summary = "上传XML文件", description = "上传XML文件并进行解析准备")
// public Wrapper<FileRecordVO> uploadFile(
// @Parameter(description = "XML文件", required = true)
// @RequestParam("file") MultipartFile file) {
// try {
// // 验证文件类型
// if (!isValidXmlFile(file)) {
// return WrapMapper.fail("请上传有效的XML文件");
// }
//
// // 创建上传目录
// FileUtil.createDirectory(uploadDir);
//
// // 生成唯一文件名
// String originalFilename = file.getOriginalFilename();
// String uniqueFilename = FileUtil.generateUniqueFileName(originalFilename);
// String filePath = Paths.get(uploadDir, uniqueFilename).toString();
//
// // 保存文件
// file.transferTo(new File(filePath));
//
// // 创建文件记录
// FileRecordDTO record = new FileRecordDTO();
// record.setFileName(originalFilename);
// record.setFilePath(filePath);
// record.setFileSize(file.getSize());
// record.setStatus("UPLOADED");
// record.setProcessLog("文件上传成功");
//
// String recordId = fileRecordService.create(record);
// FileRecordVO result = fileRecordService.getById(recordId);
//
// return WrapMapper.ok(result, "文件上传成功");
// } catch (BusinessException e) {
// log.error("文件上传失败: {}", e.getMessage(), e);
// return WrapMapper.fail(e.getMessage());
// } catch (Exception e) {
// log.error("文件上传异常: {}", e.getMessage(), e);
// return WrapMapper.fail("文件上传失败");
// }
// }
//
// /**
// * 解析XML文件
// *
// * @param recordId 文件记录ID
// * @return 操作结果
// */
// @PostMapping("/parse/{recordId}")
// @Operation(summary = "解析XML文件", description = "解析已上传的XML文件")
// public Wrapper<FileRecordVO> parseFile(
// @Parameter(description = "文件记录ID", required = true)
// @PathVariable String recordId) {
// try {
// FileRecordVO record = fileRecordService.getById(recordId);
// if (record == null) {
// return WrapMapper.fail("文件记录不存在");
// }
//
// // 更新状态为解析中
// fileRecordService.updateStatus(recordId, "PARSING", "开始解析XML文件");
//
// // 解析XML文件
// String xmlFilePath = record.getFilePath();
// String txtFilePath = generateTxtFilePath(xmlFilePath);
//
// try {
// XmlParserUtil.parseXmlToTxt(xmlFilePath, txtFilePath);
//
// // 更新状态为解析成功
// fileRecordService.updateStatus(recordId, "PARSED", "XML文件解析成功");
//
// FileRecordVO result = fileRecordService.getById(recordId);
// return WrapMapper.ok(result, "XML文件解析成功");
//
// } catch (Exception e) {
// // 更新状态为解析失败
// fileRecordService.updateStatus(recordId, "PARSE_FAILED", "XML文件解析失败: " + e.getMessage());
// throw new BusinessException("XML文件解析失败: " + e.getMessage());
// }
//
// } catch (BusinessException e) {
// log.error("文件解析失败: {}", e.getMessage(), e);
// return WrapMapper.fail(e.getMessage());
// } catch (Exception e) {
// log.error("文件解析异常: {}", e.getMessage(), e);
// return WrapMapper.fail("文件解析失败");
// }
// }
//
// /**
// * 获取文件记录详情
// *
// * @param recordId 文件记录ID
// * @return 文件记录详情
// */
// @GetMapping("/{recordId}")
// @Operation(summary = "获取文件记录详情", description = "根据ID获取文件记录的详细信息")
// public Wrapper<FileRecordVO> getFileRecord(
// @Parameter(description = "文件记录ID", required = true)
// @PathVariable String recordId) {
// try {
// FileRecordVO result = fileRecordService.getById(recordId);
// return WrapMapper.ok(result, "获取文件记录详情成功");
// } catch (BusinessException e) {
// log.error("获取文件记录详情失败: {}", e.getMessage(), e);
// return WrapMapper.fail(e.getMessage());
// } catch (Exception e) {
// log.error("获取文件记录详情异常: {}", e.getMessage(), e);
// return WrapMapper.fail("获取文件记录详情失败");
// }
// }
//
// /**
// * 分页查询文件记录列表
// *
// * @param pageNumber 页码
// * @param pageSize 每页大小
// * @return 分页结果
// */
// @GetMapping("/page")
// @Operation(summary = "分页查询文件记录", description = "分页查询文件记录列表")
// public Wrapper<Page<FileRecordVO>> pageList(
// @Parameter(description = "页码", example = "1")
// @RequestParam(defaultValue = "1") Integer pageNumber,
// @Parameter(description = "每页大小", example = "10")
// @RequestParam(defaultValue = "10") Integer pageSize) {
// try {
// Page<FileRecordVO> result = fileRecordService.pageList(pageNumber, pageSize);
// return WrapMapper.ok(result, "查询文件记录列表成功");
// } catch (Exception e) {
// log.error("查询文件记录列表异常: {}", e.getMessage(), e);
// return WrapMapper.fail("查询文件记录列表失败");
// }
// }
//
// /**
// * 获取所有文件记录列表
// *
// * @return 文件记录列表
// */
// @GetMapping("/list")
// @Operation(summary = "获取所有文件记录", description = "获取所有文件记录的列表")
// public Wrapper<List<FileRecordVO>> listAll() {
// try {
// List<FileRecordVO> result = fileRecordService.listAll();
// return WrapMapper.ok(result, "获取所有文件记录成功");
// } catch (Exception e) {
// log.error("获取所有文件记录异常: {}", e.getMessage(), e);
// return WrapMapper.fail("获取所有文件记录失败");
// }
// }
//
// /**
// * 验证是否为有效的XML文件
// *
// * @param file 上传的文件
// * @return 是否有效
// */
// private boolean isValidXmlFile(MultipartFile file) {
// if (file == null || file.isEmpty()) {
// return false;
// }
//
// String originalFilename = file.getOriginalFilename();
// if (originalFilename == null) {
// return false;
// }
//
// // 检查文件扩展名
// String extension = FileUtil.getFileExtension(originalFilename);
// return "xml".equalsIgnoreCase(extension);
// }
//
// /**
// * 生成TXT文件路径
// *
// * @param xmlFilePath XML文件路径
// * @return TXT文件路径
// */
// private String generateTxtFilePath(String xmlFilePath) {
// Path xmlPath = Paths.get(xmlFilePath);
// String xmlFileName = xmlPath.getFileName().toString();
// String txtFileName = xmlFileName.replace(".xml", ".txt");
// return xmlPath.getParent().resolve(txtFileName).toString();
// }
//}

View File

@ -0,0 +1,188 @@
//package com.example.demo.parser.controller;
//
//import com.example.demo.common.exception.BusinessException;
//import com.example.demo.common.wrapper.WrapMapper;
//import com.example.demo.common.wrapper.Wrapper;
//import com.example.demo.parser.model.dto.MapperRuleDTO;
//import com.example.demo.parser.model.vo.MapperRuleVO;
//import com.example.demo.parser.service.MapperRuleService;
//import com.mybatisflex.core.paginate.Page;
//import io.swagger.v3.oas.annotations.Operation;
//import io.swagger.v3.oas.annotations.Parameter;
//import io.swagger.v3.oas.annotations.tags.Tag;
//import jakarta.validation.Valid;
//import lombok.RequiredArgsConstructor;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.validation.annotation.Validated;
//import org.springframework.web.bind.annotation.*;
//
//import java.util.List;
//
///**
// * 映射规则控制器
// * 提供映射规则的RESTful API接口
// *
// * @author system
// * @version 1.0
// */
//@Slf4j
//@RestController
//@RequestMapping("/parser/mapper-rules")
//@RequiredArgsConstructor
//@Validated
//@Tag(name = "映射规则管理", description = "提供XML到TXT映射规则的增删改查接口")
//public class MapperRuleController {
//
// private final MapperRuleService mapperRuleService;
//
// /**
// * 创建映射规则
// *
// * @param dto 映射规则数据传输对象
// * @return 操作结果
// */
// @PostMapping
// @Operation(summary = "创建映射规则", description = "创建新的XML到TXT映射规则")
// public Wrapper<String> create(@Valid @RequestBody MapperRuleDTO dto) {
// try {
// String id = mapperRuleService.create(dto);
// return WrapMapper.ok(id, "创建映射规则成功");
// } catch (BusinessException e) {
// log.error("创建映射规则失败: {}", e.getMessage(), e);
// return WrapMapper.fail(e.getMessage());
// } catch (Exception e) {
// log.error("创建映射规则异常: {}", e.getMessage(), e);
// return WrapMapper.fail("创建映射规则失败");
// }
// }
//
// /**
// * 删除映射规则
// *
// * @param id 映射规则ID
// * @return 操作结果
// */
// @DeleteMapping("/{id}")
// @Operation(summary = "删除映射规则", description = "根据ID删除映射规则")
// public Wrapper<Boolean> delete(
// @Parameter(description = "映射规则ID", required = true)
// @PathVariable String id) {
// try {
// boolean result = mapperRuleService.delete(id);
// return WrapMapper.ok(result, "删除映射规则成功");
// } catch (BusinessException e) {
// log.error("删除映射规则失败: {}", e.getMessage(), e);
// return WrapMapper.fail(e.getMessage());
// } catch (Exception e) {
// log.error("删除映射规则异常: {}", e.getMessage(), e);
// return WrapMapper.fail("删除映射规则失败");
// }
// }
//
// /**
// * 更新映射规则
// *
// * @param dto 映射规则数据传输对象
// * @return 操作结果
// */
// @PutMapping
// @Operation(summary = "更新映射规则", description = "更新现有的映射规则")
// public Wrapper<Boolean> update(@Valid @RequestBody MapperRuleDTO dto) {
// try {
// boolean result = mapperRuleService.update(dto);
// return WrapMapper.ok(result, "更新映射规则成功");
// } catch (BusinessException e) {
// log.error("更新映射规则失败: {}", e.getMessage(), e);
// return WrapMapper.fail(e.getMessage());
// } catch (Exception e) {
// log.error("更新映射规则异常: {}", e.getMessage(), e);
// return WrapMapper.fail("更新映射规则失败");
// }
// }
//
// /**
// * 根据ID获取映射规则详情
// *
// * @param id 映射规则ID
// * @return 映射规则详情
// */
// @GetMapping("/{id}")
// @Operation(summary = "获取映射规则详情", description = "根据ID获取映射规则的详细信息")
// public Wrapper<MapperRuleVO> getById(
// @Parameter(description = "映射规则ID", required = true)
// @PathVariable String id) {
// try {
// MapperRuleVO result = mapperRuleService.getById(id);
// return WrapMapper.ok(result, "获取映射规则详情成功");
// } catch (BusinessException e) {
// log.error("获取映射规则详情失败: {}", e.getMessage(), e);
// return WrapMapper.fail(e.getMessage());
// } catch (Exception e) {
// log.error("获取映射规则详情异常: {}", e.getMessage(), e);
// return WrapMapper.fail("获取映射规则详情失败");
// }
// }
//
// /**
// * 分页查询映射规则列表
// *
// * @param pageNumber 页码
// * @param pageSize 每页大小
// * @return 分页结果
// */
// @GetMapping("/page")
// @Operation(summary = "分页查询映射规则", description = "分页查询映射规则列表")
// public Wrapper<Page<MapperRuleVO>> pageList(
// @Parameter(description = "页码", example = "1")
// @RequestParam(defaultValue = "1") Integer pageNumber,
// @Parameter(description = "每页大小", example = "10")
// @RequestParam(defaultValue = "10") Integer pageSize) {
// try {
// Page<MapperRuleVO> result = mapperRuleService.pageList(pageNumber, pageSize);
// return WrapMapper.ok(result, "查询映射规则列表成功");
// } catch (Exception e) {
// log.error("查询映射规则列表异常: {}", e.getMessage(), e);
// return WrapMapper.fail("查询映射规则列表失败");
// }
// }
//
// /**
// * 根据解析规则ID获取映射规则列表
// *
// * @param parseRuleId 解析规则ID
// * @return 映射规则列表
// */
// @GetMapping("/by-parse-rule/{parseRuleId}")
// @Operation(summary = "根据解析规则获取映射规则", description = "根据解析规则ID获取对应的映射规则列表")
// public Wrapper<List<MapperRuleVO>> getByParseRuleId(
// @Parameter(description = "解析规则ID", required = true)
// @PathVariable String parseRuleId) {
// try {
// List<MapperRuleVO> result = mapperRuleService.getByParseRuleId(parseRuleId);
// return WrapMapper.ok(result, "根据解析规则获取映射规则成功");
// } catch (BusinessException e) {
// log.error("根据解析规则获取映射规则失败: {}", e.getMessage(), e);
// return WrapMapper.fail(e.getMessage());
// } catch (Exception e) {
// log.error("根据解析规则获取映射规则异常: {}", e.getMessage(), e);
// return WrapMapper.fail("根据解析规则获取映射规则失败");
// }
// }
//
// /**
// * 获取所有映射规则列表
// *
// * @return 映射规则列表
// */
// @GetMapping("/list")
// @Operation(summary = "获取所有映射规则", description = "获取所有映射规则的列表")
// public Wrapper<List<MapperRuleVO>> listAll() {
// try {
// List<MapperRuleVO> result = mapperRuleService.listAll();
// return WrapMapper.ok(result, "获取所有映射规则成功");
// } catch (Exception e) {
// log.error("获取所有映射规则异常: {}", e.getMessage(), e);
// return WrapMapper.fail("获取所有映射规则失败");
// }
// }
//}

View File

@ -0,0 +1,188 @@
//package com.example.demo.parser.controller;
//
//import cn.zhxu.bs.SearchResult;
//import com.example.demo.common.exception.BusinessException;
//import com.example.demo.common.wrapper.WrapMapper;
//import com.example.demo.common.wrapper.Wrapper;
//import com.example.demo.parser.entity.ParseRuleEntity;
//import com.example.demo.parser.model.dto.ParseRuleDTO;
//import com.example.demo.parser.model.vo.ParseRuleVO;
//import com.example.demo.parser.service.ParseRuleService;
//import com.mybatisflex.core.paginate.Page;
//import io.swagger.v3.oas.annotations.Operation;
//import io.swagger.v3.oas.annotations.Parameter;
//import io.swagger.v3.oas.annotations.tags.Tag;
//import jakarta.validation.Valid;
//import lombok.RequiredArgsConstructor;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.validation.annotation.Validated;
//import org.springframework.web.bind.annotation.*;
//
//import java.util.List;
//
///**
// * 解析规则控制器
// * 提供解析规则的RESTful API接口
// *
// * @author system
// * @version 1.0
// */
//@Slf4j
//@RestController
//@RequestMapping("/parser/parse-rules")
//@RequiredArgsConstructor
//@Validated
//@Tag(name = "解析规则管理", description = "提供XML解析规则的增删改查接口")
//public class ParseRuleController {
//
// private final ParseRuleService parseRuleService;
//
// /**
// * 创建解析规则
// *
// * @param dto 解析规则数据传输对象
// * @return 操作结果
// */
// @PostMapping
// @Operation(summary = "创建解析规则", description = "创建新的XML解析规则")
// public Wrapper<String> create(@Valid @RequestBody ParseRuleDTO dto) {
// try {
// String id = parseRuleService.create(dto);
// return WrapMapper.ok(id, "创建解析规则成功");
// } catch (BusinessException e) {
// log.error("创建解析规则失败: {}", e.getMessage(), e);
// return WrapMapper.fail(e.getMessage());
// } catch (Exception e) {
// log.error("创建解析规则异常: {}", e.getMessage(), e);
// return WrapMapper.fail("创建解析规则失败");
// }
// }
//
// /**
// * 删除解析规则
// *
// * @param id 解析规则ID
// * @return 操作结果
// */
// @DeleteMapping("/{id}")
// @Operation(summary = "删除解析规则", description = "根据ID删除解析规则")
// public Wrapper<Boolean> delete(
// @Parameter(description = "解析规则ID", required = true)
// @PathVariable String id) {
// try {
// boolean result = parseRuleService.delete(id);
// return WrapMapper.ok(result, "删除解析规则成功");
// } catch (BusinessException e) {
// log.error("删除解析规则失败: {}", e.getMessage(), e);
// return WrapMapper.fail(e.getMessage());
// } catch (Exception e) {
// log.error("删除解析规则异常: {}", e.getMessage(), e);
// return WrapMapper.fail("删除解析规则失败");
// }
// }
//
// /**
// * 更新解析规则
// *
// * @param dto 解析规则数据传输对象
// * @return 操作结果
// */
// @PutMapping
// @Operation(summary = "更新解析规则", description = "更新现有的解析规则")
// public Wrapper<Boolean> update(@Valid @RequestBody ParseRuleDTO dto) {
// try {
// boolean result = parseRuleService.update(dto);
// return WrapMapper.ok(result, "更新解析规则成功");
// } catch (BusinessException e) {
// log.error("更新解析规则失败: {}", e.getMessage(), e);
// return WrapMapper.fail(e.getMessage());
// } catch (Exception e) {
// log.error("更新解析规则异常: {}", e.getMessage(), e);
// return WrapMapper.fail("更新解析规则失败");
// }
// }
//
// /**
// * 根据ID获取解析规则详情
// *
// * @param id 解析规则ID
// * @return 解析规则详情
// */
// @GetMapping("/{id}")
// @Operation(summary = "获取解析规则详情", description = "根据ID获取解析规则的详细信息")
// public Wrapper<ParseRuleVO> getById(
// @Parameter(description = "解析规则ID", required = true)
// @PathVariable String id) {
// try {
// ParseRuleVO result = parseRuleService.getById(id);
// return WrapMapper.ok(result, "获取解析规则详情成功");
// } catch (BusinessException e) {
// log.error("获取解析规则详情失败: {}", e.getMessage(), e);
// return WrapMapper.fail(e.getMessage());
// } catch (Exception e) {
// log.error("获取解析规则详情异常: {}", e.getMessage(), e);
// return WrapMapper.fail("获取解析规则详情失败");
// }
// }
//
// /**
// * 分页查询解析规则列表
// *
// * @param pageNumber 页码
// * @param pageSize 每页大小
// * @return 分页结果
// */
// @GetMapping("/page")
// @Operation(summary = "分页查询解析规则", description = "分页查询解析规则列表")
// public Wrapper<Page<ParseRuleVO>> pageList(
// @Parameter(description = "页码", example = "1")
// @RequestParam(defaultValue = "1") Integer pageNumber,
// @Parameter(description = "每页大小", example = "10")
// @RequestParam(defaultValue = "10") Integer pageSize) {
// try {
// Page<ParseRuleVO> result = parseRuleService.pageList(pageNumber, pageSize);
// return WrapMapper.ok(result, "查询解析规则列表成功");
// } catch (Exception e) {
// log.error("查询解析规则列表异常: {}", e.getMessage(), e);
// return WrapMapper.fail("查询解析规则列表失败");
// }
// }
//
// /**
// * 获取所有解析规则列表
// *
// * @return 解析规则列表
// */
// @GetMapping("/list")
// @Operation(summary = "获取所有解析规则", description = "获取所有解析规则的列表")
// public Wrapper<List<ParseRuleVO>> listAll() {
// try {
// List<ParseRuleVO> result = parseRuleService.listAll();
// return WrapMapper.ok(result, "获取所有解析规则成功");
// } catch (Exception e) {
// log.error("获取所有解析规则异常: {}", e.getMessage(), e);
// return WrapMapper.fail("获取所有解析规则失败");
// }
// }
//
// /**
// * 根据XML标签名获取解析规则详情
// *
// * @param xmlTag XML标签名
// * @return 解析规则详情
// */
// @GetMapping("/by-xml-tag/{xmlTag}")
// @Operation(summary = "根据XML标签名获取解析规则详情")
// public Wrapper<ParseRuleVO> getByXmlTag(@PathVariable String xmlTag) {
// log.info("根据XML标签名获取解析规则详情: {}", xmlTag);
//
// ParseRuleEntity entity = parseRuleService.getByXmlTag(xmlTag);
// if (entity == null) {
// return WrapMapper.fail("解析规则不存在: " + xmlTag);
// }
//
// // 通过getById方法获取VO对象
// ParseRuleVO result = parseRuleService.getById(entity.getId());
// return WrapMapper.ok(result);
// }
//}

View File

@ -0,0 +1,97 @@
package com.example.demo.parser.entity;
import com.example.demo.common.domain.BaseEntity;
import com.mybatisflex.annotation.Table;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.experimental.SuperBuilder;
import java.io.Serial;
import java.util.Date;
/**
* 文件记录实体类
* 对应数据库中的file_record表用于存储文件上传解析转换等操作记录
*
* @author system
* @version 1.0
*/
@Schema(description = "文件记录")
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Table("file_record")
public class FileRecordEntity extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 文件名
*/
@Schema(description = "文件名")
private String fileName;
/**
* 文件路径
*/
@Schema(description = "文件路径")
private String filePath;
/**
* 文件大小
*/
@Schema(description = "文件大小")
private Long fileSize;
/**
* 文件类型xml, txt
*/
@Schema(description = "文件类型")
private String fileType;
/**
* 文件状态uploaded, parsed, converted
*/
@Schema(description = "文件状态")
private String status;
/**
* 上传时间
*/
@Schema(description = "上传时间")
private Date uploadTime;
/**
* 处理时间
*/
@Schema(description = "处理时间")
private Date processTime;
/**
* 处理日志
*/
@Schema(description = "处理日志")
private String processLog;
/**
* 处理结果文件ID
*/
@Schema(description = "处理结果文件ID")
private Long resultFileId;
/**
* 关联的解析规则ID
*/
@Schema(description = "关联的解析规则ID")
private Long parseRuleId;
/**
* 关联的映射规则ID
*/
@Schema(description = "关联的映射规则ID")
private Long mapperRuleId;
}

View File

@ -0,0 +1,60 @@
package com.example.demo.parser.entity;
import com.example.demo.common.domain.BaseEntity;
import com.mybatisflex.annotation.Table;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.experimental.SuperBuilder;
import java.io.Serial;
/**
* 映射规则实体类
* 对应数据库中的mapper_rule表用于存储XML到TXT的映射规则
*
* @author system
* @version 1.0
*/
@Schema(description = "映射规则")
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Table("mapper_rule")
public class MapperRuleEntity extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 关联的解析规则ID
*/
@Schema(description = "关联的解析规则ID")
private String parseRuleId;
/**
* TXT文件中的键名
*/
@Schema(description = "TXT文件中的键名")
private String txtKey;
/**
* 转换模板
*/
@Schema(description = "转换模板")
private String template;
/**
* 父级键名
*/
@Schema(description = "父级键名")
private String parentKey;
/**
* 排序顺序
*/
@Schema(description = "排序顺序")
private Integer sortOrder;
}

View File

@ -0,0 +1,54 @@
package com.example.demo.parser.entity;
import com.example.demo.common.domain.BaseEntity;
import com.mybatisflex.annotation.Table;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.experimental.SuperBuilder;
import java.io.Serial;
/**
* 解析规则实体类
* 对应数据库中的parse_rule表用于存储XML解析规则
*
* @author system
* @version 1.0
*/
@Schema(description = "解析规则")
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Table("parse_rule")
public class ParseRuleEntity extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* XML标签名
*/
@Schema(description = "XML标签名")
private String xmlTag;
/**
* 标签类型root, node, leaf
*/
@Schema(description = "标签类型")
private String tagType;
/**
* 是否允许为空0-不允许1-允许
*/
@Schema(description = "是否允许为空")
private String isNull;
/**
* 节点路径
*/
@Schema(description = "节点路径")
private String nodePath;
}

View File

@ -0,0 +1,18 @@
package com.example.demo.parser.mapper;
import com.example.demo.parser.entity.FileRecordEntity;
import com.mybatisflex.core.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* 文件记录Mapper接口
* 用于文件记录的数据库操作
*
* @author system
* @version 1.0
*/
@Mapper
public interface FileRecordMapper extends BaseMapper<FileRecordEntity> {
// 可以添加自定义的SQL方法
}

View File

@ -0,0 +1,18 @@
package com.example.demo.parser.mapper;
import com.example.demo.parser.entity.MapperRuleEntity;
import com.mybatisflex.core.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* 映射规则Mapper接口
* 用于映射规则的数据库操作
*
* @author system
* @version 1.0
*/
@Mapper
public interface MapperRuleMapper extends BaseMapper<MapperRuleEntity> {
// 可以添加自定义的SQL方法
}

View File

@ -0,0 +1,18 @@
package com.example.demo.parser.mapper;
import com.example.demo.parser.entity.ParseRuleEntity;
import com.mybatisflex.core.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* 解析规则Mapper接口
* 用于解析规则的数据库操作
*
* @author system
* @version 1.0
*/
@Mapper
public interface ParseRuleMapper extends BaseMapper<ParseRuleEntity> {
// 可以添加自定义的SQL方法
}

View File

@ -0,0 +1,103 @@
package com.example.demo.parser.model.dto;
import cn.zhxu.bs.bean.DbField;
import com.example.demo.common.domain.BaseDTO;
import com.example.demo.common.domain.BaseQueryDTO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.SuperBuilder;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 文件记录查询数据传输对象
* 用于映射规则的创建和更新操作
*
* @author system
* @version 1.0
*/
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class FileRecordDTO extends BaseDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 文件名模糊查询
*/
@Schema(description = "文件名")
@DbField(value = "file_name")
private String fileName;
/**
* 文件路径模糊查询
*/
@Schema(description = "文件路径")
@DbField(value = "file_path")
private String filePath;
/**
* 文件大小开始值
*/
@Schema(description = "文件大小开始值")
@DbField(value = "file_size")
private Long fileSizeStart;
/**
* 文件大小结束值
*/
@Schema(description = "文件大小结束值")
@DbField(value = "file_size")
private Long fileSizeEnd;
/**
* 文件类型
*/
@Schema(description = "文件类型")
@DbField("file_type")
private String fileType;
/**
* 文件状态
*/
@Schema(description = "文件状态")
@DbField("status")
private Integer status;
/**
* 上传时间开始
*/
@Schema(description = "上传时间开始")
@DbField(value = "upload_time")
private Date uploadTimeStart;
/**
* 上传时间结束
*/
@Schema(description = "上传时间结束")
@DbField(value = "upload_time")
private Date uploadTimeEnd;
/**
* 处理时间开始
*/
@Schema(description = "处理时间开始")
@DbField(value = "process_time")
private Date processTimeStart;
/**
* 处理时间结束
*/
@Schema(description = "处理时间结束")
@DbField(value = "process_time")
private Date processTimeEnd;
}

View File

@ -0,0 +1,98 @@
package com.example.demo.parser.model.dto;
import cn.zhxu.bs.bean.DbField;
import com.example.demo.common.domain.BaseQueryDTO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.experimental.SuperBuilder;
import java.io.Serial;
import java.util.Date;
/**
* 文件记录查询数据传输对象
* 用于封装文件记录的查询条件
*
* @author system
* @version 1.0
*/
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class FileRecordQueryDTO extends BaseQueryDTO {
@Serial
private static final long serialVersionUID = 1L;
/**
* 文件名模糊查询
*/
@Schema(description = "文件名")
@DbField(value = "file_name")
private String fileName;
/**
* 文件路径模糊查询
*/
@Schema(description = "文件路径")
@DbField(value = "file_path")
private String filePath;
/**
* 文件大小开始值
*/
@Schema(description = "文件大小开始值")
@DbField(value = "file_size")
private Long fileSizeStart;
/**
* 文件大小结束值
*/
@Schema(description = "文件大小结束值")
@DbField(value = "file_size")
private Long fileSizeEnd;
/**
* 文件类型
*/
@Schema(description = "文件类型")
@DbField("file_type")
private String fileType;
/**
* 文件状态
*/
@Schema(description = "文件状态")
@DbField("status")
private Integer status;
/**
* 上传时间开始
*/
@Schema(description = "上传时间开始")
@DbField(value = "upload_time")
private Date uploadTimeStart;
/**
* 上传时间结束
*/
@Schema(description = "上传时间结束")
@DbField(value = "upload_time")
private Date uploadTimeEnd;
/**
* 处理时间开始
*/
@Schema(description = "处理时间开始")
@DbField(value = "process_time")
private Date processTimeStart;
/**
* 处理时间结束
*/
@Schema(description = "处理时间结束")
@DbField(value = "process_time")
private Date processTimeEnd;
}

View File

@ -0,0 +1,68 @@
package com.example.demo.parser.model.dto;
import com.example.demo.common.domain.BaseDTO;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.*;
import lombok.experimental.SuperBuilder;
import java.io.Serial;
import java.io.Serializable;
/**
* 映射规则数据传输对象
* 用于映射规则的创建和更新操作
*
* @author system
* @version 1.0
*/
@Schema(description = "映射规则数据传输对象")
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class MapperRuleDTO extends BaseDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 关联的解析规则ID
*/
@NotBlank(message = "关联的解析规则ID不能为空")
@Schema(description = "关联的解析规则ID")
private String parseRuleId;
/**
* TXT文件中的键名
*/
@NotBlank(message = "TXT文件中的键名不能为空")
@Size(max = 100, message = "TXT文件中的键名不能超过100个字符")
@Schema(description = "TXT文件中的键名")
private String txtKey;
/**
* 转换模板
*/
@Size(max = 255, message = "转换模板不能超过255个字符")
@Schema(description = "转换模板")
private String template;
/**
* 父级键名
*/
@Size(max = 100, message = "父级键名不能超过100个字符")
@Schema(description = "父级键名")
private String parentKey;
/**
* 排序顺序
*/
@NotNull(message = "排序顺序不能为空")
@Schema(description = "排序顺序")
private Integer sortOrder;
}

View File

@ -0,0 +1,65 @@
package com.example.demo.parser.model.dto;
import com.example.demo.common.domain.BaseQueryDTO;
import cn.zhxu.bs.bean.DbField;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.experimental.SuperBuilder;
import java.io.Serial;
import java.io.Serializable;
/**
* 映射规则查询数据传输对象
* 用于封装映射规则的查询条件
*
* @author system
* @version 1.0
*/
@Schema(description = "映射规则查询数据传输对象")
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class MapperRuleQueryDTO extends BaseQueryDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 关联的解析规则ID
*/
@DbField("parse_rule_id")
@Schema(description = "关联的解析规则ID")
private String parseRuleId;
/**
* TXT文件中的键名
*/
@DbField("txt_key")
@Schema(description = "TXT文件中的键名")
private String txtKey;
/**
* 父级键名
*/
@DbField("parent_key")
@Schema(description = "父级键名")
private String parentKey;
/**
* 排序顺序开始
*/
@DbField("sort_order")
@Schema(description = "排序顺序开始")
private Integer sortOrderStart;
/**
* 排序顺序结束
*/
@DbField("sort_order")
@Schema(description = "排序顺序结束")
private Integer sortOrderEnd;
}

View File

@ -0,0 +1,61 @@
package com.example.demo.parser.model.dto;
import com.example.demo.common.domain.BaseDTO;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.*;
import lombok.experimental.SuperBuilder;
import java.io.Serial;
import java.io.Serializable;
/**
* 解析规则数据传输对象
* 用于解析规则的创建和更新操作
*
* @author system
* @version 1.0
*/
@Schema(description = "解析规则数据传输对象")
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class ParseRuleDTO extends BaseDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* XML标签名
*/
@NotBlank(message = "XML标签名不能为空")
@Size(max = 100, message = "XML标签名不能超过100个字符")
@Schema(description = "XML标签名")
private String xmlTag;
/**
* 标签类型root, node, leaf
*/
@NotBlank(message = "标签类型不能为空")
@Size(max = 20, message = "标签类型不能超过20个字符")
@Schema(description = "标签类型")
private String tagType;
/**
* 是否允许为空0-不允许1-允许
*/
@Size(max = 1, message = "是否允许为空不能超过1个字符")
@Schema(description = "是否允许为空")
private String isNull;
/**
* 节点路径
*/
@Size(max = 255, message = "节点路径不能超过255个字符")
@Schema(description = "节点路径")
private String nodePath;
}

View File

@ -0,0 +1,58 @@
package com.example.demo.parser.model.dto;
import com.example.demo.common.domain.BaseQueryDTO;
import cn.zhxu.bs.bean.DbField;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.experimental.SuperBuilder;
import java.io.Serial;
import java.io.Serializable;
/**
* 解析规则查询数据传输对象
* 用于封装解析规则的查询条件
*
* @author system
* @version 1.0
*/
@Schema(description = "解析规则查询数据传输对象")
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class ParseRuleQueryDTO extends BaseQueryDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* XML标签名
*/
@DbField("xml_tag")
@Schema(description = "XML标签名")
private String xmlTag;
/**
* 标签类型
*/
@DbField("tag_type")
@Schema(description = "标签类型")
private String tagType;
/**
* 是否允许为空
*/
@DbField("is_null")
@Schema(description = "是否允许为空")
private String isNull;
/**
* 节点路径
*/
@DbField("node_path")
@Schema(description = "节点路径")
private String nodePath;
}

View File

@ -0,0 +1,106 @@
package com.example.demo.parser.model.vo;
import com.example.demo.common.domain.BaseVO;
import cn.zhxu.bs.bean.SearchBean;
import com.fhs.core.trans.vo.TransPojo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.experimental.SuperBuilder;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 文件记录视图对象
* 用于向前端返回文件记录数据
*
* @author system
* @version 1.0
*/
@Schema(description = "文件记录视图对象")
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@SearchBean(
tables = "file_record",
autoMapTo = "a"
)
public class FileRecordVO extends BaseVO implements TransPojo, Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 文件名
*/
@Schema(description = "文件名")
private String fileName;
/**
* 文件路径
*/
@Schema(description = "文件路径")
private String filePath;
/**
* 文件大小
*/
@Schema(description = "文件大小")
private Long fileSize;
/**
* 文件类型xml, txt
*/
@Schema(description = "文件类型")
private String fileType;
/**
* 文件状态uploaded, parsed, converted
*/
@Schema(description = "文件状态")
private String status;
/**
* 上传时间
*/
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description = "上传时间")
private Date uploadTime;
/**
* 处理时间
*/
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description = "处理时间")
private Date processTime;
/**
* 处理日志
*/
@Schema(description = "处理日志")
private String processLog;
/**
* 处理结果文件ID
*/
@Schema(description = "处理结果文件ID")
private Long resultFileId;
/**
* 关联的解析规则ID
*/
@Schema(description = "关联的解析规则ID")
private Long parseRuleId;
/**
* 关联的映射规则ID
*/
@Schema(description = "关联的映射规则ID")
private Long mapperRuleId;
}

View File

@ -0,0 +1,65 @@
package com.example.demo.parser.model.vo;
import com.example.demo.common.domain.BaseVO;
import cn.zhxu.bs.bean.SearchBean;
import com.fhs.core.trans.vo.TransPojo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.experimental.SuperBuilder;
import java.io.Serial;
import java.io.Serializable;
/**
* 映射规则视图对象
* 用于向前端返回映射规则数据
*
* @author system
* @version 1.0
*/
@Schema(description = "映射规则视图对象")
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@SearchBean(
tables = "mapper_rule",
autoMapTo = "a"
)
public class MapperRuleVO extends BaseVO implements TransPojo, Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 关联的解析规则ID
*/
@Schema(description = "关联的解析规则ID")
private String parseRuleId;
/**
* TXT文件中的键名
*/
@Schema(description = "TXT文件中的键名")
private String txtKey;
/**
* 转换模板
*/
@Schema(description = "转换模板")
private String template;
/**
* 父级键名
*/
@Schema(description = "父级键名")
private String parentKey;
/**
* 排序顺序
*/
@Schema(description = "排序顺序")
private Integer sortOrder;
}

View File

@ -0,0 +1,59 @@
package com.example.demo.parser.model.vo;
import com.example.demo.common.domain.BaseVO;
import cn.zhxu.bs.bean.SearchBean;
import com.fhs.core.trans.vo.TransPojo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.experimental.SuperBuilder;
import java.io.Serial;
import java.io.Serializable;
/**
* 解析规则视图对象
* 用于向前端返回解析规则数据
*
* @author system
* @version 1.0
*/
@Schema(description = "解析规则视图对象")
@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@SearchBean(
tables = "parse_rule",
autoMapTo = "a"
)
public class ParseRuleVO extends BaseVO implements TransPojo, Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* XML标签名
*/
@Schema(description = "XML标签名")
private String xmlTag;
/**
* 标签类型root, node, leaf
*/
@Schema(description = "标签类型")
private String tagType;
/**
* 是否允许为空0-不允许1-允许
*/
@Schema(description = "是否允许为空")
private String isNull;
/**
* 节点路径
*/
@Schema(description = "节点路径")
private String nodePath;
}

View File

@ -0,0 +1,90 @@
//package com.example.demo.parser.service;
//
//import com.example.demo.parser.model.bo.TemplateData;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.stereotype.Service;
//
//import java.io.StringWriter;
//import java.util.HashMap;
//import java.util.Map;
//
///**
// * 动态模板生成服务
// * 使用Jinja2模板引擎生成格式化的动态代码
// */
//@Slf4j
//@Service
//public class DynamicTemplateService {
//
// // 默认的缩进空格数
// private static final int DEFAULT_INDENT_SPACES = 4;
//
// /**
// * 生成动态代码
// * @param templateData 模板数据
// * @return 生成的格式化代码
// */
// public String generateDynamicCode(TemplateData templateData) {
// return generateDynamicCode(templateData, DEFAULT_INDENT_SPACES);
// }
//
// /**
// * 生成动态代码可自定义缩进空格数
// * @param templateData 模板数据
// * @param indentSpaces 缩进空格数
// * @return 生成的格式化代码
// */
// public String generateDynamicCode(TemplateData templateData, int indentSpaces) {
// try {
// // 创建Jinja2环境
// Jinja2Environment env = createJinja2Environment();
//
// // 准备模板上下文数据
// Map<String, Object> context = prepareTemplateContext(templateData, indentSpaces);
//
// // 加载模板
// Jinja2Template template = env.getTemplate("dynamic_template.j2");
//
// // 渲染模板
// StringWriter writer = new StringWriter();
// template.render(context, writer);
//
// return writer.toString();
//
// } catch (Exception e) {
// log.error("生成动态代码时发生错误", e);
// throw new RuntimeException("模板生成失败", e);
// }
// }
//
// /**
// * 创建Jinja2环境配置
// */
// private Jinja2Environment createJinja2Environment() {
// // 这里使用伪代码实际需要根据具体的Jinja2 Java实现来配置
// // 例如使用 com.hubspot.jinjava.Jinjava
// return new Jinja2Environment();
// }
//
// /**
// * 准备模板上下文数据
// */
// private Map<String, Object> prepareTemplateContext(TemplateData templateData, int indentSpaces) {
// Map<String, Object> context = new HashMap<>();
//
// context.put("globalComment", templateData.getGlobalComment());
// context.put("levelConfigs", templateData.getLevelConfigs());
// context.put("conditionMap", templateData.getConditionMap());
// context.put("indentSpaces", indentSpaces);
// context.put("indent", " ".repeat(indentSpaces));
//
// return context;
// }
//
// /**
// * 工具方法生成缩进字符串
// */
// public static String generateIndent(int level, int spaces) {
// return " ".repeat(level * spaces);
// }
//}

View File

@ -0,0 +1,19 @@
package com.example.demo.parser.service;
import com.example.demo.common.typography.BaseService;
import com.example.demo.parser.entity.FileRecordEntity;
import com.example.demo.parser.model.dto.FileRecordDTO;
import com.example.demo.parser.model.dto.FileRecordQueryDTO;
import com.example.demo.parser.model.vo.FileRecordVO;
/**
* 文件记录服务接口
* 提供文件记录的CRUD及文件上传下载等业务操作
*
* @author system
* @since 1.0.0
*/
public interface FileRecordService
extends BaseService<FileRecordEntity, FileRecordVO, FileRecordDTO, FileRecordQueryDTO> {
}

View File

@ -0,0 +1,18 @@
package com.example.demo.parser.service;
import com.example.demo.common.typography.BaseService;
import com.example.demo.parser.entity.MapperRuleEntity;
import com.example.demo.parser.model.dto.MapperRuleDTO;
import com.example.demo.parser.model.dto.MapperRuleQueryDTO;
import com.example.demo.parser.model.vo.MapperRuleVO;
/**
* 映射规则服务接口
* 提供映射规则的CRUD及其他业务操作
*
* @author system
* @since 1.0.0
*/
public interface MapperRuleService
extends BaseService<MapperRuleEntity, MapperRuleVO, MapperRuleDTO, MapperRuleQueryDTO> {
}

View File

@ -0,0 +1,18 @@
package com.example.demo.parser.service;
import com.example.demo.common.typography.BaseService;
import com.example.demo.parser.entity.ParseRuleEntity;
import com.example.demo.parser.model.dto.ParseRuleDTO;
import com.example.demo.parser.model.dto.ParseRuleQueryDTO;
import com.example.demo.parser.model.vo.ParseRuleVO;
/**
* 解析规则服务接口
* 提供解析规则的CRUD及其他业务操作
*
* @author system
* @since 1.0.0
*/
public interface ParseRuleService
extends BaseService<ParseRuleEntity, ParseRuleVO, ParseRuleDTO, ParseRuleQueryDTO> {
}

View File

@ -0,0 +1,37 @@
//package com.example.demo.parser.service.impl;
//
//import cn.zhxu.bs.BeanSearcher;
//import com.example.demo.common.typography.BaseServiceImpl;
//import com.example.demo.parser.entity.FileRecordEntity;
//import com.example.demo.parser.mapper.FileRecordMapper;
//import com.example.demo.parser.model.dto.FileRecordDTO;
//import com.example.demo.parser.model.dto.FileRecordQueryDTO;
//import com.example.demo.parser.model.vo.FileRecordVO;
//import com.example.demo.parser.service.FileRecordService;
//// import com.fhs.core.trans.TransService;
//import com.fhs.trans.service.impl.TransService;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.stereotype.Service;
//import org.springframework.transaction.annotation.Transactional;
//
///**
// * 文件记录服务实现类
// * 提供文件记录的CRUD和查询功能
// *
// * @author system
// * @version 1.0
// */
//@Slf4j
//@Service
//@Transactional(rollbackFor = Exception.class)
//public class FileRecordServiceImpl
// extends BaseServiceImpl<FileRecordEntity, FileRecordVO, FileRecordDTO, FileRecordQueryDTO, FileRecordMapper>
// implements FileRecordService {
//
// public FileRecordServiceImpl(
// BeanSearcher beanSearcher,
// TransService transService
// ) {
// super(log, FileRecordServiceImpl.class.getSimpleName(), FileRecordVO.class, beanSearcher, transService);
// }
//}

View File

@ -0,0 +1,52 @@
//package com.example.demo.parser.service.impl;
//
//import cn.zhxu.bs.BeanSearcher;
//import com.example.demo.common.exception.BusinessException;
//import com.example.demo.common.typography.BaseServiceImpl;
//import com.example.demo.parser.entity.FileRecordEntity;
//import com.example.demo.parser.entity.MapperRuleEntity;
//import com.example.demo.parser.mapper.FileRecordMapper;
//import com.example.demo.parser.mapper.MapperRuleMapper;
//import com.example.demo.parser.model.dto.FileRecordDTO;
//import com.example.demo.parser.model.dto.FileRecordQueryDTO;
//import com.example.demo.parser.model.dto.MapperRuleDTO;
//import com.example.demo.parser.model.dto.MapperRuleQueryDTO;
//import com.example.demo.parser.model.vo.FileRecordVO;
//import com.example.demo.parser.model.vo.MapperRuleVO;
//import com.example.demo.parser.service.MapperRuleService;
//import com.example.demo.parser.service.ParseRuleService;
//// import com.fhs.core.trans.TransService;
//import com.fhs.trans.service.impl.TransService;
//import com.mybatisflex.core.paginate.Page;
//import com.mybatisflex.core.query.QueryWrapper;
//import com.mybatisflex.spring.service.impl.ServiceImpl;
//import lombok.RequiredArgsConstructor;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.stereotype.Service;
//import org.springframework.transaction.annotation.Transactional;
//
//import java.util.List;
//
//import static com.example.demo.parser.entity.table.MapperRuleEntityTableDef.MAPPER_RULE_ENTITY;
//
///**
// * 映射规则服务实现类
// * 提供映射规则的CRUD和查询功能
// *
// * @author system
// * @version 1.0
// */
//@Slf4j
//@Service
//@Transactional(rollbackFor = Exception.class)
//public class MapperRuleServiceImpl
// extends BaseServiceImpl<MapperRuleEntity, MapperRuleVO, MapperRuleDTO, MapperRuleQueryDTO, MapperRuleMapper> {
//
// public MapperRuleServiceImpl(
// BeanSearcher beanSearcher,
// TransService transService
// ) {
// super(log, MapperRuleServiceImpl.class.getSimpleName(), MapperRuleVO.class, beanSearcher, transService);
// }
//
//}

View File

@ -0,0 +1,51 @@
//package com.example.demo.parser.service.impl;
//
//import cn.zhxu.bs.BeanSearcher;
//import com.example.demo.common.exception.BusinessException;
//import com.example.demo.common.typography.BaseServiceImpl;
//import com.example.demo.parser.entity.FileRecordEntity;
//import com.example.demo.parser.entity.ParseRuleEntity;
//import com.example.demo.parser.mapper.FileRecordMapper;
//import com.example.demo.parser.mapper.ParseRuleMapper;
//import com.example.demo.parser.model.dto.FileRecordDTO;
//import com.example.demo.parser.model.dto.FileRecordQueryDTO;
//import com.example.demo.parser.model.dto.ParseRuleDTO;
//import com.example.demo.parser.model.dto.ParseRuleQueryDTO;
//import com.example.demo.parser.model.vo.FileRecordVO;
//import com.example.demo.parser.model.vo.ParseRuleVO;
//import com.example.demo.parser.service.ParseRuleService;
//// import com.fhs.core.trans.TransService;
//import com.fhs.trans.service.impl.TransService;
//import com.mybatisflex.core.paginate.Page;
//import com.mybatisflex.core.query.QueryWrapper;
//import com.mybatisflex.spring.service.impl.ServiceImpl;
//import lombok.RequiredArgsConstructor;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.stereotype.Service;
//import org.springframework.transaction.annotation.Transactional;
//
//import java.util.List;
//
//import static com.example.demo.parser.entity.table.ParseRuleEntityTableDef.PARSE_RULE_ENTITY;
//
///**
// * 解析规则服务实现类
// * 提供解析规则的CRUD和查询功能
// *
// * @author system
// * @version 1.0
// */
//@Slf4j
//@Service
//@Transactional(rollbackFor = Exception.class)
//public class ParseRuleServiceImpl
// extends BaseServiceImpl<ParseRuleEntity, ParseRuleVO, ParseRuleDTO, ParseRuleQueryDTO, ParseRuleMapper> {
//
// public ParseRuleServiceImpl(
// BeanSearcher beanSearcher,
// TransService transService
// ) {
// super(log, ParseRuleServiceImpl.class.getSimpleName(), ParseRuleVO.class, beanSearcher, transService);
// }
//
//}

View File

@ -0,0 +1,22 @@
# Spring Boot 应用配置
spring:
# H2缓存数据库配置
datasource:
h2:
url: jdbc:h2:mem:cacheDb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
driver-class-name: org.h2.Driver
username: sa
password:
hikari:
maximum-pool-size: 5
connection-timeout: 30000
# H2控制台配置
h2:
console:
enabled: true
path: /h2-console
settings:
web-allow-others: true
# 缓存数据库初始化配置由自定义配置类H2DataSourceConfig管理

View File

@ -0,0 +1,38 @@
# Bean-Searcher 配置
bean-searcher:
sql:
default-mapping:
#表名和字段名是否驼峰转小写下划线since v3.7.0
underline-case: true
#表名和字段名是否大写
upper-case: true
redundant-suffixes:
- VO
- DTO
# MyBatisFlex公共配置
# https://mybatis-flex.com/zh/base/configuration.html
mybatis-flex:
configuration:
## 以下为mybatis原生配置 https://mybatis.org/mybatis-3/zh/configuration.html
# 自动驼峰命名规则camel case映射
map_underscore_to_camel_case: true
# MyBatis 自动映射策略
# NONE不启用 PARTIAL只对非嵌套 resultMap 自动映射 FULL对所有 resultMap 自动映射
auto_mapping_behavior: FULL
# MyBatis 自动映射时未知列或未知属性处理策
# NONE不做处理 WARNING打印相关警告 FAILING抛出异常和详细信息
auto_mapping_unknown_column_behavior: NONE
# 更详细的日志输出 会有性能损耗 org.apache.ibatis.logging.stdout.StdOutImpl
# 关闭日志记录 org.apache.ibatis.logging.nologging.NoLoggingImpl
# 默认日志输出 org.apache.ibatis.logging.slf4j.Slf4jImpl
log_impl: org.apache.ibatis.logging.stdout.StdOutImpl
# logImpl: org.apache.ibatis.logging.nologging.NoLoggingImpl
cacheEnabled: true
global-config:
# 是否控制台打印 MyBatis-Flex 的 LOGO 及版本号
print-banner: true
# 全局的 ID 生成策略配置:雪花算法
key-config:
key-type: Generator
value: snowFlakeId

View File

@ -0,0 +1,17 @@
# 自定义配置
xml-parser:
# 文件存储配置
file:
upload-dir: ${user.dir}/upload
temp-dir: ${user.dir}/temp
# 解析配置
parser:
default-encoding: UTF-8
validate-xml: true
# 转换配置
converter:
default-encoding: UTF-8
indent-size: 4

View File

View File

@ -0,0 +1,54 @@
# ===== SpringDoc配置 =====#
springdoc:
swagger-ui:
# 自定义的文档界面访问路径。默认访问路径是/swagger-ui.html
path: /springdoc/docs.html
# 字符串类型一共三个值来控制操作和标记的默认展开设置。它可以是“list”仅展开标记、“full”展开标记和操作或“none”不展开任何内容
docExpansion: none
# 布尔值。控制“试用”请求的请求持续时间(毫秒)的显示。
displayRequestDuration: true
# 布尔值。控制供应商扩展x-)字段和操作、参数和架构值的显示。
showExtensions: true
# 布尔值。控制参数的扩展名pattern、maxLength、minLength、maximum、minminimum字段和值的显示。
showCommonExtensions: true
# 布尔值。禁用swagger用户界面默认petstore url。从v1.4.1开始提供)。
disable-swagger-default-url: true
api-docs:
# enabled the /v3/api-docs endpoint
enabled: true
# 自定义的文档api元数据访问路径。默认访问路径是/v3/api-docs
# path: /springdoc/api-docs
path: /v3/api-docs
# 布尔值。在@Schema名称name、标题title和说明description三个属性上启用属性解析程序。
resolve-schema-properties: true
paths-to-match:
- '/parser/**'
# 布尔值。实现OpenApi规范的打印。
writer-with-default-pretty-printer: true
show-actuator: true
default-flat-param-object: true
group-configs:
- group: 'parser'
pathsToMatch:
- '/parser/**'
packagesToScan:
- com.example.demo.parser
# Knife4j OpenAPI3 文档配置
knife4j:
#是否启用增强设置
enable: true
#开启生产环境屏蔽
production: false
#开启跨域
cors: false
#是否启用登录认证
basic:
enable: true
username: admin
password: 123456
setting: # 前端UI的个性化配置属性
language: zh_cn # 显示语言中文
enable-version: true
enable-swagger-models: true # 是否显示界面中SwaggerModel功能
swagger-model-name: SwaggerModel2 # 重命名SwaggerModel名称,默认
enable-document-manage: true # 是否显示界面中"文档管理"功能

View File

@ -0,0 +1,15 @@
# Spring Boot 应用配置
spring:
# 数据库配置 - SQLite主数据库
datasource:
sqlite:
# url: jdbc:sqlite:${user.dir}/data/xml-parser.db
url: jdbc:sqlite:parser.db
driver-class-name: org.sqlite.JDBC
username: sa
password:
hikari:
maximum-pool-size: 5
connection-timeout: 30000
# SQLite数据库初始化配置由自定义配置类SqliteDataSourceConfig管理

View File

@ -0,0 +1,27 @@
# 服务器配置
server:
port: 8080
servlet:
context-path: /parser
# 通用 log 输出配置
logging:
config: classpath:logback-spring.xml
# Spring Boot 应用配置
spring:
# 启用JAVA21虚拟线程
threads:
virtual:
enabled: true
# 文件上传配置
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
profiles:
active: dev
group:
dev: orm,h2,sqlite,parser,rule,springdoc
prod: orm,h2,sqlite,parser,rule

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<作战部队武器装备>
<装备类型>武装直升机</装备类型>
<武器装备型号>Z-10</武器装备型号>
<武器装备名称>直-10攻击直升机</武器装备名称>
<武器装备数量>18</武器装备数量>
</作战部队武器装备>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<作战部队武器装备>
<装备类型>自行火炮</装备类型>
<武器装备型号>PLZ-05</武器装备型号>
<武器装备名称>05式自行榴弹炮</武器装备名称>
<武器装备数量>36</武器装备数量>
</作战部队武器装备>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<作战部队武器装备>
<装备类型>战斗机</装备类型>
<武器装备型号>J-20</武器装备型号>
<武器装备名称>歼-20隐形战斗机</武器装备名称>
<武器装备数量>24</武器装备数量>
</作战部队武器装备>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<作战部队武器装备>
<装备类型>主战坦克</装备类型>
<武器装备型号>99A</武器装备型号>
<武器装备名称>99A式主战坦克</武器装备名称>
<武器装备数量>50</武器装备数量>
</作战部队武器装备>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<作战部队武器装备>
<装备类型>驱逐舰</装备类型>
<武器装备型号>055</武器装备型号>
<武器装备名称>055型导弹驱逐舰</武器装备名称>
<武器装备数量>2</武器装备数量>
</作战部队武器装备>

View File

@ -0,0 +1,78 @@
{
"conditionMap": {},
"initialIndent": "",
"levelConfigs": [
{
"levelName": "platform",
"subLevels": [
{
"levelName": "aux_data",
"subLevels": [],
"valueConfigs": [
{
"values": [
{
"combined": false,
"value": "string batchnumber = \"作战部队武器装备.武器装备数量\""
}
]
}
],
"values": []
}
],
"valueConfigs": [
{
"valueName": "side",
"values": [
{
"combined": false,
"value": "red"
}
]
},
{
"valueName": "icon",
"values": [
{
"combined": false,
"value": "weasel"
}
]
},
{
"valueName": "commander",
"values": [
{
"combined": false,
"value": "north_cap_lead"
}
]
},
{
"valueName": "position",
"values": [
{
"combined": false,
"value": "36:38:08:13n 109:06:46:76e altitude 35000.0 ft msl"
}
]
},
{
"valueName": "heading",
"values": [
{
"combined": false,
"unit": "deg",
"value": 307
}
]
}
],
"values": [
"作战部队武器装备.武器装备名称",
"作战部队武器装备.武器装备型号"
]
}
]
}

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<单个空中平台任务数据>
<机型>Z-19</机型>
<机型名称>直-19侦察武装直升机</机型名称>
<架数>6</架数>
<塔康工作频道>15</塔康工作频道>
<主挂载武器>AKD-10空地导弹</主挂载武器>
<次挂载武器>HY-90航空火箭弹</次挂载武器>
<平台识别码>Z19_Attack01</平台识别码>
<平台识别号>1901</平台识别号>
</单个空中平台任务数据>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<单个空中平台任务数据>
<机型>J-16</机型>
<机型名称>歼-16多用途战斗机</机型名称>
<架数>4</架数>
<塔康工作频道>12</塔康工作频道>
<主挂载武器>PL-15中距空空导弹</主挂载武器>
<次挂载武器>PL-10近距格斗导弹</次挂载武器>
<平台识别码>J16_Red01</平台识别码>
<平台识别号>7801</平台识别号>
</单个空中平台任务数据>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<单个空中平台任务数据>
<机型>KJ-500</机型>
<机型名称>空警-500预警机</机型名称>
<架数>2</架数>
<塔康工作频道>05</塔康工作频道>
<主挂载武器></主挂载武器>
<次挂载武器></次挂载武器>
<平台识别码>KJ500_Control01</平台识别码>
<平台识别号>5001</平台识别号>
</单个空中平台任务数据>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<单个空中平台任务数据>
<机型>Y-20</机型>
<机型名称>运-20大型运输机</机型名称>
<架数>3</架数>
<塔康工作频道>08</塔康工作频道>
<主挂载武器></主挂载武器>
<次挂载武器></次挂载武器>
<平台识别码>Y20_Blue01</平台识别码>
<平台识别号>2101</平台识别号>
</单个空中平台任务数据>

View File

@ -0,0 +1,115 @@
{
"conditionMap": {},
"levelConfigs": [
{
"levelName": "platform",
"enableLoop": true,
"loopCount": "单个空中平台任务数据.架数",
"subLevels": [
{
"levelName": "comm",
"subLevels": [],
"valueConfigs": [
{
"values": [
{
"combined": false,
"value": "string tacanWorkChannel = \"单个空中平台任务数据.塔康工作频道\" # 塔康工作频道"
}
]
}
],
"values": [
"xxx",
"默认通信链"
]
},
{
"levelName": "aux_data",
"subLevels": [],
"valueConfigs": [
{
"values": [
{
"combined": false,
"value": "string platformIdCardCode = \"单个空中平台任务数据.平台识别码\" # 平台识别码"
}
]
},
{
"values": [
{
"combined": false,
"value": "string platformIdCardNumber = \"单个空中平台任务数据.平台识别号\" # 平台识别号"
}
]
}
],
"values": []
},
{
"levelName": "weapon",
"subLevels": [],
"valueConfigs": [
{
"valueName": "quantity",
"values": [
{
"combined": false,
"value": "2"
}
]
}
],
"values": [
"单个空中平台任务数据.主挂载武器",
"单个空中平台任务数据.挂载类型"
]
},
{
"levelName": "weapon",
"subLevels": [],
"valueConfigs": [
{
"valueName": "quantity",
"values": [
{
"combined": false,
"value": "3"
}
]
}
],
"values": [
"单个空中平台任务数据.次挂载武器",
"单个空中平台任务数据.挂载类型"
]
}
],
"valueConfigs": [
{
"valueName": "side",
"values": [
{
"combined": false,
"value": "red"
}
]
},
{
"valueName": "icon",
"values": [
{
"combined": false,
"value": "weasel"
}
]
}
],
"values": [
"单个空中平台任务数据.平台名称",
"单个空中平台任务数据.机型"
]
}
]
}

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<任务航线>
<航线点型号>WP003</航线点型号>
<航线点名称>目标区域</航线点名称>
<航线点坐标>40.0042,116.6074</航线点坐标>
<航线点类型>目标点</航线点类型>
<准时到达时间>08:45:00</准时到达时间>
<转弯方式>盘旋</转弯方式>
<转向方式>保持</转向方式>
<坡度>15</坡度>
<速度>350</速度>
<高度>2500</高度>
<高度属性>相对高度</高度属性>
<升将率>0</升将率>
</任务航线>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<任务航线>
<航线点型号>WP002</航线点型号>
<航线点名称>导航点A</航线点名称>
<航线点坐标>39.9242,116.5074</航线点坐标>
<航线点类型>航路点</航线点类型>
<准时到达时间>08:15:30</准时到达时间>
<转弯方式>飞越转弯</转弯方式>
<转向方式>右转</转向方式>
<坡度>30</坡度>
<速度>450</速度>
<高度>3000</高度>
<高度属性>绝对高度</高度属性>
<升降率>8</升降率>
</任务航线>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<任务航线>
<航线点型号>WP005</航线点型号>
<航线点名称>降落点</航线点名称>
<航线点坐标>39.9042,116.4074</航线点坐标>
<航线点类型>降落点</航线点类型>
<准时到达时间>09:45:00</准时到达时间>
<转弯方式>直接进近</转弯方式>
<转向方式>保持</转向方式>
<坡度>10</坡度>
<速度>250 m/s</速度>
<高度>500</高度>
<高度属性>相对高度</高度属性>
<升将率>-5</升将率>
</任务航线>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<任务航线>
<航线点型号>WP001</航线点型号>
<航线点名称>起飞点</航线点名称>
<航线点坐标>39.9042,116.4074</航线点坐标>
<航线点类型>起飞点</航线点类型>
<准时到达时间>08:00:00</准时到达时间>
<转弯方式>直接转弯</转弯方式>
<转向方式>左转</转向方式>
<坡度>25</坡度>
<速度>300</速度>
<高度>1000</高度>
<高度属性>相对高度</高度属性>
<升将率>5</升将率>
</任务航线>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<任务航线>
<航线点型号>WP004</航线点型号>
<航线点名称>返航点</航线点名称>
<航线点坐标>39.9542,116.4574</航线点坐标>
<航线点类型>返航点</航线点类型>
<准时到达时间>09:30:00</准时到达时间>
<转弯方式>标准转弯</转弯方式>
<转向方式>左转</转向方式>
<坡度>20</坡度>
<速度>400</速度>
<高度>2000</高度>
<高度属性>绝对高度</高度属性>
<升将率>-3</升将率>
</任务航线>

View File

@ -0,0 +1,153 @@
{
"conditionMap": {},
"levelConfigs": [
{
"levelName": "platform",
"subLevels": [
{
"levelName": "route",
"subLevels": [
{
"comment": "航线点型号为 任务航线.航线点型号 ,名称为 任务航线.航线点名称",
"levelName": "waypoint",
"subLevels": [],
"valueConfigs": [
{
"comment": "航线点坐标",
"valueName": "position",
"values": [
{
"combined": false,
"value": "39.9242N"
},
{
"combined": false,
"value": "116.5074E"
}
]
},
{
"comment": "航线点类型",
"valueName": "waypoint_type",
"values": [
{
"combined": false,
"value": "任务航线.航线点类型"
}
]
},
{
"comment": "准时到达时间",
"valueName": "eta",
"values": [
{
"combined": false,
"value": "任务航线.准时到达时间"
}
]
},
{
"comment": "转弯方式",
"valueName": "turn_method",
"values": [
{
"combined": false,
"value": "任务航线.转弯方式"
}
]
},
{
"comment": "转向方式",
"valueName": "turn_direction",
"values": [
{
"combined": false,
"value": "任务航线.转向方式"
}
]
},
{
"comment": "坡度",
"valueName": "bank_angle",
"values": [
{
"combined": false,
"unit": "deg",
"value": "任务航线.坡度"
}
]
},
{
"comment": "速度",
"valueName": "speed",
"values": [
{
"combined": false,
"unit": "km/h",
"value": "任务航线.速度"
}
]
},
{
"comment": "高度",
"valueName": "altitude",
"values": [
{
"combined": false,
"unit": "m",
"value": "任务航线.高度"
}
]
},
{
"comment": "高度属性",
"valueName": "altitude_type",
"values": [
{
"combined": false,
"value": "任务航线.高度属性"
}
]
},
{
"comment": "升降率",
"valueName": "climb_rate",
"values": [
{
"combined": false,
"unit": "m/s",
"value": "任务航线.升降率"
}
]
}
],
"values": [
"任务航线.航线点型号",
"任务航线.航线点名称"
]
}
],
"valueConfigs": [],
"values": []
}
],
"valueConfigs": [
{
"comment": "初始航向为0度",
"valueName": "heading",
"values": [
{
"combined": false,
"unit": "deg",
"value": 0
}
]
}
],
"values": [
"mission_plane",
"AIRCRAFT"
]
}
]
}

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<空域数据>
<空域ID>A001</空域ID>
<空域名称>训练空域Alpha</空域名称>
<协调措施所属的大类型>军事训练</协调措施所属的大类型>
<空域的具体协调措施类型>实弹射击</空域的具体协调措施类型>
<空域管控状态>激活</空域管控状态>
<空域生效时间段>
<日期时间使用模式>周期执行</日期时间使用模式>
<开始时间>2024-06-01T08:00:00</开始时间>
<结束时间>2024-06-01T12:00:00</结束时间>
<结束时间标识符>绝对时间</结束时间标识符>
<间隔频率>每日</间隔频率>
<间隔结束时间>2024-06-30T12:00:00</间隔结束时间>
<相对时开始时间>P0D</相对时开始时间>
<相对时结束数据>P4H</相对时结束数据>
<时间类型>UTC</时间类型>
</空域生效时间段>
<代表空域相关的控制点>
<控制点类型>中心点</控制点类型>
<控制点名称>训练区中心</控制点名称>
<控制点ID>CP001</控制点ID>
<控制点的坐标位置经度>116.4074</控制点的坐标位置经度>
<控制点的坐标位置纬度>39.9042</控制点的坐标位置纬度>
<控制点的顶高>10000</控制点的顶高>
<控制点的底高>0</控制点的底高>
<是否隐藏控制点>false</是否隐藏控制点>
</代表空域相关的控制点>
<空域几何数据>
<形状类型>圆形</形状类型>
<几何数据信息>
<经度>116.4074</经度>
<纬度>39.9042</纬度>
</几何数据信息>
<数据点数目>1</数据点数目>
</空域几何数据>
<空域管控状态>限制使用</空域管控状态>
</空域数据>

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<空域数据>
<空域ID>A003</空域ID>
<空域名称>民航走廊Gamma</空域名称>
<协调措施所属的大类型>民航运输</协调措施所属的大类型>
<空域的具体协调措施类型>航线管制</空域的具体协调措施类型>
<空域管控状态>部分限制</空域管控状态>
<空域生效时间段>
<日期时间使用模式>定时执行</日期时间使用模式>
<开始时间>2024-06-01T06:00:00</开始时间>
<结束时间>2024-06-01T22:00:00</结束时间>
<结束时间标识符>绝对时间</结束时间标识符>
<间隔频率>每日</间隔频率>
<间隔结束时间>2024-12-31T22:00:00</间隔结束时间>
<相对时开始时间>P0D</相对时开始时间>
<相对时结束数据>P16H</相对时结束数据>
<时间类型>LOCAL</时间类型>
</空域生效时间段>
<代表空域相关的控制点>
<控制点类型>入口点</控制点类型>
<控制点名称>走廊入口</控制点名称>
<控制点ID>CP003</控制点ID>
<控制点的坐标位置经度>116.5000</控制点的坐标位置经度>
<控制点的坐标位置纬度>40.0000</控制点的坐标位置纬度>
<控制点的顶高>12000</控制点的顶高>
<控制点的底高>8000</控制点的底高>
<是否隐藏控制点>true</是否隐藏控制点>
</代表空域相关的控制点>
<空域几何数据>
<形状类型>走廊</形状类型>
<几何数据信息>
<经度>116.5000</经度>
<纬度>40.0000</纬度>
</几何数据信息>
<数据点数目>2</数据点数目>
</空域几何数据>
<空域管控状态>管制运行</空域管控状态>
</空域数据>

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<空域数据>
<空域ID>A002</空域ID>
<空域名称>禁飞区Beta</空域名称>
<协调措施所属的大类型>安全管制</协调措施所属的大类型>
<空域的具体协调措施类型>永久禁飞</空域的具体协调措施类型>
<空域管控状态>持续生效</空域管控状态>
<空域生效时间段>
<日期时间使用模式>永久生效</日期时间使用模式>
<开始时间>2020-01-01T00:00:00</开始时间>
<结束时间>2099-12-31T23:59:59</结束时间>
<结束时间标识符>绝对时间</结束时间标识符>
<间隔频率></间隔频率>
<间隔结束时间>2099-12-31T23:59:59</间隔结束时间>
<相对时开始时间>P0D</相对时开始时间>
<相对时结束数据>P0D</相对时结束数据>
<时间类型>UTC</时间类型>
</空域生效时间段>
<代表空域相关的控制点>
<控制点类型>边界点</控制点类型>
<控制点名称>禁飞区西南角</控制点名称>
<控制点ID>CP002</控制点ID>
<控制点的坐标位置经度>116.3000</控制点的坐标位置经度>
<控制点的坐标位置纬度>39.8000</控制点的坐标位置纬度>
<控制点的顶高>18000</控制点的顶高>
<控制点的底高>0</控制点的底高>
<是否隐藏控制点>false</是否隐藏控制点>
</代表空域相关的控制点>
<空域几何数据>
<形状类型>多边形</形状类型>
<几何数据信息>
<经度>116.3000</经度>
<纬度>39.8000</纬度>
</几何数据信息>
<数据点数目>5</数据点数目>
</空域几何数据>
<空域管控状态>完全禁止</空域管控状态>
</空域数据>

View File

@ -0,0 +1,275 @@
{
"conditionMap": {},
"levelConfigs": [
{
"levelName": "platform",
"subLevels": [
{
"comment": "空域生效时间配置",
"levelName": "time_window",
"subLevels": [],
"valueConfigs": [
{
"comment": "日期时间使用模式",
"valueName": "mode",
"values": [
{
"combined": false,
"value": "空域数据.空域生效时间段.日期时间使用模式"
}
]
},
{
"comment": "开始时间",
"valueName": "start",
"values": [
{
"combined": false,
"value": "空域数据.空域生效时间段.开始时间"
}
]
},
{
"comment": "结束时间",
"valueName": "end",
"values": [
{
"combined": false,
"value": "空域数据.空域生效时间段.结束时间"
}
]
},
{
"comment": "结束时间标识符",
"valueName": "end_type",
"values": [
{
"combined": false,
"value": "空域数据.空域生效时间段.结束时间标识符"
}
]
},
{
"comment": "间隔频率",
"valueName": "interval",
"values": [
{
"combined": false,
"value": "空域数据.空域生效时间段.间隔频率"
}
]
},
{
"comment": "间隔结束时间",
"valueName": "interval_end",
"values": [
{
"combined": false,
"value": "空域数据.空域生效时间段.间隔结束时间"
}
]
},
{
"comment": "相对时开始时间",
"valueName": "relative_start",
"values": [
{
"combined": false,
"value": "空域数据.空域生效时间段.相对时开始时间"
}
]
},
{
"comment": "相对时结束数据",
"valueName": "relative_end",
"values": [
{
"combined": false,
"value": "空域数据.空域生效时间段.相对时结束数据"
}
]
},
{
"comment": "时间类型",
"valueName": "time_format",
"values": [
{
"combined": false,
"value": "空域数据.空域生效时间段.时间类型"
}
]
}
],
"values": []
},
{
"comment": "控制点ID和名称",
"levelName": "control_point",
"subLevels": [],
"valueConfigs": [
{
"comment": "控制点类型",
"valueName": "type",
"values": [
{
"combined": false,
"value": "空域数据.代表空域相关的控制点.控制点类型"
}
]
},
{
"comment": "控制点坐标(纬度,经度)",
"valueName": "position",
"values": [
{
"combined": false,
"value": "空域数据.空域几何数据.几何数据信息.纬度N 空域数据.空域几何数据.几何数据信息.经度E"
}
]
},
{
"comment": "控制点顶高",
"valueName": "top_altitude",
"values": [
{
"combined": false,
"unit": "m",
"value": "空域数据.代表空域相关的控制点.控制点的顶高"
}
]
},
{
"comment": "控制点底高",
"valueName": "bottom_altitude",
"values": [
{
"combined": false,
"unit": "m",
"value": "空域数据.代表空域相关的控制点.控制点的底高"
}
]
},
{
"comment": "是否隐藏控制点false表示显示",
"valueName": "visible",
"values": [
{
"combined": false,
"value": "空域数据.代表空域相关的控制点.是否隐藏控制点"
}
]
}
],
"values": [
"空域数据.代表空域相关的控制点.控制点ID",
"空域数据.代表空域相关的控制点.控制点名称"
]
},
{
"comment": "空域几何形状配置",
"levelName": "geometry",
"subLevels": [],
"valueConfigs": [
{
"comment": "形状类型",
"valueName": "shape",
"values": [
{
"combined": false,
"value": "空域数据.空域几何数据.形状类型"
}
]
},
{
"comment": "圆心坐标",
"valueName": "center",
"values": [
{
"combined": false,
"value": "空域数据.代表空域相关的控制点.控制点的坐标位置纬度N 空域数据.代表空域相关的控制点.控制点的坐标位置经度E"
}
]
},
{
"comment": "数据点数目",
"valueName": "point_count",
"values": [
{
"combined": false,
"value": "空域数据.空域几何数据.数据点数目"
}
]
}
],
"values": []
}
],
"valueConfigs": [
{
"comment": "空域ID",
"valueName": "id",
"values": [
{
"combined": false,
"value": "空域数据.空域ID"
}
]
},
{
"comment": "空域名称",
"valueName": "name",
"values": [
{
"combined": false,
"value": "空域数据.空域名称"
}
]
},
{
"comment": "协调措施所属的大类型",
"valueName": "category",
"values": [
{
"combined": false,
"value": "空域数据.协调措施所属的大类型"
}
]
},
{
"comment": "空域的具体协调措施类型",
"valueName": "subcategory",
"values": [
{
"combined": false,
"value": "空域数据.空域的具体协调措施类型"
}
]
},
{
"comment": "空域管控状态",
"valueName": "status",
"values": [
{
"combined": false,
"value": "空域数据.空域管控状态"
}
]
},
{
"comment": "空域管控状态",
"valueName": "control_status",
"values": [
{
"combined": false,
"value": "limit"
}
]
}
],
"values": [
"airspace",
"AERIAL_REGION"
]
}
]
}

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<指令>
<描述>
<!-- label = "描述信息" -->
<!-- isNull = "true" -->
<!-- node = "XX_01" -->
<!-- 时间格式 2025-9-26_10:23:11 -->
<!--
-->
<空中平台任务数据>1</空中平台任务数据>
<任务K点>2</任务K点>
<单个空中平台></单个空中平台>
<任务航线></任务航线>
<空域数据></空域数据>
<空中指挥监视></空中指挥监视>
<所辖任务></所辖任务>
<空中打击></空中打击>
<空中支援></空中支援>
<任务包指挥></任务包指挥>
<电子战></电子战>
<空中巡逻></空中巡逻>
<空中加油></空中加油>
</描述>
<详细>
</详细>
<ACO>
</ACO>
<SpinSL>
</SpinSL>
</指令>

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<employees>
<employee id="101">
<name>张三</name>
<department>技术部</department>
<salary>15000</salary>
<skills>
<skill>Java</skill>
<skill>Spring</skill>
<skill>MySQL</skill>
</skills>
</employee>
<employee id="102">
<name>李四</name>
<department>市场部</department>
<salary>12000</salary>
<skills>
<skill>市场营销</skill>
<skill>客户关系</skill>
</skills>
</employee>
<employee id="103">
<name>王五</name>
<department>技术部</department>
<salary>18000</salary>
<skills>
<skill>Python</skill>
<skill>机器学习</skill>
<skill>Docker</skill>
</skills>
</employee>
</employees>

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