核心SDK提交

This commit is contained in:
ZZX9599
2025-09-08 17:06:22 +08:00
commit 7964ce1569
57 changed files with 2060 additions and 0 deletions

View File

@ -0,0 +1,23 @@
package com.yjdsj.common.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class CustomCorsFilter {
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}

View File

@ -0,0 +1,15 @@
package com.yjdsj.common.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Data
@Component
public class ServerConfig {
@Value("${server.port}")
private int port;
@Value("${server.host}")
private String host;
}

View File

@ -0,0 +1,34 @@
package com.yjdsj.common.config;
import io.swagger.annotations.ApiOperation;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
@Configuration
@EnableSwagger2WebMvc
public class SwaggerConfig {
@Bean
public Docket webApiConfig() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("对接API")
.description("对接相关接口")
.version("1.0")
.build();
}
}

View File

@ -0,0 +1,18 @@
package com.yjdsj.common.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*") // 允许所有来源
.allowedMethods("*") // 允许所有方法GET, POST, PUT, DELETE 等)
.allowedHeaders("*") // 允许所有头
.allowCredentials(true) // 允许发送凭证cookies 等)
.maxAge(3600); // 预检请求的缓存时间(单位:秒)
}
}

View File

@ -0,0 +1,33 @@
package com.yjdsj.common.controller;
import com.yjdsj.common.map.SourceMap;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@Api(tags = "资源管理")
@Slf4j
@RestController
@RequestMapping("/sourceMap")
public class SourceMapController {
@Resource
private SourceMap sourceMap;
// 添加资源映射关系
@PostMapping("/add")
@ApiOperation(value = "添加资源映射关系")
public Object addSourceMapping(@RequestParam String filePath) {
return sourceMap.addSourceMapping(filePath);
}
// 移除资源映射关系
@DeleteMapping("/remove")
@ApiOperation(value = "移除资源映射关系")
public void removeSourceMapping(@RequestParam String filePath) {
sourceMap.removeSourceMapping(filePath);
}
}

View File

@ -0,0 +1,38 @@
package com.yjdsj.common.ds;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.annotation.Resource;
import javax.sql.DataSource;
@Configuration
public class DataSourceConfig {
@Resource
private DynamicDataSourceManager dynamicDataSourceManager;
@Bean(name = "dynamicDataSource")
public DataSource dynamicDataSource() {
DynamicRoutingDataSource dynamicRoutingDataSource = new DynamicRoutingDataSource(dynamicDataSourceManager);
return dynamicRoutingDataSource;
}
@Bean
public SqlSessionFactory sqlSessionFactory(@Autowired DataSource dynamicDataSource) throws Exception {
SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
sessionFactoryBean.setDataSource(dynamicDataSource);
sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*.xml"));
return sessionFactoryBean.getObject();
}
@Bean
public SqlSessionTemplate sqlSessionTemplate(@Autowired SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}

View File

@ -0,0 +1,18 @@
package com.yjdsj.common.ds;
public class DynamicDataSourceContextHolder {
private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
public static void setDataSourceKey(String key) {
CONTEXT_HOLDER.set(key);
}
public static String getDataSourceKey() {
return CONTEXT_HOLDER.get();
}
public static void clearDataSourceKey() {
CONTEXT_HOLDER.remove();
}
}

View File

@ -0,0 +1,46 @@
package com.yjdsj.common.ds;
import com.yjdsj.common.map.SourceMap;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
@Component
public class DynamicDataSourceManager {
private final Map<String, DataSource> dataSourceCache = new HashMap<>();
private final SourceMap sourceMap;
@Autowired
public DynamicDataSourceManager(SourceMap sourceMap) {
this.sourceMap = sourceMap;
}
public DataSource getDataSource(String dbName) {
// 检查缓存中是否已有数据源
if (dataSourceCache.containsKey(dbName)) {
return dataSourceCache.get(dbName);
} else {
// 动态创建数据源
String dbPath = sourceMap.getSourceMapping(dbName);
if (dbPath != null) {
DataSource dataSource = createDataSource(dbPath);
dataSourceCache.put(dbName, dataSource);
return dataSource;
} else {
throw new IllegalArgumentException("Data source not found for name: " + dbName);
}
}
}
private DataSource createDataSource(String dbPath) {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl("jdbc:sqlite:" + dbPath);
dataSource.setDriverClassName("org.sqlite.JDBC");
return dataSource;
}
}

View File

@ -0,0 +1,28 @@
package com.yjdsj.common.ds;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.sql.DataSource;
import java.util.HashMap;
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
private final DynamicDataSourceManager dataSourceManager;
public DynamicRoutingDataSource(DynamicDataSourceManager dataSourceManager) {
this.dataSourceManager = dataSourceManager;
this.setTargetDataSources(new HashMap<>());
this.afterPropertiesSet();
}
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceContextHolder.getDataSourceKey();
}
@Override
protected DataSource determineTargetDataSource() {
String dataSourceKey = (String) determineCurrentLookupKey();
return dataSourceManager.getDataSource(dataSourceKey);
}
}

View File

