提交 75f817ae 作者: 涂茂林

合并分支 'dev_fzm' 到 'dev_tml'

Dev fzm

查看合并请求 chemical-kesai/kshg-api!34
# 变量
variables:
# 本地镜像地址,用于拉取镜像以及发布
REGISTRY_REMOTE: localhost:18500
# 容器名称
CONTAINER_NAME: kshg-api
# 对外访问端口
EXPOSE_PORT: 18181
# Pipelines 步骤
stages:
- build
- test
- deploy
# 缓存配置
cache:
paths:
- .gradle/wrapper
- .gradle/caches
# 编译项目
build-job:
stage: build
image: java:8
# 缓存配置
cache:
paths:
- /root/.gradle/cache/
- /root/.gradle/.tmp/
- /root/.m2/
image: $REGISTRY_REMOTE/jdk-17
only:
- beta
- preview
- tags
# 使用 CI Runner,在 GitLab-Runner 中注册好的 Runner
tags:
- CI
- YR-CI
before_script:
- chmod +x ./gradlew
script:
- ./gradlew assemble
- ./gradlew app:assemble -Dskip-hooks
artifacts:
# 配置构建结果过期时间
expire_in: 1 week
expire_in: 1 day
# 保留目录
paths:
- build/libs/*.jar
- app/build/libs/*.jar
# 发布,在本地构建镜像并推送到发布环境的镜像库
deploy-job:
stage: deploy
image: docker:latest
image: $REGISTRY_REMOTE/docker
# 部署依赖编译
dependencies:
- build-job
only:
- tags
- beta
# 使用 CD Runner,在 GitLab-Runner 中注册好的 Runner(此处配置成使用宿主环境构建)
tags:
- CD
- YR-CD
script:
# 基于 Dockerfile 构建镜像
- docker build -t $TAG .
# 登录到发布环境的私服
- docker login -u $REGISTRY_REMOTE_USER -p $REGISTRY_REMOTE_PASSWORD https://$REGISTRY_REMOTE
# 将刚刚构建的镜像推送到私服
- docker push $TAG
# 尝试删除上一个容器
- id=$(docker ps -aqf name=$CONTAINER_NAME) && [ "$id" ] && docker rm -f $id || true
# 在本地运行构建好的镜像
- docker run -d --name $CONTAINER_NAME -p $EXPOSE_PORT:8181 -p 9999:9999 $TAG
variables:
# 读取 GitLab CI/CD 配置的 Secret variables
REGISTRY_REMOTE: $REGISTRY_REMOTE
REGISTRY_REMOTE_USER: $REGISTRY_REMOTE_USER
REGISTRY_REMOTE_PASSWORD: $REGISTRY_REMOTE_PASSWORD
# 设置镜像 tag,使用 git tag 标识作为镜像 tag
TAG: ${REGISTRY_REMOTE}/kshg/kshg-api:${CI_BUILD_REF_NAME}
TAG: $REGISTRY_REMOTE/basic/$CONTAINER_NAME:$CI_BUILD_REF_NAME
# 指定基础镜像,在其上进行定制
FROM java:8
FROM localhost:18500/jdk-17
# 维护者信息
MAINTAINER ifzm <fangzhimin@yiring.com>
......@@ -14,10 +14,10 @@ COPY app/build/libs/app-0.0.1-SNAPSHOT.jar app.jar
# bash方式执行,使 app.jar 可访问
# RUN新建立一层,在其上执行这些命令,执行结束后, commit 这一层的修改,构成新的镜像。
RUN bash -c "touch /app.jar"
# RUN bash -c "touch /app.jar"
# 声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务
EXPOSE 8181
EXPOSE 8181 9999
# 指定容器启动程序及参数 <ENTRYPOINT> "<CMD>"
ENTRYPOINT ["java", "-jar", "app.jar", "--spring.profiles.active=prod"]
ENTRYPOINT ["java", "-jar", "app.jar", "--spring.profiles.active=beta"]
......@@ -38,3 +38,4 @@
> 引用
1. [JTS](https://github.com/locationtech/jts)
2. [GeoTools](http://docs.geotools.org/)
3. [PostGIS](https://blog.csdn.net/qq_27816785/article/details/124540160)
......@@ -104,11 +104,11 @@ public class MockPositionMessageJob {
}
private String mockTag() {
return "BTT33333331";
return "BTT34070736";
}
private Long mockAreaId() {
return 10019L;
return 1L;
}
private JSONObject mockPositionMessage(JSONObject extra) {
......@@ -128,6 +128,7 @@ public class MockPositionMessageJob {
params.put("volt", 3650);
params.put("voltUnit", "mV");
params.put("floor", 1);
params.put("out", false);
params.putAll(extra);
JSONObject body = new JSONObject();
......
......@@ -28,7 +28,10 @@ import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.persistence.criteria.Order;
......
......@@ -12,12 +12,12 @@ import com.yiring.app.domain.log.ZyRealtimeLog;
import com.yiring.app.domain.log.ZyRealtimeLogRepository;
import com.yiring.app.param.key.KeyAlarmAddParam;
import com.yiring.app.service.message.PositionMessageService;
import com.yiring.app.stomp.message.PositionMessage;
import com.yiring.app.util.GeoUtils;
import com.yiring.app.vo.equipment.EquipmentVo;
import com.yiring.auth.domain.dept.Department;
import com.yiring.auth.domain.user.User;
import com.yiring.auth.domain.user.UserRepository;
import com.yiring.common.annotation.Times;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
......@@ -81,16 +81,19 @@ public class PositionMessageServiceImpl implements PositionMessageService {
@Resource
UserRepository userRepository;
@Times("Message Consume")
@Override
public void consume(String message) {
// 将消息转换成 JSON 格式
JSONObject info = JSON.parseObject(message);
log.info("Receiver Message: {}", info);
log.debug("Receiver Message: {}", info);
// 解构消息内容
JSONObject data = info.getJSONObject("params");
String method = info.getString("method");
if (method == null) {
log.warn("Unknown Message: {}", info);
return;
}
// 记录日志
ZyRealtimeLog realtimeLog = ZyRealtimeLog.builder().method(method).raw(info).build();
......@@ -120,13 +123,6 @@ public class PositionMessageServiceImpl implements PositionMessageService {
// TODO
log.info("Position Message: {}", data);
// 包装消息
// TODO
// 1. 解析消息内容,进行围栏、出入标识判断等处理,将定位记录录入数据库
// 2. 创建一条需要进行消息推送的记录
// 3. 将记录推送的消息推送模块
// 4. 检查是否触发围栏告警,记录告警数据,并推送消息
// 查询定位标签
String tagId = data.getString("tagId");
Example<LocationTag> example = Example.of(LocationTag.builder().code(tagId).build());
......@@ -176,98 +172,158 @@ public class PositionMessageServiceImpl implements PositionMessageService {
locationLog.setPoint(point);
// 定位信标
Set<String> beaconCodes = Arrays
.stream(data.getString("beacons").split(","))
.map(beacon -> beacon.replaceAll("\\(.*\\)", ""))
String beacons = data.getString("beacons");
if (beacons != null) {
Set<String> beaconCodes = Arrays
.stream(beacons.split(","))
.map(beacon -> beacon.replaceAll("\\(.*\\)", ""))
.collect(Collectors.toSet());
locationLog.setBeacons(new JSONArray().fluentAddAll(beaconCodes));
}
// 查询所有围栏信息
List<LocationFence> fences = locationFenceRepository.findAll();
// 找出当前定位在哪些围栏内(同楼层,经纬度范围内)
Set<Long> fenceIds = fences
.stream()
.filter(fence -> fence.getMapId().equals(locationLog.getAreaId()) && fence.getGeometry().contains(point))
.map(LocationFence::getId)
.collect(Collectors.toSet());
locationLog.setBeacons(new JSONArray().fluentAddAll(beaconCodes));
locationLog.setFences(new JSONArray().fluentAddAll(fenceIds));
// 计算出入标记(围栏、区域)
List<LocationTurnover> turnovers = new ArrayList<>();
// 查询出所有的区域
List<District> districts = districtRepository.findAll();
// 找出当前定位在哪些围栏内(同楼层,经纬度范围内)
Set<Long> districtIds = districts
.stream()
.filter(district -> point.within(district.getGeometry()))
.map(District::getId)
.collect(Collectors.toSet());
locationLog.setDistricts(new JSONArray().fluentAddAll(districtIds));
// 查询定位在围栏内的围栏信息(同时根据地图区域查询,用来区分不同楼层的围栏)
List<LocationFence> fences = locationFenceRepository.findByGeometryContains(locationLog.getAreaId(), point);
Set<Long> fenceIds = fences.stream().map(LocationFence::getId).collect(Collectors.toSet());
locationLog.setFences(new JSONArray().fluentAddAll(fenceIds));
// 计算围栏进出
for (LocationFence fence : fences) {
// 查询当前围栏的防抖时间内的所有定位记录
List<LocationLog> logs = findByTagTimeIdAndThreshold(id, fence.getThreshold());
List<JSONArray> list = logs.stream().map(LocationLog::getFences).toList();
if (list.isEmpty()) {
continue;
// 找出区域与围栏配置的最大防抖时间
Optional<LocationFence> maxThresholdFence = fences
.stream()
.max(Comparator.comparing(LocationFence::getThreshold));
Optional<District> maxThresholdDistrict = districts
.stream()
.max(Comparator.comparing(District::getDebouncingDuration));
Optional<Integer> maxThreshold = Stream
.of(
maxThresholdFence.map(LocationFence::getThreshold).orElse(0),
maxThresholdDistrict.map(District::getDebouncingDuration).orElse(0)
)
.max(Integer::compareTo);
if (maxThreshold.get() > 0) {
// 查询最大防抖时间段内的定位日志记录
List<LocationLog> logs = findByTagTimeIdAndThreshold(id, maxThreshold.get());
// 计算出入标记(围栏、区域)
List<LocationTurnover> turnovers = new ArrayList<>();
// 统计所有围栏
turnovers.addAll(statisticalTurnovers(fences, id, logs));
// 统计所有区域
turnovers.addAll(statisticalTurnovers(districts, id, logs));
// 写入围栏/区域进出记录
if (!turnovers.isEmpty()) {
locationTurnoverRepository.saveAll(turnovers);
}
}
// 检查是否进入区域
Boolean isEnter = checkEnter(list, fence.getId());
if (isEnter != null) {
// 检查是否为重复进入/退出
Optional<LocationTurnover> enter = findRepeatTurnoverRecord(
fence.getId(),
LocationTurnover.Type.FENCE,
id.getTag(),
isEnter
);
if (enter.isEmpty()) {
// 尝试将上一次记录标记为非最新记录
trySetPrevTurnoverExpired(fence.getId(), LocationTurnover.Type.FENCE, id.getTag());
// 写入定位数据
locationLogRepository.saveAndFlush(locationLog);
// 当前标签进入/离开围栏的动作标记为最新记录
LocationTurnover turnover = LocationTurnover
.builder()
.enter(isEnter)
.type(LocationTurnover.Type.FENCE)
.sourceId(fence.getId())
.tag(id.getTag())
.time(id.getTime())
.user(id.getTag().getUser())
.isLatest(true)
.build();
turnovers.add(turnover);
// 更新定位标签卡状态信息
if (!tag.getSilent().equals(locationLog.getSilent())) {
// 如果运动状态发生变更,记录状态变更时间
tag.setTime(id.getTime());
}
tag.setSilent(locationLog.getSilent());
tag.setOut(locationLog.getOut());
tag.setPoint(locationLog.getPoint());
tag.setVolt(locationLog.getVolt());
tag.setVoltUnit(locationLog.getVoltUnit());
locationTagRepository.save(tag);
// 更新围栏内的标签
fence.setTags(resetInTags(tag, isEnter, fence.getTags()));
// 有人员进出围栏,需要检查是否触发围栏报警规则
// TODO: 通过定时任务调度异步实现,提高定位消息消费能力
// 1. 判断是否触发围栏报警规则,触发则记录报警记录,同时记录报警记录触发所需推送的消息
// 2. 同时进行 WebSocket 消息推送
}
// 更新围栏内的标签数据
locationFenceRepository.saveAll(fences);
// 更新区域内的标签数据
districtRepository.saveAll(districts);
// WebSocket 推送定位消息
// 消息内容需要确定 TODO
PositionMessage message = PositionMessage
.builder()
.time(id.getTime())
.tagId(id.getTag().getId())
.tagCode(id.getTag().getCode())
.point(locationLog.getPoint())
.build();
simpMessagingTemplate.convertAndSend("/topic/position", message);
}
/**
* 统计进出记录
* @param areas 区域/围栏列表
* @param id 定位日志主键
* @param logs 定位日志列表
* @return 进出记录列表
*/
public <E> List<LocationTurnover> statisticalTurnovers(List<E> areas, TagTimeId id, List<LocationLog> logs) {
List<LocationTurnover> turnovers = new ArrayList<>();
// 遍历所有区域/围栏
for (Object area : areas) {
// 收集不同表共同关键信息
LocationTurnover.Type type;
Long sourceId;
int threshold;
if (area instanceof LocationFence fence) {
sourceId = fence.getId();
threshold = fence.getThreshold();
type = LocationTurnover.Type.FENCE;
} else if (area instanceof District district) {
sourceId = district.getId();
threshold = district.getDebouncingDuration();
type = LocationTurnover.Type.DISTRICT;
} else {
continue;
}
}
// 查询定位在区域内的区域信息
List<District> districts = districtRepository.findByGeometryContains(point);
Set<Long> districtIds = districts.stream().map(District::getId).collect(Collectors.toSet());
locationLog.setDistricts(new JSONArray().fluentAddAll(districtIds));
// 计算区域进出
for (District district : districts) {
// 查询当前区域的防抖时间内的所有定位记录
List<LocationLog> logs = findByTagTimeIdAndThreshold(id, district.getDebouncingDuration());
List<JSONArray> list = logs.stream().map(LocationLog::getDistricts).toList();
if (list.isEmpty()) {
// 获取需要过滤的时间段
LocalDateTime startTime = id.getTime().minusSeconds(threshold);
LocalDateTime endTime = id.getTime();
// 过滤出围栏防抖时间段内的定位日志记录
Set<LocationLog> collect = logs
.stream()
.filter(item -> item.getId().getTime().isBefore(endTime) && item.getId().getTime().isAfter(startTime))
.collect(Collectors.toSet());
// 找出定位记录中围栏集合
LocationTurnover.Type finalType = type;
List<JSONArray> includes = collect
.stream()
.map(item -> LocationTurnover.Type.FENCE.equals(finalType) ? item.getFences() : item.getDistricts())
.toList();
if (includes.isEmpty()) {
continue;
}
// 检查是否进入区域
Boolean isEnter = checkEnter(list, district.getId());
Boolean isEnter = checkEnter(includes, sourceId);
if (isEnter != null) {
// 检查是否为重复进入/退出
Optional<LocationTurnover> enter = findRepeatTurnoverRecord(
district.getId(),
LocationTurnover.Type.DISTRICT,
id.getTag(),
isEnter
);
if (enter.isEmpty()) {
// 检查是否为重复进入/退出(一定是先有进入记录才会有离开记录)
Optional<LocationTurnover> repeat = findRepeatTurnoverRecord(sourceId, type, id.getTag(), isEnter);
if (repeat.isEmpty()) {
// 尝试将上一次记录标记为非最新记录
trySetPrevTurnoverExpired(district.getId(), LocationTurnover.Type.DISTRICT, id.getTag());
trySetPrevTurnoverExpired(sourceId, type, id.getTag());
// 当前标签进入/离开围栏的动作标记为最新记录
// 记录当前标签进入/离开围栏/区域的动作,标记为最新记录
LocationTurnover turnover = LocationTurnover
.builder()
.enter(isEnter)
.type(LocationTurnover.Type.DISTRICT)
.sourceId(district.getId())
.type(type)
.sourceId(sourceId)
.tag(id.getTag())
.time(id.getTime())
.user(id.getTag().getUser())
......@@ -275,41 +331,18 @@ public class PositionMessageServiceImpl implements PositionMessageService {
.build();
turnovers.add(turnover);
// 更新区域内的标签
district.setTags(resetInTags(tag, isEnter, district.getTags()));
// 更新范围内的标签信息
if (area instanceof LocationFence fence) {
fence.setTags(resetInTags(id.getTag(), isEnter, fence.getTags()));
} else {
District district = (District) area;
district.setTags(resetInTags(id.getTag(), isEnter, district.getTags()));
}
}
}
}
// 写入定位数据
locationLogRepository.saveAndFlush(locationLog);
// 更新定位标签卡状态信息
tag.setOut(locationLog.getOut());
tag.setPoint(locationLog.getPoint());
tag.setVolt(locationLog.getVolt());
tag.setVoltUnit(locationLog.getVoltUnit());
tag.setSilent(locationLog.getSilent());
locationTagRepository.save(tag);
// 更新围栏内的标签数据
locationFenceRepository.saveAll(fences);
// 更新区域内的标签数据
districtRepository.saveAll(districts);
// 写入围栏/区域进出记录
locationTurnoverRepository.saveAll(turnovers);
// WebSocket 推送定位消息
// 消息内容需要确定 TODO
JSONObject message = new JSONObject();
message.put("type", "location");
message.put("time", id.getTime());
message.put("tagId", id.getTag().getId());
message.put("tagCode", id.getTag().getCode());
message.put("entityId", locationLog.getPoint());
message.put("point", locationLog.getPoint());
simpMessagingTemplate.convertAndSend("/topic/position", message.toJSONString());
return turnovers;
}
/**
......@@ -336,8 +369,8 @@ public class PositionMessageServiceImpl implements PositionMessageService {
* @return true 进入,false 退出,null 未发生变化
*/
public Boolean checkEnter(List<JSONArray> array, Long id) {
long count = array.stream().filter(ids -> ids != null && ids.contains(id)).count();
Boolean isEnter = null;
long count = array.stream().filter(ids -> ids != null && ids.contains(id)).count();
if (count == array.size()) {
isEnter = true;
} else if (count == 0) {
......@@ -373,14 +406,20 @@ public class PositionMessageServiceImpl implements PositionMessageService {
pageable
);
if (page.getTotalElements() > 0) {
long elements = page.getTotalElements();
if (elements == 0 && Boolean.FALSE.equals(enter)) {
// 如果标签在目标区域没有过进入记录,但是确判断为离开,这时需拟一个记录,避免记录一个没有进入确有离开记录的情况
return Optional.of(new LocationTurnover());
}
if (elements > 0) {
// 检查是否重复进入
Stream<LocationTurnover> stream = page.get();
if (enter == null || stream.anyMatch(turnover -> turnover.getEnter() == enter)) {
return stream.findFirst();
if (enter == null || page.get().anyMatch(turnover -> turnover.getEnter() == enter)) {
return page.stream().findFirst();
}
}
// 需要记录
return Optional.empty();
}
......@@ -399,6 +438,13 @@ public class PositionMessageServiceImpl implements PositionMessageService {
}
}
/**
* 重置标签集合
* @param tag 标签
* @param enter 进入/离开
* @param tags 标签集合
* @return 重置后的标签集合
*/
public Set<LocationTag> resetInTags(LocationTag tag, Boolean enter, Set<LocationTag> tags) {
if (Boolean.TRUE.equals(enter)) {
tags.add(tag);
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.stomp.message;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import lombok.*;
import lombok.experimental.FieldDefaults;
import org.locationtech.jts.geom.Point;
/**
* @author Jim
* @version 0.1
* 2022/5/16 19:32
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
public class PositionMessage implements Serializable {
@Serial
private static final long serialVersionUID = -1806101353088274819L;
@Builder.Default
String type = "position";
LocalDateTime time;
Long tagId;
String tagCode;
Long entityId;
Point point;
}
......@@ -13,6 +13,7 @@ import java.util.Arrays;
import java.util.List;
import javax.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.geolatte.geom.jts.JTS;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.io.ParseException;
......@@ -61,12 +62,12 @@ public class ExampleController {
}
@GetMapping("test2")
public Result<Geometry> test2() throws ParseException {
public Result<org.geolatte.geom.Polygon<?>> test2() throws ParseException {
WKTReader reader = new WKTReader();
Geometry geometry = reader.read(
"POLYGON((114.13726247683384 22.57453153296995,114.13726253585672 22.57362062876488,114.1379932868094 22.57336379439826,114.13860672275516 22.573820711775532,114.13726247683384 22.57453153296995))"
);
Polygon polygon = (Polygon) geometry;
return Result.ok(polygon);
return Result.ok(JTS.from(polygon));
}
}
# 环境变量
env:
host: 192.168.0.156
spring:
servlet:
multipart:
enabled: true
max-file-size: 50MB
max-request-size: 100MB
datasource:
url: jdbc:postgresql://${env.host}:5432/kshg_app_beta
username: admin
password: 123456
jpa:
database-platform: com.yiring.app.config.dialect.PostgresDialect
open-in-view: true
hibernate:
ddl-auto: update
show-sql: false
properties:
hibernate:
format_sql: true
types.print.banner: false
redis:
database: 10
host: ${env.host}
rabbitmq:
host: ${env.host}
port: 5672
username: admin
password: 123456
virtual-host: beta
data:
redis:
repositories:
enabled: false
# 处理多网卡选举
cloud:
inetutils:
preferred-networks: 192.168.0
# knife4j(swagger)
knife4j:
enable: true
basic:
enable: false
username: admin
password: 123456
setting:
enableOpenApi: false
enableDebug: true
# minio
minio:
access-key: minioadmin
secret-key: minioadmin
end-point: "http://${env.host}:18100"
bucket: kshg
domain: ${minio.endpoint}/${minio.bucket}
# 任务调度
xxl:
job:
### 调度中心部署跟地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册;
admin-addresses: http://${env.host}:8080/xxl-job-admin
### 执行器通讯TOKEN [选填]:非空时启用;
access-token: local
### 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
executor-app-name: kshg-app-beta
### 执行器注册 [选填]:优先使用该配置作为注册地址,为空时使用内嵌服务 ”IP:PORT“ 作为注册地址。从而更灵活的支持容器类型执行器动态IP和动态映射端口问题。
executor-address:
### 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务";
executor-ip:
### 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
executor-port:
### 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
executor-log-path: /data/applogs/xxl-job/jobhandler
### 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能;
executor-log-retention-days: 30
# 日志
logging:
level:
# sql bind parameter
# org.hibernate.type.descriptor.sql.BasicBinder: trace
org.hibernate.type.descriptor.sql.BasicBinder: error
# 真源定位系统相关配置
zy-config:
host: project.yz-online.com
# RabbitMQ 订阅配置
rabbitmq:
mock: false
enabled: false
host: 123.60.56.5
port: 5672
username: tenant
password: tenant
virtual-host: /
queue-name: tenant_msg_${zy-config.open.client-secret}_${zy-config.open.client-id}
# 开放接口信息配置
open:
api: https://nl.yz-cloud.com/positionApi
client-id: sc22030527
grant-type: client_credentials
client-secret: C18422B9
tenant: sc22030527
# 代理接口信息配置
proxy:
api: https://nl.yz-cloud.com
tenant: sc22030527
# 应用平台账户信息
client:
username: client
password: client@yiring.com
# 管理后台账户信息
manage:
username: manage
password: manage@yiring.com
feign:
httpclient:
enabled: false
okhttp:
enabled: true
......@@ -17,7 +17,7 @@ spring:
open-in-view: true
hibernate:
ddl-auto: update
show-sql: true
show-sql: false
properties:
hibernate:
format_sql: true
......@@ -83,40 +83,41 @@ xxl:
logging:
level:
# sql bind parameter
org.hibernate.type.descriptor.sql.BasicBinder: trace
# org.hibernate.type.descriptor.sql.BasicBinder: error
# org.hibernate.type.descriptor.sql.BasicBinder: trace
org.hibernate.type.descriptor.sql.BasicBinder: error
# 真源定位系统相关配置
zy-config:
host: project.yz-online.com
# RabbitMQ 订阅配置
rabbitmq:
mock: false
enabled: false
host: ${zy-config.host}
port: 672
username: admin
password: admin
host: 123.60.56.5
port: 5672
username: tenant
password: tenant
virtual-host: /
queue-name: tenant_msg_${zy-config.open.client-secret}_${zy-config.open.client-id}_mock
queue-name: tenant_msg_${zy-config.open.client-secret}_${zy-config.open.client-id}
# 开放接口信息配置
open:
api: http://${zy-config.host}:789/positionApi
client-id: sc21080400
api: https://nl.yz-cloud.com/positionApi
client-id: sc22030527
grant-type: client_credentials
client-secret: 12A14FDC
tenant: sc21080400
client-secret: C18422B9
tenant: sc22030527
# 代理接口信息配置
proxy:
api: https://nl.yz-cloud.com
tenant: ts00000006
tenant: sc22030527
# 应用平台账户信息
client:
username: test1234
password: 123456
username: client
password: client@yiring.com
# 管理后台账户信息
manage:
username: test123
password: test123
username: manage
password: manage@yiring.com
feign:
httpclient:
......
......@@ -5,7 +5,7 @@ server:
spring:
application:
name: "kshg-api"
name: "kshg-api-beta"
profiles:
include: auth, conf-patch
active: dev
......
......@@ -14,15 +14,16 @@ dependencies {
implementation fileTree(dir: project.rootDir.getPath() + '\\libs', includes: ['*jar'])
// JTS 几何对象操作库
implementation "org.locationtech.jts:jts-core:${jtsVersion}"
// https://mvnrepository.com/artifact/org.n52.jackson/jackson-datatype-jts/1.2.10
implementation("org.n52.jackson:jackson-datatype-jts:1.2.10") {
exclude group: 'com.fasterxml.jackson.core', module: 'jackson-databind'
exclude group: 'com.fasterxml.jackson.core', module: 'jackson-annotations'
exclude group: 'com.fasterxml.jackson.core', module: 'jackson-core'
exclude group: 'org.locationtech.jts', module: 'jts-core'
exclude group: 'com.fasterxml.jackson.core'
exclude group: 'org.locationtech.jts'
}
// JTS 几何对象操作库
implementation "org.geolatte:geolatte-geom:${geolatteVersion}"
implementation("org.geolatte:geolatte-geojson:${geolatteVersion}") {
exclude group: 'com.fasterxml.jackson.core'
}
}
......@@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import javax.annotation.Resource;
import org.geolatte.geom.json.GeolatteGeomModule;
import org.n52.jackson.datatype.jts.JtsModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
......@@ -35,6 +36,7 @@ public class JacksonConfig {
mapper.registerModule(javaTimeModule);
// JTS Geometry support
mapper.registerModule(new JtsModule());
mapper.registerModule(new GeolatteGeomModule());
// feat: add AdminServerModule
return mapper;
}
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.common.core.redis;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
/**
* redis缓存 工具类
*
* @author tzl
* 2022/4/13 15:36
*/
@Component
public class RedisCache {
@Autowired
public RedisTemplate redisTemplate;
/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
*/
public <T> void setCacheObject(final String key, final T value) {
redisTemplate.opsForValue().set(key, value);
}
/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
* @param timeout 时间
* @param timeUnit 时间颗粒度
*/
public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
}
/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @return true=设置成功;false=设置失败
*/
public boolean expire(final String key, final long timeout) {
return expire(key, timeout, TimeUnit.SECONDS);
}
/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @param unit 时间单位
* @return true=设置成功;false=设置失败
*/
public boolean expire(final String key, final long timeout, final TimeUnit unit) {
return Boolean.TRUE.equals(redisTemplate.expire(key, timeout, unit));
}
/**
* 获得缓存的基本对象。
*
* @param key 缓存键值
* @return 缓存键值对应的数据
*/
public <T> T getCacheObject(final String key) {
ValueOperations<String, T> operation = redisTemplate.opsForValue();
return operation.get(key);
}
/**
* 删除单个对象
*
* @param key
*/
public boolean deleteObject(final String key) {
return Boolean.TRUE.equals(redisTemplate.delete(key));
}
/**
* 删除集合对象
*
* @param collection 多个对象
* @return
*/
public long deleteObject(final Collection collection) {
return redisTemplate.delete(collection);
}
/**
* 缓存List数据
*
* @param key 缓存的键值
* @param dataList 待缓存的List数据
* @return 缓存的对象
*/
public <T> long setCacheList(final String key, final List<T> dataList) {
Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
return count == null ? 0 : count;
}
/**
* 获得缓存的list对象
*
* @param key 缓存的键值
* @return 缓存键值对应的数据
*/
public <T> List<T> getCacheList(final String key) {
return redisTemplate.opsForList().range(key, 0, -1);
}
/**
* 缓存Set
*
* @param key 缓存键值
* @param dataSet 缓存的数据
* @return 缓存数据的对象
*/
public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) {
BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
for (T t : dataSet) {
setOperation.add(t);
}
return setOperation;
}
/**
* 获得缓存的set
*
* @param key String
* @return
*/
public <T> Set<T> getCacheSet(final String key) {
return redisTemplate.opsForSet().members(key);
}
/**
* 缓存Map
*
* @param key
* @param dataMap
*/
public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
if (dataMap != null) {
redisTemplate.opsForHash().putAll(key, dataMap);
}
}
/**
* 获得缓存的Map
*
* @param key
* @return
*/
public <T> Map<String, T> getCacheMap(final String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* 往Hash中存入数据
*
* @param key Redis键
* @param hKey Hash键
* @param value 值
*/
public <T> void setCacheMapValue(final String key, final String hKey, final T value) {
redisTemplate.opsForHash().put(key, hKey, value);
}
/**
* 获取Hash中的数据
*
* @param key Redis键
* @param hKey Hash键
* @return Hash中的对象
*/
public <T> T getCacheMapValue(final String key, final String hKey) {
HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
return opsForHash.get(key, hKey);
}
/**
* 删除Hash中的数据
*
* @param key
* @param hKey
*/
public void delCacheMapValue(final String key, final String hKey) {
HashOperations hashOperations = redisTemplate.opsForHash();
hashOperations.delete(key, hKey);
}
/**
* 获取多个Hash中的数据
*
* @param key Redis键
* @param hKeys Hash键集合
* @return Hash对象集合
*/
public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) {
return redisTemplate.opsForHash().multiGet(key, hKeys);
}
/**
* 获得缓存的基本对象列表
*
* @param pattern 字符串前缀
* @return 对象列表
*/
public Collection<String> keys(final String pattern) {
return redisTemplate.keys(pattern);
}
}
......@@ -40,7 +40,7 @@ import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
*/
@Slf4j
@Profile(value = { "default", "dev", "mock", "test", "preview" })
@Profile("!prod")
@EnableSwagger2WebMvc
@Configuration
@Import(BeanValidatorPluginsConfiguration.class)
......
......@@ -10,9 +10,9 @@ buildscript {
// https://mvnrepository.com/artifact/io.swagger/swagger-annotations
swaggerAnnotationsVersion = '1.6.6'
// https://mvnrepository.com/artifact/cn.dev33/sa-token-spring-boot-starter
saTokenVersion = '1.29.1.trial'
saTokenVersion = '1.30.0'
// https://mvnrepository.com/artifact/cn.hutool/hutool-all
hutoolVersion = '5.8.0.M3'
hutoolVersion = '5.8.0'
// https://mvnrepository.com/artifact/com.alibaba/fastjson
fastJsonVersion = '1.2.80'
// https://mvnrepository.com/artifact/com.xuxueli/xxl-job-core
......@@ -20,7 +20,7 @@ buildscript {
// https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp
okhttpVersion = '4.9.3'
// https://mvnrepository.com/artifact/io.minio/minio
minioVersion = '8.3.8'
minioVersion = '8.4.1'
// https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter
mybatisPlusVersion = '3.5.1'
// https://mvnrepository.com/artifact/org.hibernate/hibernate-spatial
......@@ -33,6 +33,8 @@ buildscript {
myexcelVersion = '4.1.1'
// https://mvnrepository.com/artifact/io.github.openfeign/feign-okhttp
feignOkhttpVersion= '11.8'
// https://mvnrepository.com/artifact/org.geolatte/geolatte-geom
geolatteVersion = '1.8.2'
}
}
......@@ -133,13 +135,25 @@ subprojects {
}
}
// GitHook pre-commit (spotless, spotbugs)
def hook = new File("$rootProject.projectDir/.git/hooks/pre-commit")
hook.text = """#!/bin/bash
#set -x
./gradlew spotlessCheck
task hooks() {
try {
// GitHook pre-commit (spotless, spotbugs)
def hook = new File("$rootProject.projectDir/.git/hooks/pre-commit")
hook.text = """#!/bin/bash
#set -x
./gradlew spotlessCheck
RESULT=\$?
exit \$RESULT
"""
} catch (ignored) {}
}
RESULT=\$?
exit \$RESULT
"""
gradle.getTaskGraph().whenReady {
def skipHooks = gradle.startParameter.getSystemPropertiesArgs().containsKey('skip-hooks')
printf("skip-hooks: %s", skipHooks)
if (!skipHooks) {
hooks
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论