19 Commits

Author SHA1 Message Date
wzy-warehouse 71ae772ede Merge remote-tracking branch 'refs/remotes/origin/main' into wzy 2026-06-24 09:54:27 +08:00
wzy-warehouse 8d9cbc3912 Merge branch 'refs/heads/zzw' into wzy
# Conflicts:
#	src/main/java/com/gis/xian/enums/DisasterTypeEnum.java
#	src/main/java/com/gis/xian/task/InitializeData.java
2026-06-22 14:03:00 +08:00
wzy-warehouse c04b985ce6 删除不必要的文件 2026-06-18 20:35:53 +08:00
wzy-warehouse bc5b6fe50a 取消qgis子包,service提到顶层,trigger添加type参数 2026-06-18 20:34:14 +08:00
wzy-warehouse ec1549330a 重构QGIS层:删除dto/entity/mapper,统一为单参数Controller直调Python 2026-06-18 18:29:45 +08:00
wzy-warehouse b6bdc913ec 删除 BaseConstants.java,常量内联到各调用处 2026-06-18 18:13:46 +08:00
wzy-warehouse a7c4615227 refactor: 删除RestClientConfig+HttpRequestClientUtils,FeignServiceImpl改用Spring Boot内置RestClient 2026-06-18 18:08:52 +08:00
wzy-warehouse 175cbc0b43 refactor: 删除QgisProperties,FeignServiceImpl用@Value注入url 2026-06-18 18:04:08 +08:00
wzy-warehouse 16b0206318 refactor: 只传simulationId给Python,删除模板文件 2026-06-18 18:02:51 +08:00
wzy-warehouse 12a134fbfe chore: 清理孤立DTO和空目录,精简QgisProperties配置 2026-06-18 17:57:10 +08:00
wzy-warehouse a312cb4568 refactor: 简化QGIS系统 - 移除RabbitMQ/影响场/距离计算,统一trigger接口 2026-06-18 16:11:15 +08:00
zxyroy d37d9c2361 修改后端readme 2026-06-17 22:10:41 +08:00
zzw 51960eaad4 修改QGIS项目结构 2026-06-17 20:04:39 +08:00
zzw 9d3e51be31 QGIS暴雨专题图产出功能 2026-06-09 08:56:18 +08:00
zzw 60443470b1 QGIS地震专题图修改将图片保存到数据库中 2026-06-08 16:34:02 +08:00
zzw a3fae6630a QGIS地震专题图修改配置文件 2026-06-03 18:30:16 +08:00
zzw b004b5beae Merge remote-tracking branch 'refs/remotes/origin/main' into zzw
# Conflicts:
#	src/main/resources/application.yml
2026-06-03 10:34:38 +08:00
zzw e2c013c86b QGIS地震专题图产出 2026-06-02 17:10:57 +08:00
zzw 6bb5cf46f7 QGIS地震专题图产出 2026-06-02 17:10:47 +08:00
20 changed files with 1031 additions and 26 deletions
+2 -2
View File
@@ -1,5 +1,5 @@
# basic_template_not_login_back
开发基本模版——后端
# xian_api_new
新版西安项目——后端
# basic_template_not_login_back
+49 -8
View File
@@ -7,12 +7,12 @@
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<mybatis.spring.version>3.0.5</mybatis.spring.version>
<druid.version>1.2.27</druid.version>
<postgresql.version>42.7.8</postgresql.version>
<lombok.version>1.18.42</lombok.version>
<bcprov-jdk15to18.version>1.82</bcprov-jdk15to18.version>
<fastjson.version>2.0.60</fastjson.version>
<mybatis-plus.version>3.5.9</mybatis-plus.version>
</properties>
<parent>
@@ -53,11 +53,11 @@
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- MyBatis 整合 Spring Boot -->
<!-- mybatis-plus 整合 Spring Boot -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.spring.version}</version>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!-- 数据库连接池 Druid -->
@@ -72,7 +72,7 @@
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>${postgresql.version}</version>
<scope>runtime</scope>
<!-- <scope>runtime</scope>-->
</dependency>
<!-- WebSocket 支持 -->
@@ -126,6 +126,47 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- GIS空间数据处理工具 -->
<dependency>
<groupId>org.locationtech.jts</groupId>
<artifactId>jts-core</artifactId>
<version>1.19.0</version>
</dependency>
<!-- PostGIS TypeHandler 支持 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-typehandlers-jsr310</artifactId>
<version>1.0.2</version>
</dependency>
<!-- PostGIS JTS 支持 -->
<dependency>
<groupId>net.postgis</groupId>
<artifactId>postgis-jdbc</artifactId>
<version>2021.1.0</version>
</dependency>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-spatial</artifactId>
<version>6.2.0.Final</version>
</dependency>
<!-- 坐标投影转换 -->
<dependency>
<groupId>org.locationtech.proj4j</groupId>
<artifactId>proj4j</artifactId>
<version>1.1.4</version>
</dependency>
<!--常用工具类 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
</dependencies>
<profiles>
@@ -139,7 +180,7 @@
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<!-- 生产环境 -->
<profile>
<id>prod</id>
@@ -173,7 +214,7 @@
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -28,4 +28,4 @@ public class XianApplication {
XianApplication app = context.getBean(XianApplication.class);
System.out.println("后端服务启动成功!访问地址: http://localhost:" + app.port);
}
}
}
@@ -12,9 +12,12 @@ import org.springframework.stereotype.Component;
@Order(1)
@Slf4j
public class DataSourceAspect {
@Around("@annotation(dataSource) || @within(dataSource)")
public Object around(ProceedingJoinPoint point, DataSource dataSource) throws Throwable {
if (dataSource == null) {
return point.proceed();
}
try {
String dsName = dataSource.value();
log.debug("切换数据源: {}", dsName);
@@ -12,19 +12,25 @@ import java.util.Map;
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties("spring.datasource.master")
public DataSource master() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.slave")
public DataSource slave() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.slave1")
public DataSource slave1() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@Primary
public DataSource dataSource() {
@@ -32,6 +38,7 @@ public class DataSourceConfig {
Map<Object, Object> map = new HashMap<>();
map.put("master", master());
map.put("slave", slave());
map.put("slave1", slave1());
ds.setTargetDataSources(map);
ds.setDefaultTargetDataSource(master());
return ds;
@@ -0,0 +1,138 @@
package com.gis.xian.config.typehandler;
import net.postgis.jdbc.PGgeometry;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.PrecisionModel;
import org.locationtech.jts.io.WKTReader;
import org.locationtech.jts.io.WKTWriter;
import org.postgresql.util.PGobject;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 修复编译报错版:PostgreSQL geometry → JTS Geometry 类型处理器
* 解决 JTS Geometry 与 PostGIS Geometry 类的冲突问题
*/
@MappedTypes(Geometry.class) // 实体类字段类型(JTS 的 Geometry
@MappedJdbcTypes(JdbcType.OTHER) // 数据库 geometry 对应 JDBC 类型 OTHER
public class GeometryTypeHandler extends BaseTypeHandler<Geometry> {
// WKT 解析器(JTS → 数据库,线程安全)
private static final WKTReader WKT_READER = new WKTReader();
// WKT 生成器(数据库 → JTS,线程安全)
private static final WKTWriter WKT_WRITER = new WKTWriter();
private static final GeometryFactory GEOMETRY_FACTORY = new GeometryFactory(
new PrecisionModel(PrecisionModel.FLOATING),
4490
);
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Geometry parameter, JdbcType jdbcType) throws SQLException {
try {
// 将 JTS 的 Geometry 转为标准 WKT 字符串
String wktText = WKT_WRITER.write(parameter);
// 用 WKT 字符串创建 PGgeometry 对象
PGgeometry pgGeometry = new PGgeometry(wktText);
// 存入 PreparedStatement
ps.setObject(i, pgGeometry);
} catch (Exception e) {
throw new SQLException("将 JTS Geometry 转为 PGgeometry 失败", e);
}
}
@Override
public Geometry getNullableResult(ResultSet rs, String columnName) throws SQLException {
return convertToGeometry(rs.getObject(columnName));
}
@Override
public Geometry getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return convertToGeometry(rs.getObject(columnIndex));
}
@Override
public Geometry getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return convertToGeometry(cs.getObject(columnIndex));
}
private Geometry convertToGeometry(Object value) {
// 处理 null 值
if (value == null) {
return null;
}
String wktText = null;
try {
// 兼容 PostGIS 的 PGgeometry 格式
if (value instanceof PGgeometry) {
PGgeometry pgGeometry = (PGgeometry) value;
// 转为标准 WKT 文本
wktText = pgGeometry.toString();
}
// 兼容 PostgreSQL 的 PGobject 格式
else if (value instanceof PGobject) {
PGobject pgObject = (PGobject) value;
String pgValue = pgObject.getValue();
if (pgValue != null && !pgValue.trim().isEmpty()) {
wktText = new PGgeometry(pgValue).toString();
}
}
// 兼容纯 WKT 字符串格式
else if (value instanceof String) {
wktText = (String) value;
}
// 未知格式直接返回 null
else {
return null;
}
// 通用清洗 WKT 字符串
String pureWkt = cleanWkt(wktText);
if (pureWkt != null && !pureWkt.trim().isEmpty() && !"NULL".equalsIgnoreCase(pureWkt)) {
Geometry geometry = WKT_READER.read(pureWkt);
// 给几何对象设置 SRID=4490
geometry.setSRID(4490);
return geometry;
}
return null;
} catch (Exception e) {
System.err.println("解析 geometry 字段失败,原始 WKT" + wktText + ",异常:" + e.getMessage());
return null;
}
}
/**
* 通用版 WKT 清洗方法:支持 Point、LINESTRING 等常见几何类型
*/
private String cleanWkt(String wkt) {
if (wkt == null) {
return null;
}
// 步骤1:去除所有不可见字符(换行、回车、制表符)
String cleaned = wkt.replaceAll("[\n\r\t]", "");
// 步骤2:去除 SRID 前缀(如 "SRID=4326;"
cleaned = cleaned.replaceAll("^SRID=\\d+;", "");
// 步骤3:将多个连续空格替换为单个空格(避免坐标间多空格干扰)
cleaned = cleaned.replaceAll("\\s+", " ");
// 步骤4:去除几何类型与括号间的多余空格(适配 Point、LINESTRING
cleaned = cleaned.replaceAll("(POINT|LINESTRING|POLYGON)\\s*\\(", "$1(");
cleaned = cleaned.replaceAll("\\)\\s*$", ")");
// 步骤5:去除首尾多余空格
cleaned = cleaned.trim();
// 步骤6:验证是否为支持的几何类型(可根据需求扩展)
if (!cleaned.startsWith("POINT(") && !cleaned.startsWith("LINESTRING(") && !cleaned.startsWith("POLYGON(")) {
System.err.println("不支持的几何类型,WKT" + cleaned);
return null;
}
return cleaned;
}
}
@@ -0,0 +1,25 @@
package com.gis.xian.controller;
import com.gis.xian.service.IFeignService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
/**
* 专题图触发接口
* 统一入口,接收 simulationId 和 type,调用 Python 端处理
*/
@Slf4j
@RestController
@RequestMapping("/open")
public class QgisController {
@Resource
private IFeignService feignService;
@PostMapping("/qgis/trigger")
public void trigger(@RequestParam String simulationId, @RequestParam String type) {
log.info("收到专题图触发请求: simulationId={}, type={}", simulationId, type);
feignService.trigger(simulationId, type);
}
}
@@ -0,0 +1,15 @@
package com.gis.xian.service;
/**
* 专题图触发接口
* 只负责调用 Python 端,不返回结果
*/
public interface IFeignService {
/**
* 触发专题图生成
* @param simulationId 模拟ID
* @param type 灾害类型(earthquake / rain
*/
void trigger(String simulationId, String type);
}
@@ -0,0 +1,49 @@
package com.gis.xian.service.impl;
import com.gis.xian.service.IFeignService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;
import java.util.Map;
/**
* 专题图触发服务
* 只负责调用 Python QGIS 服务,不处理计算和存库
*/
@Slf4j
@Service
public class FeignServiceImpl implements IFeignService {
@Resource
private RestClient.Builder restClientBuilder;
@Value("${qgis.url}")
private String qgisUrl;
@Override
public void trigger(String simulationId, String type) {
if (simulationId == null || simulationId.isBlank()) {
log.error("触发参数为空,simulationId={}", simulationId);
return;
}
log.info("触发专题图生成: simulationId={}, type={}", simulationId, type);
try {
RestClient client = restClientBuilder.build();
String result = client.post()
.uri(qgisUrl)
.contentType(MediaType.APPLICATION_JSON)
.body(Map.of("simulationId", simulationId, "type", type))
.retrieve()
.body(String.class);
log.info("Python 端响应: {}", result);
} catch (Exception e) {
log.error("调用 Python QGIS 服务失败: {}", e.getMessage(), e);
}
}
}
@@ -141,6 +141,7 @@ public class InitializeData {
log.info("加载隐患点信息(崩塌)并写入redis完成");
});
// 隐患点 - 泥石流
CompletableFuture<Void> debrisFlowFuture = CompletableFuture.runAsync(() -> {
redisTemplate.opsForValue().set(debrisFlowKey, JSON.toJSONString(
@@ -263,7 +264,7 @@ public class InitializeData {
// 等待所有任务完成
CompletableFuture.allOf(
allFuture, landslideFuture, collapseFuture, debrisFlowFuture,
allFuture, landslideFuture, debrisFlowFuture,
flashFloodFuture, waterLoggingFuture,
riskFuture, hospitalsFuture,
dangerousSourceFuture, emergencyShelterFuture, firefighterFuture, storePointsFuture, schoolFuture,
@@ -0,0 +1,682 @@
package com.gis.xian.utils;
import org.springframework.util.AntPathMatcher;
import java.util.*;
/**
* @author zzw
* @description: 字符串工具类 (基于RuoYi风格扩展)
* @date 2026/5/26 上午9:25
*/
public class StringUtils extends org.apache.commons.lang3.StringUtils {
/** 空字符串 */
private static final String NULLSTR = "";
/** 下划线 */
private static final char SEPARATOR = '_';
/** 星号 */
private static final char ASTERISK = '*';
/**
* 获取参数不为空值
*
* @param value defaultValue 要判断的value
* @return value 返回值
*/
public static <T> T nvl(T value, T defaultValue)
{
return value != null ? value : defaultValue;
}
/**
* * 判断一个Collection是否为空, 包含ListSetQueue
*
* @param coll 要判断的Collection
* @return true:为空 false:非空
*/
public static boolean isEmpty(Collection<?> coll)
{
return isNull(coll) || coll.isEmpty();
}
/**
* * 判断一个Collection是否非空,包含ListSetQueue
*
* @param coll 要判断的Collection
* @return true:非空 false:空
*/
public static boolean isNotEmpty(Collection<?> coll)
{
return !isEmpty(coll);
}
/**
* * 判断一个对象数组是否为空
*
* @param objects 要判断的对象数组
** @return true:为空 false:非空
*/
public static boolean isEmpty(Object[] objects)
{
return isNull(objects) || (objects.length == 0);
}
/**
* * 判断一个对象数组是否非空
*
* @param objects 要判断的对象数组
* @return true:非空 false:空
*/
public static boolean isNotEmpty(Object[] objects)
{
return !isEmpty(objects);
}
/**
* * 判断一个Map是否为空
*
* @param map 要判断的Map
* @return true:为空 false:非空
*/
public static boolean isEmpty(Map<?, ?> map)
{
return isNull(map) || map.isEmpty();
}
/**
* * 判断一个Map是否为空
*
* @param map 要判断的Map
* @return true:非空 false:空
*/
public static boolean isNotEmpty(Map<?, ?> map)
{
return !isEmpty(map);
}
/**
* * 判断一个字符串是否为空串
*
* @param str String
* @return true:为空 false:非空
*/
public static boolean isEmpty(String str)
{
return isNull(str) || NULLSTR.equals(str.trim());
}
/**
* * 判断一个字符串是否为非空串
*
* @param str String
* @return true:非空串 false:空串
*/
public static boolean isNotEmpty(String str)
{
return !isEmpty(str);
}
/**
* * 判断一个对象是否为空
*
* @param object Object
* @return true:为空 false:非空
*/
public static boolean isNull(Object object)
{
return object == null;
}
/**
* * 判断一个对象是否非空
*
* @param object Object
* @return true:非空 false:空
*/
public static boolean isNotNull(Object object)
{
return !isNull(object);
}
/**
* * 判断一个对象是否是数组类型(Java基本型别的数组)
*
* @param object 对象
* @return true:是数组 false:不是数组
*/
public static boolean isArray(Object object)
{
return isNotNull(object) && object.getClass().isArray();
}
/**
* 去空格
*/
public static String trim(String str)
{
return (str == null ? "" : str.trim());
}
/**
* 替换指定字符串的指定区间内字符为"*"
*
* @param str 字符串
* @param startInclude 开始位置(包含)
* @param endExclude 结束位置(不包含)
* @return 替换后的字符串
*/
public static String hide(CharSequence str, int startInclude, int endExclude)
{
if (isEmpty(str))
{
return NULLSTR;
}
final int strLength = str.length();
if (startInclude > strLength)
{
return NULLSTR;
}
if (endExclude > strLength)
{
endExclude = strLength;
}
if (startInclude > endExclude)
{
// 如果起始位置大于结束位置,不替换
return NULLSTR;
}
final char[] chars = new char[strLength];
for (int i = 0; i < strLength; i++)
{
if (i >= startInclude && i < endExclude)
{
chars[i] = ASTERISK;
}
else
{
chars[i] = str.charAt(i);
}
}
return new String(chars);
}
/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @return 结果
*/
public static String substring(final String str, int start)
{
if (str == null)
{
return NULLSTR;
}
if (start < 0)
{
start = str.length() + start;
}
if (start < 0)
{
start = 0;
}
if (start > str.length())
{
return NULLSTR;
}
return str.substring(start);
}
/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @param end 结束
* @return 结果
*/
public static String substring(final String str, int start, int end)
{
if (str == null)
{
return NULLSTR;
}
if (end < 0)
{
end = str.length() + end;
}
if (start < 0)
{
start = str.length() + start;
}
if (end > str.length())
{
end = str.length();
}
if (start > end)
{
return NULLSTR;
}
if (start < 0)
{
start = 0;
}
if (end < 0)
{
end = 0;
}
return str.substring(start, end);
}
/**
* 在字符串中查找第一个出现的 `open` 和最后一个出现的 `close` 之间的子字符串
*
* @param str 要截取的字符串
* @param open 起始字符串
* @param close 结束字符串
* @return 截取结果
*/
public static String substringBetweenLast(final String str, final String open, final String close)
{
if (isEmpty(str) || isEmpty(open) || isEmpty(close))
{
return NULLSTR;
}
final int start = str.indexOf(open);
if (start != INDEX_NOT_FOUND)
{
final int end = str.lastIndexOf(close);
if (end != INDEX_NOT_FOUND)
{
return str.substring(start + open.length(), end);
}
}
return NULLSTR;
}
/**
* 判断是否为空,并且不是空白字符
*
* @param str 要判断的value
* @return 结果
*/
public static boolean hasText(String str)
{
return (str != null && !str.isEmpty() && containsText(str));
}
private static boolean containsText(CharSequence str)
{
int strLen = str.length();
for (int i = 0; i < strLen; i++)
{
if (!Character.isWhitespace(str.charAt(i)))
{
return true;
}
}
return false;
}
/**
* 字符串转set
*
* @param str 字符串
* @param sep 分隔符
* @return set集合
*/
public static final Set<String> str2Set(String str, String sep)
{
return new HashSet<String>(str2List(str, sep, true, false));
}
/**
* 字符串转list
*
* @param str 字符串
* @param sep 分隔符
* @return list集合
*/
public static final List<String> str2List(String str, String sep)
{
return str2List(str, sep, true, false);
}
/**
* 字符串转list
*
* @param str 字符串
* @param sep 分隔符
* @param filterBlank 过滤纯空白
* @param trim 去掉首尾空白
* @return list集合
*/
public static final List<String> str2List(String str, String sep, boolean filterBlank, boolean trim)
{
List<String> list = new ArrayList<String>();
if (StringUtils.isEmpty(str))
{
return list;
}
// 过滤空白字符串
if (filterBlank && StringUtils.isBlank(str))
{
return list;
}
String[] split = str.split(sep);
for (String string : split)
{
if (filterBlank && StringUtils.isBlank(string))
{
continue;
}
if (trim)
{
string = string.trim();
}
list.add(string);
}
return list;
}
/**
* 判断给定的collection列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value
*
* @param collection 给定的集合
* @param array 给定的数组
* @return boolean 结果
*/
public static boolean containsAny(Collection<String> collection, String... array)
{
if (isEmpty(collection) || isEmpty(array))
{
return false;
}
else
{
for (String str : array)
{
if (collection.contains(str))
{
return true;
}
}
return false;
}
}
/**
* 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写
*
* @param cs 指定字符串
* @param searchCharSequences 需要检查的字符串数组
* @return 是否包含任意一个字符串
*/
public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences)
{
if (isEmpty(cs) || isEmpty(searchCharSequences))
{
return false;
}
for (CharSequence testStr : searchCharSequences)
{
if (containsIgnoreCase(cs, testStr))
{
return true;
}
}
return false;
}
/**
* 驼峰转下划线命名
*/
public static String toUnderScoreCase(String str)
{
if (str == null)
{
return null;
}
StringBuilder sb = new StringBuilder();
// 前置字符是否大写
boolean preCharIsUpperCase = true;
// 当前字符是否大写
boolean curreCharIsUpperCase = true;
// 下一字符是否大写
boolean nexteCharIsUpperCase = true;
for (int i = 0; i < str.length(); i++)
{
char c = str.charAt(i);
if (i > 0)
{
preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
}
else
{
preCharIsUpperCase = false;
}
curreCharIsUpperCase = Character.isUpperCase(c);
if (i < (str.length() - 1))
{
nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
}
if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase)
{
sb.append(SEPARATOR);
}
else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase)
{
sb.append(SEPARATOR);
}
sb.append(Character.toLowerCase(c));
}
return sb.toString();
}
/**
* 是否包含字符串
*
* @param str 验证字符串
* @param strs 字符串组
* @return 包含返回true
*/
public static boolean inStringIgnoreCase(String str, String... strs)
{
if (str != null && strs != null)
{
for (String s : strs)
{
if (str.equalsIgnoreCase(trim(s)))
{
return true;
}
}
}
return false;
}
/**
* 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld
*
* @param name 转换前的下划线大写方式命名的字符串
* @return 转换后的驼峰式命名的字符串
*/
public static String convertToCamelCase(String name)
{
StringBuilder result = new StringBuilder();
// 快速检查
if (name == null || name.isEmpty())
{
// 没必要转换
return "";
}
else if (!name.contains("_"))
{
// 不含下划线,仅将首字母大写
return name.substring(0, 1).toUpperCase() + name.substring(1);
}
// 用下划线将原始字符串分割
String[] camels = name.split("_");
for (String camel : camels)
{
// 跳过原始字符串中开头、结尾的下换线或双重下划线
if (camel.isEmpty())
{
continue;
}
// 首字母大写
result.append(camel.substring(0, 1).toUpperCase());
result.append(camel.substring(1).toLowerCase());
}
return result.toString();
}
/**
* 驼峰式命名法
* 例如:user_name->userName
*/
public static String toCamelCase(String s)
{
if (s == null)
{
return null;
}
if (s.indexOf(SEPARATOR) == -1)
{
return s;
}
s = s.toLowerCase();
StringBuilder sb = new StringBuilder(s.length());
boolean upperCase = false;
for (int i = 0; i < s.length(); i++)
{
char c = s.charAt(i);
if (c == SEPARATOR)
{
upperCase = true;
}
else if (upperCase)
{
sb.append(Character.toUpperCase(c));
upperCase = false;
}
else
{
sb.append(c);
}
}
return sb.toString();
}
/**
* 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
*
* @param str 指定字符串
* @param strs 需要检查的字符串数组
* @return 是否匹配
*/
public static boolean matches(String str, List<String> strs)
{
if (isEmpty(str) || isEmpty(strs))
{
return false;
}
for (String pattern : strs)
{
if (isMatch(pattern, str))
{
return true;
}
}
return false;
}
/**
* 判断url是否与规则配置:
* ? 表示单个字符;
* * 表示一层路径内的任意字符串,不可跨层级;
* ** 表示任意层路径;
*
* @param pattern 匹配规则
* @param url 需要匹配的url
* @return
*/
public static boolean isMatch(String pattern, String url)
{
AntPathMatcher matcher = new AntPathMatcher();
return matcher.match(pattern, url);
}
@SuppressWarnings("unchecked")
public static <T> T cast(Object obj)
{
return (T) obj;
}
/**
* 数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。
*
* @param num 数字对象
* @param size 字符串指定长度
* @return 返回数字的字符串格式,该字符串为指定长度。
*/
public static final String padl(final Number num, final int size)
{
return padl(num.toString(), size, '0');
}
/**
* 字符串左补齐。如果原始字符串s长度大于size,则只保留最后size个字符。
*
* @param s 原始字符串
* @param size 字符串指定长度
* @param c 用于补齐的字符
* @return 返回指定长度的字符串,由原字符串左补齐或截取得到。
*/
public static final String padl(final String s, final int size, final char c)
{
final StringBuilder sb = new StringBuilder(size);
if (s != null)
{
final int len = s.length();
if (s.length() <= size)
{
for (int i = size - len; i > 0; i--)
{
sb.append(c);
}
sb.append(s);
}
else
{
return s.substring(len - size, len);
}
}
else
{
for (int i = size; i > 0; i--)
{
sb.append(c);
}
}
return sb.toString();
}
}
+8 -3
View File
@@ -5,7 +5,11 @@ server:
# 开发环境配置
spring:
config:
import: classpath:config/database/application-database-dev.yml
import:
- classpath:config/database/application-database-dev.yml
- classpath:config/qgis/application-qgis-dev.yml
- classpath:config/customize/application-customize-dev.yml
# redis
data:
@@ -15,7 +19,6 @@ spring:
password: zhangsan
database: 0
connect-timeout: 3000ms
# 日志配置
logging:
level:
@@ -43,15 +46,17 @@ safety:
- /druid
- /websocket/info
- /websocket/**
- /open/**
# 请求无需解密的路径
no-decrypt-paths:
- /crypto/sm2/public-key
- /druid
- /websocket/info
- /websocket/**
- /open/**
# 算法服务器配置
algorithm:
server:
# 开发环境算法服务器地址
url: http://localhost:8082
url: http://localhost:8082
+5 -2
View File
@@ -5,7 +5,10 @@ server:
# 生产环境配置
spring:
config:
import: classpath:config/database/application-database-prod.yml
import:
- classpath:config/database/application-database-prod.yml
- classpath:config/qgis/application-qgis-prod.yml
- classpath:config/customize/application-customize-prod.yml
# redis
data:
@@ -51,4 +54,4 @@ safety:
algorithm:
server:
# 生产环境算法服务器地址
url: http://localhost:8081
url: http://localhost:8081
+5 -3
View File
@@ -5,9 +5,11 @@ spring:
config:
import: classpath:config/redis/redis-key.yml
# MyBatis 配置
mybatis:
# MyBatis-plus 配置
mybatis-plus:
mapper-locations: classpath:com/gis/xian/mapper/*.xml
type-aliases-package: com.gis.xian.entity
configuration:
map-underscore-to-camel-case: true
map-underscore-to-camel-case: true
# 添加 TypeHandler 扫描包路径
type-handlers-package: com.gis.xian.handler
@@ -0,0 +1,8 @@
# qgis配置
qgis:
# 地震专题图模板路径
eq-maps-template-path: D:/代码/xian_api_new/src/main/resources/template/qgis-template/eq/
# 暴雨专题图模板路径
rain-maps-template-path: D:/代码/xian_api_new/src/main/resources/template/qgis-template/rain/
# QGIS基础路径
base-path: F:/files/xian/maps/
@@ -0,0 +1,8 @@
# qgis配置
qgis:
# 地震专题图模板路径
eq-maps-template-path: D:/代码/xian_api_new/src/main/resources/template/qgis-template/eq/
# 暴雨专题图模板路径
rain-maps-template-path: D:/代码/xian_api_new/src/main/resources/template/qgis-template/rain/
# QGIS基础路径
base-path: F:/files/xian/maps/
@@ -35,4 +35,10 @@ spring:
url: jdbc:postgresql://47.92.216.173:7654/assess_disaster?characterEncoding=utf8&TimeZone=Asia/Shanghai
username: postgres
password: zhangsan
driver-class-name: org.postgresql.Driver
driver-class-name: org.postgresql.Driver
slave1:
url: jdbc:postgresql://47.92.216.173:7654/yjzyk_xian?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=Asia/Shanghai&postgis=true
username: postgres
password: zhangsan
driver-class-name: org.postgresql.Driver
@@ -32,4 +32,10 @@ spring:
url: jdbc:postgresql://10.22.245.138:54321/xianDCAccess?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=Asia/Shanghai
username: zaihailian
password: XAYJ@gis2603
driver-class-name: org.postgresql.Driver
driver-class-name: org.postgresql.Driver
slave1:
url: jdbc:postgresql://47.92.216.173:7654/yjzyk_xian?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=Asia/Shanghai&postgis=true
username: postgres
password: zhangsan
driver-class-name: org.postgresql.Driver
@@ -0,0 +1,3 @@
# qgis配置
qgis:
url: http://localhost:18998/qgis/make/map
@@ -0,0 +1,3 @@
# qgis配置
qgis:
url: http://localhost:18998/qgis/make/map