@ -0,0 +1,61 @@
package com.yjdsj.common.generator;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import java.util.Collections;
/**
*
* @date 2024/6/26 14:42
*/
public class CodeGenerator {
private static String databasePath = "D:\\DJ\\source\\广西提供poi.poi"; // SQLite 数据库文件路径
private static String author = "周志雄";
public static void main(String[] args) {
Generation(databasePath, "tbl_pois"); // 生成指定表的代码,这里以 "users" 表为例
}
public static void Generation(String databasePath, String... tableName) {
FastAutoGenerator.create("jdbc:sqlite:" + databasePath, "", "")
.globalConfig(builder -> {
builder.author(author) // 设置作者名
.enableSwagger() // 启用Swagger
.outputDir(System.getProperty("user.dir") + "/src/main/java"); // 指定输出目录
})
.packageConfig(builder -> {
builder.entity("domain") // 实体类包名
.parent("com.xzjm.poi") // 父包名
.controller("controller") // 控制层包名
.mapper("mapper") // mapper 层包名
.service("service") // service 层包名
.serviceImpl("service.impl") // service 实现类包名
// 自定义 mapper.xml 文件输出目录
.pathInfo(Collections.singletonMap(OutputFile.mapperXml, System.getProperty("user.dir") + "/src/main/resources/mapper"));
})
.strategyConfig(builder -> {
builder.addInclude(tableName) // 设置要生成的表名
.addTablePrefix("t_") // 设置表前缀过滤(如果没有,可以去掉)
.entityBuilder()
.enableLombok() // 启用 Lombok
.naming(NamingStrategy.underline_to_camel) // 表名映射为实体类驼峰命名
.columnNaming(NamingStrategy.underline_to_camel) // 字段映射为驼峰命名
.mapperBuilder()
.enableMapperAnnotation() // 启用 @Mapper 注解
.enableBaseResultMap() // 启用 BaseResultMap 生成
.enableBaseColumnList() // 启用 BaseColumnList 生成
.formatMapperFileName("%sMapper") // 格式化 Mapper 文件名称
.formatXmlFileName("%sMapper") // 格式化 XML 文件名称
.serviceBuilder()
.formatServiceFileName("%sService") // 格式化 Service 接口文件名称
.formatServiceImplFileName("%sServiceImpl") // 格式化 Service 实现类文件名称
.controllerBuilder()
.enableRestStyle() // 启用 Restful 风格
.formatFileName("%sController") // 格式化 Controller 文件名称
.enableHyphenStyle(); // 启用驼峰转连字符
}).execute();
}
}

View File

@ -0,0 +1,36 @@
package com.yjdsj.common.handler;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
*
* @date 2024/8/20 11:46
*/
public class BlobTypeHandler extends BaseTypeHandler<byte[]> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, byte[] parameter, JdbcType jdbcType) throws SQLException {
ps.setBytes(i, parameter);
}
@Override
public byte[] getNullableResult(ResultSet rs, String columnName) throws SQLException {
return rs.getBytes(columnName);
}
@Override
public byte[] getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return rs.getBytes(columnIndex);
}
@Override
public byte[] getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return cs.getBytes(columnIndex);
}
}

View File

@ -0,0 +1,9 @@
package com.yjdsj.common.map;
import lombok.Data;
@Data
public class MapDto {
private String filePath;
private Integer userId;
}

View File

@ -0,0 +1,91 @@
package com.yjdsj.common.map;
import com.yjdsj.common.utils.MD5HashUtil;
import org.springframework.stereotype.Component;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Component
public class SourceMap {
private Map<String, String> sourceMap = new ConcurrentHashMap<>();
// 添加资源映射关系
public String addSourceMapping(String filePath) {
sourceMap.put(MD5HashUtil.toMD5(filePath), filePath);
return MD5HashUtil.toMD5(filePath);
}
// 移除资源映射关系
public void removeSourceMapping(String filePath) {
sourceMap.remove(MD5HashUtil.toMD5(filePath));
}
// 获取资源映射关系
public String getSourceMapping(String mark) {
return sourceMap.get(mark);
}
// 获取倾斜模型资源列表
public Map<String, String> getCltSourceList() {
Map<String, String> sourceList = new HashMap<>();
for (Map.Entry<String, String> entry : sourceMap.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
if (value.endsWith(".clt")) {
String fileName = getFileNameWithExtension(value);
sourceList.put(key, fileName);
}
}
return sourceList;
}
// 获取图层资源列表
public Map<String, String> getMBTilesSourceList() {
Map<String, String> sourceList = new HashMap<>();
for (Map.Entry<String, String> entry : sourceMap.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
if (value.endsWith(".mbtiles")) {
String fileName = getFileNameWithExtension(value);
sourceList.put(key, fileName);
}
}
return sourceList;
}
// 获取地形资源列表
public Map<String, String> getPakSourceList() {
Map<String, String> sourceList = new HashMap<>();
for (Map.Entry<String, String> entry : sourceMap.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
if (value.endsWith(".pak")) {
String fileName = getFileNameWithExtension(value);
sourceList.put(key, fileName);
}
}
return sourceList;
}
/**
* 获取文件名和后缀
*/
public static String getFileNameWithExtension(String filePath) {
Path path = Paths.get(filePath); // 获取路径
return path.getFileName().toString(); // 返回文件名和后缀
}
/**
* 遍历数据并打印内容、无参
*/
public void printSourceMap() {
for (Map.Entry<String, String> entry : sourceMap.entrySet()) {
System.out.println("MD5 Key: " + entry.getKey() + ", File Path: " + entry.getValue());
}
}
}

