Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
B
basic-api-boot
概览
概览
详情
活动
周期分析
版本库
存储库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
Basic
basic-api-boot
Commits
e358cfcb
提交
e358cfcb
authored
5月 18, 2022
作者:
方治民
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: 测试定位系统真实定位数据、jaskson 序列化配置调整、swagger 配置仅在 prod 下不生效、gitlab-ci 更新
上级
0aa2b74a
显示空白字符变更
内嵌
并排
正在显示
16 个修改的文件
包含
419 行增加
和
405 行删除
+419
-405
.gitlab-ci.yml
.gitlab-ci.yml
+30
-23
Dockerfile
Dockerfile
+4
-4
README.md
README.md
+1
-0
LocationTag.java
...main/java/com/yiring/app/domain/location/LocationTag.java
+4
-0
MockPositionMessageJob.java
.../main/java/com/yiring/app/job/MockPositionMessageJob.java
+3
-2
PositionMessageServiceImpl.java
.../app/service/message/impl/PositionMessageServiceImpl.java
+157
-111
PositionMessage.java
...in/java/com/yiring/app/stomp/message/PositionMessage.java
+35
-0
ExampleController.java
app/src/main/java/com/yiring/app/web/ExampleController.java
+3
-2
application-beta.yml
app/src/main/resources/application-beta.yml
+127
-0
application-dev.yml
app/src/main/resources/application-dev.yml
+18
-17
application.yml
app/src/main/resources/application.yml
+1
-1
build.gradle
basic-common/core/build.gradle
+8
-7
JacksonConfig.java
...src/main/java/com/yiring/common/config/JacksonConfig.java
+2
-0
RedisCache.java
...rc/main/java/com/yiring/common/core/redis/RedisCache.java
+0
-226
SwaggerConfig.java
...rc/main/java/com/yiring/common/swagger/SwaggerConfig.java
+1
-1
build.gradle
build.gradle
+25
-11
没有找到文件。
.gitlab-ci.yml
浏览文件 @
e358cfcb
# 变量
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 a
ssemble
-
./gradlew a
pp: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
Dockerfile
浏览文件 @
e358cfcb
# 指定基础镜像,在其上进行定制
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
"]
README.md
浏览文件 @
e358cfcb
...
...
@@ -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
)
app/src/main/java/com/yiring/app/domain/location/LocationTag.java
浏览文件 @
e358cfcb
...
...
@@ -6,6 +6,7 @@ import com.yiring.common.annotation.FieldMapping;
import
com.yiring.common.domain.BasicEntity
;
import
java.io.Serial
;
import
java.io.Serializable
;
import
java.time.LocalDateTime
;
import
javax.persistence.*
;
import
lombok.*
;
import
lombok.experimental.FieldDefaults
;
...
...
@@ -107,6 +108,9 @@ public class LocationTag extends BasicEntity implements Serializable {
@Comment
(
"是否在厂外"
)
Boolean
out
;
@Comment
(
"运动状态变更时间"
)
LocalDateTime
silentStatusUpdateTime
;
@SuppressWarnings
({
"unused"
})
public
enum
Type
{
BTT01
(
"蓝牙人员定位卡"
),
...
...
app/src/main/java/com/yiring/app/job/MockPositionMessageJob.java
浏览文件 @
e358cfcb
...
...
@@ -104,11 +104,11 @@ public class MockPositionMessageJob {
}
private
String
mockTag
()
{
return
"BTT3
3333331
"
;
return
"BTT3
4070736
"
;
}
private
Long
mockAreaId
()
{
return
1
0019
L
;
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
();
...
...
app/src/main/java/com/yiring/app/service/message/impl/PositionMessageServiceImpl.java
浏览文件 @
e358cfcb
...
...
@@ -12,11 +12,11 @@ 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.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
;
...
...
@@ -79,16 +79,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
();
...
...
@@ -118,13 +121,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
());
...
...
@@ -174,98 +170,158 @@ public class PositionMessageServiceImpl implements PositionMessageService {
locationLog
.
setPoint
(
point
);
// 定位信标
String
beacons
=
data
.
getString
(
"beacons"
);
if
(
beacons
!=
null
)
{
Set
<
String
>
beaconCodes
=
Arrays
.
stream
(
data
.
getString
(
"beacons"
)
.
split
(
","
))
.
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
.
setFences
(
new
JSONArray
().
fluentAddAll
(
fenceIds
));
// 查询出所有的区域
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
));
// 找出区域与围栏配置的最大防抖时间
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
);
}
}
// 查询定位在围栏内的围栏信息(同时根据地图区域查询,用来区分不同楼层的围栏)
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
;
// 写入定位数据
locationLogRepository
.
saveAndFlush
(
locationLog
);
// 更新定位标签卡状态信息
if
(!
tag
.
getSilent
().
equals
(
locationLog
.
getSilent
()))
{
// 如果运动状态发生变更,记录状态变更时间
tag
.
setSilentStatusUpdateTime
(
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
);
// 检查是否进入区域
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
());
// 更新围栏内的标签数据
locationFenceRepository
.
saveAll
(
fences
);
// 更新区域内的标签数据
districtRepository
.
saveAll
(
districts
);
// 当前标签进入/离开围栏的动作标记为最新记录
LocationTurnover
turnover
=
LocationTurnover
// WebSocket 推送定位消息
// 消息内容需要确定 TODO
PositionMessage
message
=
PositionMessage
.
builder
()
.
enter
(
isEnter
)
.
type
(
LocationTurnover
.
Type
.
FENCE
)
.
sourceId
(
fence
.
getId
())
.
tag
(
id
.
getTag
())
.
time
(
id
.
getTime
())
.
user
(
id
.
getTag
().
getUser
())
.
isLatest
(
true
)
.
tagId
(
id
.
getTag
().
getId
())
.
tagCode
(
id
.
getTag
().
getCode
())
.
point
(
locationLog
.
getPoint
())
.
build
();
turnovers
.
add
(
turnover
);
// 更新围栏内的标签
fence
.
setTags
(
resetInTags
(
tag
,
isEnter
,
fence
.
getTags
()));
// 有人员进出围栏,需要检查是否触发围栏报警规则
// TODO: 通过定时任务调度异步实现,提高定位消息消费能力
// 1. 判断是否触发围栏报警规则,触发则记录报警记录,同时记录报警记录触发所需推送的消息
// 2. 同时进行 WebSocket 消息推送
}
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
())
...
...
@@ -273,41 +329,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
;
}
/**
...
...
@@ -334,8 +367,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
)
{
...
...
@@ -371,14 +404,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
();
}
...
...
@@ -397,6 +436,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
);
...
...
app/src/main/java/com/yiring/app/stomp/message/PositionMessage.java
0 → 100644
浏览文件 @
e358cfcb
/* (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
;
}
app/src/main/java/com/yiring/app/web/ExampleController.java
浏览文件 @
e358cfcb
...
...
@@ -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
)
);
}
}
app/src/main/resources/application-beta.yml
0 → 100644
浏览文件 @
e358cfcb
# 环境变量
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
app/src/main/resources/application-dev.yml
浏览文件 @
e358cfcb
...
...
@@ -17,7 +17,7 @@ spring:
open-in-view
:
true
hibernate
:
ddl-auto
:
update
show-sql
:
tru
e
show-sql
:
fals
e
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
:
5
672
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
:
sc2
1080400
api
:
http
s://nl.yz-cloud.com
/positionApi
client-id
:
sc2
2030527
grant-type
:
client_credentials
client-secret
:
12A14FDC
tenant
:
sc2
1080400
client-secret
:
C18422B9
tenant
:
sc2
2030527
# 代理接口信息配置
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
:
...
...
app/src/main/resources/application.yml
浏览文件 @
e358cfcb
...
...
@@ -5,7 +5,7 @@ server:
spring
:
application
:
name
:
"
kshg-api"
name
:
"
kshg-api
-beta
"
profiles
:
include
:
auth, conf-patch
active
:
dev
...
...
basic-common/core/build.gradle
浏览文件 @
e358cfcb
...
...
@@ -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'
}
}
basic-common/core/src/main/java/com/yiring/common/config/JacksonConfig.java
浏览文件 @
e358cfcb
...
...
@@ -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
;
}
...
...
basic-common/core/src/main/java/com/yiring/common/core/redis/RedisCache.java
deleted
100644 → 0
浏览文件 @
0aa2b74a
/* (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
);
}
}
basic-common/doc/src/main/java/com/yiring/common/swagger/SwaggerConfig.java
浏览文件 @
e358cfcb
...
...
@@ -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
)
...
...
build.gradle
浏览文件 @
e358cfcb
...
...
@@ -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
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
./gradlew spotlessCheck
RESULT=\$?
exit \$RESULT
"""
RESULT=\$?
exit \$RESULT
"""
}
catch
(
ignored
)
{}
}
gradle
.
getTaskGraph
().
whenReady
{
def
skipHooks
=
gradle
.
startParameter
.
getSystemPropertiesArgs
().
containsKey
(
'skip-hooks'
)
printf
(
"skip-hooks: %s"
,
skipHooks
)
if
(!
skipHooks
)
{
hooks
}
}
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论