View File

@ -0,0 +1,27 @@
package com.yjdsj.common.map;
import java.util.HashMap;
import java.util.Map;
/**
*
* @date 2024/8/20 11:04
*/
public class SourceTypeMap {
/**
* 文件类型映射
*/
private static Map<String, String> SourceType = new HashMap<>();
/**
* 初始化
*/
static {
SourceType.put("clt", "tileset");
}
// 获取资源对应的类型
public static String getSourceType(String fileExtension) {
return SourceType.get(fileExtension);
}
}

View File

@ -0,0 +1,23 @@
package com.yjdsj.common.utils;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class DecompressionUtil {
/**
* 将压缩数据解压并转换为字符串
*
* @param compressedData
* @return
*/
public static String decompressAndConvertToString(byte[] compressedData) {
try {
byte[] decompressedData = GzipDecompressorUtil.decompress(compressedData);
return new String(decompressedData, StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
return "Failed to decompress data: " + e.getMessage();
}
}
}

View File

@ -0,0 +1,30 @@
package com.yjdsj.common.utils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPInputStream;
public class GzipDecompressorUtil {
/**
* 解压数据
*
* @param compressedData
* @return
* @throws IOException
*/
public static byte[] decompress(byte[] compressedData) throws IOException {
try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(compressedData);
GZIPInputStream gzipInputStream = new GZIPInputStream(byteArrayInputStream);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024];
int len;
while ((len = gzipInputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, len);
}
return byteArrayOutputStream.toByteArray();
}
}
}

View File

@ -0,0 +1,7 @@
package com.yjdsj.common.utils;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonUtil {
public static final ObjectMapper mapper = new ObjectMapper();
}

View File

@ -0,0 +1,36 @@
package com.yjdsj.common.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5HashUtil {
/**
* 将输入字符串转换为MD5哈希值
*
* @param input 要转换的字符串
* @return 转换后的MD5哈希值
*/
public static String toMD5(String input) {
try {
// 获取MD5算法实例
MessageDigest md = MessageDigest.getInstance("MD5");
// 将输入字符串转换为字节数组
byte[] messageDigest = md.digest(input.getBytes());
// 将字节数组转换为十六进制字符串
StringBuilder hexString = new StringBuilder();
for (byte b : messageDigest) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
// 返回MD5哈希值
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("MD5算法不存在", e);
}
}
}

View File

@ -0,0 +1,21 @@
package com.yjdsj.common.utils;
public class PakTableName {
/**
* 根据坐标动态计算获取表名
*
* @param z
* @param x
* @param y
* @return
*/
public static String getTableName(int z, int x, int y) {
if (z < 10) {
return "blocks";
} else {
double tx = Math.floorDiv(x, 512);
double ty = Math.floorDiv(y, 512);
return "blocks_" + Integer.toString(z) + "_" + Integer.toString((int) tx) + "_" + Integer.toString((int) ty);
}
}
}

View File

@ -0,0 +1,51 @@
package com.yjdsj.common.utils;
import lombok.AllArgsConstructor;
import lombok.Data;
public class PositionUtil {
// 定义所需的常量,这些值需要根据实际应用场景设置
private static final double a = 6378137.0; // 椭球长半轴
private static final double e = 0.0818191908426; // 第一偏心率
private static final double epsilon = 1e-8; // 迭代精度
private static final double r2d = 180.0 / Math.PI; // 弧度转角度
/**
* 存储 BLH 转换结果的内部类
*/
@Data
@AllArgsConstructor
public static class BlhResult {
public double lon; // 经度
public double lat; // 纬度
public double alt; // 高度
}
/**
* 将XYZ坐标转换为BLH坐标
*/
public static BlhResult xyz2Blh(double x, double y, double z) {
double tmpX = x;
double tmpY = y;
double tmpZ = z;
double curB = 0.0;
double N = 0.0;
double calB = Math.atan2(tmpZ, Math.sqrt(tmpX * tmpX + tmpY * tmpY));
int counter = 0;
while (Math.abs(curB - calB) * r2d > epsilon && counter < 25) {
curB = calB;
N = a / Math.sqrt(1 - e * e * Math.sin(curB) * Math.sin(curB));
calB = Math.atan2(tmpZ + N * e * e * Math.sin(curB),
Math.sqrt(tmpX * tmpX + tmpY * tmpY));
counter++;
}
double longitude = Math.atan2(tmpY, tmpX) * r2d;
double latitude = curB * r2d;
double height = tmpZ / Math.sin(curB) - N * (1 - e * e);
return new BlhResult(longitude, latitude, height);
}
}