提交 dca38b0e 作者: 17607474349

Merge remote-tracking branch 'origin/dev_fzm' into dev_lijing

# Conflicts:
#	app/src/main/resources/application-dev.yml
#	basic-auth/build.gradle
# 变量
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
## 0.0.1 (2022-04-27)
### Bug Fixes
* 升级 spring-boot 版本,修复 RCE 漏洞 ([dda158f](https://gitlab.yiring.com/basic/basic-api-project/commit/dda158fcb0e4b2584c1bb0044b00b3734fbb1348))
* 修复 PageVo spotbugsMain 异常检测结果 ([847c32b](https://gitlab.yiring.com/basic/basic-api-project/commit/847c32bcd5ffa133e2e8997407bbba99e0741532))
* 修复 RedisConfig Jackson 序列化配置 ([8514e93](https://gitlab.yiring.com/basic/basic-api-project/commit/8514e938783ea37d87d75c676091f260c028e802))
* 修复权限 meta JSON 数据构建空值错误、equals 代码简化 ([f5d902b](https://gitlab.yiring.com/basic/basic-api-project/commit/f5d902b4e42b533fddf4d2fed919a0290adbcf90))
### Features
* 分离用户菜单权限树查询接口、快速失败状态异常类型及全局处理、新增通用类型集合转换工具方法、hutool-json 换成 fastjson 依赖等细节优化处理 ([a62b1f2](https://gitlab.yiring.com/basic/basic-api-project/commit/a62b1f28999c127b16be776f5d5d3fd453b7823e))
* 更新 gradle 版本、新增 sourceCompatibility=17、调整全局异常配置 ([4b2b0d9](https://gitlab.yiring.com/basic/basic-api-project/commit/4b2b0d9805f28a786fc59bd305b643b51fb9be20))
* 升级到 JDK17 进行适配 ([4b8557a](https://gitlab.yiring.com/basic/basic-api-project/commit/4b8557a1707a6603353365ab1b2c3c21dcd1c5a3))
* 适配 Spring Boot 2.6.6, 更新文档 ([674dce4](https://gitlab.yiring.com/basic/basic-api-project/commit/674dce47162f558d7bbd1273c82ae22bb7080b8f))
* 新增 BasicEntity、抽离 JacksonConfig 与 DateTimeConfig、优化 Swagger 日志输出时机、封装 Auths 公共类等 ([7d3b75d](https://gitlab.yiring.com/basic/basic-api-project/commit/7d3b75d3c12507b5cf8c26305bdab0da11e76b05))
* 新增 JTS 依赖及 Jackson 序列化配置、hibernate-types 扩展自定义类型 ([0c712c1](https://gitlab.yiring.com/basic/basic-api-project/commit/0c712c1ea1e50a5ecece0eae495557d1913e31ec))
* 新增菜单路由重定向配置、新增用户权限获取接口,用于前端鉴权、新增用户 SQL 预览文件 ([9cc0e18](https://gitlab.yiring.com/basic/basic-api-project/commit/9cc0e18b847751c5d2de145a9751eee91904b83c))
* 新增快速失败业务异常实现及示例, 新增默认的用户主页地址 ([353782a](https://gitlab.yiring.com/basic/basic-api-project/commit/353782a99deda17c2d90ea7ff9ed88ad9034f995))
* 新增默认文件上传大小限制配置 ([a7ffba3](https://gitlab.yiring.com/basic/basic-api-project/commit/a7ffba39099c1d662ee653c4686bc42024696154))
* 新增通用用户及权限相关、MinIO 文件上传实现, 依赖更新等 ([7931c58](https://gitlab.yiring.com/basic/basic-api-project/commit/7931c583cc8d15936f1f756145b52c6d2b6ffc68))
* 新增文件下载示例、关键字查询 Param 类、端口变更 ([fc1405d](https://gitlab.yiring.com/basic/basic-api-project/commit/fc1405db962378884e203807e03e005812e27709))
* 优化 Swagger 文档日志输出 ([b724899](https://gitlab.yiring.com/basic/basic-api-project/commit/b7248990d38fd6845d3727b644fe419df9621802))
* 优化日志输出 ([0b79e58](https://gitlab.yiring.com/basic/basic-api-project/commit/0b79e58c1ae1b777d19970467dbf713e608228cb))
* 增加 Host 环境变量统一配置参数 ([d336c37](https://gitlab.yiring.com/basic/basic-api-project/commit/d336c3706a8a4063d8d86eb5ed827be36524698d))
* 增加 Redis 操作序列化配置、缓存配置、实用技巧文档 ([2a892bd](https://gitlab.yiring.com/basic/basic-api-project/commit/2a892bd0369d8bf44e557a50777be04355769dba))
* add cors, context-path ... ([94cb809](https://gitlab.yiring.com/basic/basic-api-project/commit/94cb809d15fc69c9c447fdd08431c0cc6c780eea))
* init ([1c5da80](https://gitlab.yiring.com/basic/basic-api-project/commit/1c5da8050f0c9e9a3e7bfbf8f6fd805f5f613588))
* redis Bean 新增 keys 方法 ([a2f9e3f](https://gitlab.yiring.com/basic/basic-api-project/commit/a2f9e3fee626480ed2a27fc4fb4a2da767fb4e2b))
# 指定基础镜像,在其上进行定制
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"]
......@@ -18,7 +18,7 @@
<!-- prettier-ignore -->
- [开发规范说明](./doc/workflow.md)
- [技术栈说明](./doc/technique.md)
- [实用技巧](./doc/skill.md)
- 👉 [实用技巧](./doc/skill.md)
---
......@@ -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)
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.check.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.check.IParamInitStrategy;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.app.param.location.rule.TimeAndUserParam;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
/**
* @author tml
* @version 1.0
* @date 2022/4/29 9:32
*/
@Component
public class AllowEntranceStrategy implements IParamInitStrategy<LocationFenceRuleAddParam> {
public AllowEntranceStrategy() {
Integer relevanceParam = RelevanceParamEnum.ALLOW_ENTRANCE.getCode();
LocationFenceRuleContext.register(relevanceParam, this);
}
@Override
public Result<String> paramInit(LocationFenceRuleAddParam param) {
RuleParam ruleParam = param.getRuleParam();
List<TimeAndUserParam> timeAndUser = ruleParam.getTimeAndUser();
if (CollectionUtils.isEmpty(timeAndUser)) {
return Result.no(Status.EXPECTATION_FAILED, "请至少配置一条允许进入人员的规则");
}
for (TimeAndUserParam item : timeAndUser) {
if (CollectionUtils.isEmpty(item.getUser())) {
return Result.no(Status.EXPECTATION_FAILED, "请至少配置一个允许进入的人员");
}
}
ruleParam.setDuration(-1);
ruleParam.setDistance(-1);
ruleParam.setTimeAndNumber(new ArrayList<>());
return Result.ok();
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.check.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.check.IParamInitStrategy;
import com.yiring.app.param.location.rule.*;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
/**
* 最多人数校验
* @author tml
* @version 1.0
* @date 2022/4/29 9:28
*/
@Component
public class MaxPeopleNumberStrategy implements IParamInitStrategy<LocationFenceRuleAddParam> {
public MaxPeopleNumberStrategy() {
Integer relevanceParam = RelevanceParamEnum.MAX_PEOPLE_NUMBER.getCode();
LocationFenceRuleContext.register(relevanceParam, this);
}
@Override
public Result<String> paramInit(LocationFenceRuleAddParam param) {
RuleParam ruleParam = param.getRuleParam();
List<TimeAndNumberParam> timeAndNumber = ruleParam.getTimeAndNumber();
if (CollectionUtils.isEmpty(timeAndNumber)) {
return Result.no(Status.EXPECTATION_FAILED, "请至少配置一条最多人数的规则");
}
for (TimeAndNumberParam item : timeAndNumber) {
if (item.getNumber() == null || item.getNumber() < 0) {
item.setNumber(0);
}
if (item.getBeginTime() == null || item.getEndTime() == null) {
item.setBeginTime(null);
item.setEndTime(null);
}
}
//将时间和距离都设为-1
ruleParam.setDuration(-1);
ruleParam.setDistance(-1);
ArrayList<TimeAndUserParam> list = new ArrayList<>();
ruleParam.setTimeAndUser(list);
return Result.ok();
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.check.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.check.IParamInitStrategy;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.app.param.location.rule.TimeAndUserParam;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
/**
* @author tml
* @version 1.0
* @date 2022/4/29 9:32
*/
@Component
public class NotAllowLeaveStrategy implements IParamInitStrategy<LocationFenceRuleAddParam> {
public NotAllowLeaveStrategy() {
Integer relevanceParam = RelevanceParamEnum.NOT_ALLOW_LEAVE.getCode();
LocationFenceRuleContext.register(relevanceParam, this);
}
@Override
public Result<String> paramInit(LocationFenceRuleAddParam param) {
RuleParam ruleParam = param.getRuleParam();
List<TimeAndUserParam> timeAndUser = ruleParam.getTimeAndUser();
if (CollectionUtils.isEmpty(timeAndUser)) {
return Result.no(Status.EXPECTATION_FAILED, "请至少配置一条不允许离开人员的规则");
}
for (TimeAndUserParam item : timeAndUser) {
if (CollectionUtils.isEmpty(item.getUser())) {
return Result.no(Status.EXPECTATION_FAILED, "请至少配置一个不允许离开的人员");
}
}
ruleParam.setDuration(-1);
ruleParam.setDistance(-1);
ruleParam.setTimeAndNumber(new ArrayList<>());
return Result.ok();
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.check.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.check.IParamInitStrategy;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import java.util.ArrayList;
import org.springframework.stereotype.Component;
/**
* @author tml
* @version 1.0
* @date 2022/4/29 9:33
*/
@Component
public class RetentionDurationStrategy implements IParamInitStrategy<LocationFenceRuleAddParam> {
public RetentionDurationStrategy() {
Integer relevanceParam = RelevanceParamEnum.RETENTION_DURATION.getCode();
LocationFenceRuleContext.register(relevanceParam, this);
}
@Override
public Result<String> paramInit(LocationFenceRuleAddParam param) {
RuleParam ruleParam = param.getRuleParam();
if (ruleParam.getDuration() == null || ruleParam.getDuration() < 0) {
return Result.no(Status.EXPECTATION_FAILED, "滞留时长异常");
}
ruleParam.setDistance(-1);
ruleParam.setTimeAndUser(new ArrayList<>());
ruleParam.setTimeAndNumber(new ArrayList<>());
return Result.ok();
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.check.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.check.IParamInitStrategy;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import java.util.ArrayList;
import org.springframework.stereotype.Component;
/**
* @author tml
* @version 1.0
* @date 2022/4/29 9:32
*/
@Component
public class StaticDurationStrategy implements IParamInitStrategy<LocationFenceRuleAddParam> {
public StaticDurationStrategy() {
Integer relevanceParam = RelevanceParamEnum.STATIC_DURATION.getCode();
LocationFenceRuleContext.register(relevanceParam, this);
}
@Override
public Result<String> paramInit(LocationFenceRuleAddParam param) {
RuleParam ruleParam = param.getRuleParam();
if (ruleParam.getDuration() == null || ruleParam.getDuration() < 0) {
return Result.no(Status.EXPECTATION_FAILED, "静止时长异常");
}
ruleParam.setDistance(-1);
ruleParam.setTimeAndUser(new ArrayList<>());
ruleParam.setTimeAndNumber(new ArrayList<>());
return Result.ok();
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.check.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.check.IParamInitStrategy;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import java.util.ArrayList;
import org.springframework.stereotype.Component;
/**
* @author tml
* @version 1.0
* @date 2022/4/29 9:33
*/
@Component
public class TriggerAlarmDistanceStrategy implements IParamInitStrategy<LocationFenceRuleAddParam> {
public TriggerAlarmDistanceStrategy() {
Integer relevanceParam = RelevanceParamEnum.TRIGGER_ALARM_DISTANCE.getCode();
LocationFenceRuleContext.register(relevanceParam, this);
}
@Override
public Result<String> paramInit(LocationFenceRuleAddParam param) {
RuleParam ruleParam = param.getRuleParam();
if (ruleParam.getDistance() == null || ruleParam.getDistance() < 0) {
return Result.no(Status.EXPECTATION_FAILED, "触发报警距离异常");
}
ruleParam.setDuration(-1);
ruleParam.setTimeAndUser(new ArrayList<>());
ruleParam.setTimeAndNumber(new ArrayList<>());
return Result.ok();
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.check;
package com.yiring.app.design.strategy;
import com.yiring.common.core.Result;
......@@ -8,6 +8,7 @@ import com.yiring.common.core.Result;
* @version 1.0
* @date 2022/4/29 9:21
*/
@FunctionalInterface
public interface IParamInitStrategy<T> {
/**
* 校验参数
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.strategy;
import com.yiring.app.param.location.fence.LocationFenceJobParam;
import com.yiring.app.vo.location.fence.LocationFenceJobVo;
/**
* 扫描是否满足报警策略
* @author tml
* @version 1.0
* @date 2022/5/14 11:05
*/
@FunctionalInterface
public interface IScanAlarmStrategy {
/**
* 判断是否触发报警
* @param param 参数
* @return 需要报警的报警信息
*/
LocationFenceJobVo scanAlarm(LocationFenceJobParam param);
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.check.fence;
package com.yiring.app.design.strategy.fence;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.check.IParamInitStrategy;
import com.yiring.app.design.strategy.IParamInitStrategy;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.common.core.Result;
import org.springframework.stereotype.Component;
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.check.fence;
package com.yiring.app.design.strategy.fence;
import com.yiring.app.design.check.IParamInitStrategy;
import com.yiring.app.design.strategy.IParamInitStrategy;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.common.core.Result;
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.check.fence;
package com.yiring.app.design.strategy.fence;
import com.yiring.app.constant.alarm.FenceTypeEnum;
import com.yiring.app.design.check.IParamInitStrategy;
import com.yiring.app.design.strategy.IParamInitStrategy;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.common.core.Result;
import java.util.concurrent.ConcurrentHashMap;
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.strategy.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.strategy.IParamInitStrategy;
import com.yiring.app.design.strategy.IScanAlarmStrategy;
import com.yiring.app.domain.alarm.AlarmType;
import com.yiring.app.domain.location.LocationFence;
import com.yiring.app.domain.location.LocationFenceAlarm;
import com.yiring.app.domain.location.LocationTag;
import com.yiring.app.param.location.fence.LocationFenceJobParam;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.RelevanceUserParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.app.param.location.rule.TimeAndUserParam;
import com.yiring.app.util.TimeUtil;
import com.yiring.app.vo.location.fence.LocationFenceJobVo;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
/**
* 允许进入人员相关策略
* @author tml
* @version 1.0
* @date 2022/4/29 9:32
*/
@Component
public class AllowEntranceStrategy implements IParamInitStrategy<LocationFenceRuleAddParam>, IScanAlarmStrategy {
public AllowEntranceStrategy() {
Integer relevanceParam = RelevanceParamEnum.ALLOW_ENTRANCE.getCode();
LocationFenceRuleContext.register(relevanceParam, this);
}
@Override
public Result<String> paramInit(LocationFenceRuleAddParam param) {
RuleParam ruleParam = param.getRuleParam();
List<TimeAndUserParam> timeAndUser = ruleParam.getTimeAndUser();
if (CollectionUtils.isEmpty(timeAndUser)) {
return Result.no(Status.EXPECTATION_FAILED, "请至少配置一条允许进入人员的规则");
}
for (TimeAndUserParam item : timeAndUser) {
if (CollectionUtils.isEmpty(item.getUser())) {
return Result.no(Status.EXPECTATION_FAILED, "请至少配置一个允许进入的人员");
}
}
ruleParam.setDuration(-1);
ruleParam.setDistance(-1);
ruleParam.setTimeAndNumber(new ArrayList<>());
return Result.ok();
}
@Override
public LocationFenceJobVo scanAlarm(LocationFenceJobParam param) {
RuleParam rule = param.getRule();
Set<LocationTag> tagSet = param.getTagSet();
Long mapId = param.getMapId();
List<LocationFenceAlarm> oldAlarms = param.getOldAlarms();
Long fenceId = param.getFenceId();
Long alarmTypeId = param.getAlarmTypeId();
LocationFenceJobVo jobVo = new LocationFenceJobVo();
List<TimeAndUserParam> timeAndUserParamList = rule.getTimeAndUser();
TimeAndUserParam timeAndUserParam = null;
//筛选在当前时间生效的配置
for (TimeAndUserParam item : timeAndUserParamList) {
if (TimeUtil.judgeTime(LocalDateTime.now(), item.getBeginTime(), item.getEndTime())) {
timeAndUserParam = item;
break;
}
}
//如果不在配置的时间内,则将报警记录中的状态刷新为结束,并且需要添加的报警为空
if (timeAndUserParam == null) {
jobVo.setModifyAlarm(oldAlarms);
return jobVo;
}
//筛选出围栏内允许进入人员之外的人
Set<String> uuids = timeAndUserParam
.getUser()
.stream()
.map(RelevanceUserParam::getUuid)
.collect(Collectors.toSet());
List<LocationFenceAlarm> newAlarms = tagSet
.stream()
.filter(e -> !uuids.contains(e.getUser().getUuid()))
.map(e -> {
LocationFence fence = LocationFence.builder().id(fenceId).build();
AlarmType alarmType = AlarmType.builder().id(alarmTypeId).build();
return LocationFenceAlarm
.builder()
.fence(fence)
.point(e.getPoint())
.areaId(mapId)
.user(e.getUser())
.tag(e)
.startTime(LocalDateTime.now())
.type(alarmType)
.status(LocationFenceAlarm.Status.ING)
.build();
})
.collect(Collectors.toList());
//取两个集合没有相交的部分,newAlarms不重合的部分代表需要添加的报警,oldAlarms不重合的部分代表需要结束的报警
if (!CollectionUtils.isEmpty(oldAlarms)) {
Set<Long> newSet = newAlarms.stream().map(e -> e.getTag().getId()).collect(Collectors.toSet());
Set<Long> oldSet = oldAlarms.stream().map(e -> e.getTag().getId()).collect(Collectors.toSet());
newAlarms =
newAlarms.stream().filter(e -> !oldSet.contains(e.getTag().getId())).collect(Collectors.toList());
oldAlarms =
oldAlarms.stream().filter(e -> !newSet.contains(e.getTag().getId())).collect(Collectors.toList());
}
jobVo.setAddAlarm(newAlarms);
jobVo.setModifyAlarm(oldAlarms);
return jobVo;
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.check.rule;
package com.yiring.app.design.strategy.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.check.IParamInitStrategy;
import com.yiring.app.design.check.fence.LocationFenceTypeContext;
import com.yiring.app.design.strategy.IParamInitStrategy;
import com.yiring.app.design.strategy.fence.LocationFenceTypeContext;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.strategy.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.strategy.IParamInitStrategy;
import com.yiring.app.design.strategy.IScanAlarmStrategy;
import com.yiring.app.domain.alarm.AlarmType;
import com.yiring.app.domain.location.*;
import com.yiring.app.param.location.fence.LocationFenceJobParam;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.app.param.location.rule.TimeAndNumberParam;
import com.yiring.app.param.location.rule.TimeAndUserParam;
import com.yiring.app.util.TimeUtil;
import com.yiring.app.vo.location.fence.LocationFenceJobVo;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
/**
* 最多人数相关策略
* @author tml
* @version 1.0
* @date 2022/4/29 9:28
*/
@Component
public class MaxPeopleNumberStrategy implements IParamInitStrategy<LocationFenceRuleAddParam>, IScanAlarmStrategy {
@Resource
private LocationTurnoverRepository locationTurnoverRepository;
public MaxPeopleNumberStrategy() {
Integer relevanceParam = RelevanceParamEnum.MAX_PEOPLE_NUMBER.getCode();
LocationFenceRuleContext.register(relevanceParam, this);
ScanAlarmContext.register(relevanceParam, this);
}
@Override
public Result<String> paramInit(LocationFenceRuleAddParam param) {
RuleParam ruleParam = param.getRuleParam();
List<TimeAndNumberParam> timeAndNumber = ruleParam.getTimeAndNumber();
if (CollectionUtils.isEmpty(timeAndNumber)) {
return Result.no(Status.EXPECTATION_FAILED, "请至少配置一条最多人数的规则");
}
for (TimeAndNumberParam item : timeAndNumber) {
if (item.getNumber() == null || item.getNumber() < 0) {
item.setNumber(0);
}
if (item.getBeginTime() == null || item.getEndTime() == null) {
item.setBeginTime(null);
item.setEndTime(null);
}
}
//将时间和距离都设为-1
ruleParam.setDuration(-1);
ruleParam.setDistance(-1);
ArrayList<TimeAndUserParam> list = new ArrayList<>();
ruleParam.setTimeAndUser(list);
return Result.ok();
}
@Override
public LocationFenceJobVo scanAlarm(LocationFenceJobParam param) {
RuleParam rule = param.getRule();
Set<LocationTag> tagSet = param.getTagSet();
Long mapId = param.getMapId();
List<LocationFenceAlarm> oldAlarms = param.getOldAlarms();
Long fenceId = param.getFenceId();
Long alarmTypeId = param.getAlarmTypeId();
LocationFenceJobVo jobVo = new LocationFenceJobVo();
List<TimeAndNumberParam> timeAndNumberParamList = rule.getTimeAndNumber();
TimeAndNumberParam timeAndNumberParam = null;
//筛选在当前时间生效的配置
for (TimeAndNumberParam item : timeAndNumberParamList) {
if (TimeUtil.judgeTime(LocalDateTime.now(), item.getBeginTime(), item.getEndTime())) {
timeAndNumberParam = item;
break;
}
}
//如果现在不在配置的时间内,或围栏中的人少于配置的最大人数,则将报警记录中的状态刷新为结束,并且需要添加的报警为空
if (timeAndNumberParam == null || tagSet.size() <= timeAndNumberParam.getNumber()) {
jobVo.setModifyAlarm(oldAlarms);
return jobVo;
}
//多出的人数
int exceed = tagSet.size() - timeAndNumberParam.getNumber();
List<LocationFenceAlarm> newAlarms = new ArrayList<>();
//查询围栏内人员进入时的信息
String beginTime = timeAndNumberParam.getBeginTime();
String endTime = timeAndNumberParam.getEndTime();
List<LocationTurnover> turnoverList = locationTurnoverRepository.withinFence(fenceId, true);
//筛选出在配置时间段内进入的进出信息
turnoverList =
turnoverList
.stream()
.filter(e -> TimeUtil.judgeTime(e.getTime(), beginTime, endTime))
.sorted(Comparator.comparing(LocationTurnover::getTime).reversed())
.collect(Collectors.toList());
//记录触发报警的信息(例如最大人数是3,那么前三个员工进入的不会记录)
for (int i = 0; i < exceed; i++) {
LocationTurnover turnover = turnoverList.get(i);
LocationFence fence = LocationFence.builder().id(fenceId).build();
AlarmType alarmType = AlarmType.builder().id(alarmTypeId).build();
LocationFenceAlarm locationFenceAlarm = LocationFenceAlarm
.builder()
.fence(fence)
.point(turnover.getTag().getPoint())
.areaId(mapId)
.user(turnover.getTag().getUser())
.tag(turnover.getTag())
.startTime(LocalDateTime.now())
.type(alarmType)
.status(LocationFenceAlarm.Status.ING)
.build();
newAlarms.add(locationFenceAlarm);
}
//取两个集合没有相交的部分,newAlarms不重合的部分代表需要添加的报警,oldAlarms不重合的部分代表需要结束的报警
if (!CollectionUtils.isEmpty(oldAlarms)) {
Set<Long> newSet = newAlarms.stream().map(e -> e.getTag().getId()).collect(Collectors.toSet());
Set<Long> oldSet = oldAlarms.stream().map(e -> e.getTag().getId()).collect(Collectors.toSet());
newAlarms =
newAlarms.stream().filter(e -> !oldSet.contains(e.getTag().getId())).collect(Collectors.toList());
oldAlarms =
oldAlarms.stream().filter(e -> !newSet.contains(e.getTag().getId())).collect(Collectors.toList());
}
jobVo.setAddAlarm(newAlarms);
jobVo.setModifyAlarm(oldAlarms);
return jobVo;
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.check.rule;
package com.yiring.app.design.strategy.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.check.IParamInitStrategy;
import com.yiring.app.design.strategy.IParamInitStrategy;
import com.yiring.app.design.strategy.IScanAlarmStrategy;
import com.yiring.app.domain.alarm.AlarmType;
import com.yiring.app.domain.location.*;
import com.yiring.app.param.location.fence.LocationFenceJobParam;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.app.param.location.rule.TimeAndNumberParam;
import com.yiring.app.param.location.rule.TimeAndUserParam;
import com.yiring.app.util.TimeUtil;
import com.yiring.app.vo.location.fence.LocationFenceJobVo;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
/**
* 最少人数相关策略
* @author tml
* @version 1.0
* @date 2022/4/29 9:31
*/
@Component
public class MinPeopleNumberStrategy implements IParamInitStrategy<LocationFenceRuleAddParam> {
public class MinPeopleNumberStrategy implements IParamInitStrategy<LocationFenceRuleAddParam>, IScanAlarmStrategy {
@Resource
private LocationTurnoverRepository locationTurnoverRepository;
public MinPeopleNumberStrategy() {
Integer relevanceParam = RelevanceParamEnum.MIN_PEOPLE_NUMBER.getCode();
......@@ -50,4 +65,73 @@ public class MinPeopleNumberStrategy implements IParamInitStrategy<LocationFence
ruleParam.setTimeAndUser(list);
return Result.ok();
}
@Override
public LocationFenceJobVo scanAlarm(LocationFenceJobParam param) {
RuleParam rule = param.getRule();
Set<LocationTag> tagSet = param.getTagSet();
Long mapId = param.getMapId();
List<LocationFenceAlarm> oldAlarms = param.getOldAlarms();
Long fenceId = param.getFenceId();
Long alarmTypeId = param.getAlarmTypeId();
LocationFenceJobVo jobVo = new LocationFenceJobVo();
List<TimeAndNumberParam> timeAndNumberParamList = rule.getTimeAndNumber();
TimeAndNumberParam timeAndNumberParam = null;
//筛选在当前时间生效的配置
for (TimeAndNumberParam item : timeAndNumberParamList) {
if (TimeUtil.judgeTime(LocalDateTime.now(), item.getBeginTime(), item.getEndTime())) {
timeAndNumberParam = item;
break;
}
}
//如果现在不在配置的时间内,或围栏中的人大于配置的最小人数,则将报警记录中的状态刷新为结束,并且需要添加的报警为空
if (timeAndNumberParam == null || param.getTagSet().size() >= timeAndNumberParam.getNumber()) {
jobVo.setModifyAlarm(oldAlarms);
return jobVo;
}
//少的人数
int missing = timeAndNumberParam.getNumber() - tagSet.size();
List<LocationFenceAlarm> newAlarms = new ArrayList<>();
//查询出这个围栏的信息
String beginTime = timeAndNumberParam.getBeginTime();
String endTime = timeAndNumberParam.getEndTime();
List<LocationTurnover> turnoverList = locationTurnoverRepository.withinFence(fenceId, false);
//筛选出在配置时间段内出这个围栏的进出信息
turnoverList =
turnoverList
.stream()
.filter(e -> TimeUtil.judgeTime(e.getTime(), beginTime, endTime))
.sorted(Comparator.comparing(LocationTurnover::getTime).reversed())
.collect(Collectors.toList());
//记录触发报警的信息(例如最小人数是3,这段时间一开始有6个人在围栏,然后出去的4个,那么只有第四个人出去才会记录)
for (int i = 0; i < missing; i++) {
LocationTurnover turnover = turnoverList.get(i);
LocationFence fence = LocationFence.builder().id(fenceId).build();
AlarmType alarmType = AlarmType.builder().id(alarmTypeId).build();
LocationFenceAlarm locationFenceAlarm = LocationFenceAlarm
.builder()
.fence(fence)
.point(turnover.getTag().getPoint())
.areaId(mapId)
.user(turnover.getTag().getUser())
.tag(turnover.getTag())
.startTime(LocalDateTime.now())
.type(alarmType)
.status(LocationFenceAlarm.Status.ING)
.build();
newAlarms.add(locationFenceAlarm);
}
//取两个集合没有相交的部分,newAlarms不重合的部分代表需要添加的报警,oldAlarms不重合的部分代表需要结束的报警
if (!CollectionUtils.isEmpty(oldAlarms)) {
Set<Long> newSet = newAlarms.stream().map(e -> e.getTag().getId()).collect(Collectors.toSet());
Set<Long> oldSet = oldAlarms.stream().map(e -> e.getTag().getId()).collect(Collectors.toSet());
newAlarms =
newAlarms.stream().filter(e -> !oldSet.contains(e.getTag().getId())).collect(Collectors.toList());
oldAlarms =
oldAlarms.stream().filter(e -> !newSet.contains(e.getTag().getId())).collect(Collectors.toList());
}
jobVo.setAddAlarm(newAlarms);
jobVo.setModifyAlarm(oldAlarms);
return jobVo;
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.strategy.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.strategy.IParamInitStrategy;
import com.yiring.app.design.strategy.IScanAlarmStrategy;
import com.yiring.app.domain.alarm.AlarmType;
import com.yiring.app.domain.location.*;
import com.yiring.app.param.location.fence.LocationFenceJobParam;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.RelevanceUserParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.app.param.location.rule.TimeAndUserParam;
import com.yiring.app.util.TimeUtil;
import com.yiring.app.vo.location.fence.LocationFenceJobVo;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
/**
* 不允许离开人员相关策略
* @author tml
* @version 1.0
* @date 2022/4/29 9:32
*/
@Component
public class NotAllowLeaveStrategy implements IParamInitStrategy<LocationFenceRuleAddParam>, IScanAlarmStrategy {
@Resource
private LocationTurnoverRepository locationTurnoverRepository;
public NotAllowLeaveStrategy() {
Integer relevanceParam = RelevanceParamEnum.NOT_ALLOW_LEAVE.getCode();
LocationFenceRuleContext.register(relevanceParam, this);
}
@Override
public Result<String> paramInit(LocationFenceRuleAddParam param) {
RuleParam ruleParam = param.getRuleParam();
List<TimeAndUserParam> timeAndUser = ruleParam.getTimeAndUser();
if (CollectionUtils.isEmpty(timeAndUser)) {
return Result.no(Status.EXPECTATION_FAILED, "请至少配置一条不允许离开人员的规则");
}
for (TimeAndUserParam item : timeAndUser) {
if (CollectionUtils.isEmpty(item.getUser())) {
return Result.no(Status.EXPECTATION_FAILED, "请至少配置一个不允许离开的人员");
}
}
ruleParam.setDuration(-1);
ruleParam.setDistance(-1);
ruleParam.setTimeAndNumber(new ArrayList<>());
return Result.ok();
}
@Override
public LocationFenceJobVo scanAlarm(LocationFenceJobParam param) {
RuleParam rule = param.getRule();
Set<LocationTag> tagSet = param.getTagSet();
Long mapId = param.getMapId();
List<LocationFenceAlarm> oldAlarms = param.getOldAlarms();
Long fenceId = param.getFenceId();
Long alarmTypeId = param.getAlarmTypeId();
LocationFenceJobVo jobVo = new LocationFenceJobVo();
List<TimeAndUserParam> timeAndUserParamList = rule.getTimeAndUser();
TimeAndUserParam timeAndUserParam = null;
//筛选在当前时间生效的配置
for (TimeAndUserParam item : timeAndUserParamList) {
if (TimeUtil.judgeTime(LocalDateTime.now(), item.getBeginTime(), item.getEndTime())) {
timeAndUserParam = item;
break;
}
}
//如果不在配置的时间内,则将报警记录中的状态刷新为结束,并且需要添加的报警为空
if (timeAndUserParam == null) {
jobVo.setModifyAlarm(oldAlarms);
return jobVo;
}
String beginTime = timeAndUserParam.getBeginTime();
String endTime = timeAndUserParam.getEndTime();
//筛选出在配置时间段内出这个围栏的进出信息
List<LocationTurnover> turnoverList = locationTurnoverRepository.withinFence(fenceId, false);
//筛选出在配置时间段内出这个围栏的进出信息
turnoverList =
turnoverList
.stream()
.filter(e -> TimeUtil.judgeTime(e.getTime(), beginTime, endTime))
.sorted(Comparator.comparing(LocationTurnover::getTime).reversed())
.collect(Collectors.toList());
//筛选出离开围栏的人员是不允许离开的人员
Set<String> uuids = timeAndUserParam
.getUser()
.stream()
.map(RelevanceUserParam::getUuid)
.collect(Collectors.toSet());
List<LocationFenceAlarm> newAlarms = turnoverList
.stream()
.filter(e -> uuids.contains(e.getTag().getUser().getUuid()))
.map(e -> {
LocationFence fence = LocationFence.builder().id(fenceId).build();
AlarmType alarmType = AlarmType.builder().id(alarmTypeId).build();
return LocationFenceAlarm
.builder()
.fence(fence)
.point(e.getTag().getPoint())
.areaId(mapId)
.user(e.getTag().getUser())
.tag(e.getTag())
.startTime(LocalDateTime.now())
.type(alarmType)
.status(LocationFenceAlarm.Status.ING)
.build();
})
.collect(Collectors.toList());
//取两个集合没有相交的部分,newAlarms不重合的部分代表需要添加的报警,oldAlarms不重合的部分代表需要结束的报警
if (!CollectionUtils.isEmpty(oldAlarms)) {
Set<Long> newSet = newAlarms.stream().map(e -> e.getTag().getId()).collect(Collectors.toSet());
Set<Long> oldSet = oldAlarms.stream().map(e -> e.getTag().getId()).collect(Collectors.toSet());
newAlarms =
newAlarms.stream().filter(e -> !oldSet.contains(e.getTag().getId())).collect(Collectors.toList());
oldAlarms =
oldAlarms.stream().filter(e -> !newSet.contains(e.getTag().getId())).collect(Collectors.toList());
}
jobVo.setAddAlarm(newAlarms);
jobVo.setModifyAlarm(oldAlarms);
return jobVo;
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.strategy.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.strategy.IParamInitStrategy;
import com.yiring.app.design.strategy.IScanAlarmStrategy;
import com.yiring.app.domain.alarm.AlarmType;
import com.yiring.app.domain.location.*;
import com.yiring.app.param.location.fence.LocationFenceJobParam;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.app.vo.location.fence.LocationFenceJobVo;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
/**
* 滞留时长相关策略
* @author tml
* @version 1.0
* @date 2022/4/29 9:33
*/
@Component
public class RetentionDurationStrategy implements IParamInitStrategy<LocationFenceRuleAddParam>, IScanAlarmStrategy {
@Resource
private LocationTurnoverRepository locationTurnoverRepository;
public RetentionDurationStrategy() {
Integer relevanceParam = RelevanceParamEnum.RETENTION_DURATION.getCode();
LocationFenceRuleContext.register(relevanceParam, this);
}
@Override
public Result<String> paramInit(LocationFenceRuleAddParam param) {
RuleParam ruleParam = param.getRuleParam();
if (ruleParam.getDuration() == null || ruleParam.getDuration() < 0) {
return Result.no(Status.EXPECTATION_FAILED, "滞留时长异常");
}
ruleParam.setDistance(-1);
ruleParam.setTimeAndUser(new ArrayList<>());
ruleParam.setTimeAndNumber(new ArrayList<>());
return Result.ok();
}
@Override
public LocationFenceJobVo scanAlarm(LocationFenceJobParam param) {
RuleParam rule = param.getRule();
Set<LocationTag> tagSet = param.getTagSet();
Long mapId = param.getMapId();
List<LocationFenceAlarm> oldAlarms = param.getOldAlarms();
Long fenceId = param.getFenceId();
Long alarmTypeId = param.getAlarmTypeId();
LocationFenceJobVo jobVo = new LocationFenceJobVo();
//查询出最新进入该围栏的标签,计算从进入到现在滞留了多长时间,筛选出超过配置的滞留时长的人员
List<LocationTurnover> turnoverList = locationTurnoverRepository.withinFence(fenceId, true);
LocalDateTime time = LocalDateTime.now().minusMinutes(rule.getDuration());
List<LocationFenceAlarm> newAlarms = turnoverList
.stream()
.filter(e -> e.getTime().isBefore(time))
.map(e -> {
LocationFence fence = LocationFence.builder().id(fenceId).build();
AlarmType alarmType = AlarmType.builder().id(alarmTypeId).build();
return LocationFenceAlarm
.builder()
.fence(fence)
.point(e.getTag().getPoint())
.areaId(mapId)
.user(e.getTag().getUser())
.tag(e.getTag())
.startTime(LocalDateTime.now())
.type(alarmType)
.status(LocationFenceAlarm.Status.ING)
.build();
})
.collect(Collectors.toList());
//取两个集合没有相交的部分,newAlarms不重合的部分代表需要添加的报警,oldAlarms不重合的部分代表需要结束的报警
if (!CollectionUtils.isEmpty(oldAlarms)) {
Set<Long> newSet = newAlarms.stream().map(e -> e.getTag().getId()).collect(Collectors.toSet());
Set<Long> oldSet = oldAlarms.stream().map(e -> e.getTag().getId()).collect(Collectors.toSet());
newAlarms =
newAlarms.stream().filter(e -> !oldSet.contains(e.getTag().getId())).collect(Collectors.toList());
oldAlarms =
oldAlarms.stream().filter(e -> !newSet.contains(e.getTag().getId())).collect(Collectors.toList());
}
jobVo.setAddAlarm(newAlarms);
jobVo.setModifyAlarm(oldAlarms);
return jobVo;
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.strategy.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.strategy.IScanAlarmStrategy;
import com.yiring.app.param.location.fence.LocationFenceJobParam;
import com.yiring.app.vo.location.fence.LocationFenceJobVo;
import java.util.concurrent.ConcurrentHashMap;
import lombok.extern.slf4j.Slf4j;
/**
* @author tml
* @version 1.0
* @date 2022/5/14 17:51
*/
@Slf4j
public class ScanAlarmContext {
private static final ConcurrentHashMap<Integer, IScanAlarmStrategy> MAP = new ConcurrentHashMap<>(10);
public static void register(Integer relevanceParam, IScanAlarmStrategy strategy) {
MAP.put(relevanceParam, strategy);
}
public static LocationFenceJobVo scanAlarm(Integer relevanceParam, LocationFenceJobParam param) {
if (
relevanceParam == null || relevanceParam > RelevanceParamEnum.MAX || relevanceParam < RelevanceParamEnum.MIN
) {
log.warn("ScanAlarmContext.scanAlarm报警类型的关联参数异常, relevanceParam:[{}]", relevanceParam);
throw new RuntimeException("报警类型的关联参数异常");
}
IScanAlarmStrategy strategy = MAP.get(relevanceParam);
return strategy.scanAlarm(param);
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.strategy.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.strategy.IParamInitStrategy;
import com.yiring.app.design.strategy.IScanAlarmStrategy;
import com.yiring.app.domain.alarm.AlarmType;
import com.yiring.app.domain.location.LocationFence;
import com.yiring.app.domain.location.LocationFenceAlarm;
import com.yiring.app.domain.location.LocationTag;
import com.yiring.app.param.location.fence.LocationFenceJobParam;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.app.vo.location.fence.LocationFenceJobVo;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
/**
* 静止时长相关策略
* @author tml
* @version 1.0
* @date 2022/4/29 9:32
*/
@Component
public class StaticDurationStrategy implements IParamInitStrategy<LocationFenceRuleAddParam>, IScanAlarmStrategy {
public StaticDurationStrategy() {
Integer relevanceParam = RelevanceParamEnum.STATIC_DURATION.getCode();
LocationFenceRuleContext.register(relevanceParam, this);
}
@Override
public Result<String> paramInit(LocationFenceRuleAddParam param) {
RuleParam ruleParam = param.getRuleParam();
if (ruleParam.getDuration() == null || ruleParam.getDuration() < 0) {
return Result.no(Status.EXPECTATION_FAILED, "静止时长异常");
}
ruleParam.setDistance(-1);
ruleParam.setTimeAndUser(new ArrayList<>());
ruleParam.setTimeAndNumber(new ArrayList<>());
return Result.ok();
}
@Override
public LocationFenceJobVo scanAlarm(LocationFenceJobParam param) {
RuleParam rule = param.getRule();
Set<LocationTag> tagSet = param.getTagSet();
Long mapId = param.getMapId();
List<LocationFenceAlarm> oldAlarms = param.getOldAlarms();
Long fenceId = param.getFenceId();
Long alarmTypeId = param.getAlarmTypeId();
LocationFenceJobVo jobVo = new LocationFenceJobVo();
//筛选出围栏中静止的,并且静止时长超过配置规则时长的标签
LocalDateTime time = LocalDateTime.now().minusMinutes(rule.getDuration());
List<LocationFenceAlarm> newAlarms = tagSet
.stream()
.filter(LocationTag::getSilent)
.filter(e -> e.getTime().isBefore(time))
.map(e -> {
LocationFence fence = LocationFence.builder().id(fenceId).build();
AlarmType alarmType = AlarmType.builder().id(alarmTypeId).build();
return LocationFenceAlarm
.builder()
.fence(fence)
.point(e.getPoint())
.areaId(mapId)
.user(e.getUser())
.tag(e)
.startTime(LocalDateTime.now())
.type(alarmType)
.status(LocationFenceAlarm.Status.ING)
.build();
})
.collect(Collectors.toList());
//取两个集合没有相交的部分,newAlarms不重合的部分代表需要添加的报警,oldAlarms不重合的部分代表需要结束的报警
if (!CollectionUtils.isEmpty(oldAlarms)) {
Set<Long> newSet = newAlarms.stream().map(e -> e.getTag().getId()).collect(Collectors.toSet());
Set<Long> oldSet = oldAlarms.stream().map(e -> e.getTag().getId()).collect(Collectors.toSet());
newAlarms =
newAlarms.stream().filter(e -> !oldSet.contains(e.getTag().getId())).collect(Collectors.toList());
oldAlarms =
oldAlarms.stream().filter(e -> !newSet.contains(e.getTag().getId())).collect(Collectors.toList());
}
jobVo.setAddAlarm(newAlarms);
jobVo.setModifyAlarm(oldAlarms);
return jobVo;
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.design.strategy.rule;
import com.yiring.app.constant.alarm.RelevanceParamEnum;
import com.yiring.app.design.strategy.IParamInitStrategy;
import com.yiring.app.design.strategy.IScanAlarmStrategy;
import com.yiring.app.domain.alarm.AlarmType;
import com.yiring.app.domain.location.LocationFence;
import com.yiring.app.domain.location.LocationFenceAlarm;
import com.yiring.app.domain.location.LocationTag;
import com.yiring.app.domain.location.LocationTagRepository;
import com.yiring.app.param.location.fence.LocationFenceJobParam;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.app.vo.location.fence.LocationFenceJobVo;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.locationtech.jts.geom.Geometry;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
/**
* 触发报警距离相关策略
* @author tml
* @version 1.0
* @date 2022/4/29 9:33
*/
@Component
public class TriggerAlarmDistanceStrategy implements IParamInitStrategy<LocationFenceRuleAddParam>, IScanAlarmStrategy {
@Resource
private LocationTagRepository locationTagRepository;
public TriggerAlarmDistanceStrategy() {
Integer relevanceParam = RelevanceParamEnum.TRIGGER_ALARM_DISTANCE.getCode();
LocationFenceRuleContext.register(relevanceParam, this);
}
@Override
public Result<String> paramInit(LocationFenceRuleAddParam param) {
RuleParam ruleParam = param.getRuleParam();
if (ruleParam.getDistance() == null || ruleParam.getDistance() < 0) {
return Result.no(Status.EXPECTATION_FAILED, "触发报警距离异常");
}
ruleParam.setDuration(-1);
ruleParam.setTimeAndUser(new ArrayList<>());
ruleParam.setTimeAndNumber(new ArrayList<>());
return Result.ok();
}
@Override
public LocationFenceJobVo scanAlarm(LocationFenceJobParam param) {
RuleParam rule = param.getRule();
Set<LocationTag> tagSet = param.getTagSet();
Long mapId = param.getMapId();
List<LocationFenceAlarm> oldAlarms = param.getOldAlarms();
Long fenceId = param.getFenceId();
Long alarmTypeId = param.getAlarmTypeId();
Geometry geometry = param.getGeometry();
LocationFenceJobVo jobVo = new LocationFenceJobVo();
//查询出距离围栏规则之类距离的所有标签,封装成报警信息
List<LocationTag> locationTags = locationTagRepository.findByDistance(geometry, rule.getDistance());
List<LocationFenceAlarm> newAlarms = locationTags
.stream()
.map(e -> {
LocationFence fence = LocationFence.builder().id(fenceId).build();
AlarmType alarmType = AlarmType.builder().id(alarmTypeId).build();
return LocationFenceAlarm
.builder()
.fence(fence)
.point(e.getPoint())
.areaId(mapId)
.user(e.getUser())
.tag(e)
.startTime(LocalDateTime.now())
.type(alarmType)
.status(LocationFenceAlarm.Status.ING)
.build();
})
.collect(Collectors.toList());
//取两个集合没有相交的部分,newAlarms不重合的部分代表需要添加的报警,oldAlarms不重合的部分代表需要结束的报警
if (!CollectionUtils.isEmpty(oldAlarms)) {
Set<Long> newSet = newAlarms.stream().map(e -> e.getTag().getId()).collect(Collectors.toSet());
Set<Long> oldSet = oldAlarms.stream().map(e -> e.getTag().getId()).collect(Collectors.toSet());
newAlarms =
newAlarms.stream().filter(e -> !oldSet.contains(e.getTag().getId())).collect(Collectors.toList());
oldAlarms =
oldAlarms.stream().filter(e -> !newSet.contains(e.getTag().getId())).collect(Collectors.toList());
}
jobVo.setAddAlarm(newAlarms);
jobVo.setModifyAlarm(oldAlarms);
return jobVo;
}
}
......@@ -88,5 +88,9 @@ public class LocationFenceAlarm extends BasicEntity implements Serializable {
public String text() {
return this.text;
}
public static Status get(boolean flag) {
return flag ? ING : OVER;
}
}
}
......@@ -2,8 +2,13 @@
package com.yiring.app.domain.location;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
/**
......@@ -14,4 +19,22 @@ import org.springframework.stereotype.Repository;
@Repository
public interface LocationFenceAlarmRepository
extends JpaRepository<LocationFenceAlarm, Serializable>, JpaSpecificationExecutor<LocationFenceAlarm> {}
extends JpaRepository<LocationFenceAlarm, Serializable>, JpaSpecificationExecutor<LocationFenceAlarm> {
/**
* 批量关闭报警状态
* @param ids id集
* @param now 当前时间
* @return 修改量
*/
@Query("UPDATE LocationFenceAlarm SET status = 'OVER', updateTime = :now, endTime = :now WHERE id IN(:ids)")
@Modifying
int batchOver(@Param("ids") List<Long> ids, @Param("now") LocalDateTime now);
/**
* 根据状态查询
* @param status 状态
* @return 报警信息
*/
@Query("SELECT l FROM LocationFenceAlarm l WHERE l.status = ?1")
List<LocationFenceAlarm> findAllByStatus(LocationFenceAlarm.Status status);
}
......@@ -40,6 +40,14 @@ public interface LocationFenceRepository
List<LocationFence> findLikeName(String name);
/**
* 根据启用条件查询电子围栏
* @param enable 是否启用
* @return 单子围栏信息
*/
@Query("SELECT f FROM LocationFence f WHERE f.enable = ?1 AND deleted = false")
List<LocationFence> findAllByEnable(boolean enable);
/**
* 查询空间信息在围栏内的围栏信息
* @param areaId 地图区域 id
* @param geometry 空间信息
......
......@@ -7,6 +7,8 @@ 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 java.util.Objects;
import javax.persistence.*;
import lombok.*;
import lombok.experimental.FieldDefaults;
......@@ -112,6 +114,9 @@ public class LocationTag extends BasicEntity implements Serializable {
@Comment("是否在厂外")
Boolean out;
@Comment("静止/运动变更时间")
LocalDateTime time;
@SuppressWarnings({ "unused" })
public enum Type {
BTT01("蓝牙人员定位卡"),
......@@ -127,4 +132,31 @@ public class LocationTag extends BasicEntity implements Serializable {
return this.text;
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
LocationTag that = (LocationTag) o;
return (
Objects.equals(linkId, that.linkId) &&
Objects.equals(imei, that.imei) &&
Objects.equals(code, that.code) &&
type == that.type &&
Objects.equals(silent, that.silent) &&
Objects.equals(user, that.user) &&
Objects.equals(used, that.used) &&
Objects.equals(volt, that.volt) &&
Objects.equals(voltUnit, that.voltUnit) &&
Objects.equals(category, that.category) &&
Objects.equals(point, that.point) &&
Objects.equals(out, that.out) &&
Objects.equals(time, that.time)
);
}
@Override
public int hashCode() {
return Objects.hash(linkId, imei, code, type, silent, user, used, volt, voltUnit, category, point, out, time);
}
}
......@@ -7,6 +7,7 @@ import org.locationtech.jts.geom.Geometry;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
/**
......@@ -43,4 +44,13 @@ public interface LocationTagRepository
*/
@Query(value = "SELECT * FROM BS_LOCATION_TAG WHERE user_id IN (?1)", nativeQuery = true)
List<LocationTag> findByUserIds(List<Long> userIds);
/**
* 查询距离指定区域多少米的标签
* @param geometry 指定区域
* @param distance 距离(米)
* @return 定位标签
*/
@Query(value = "SELECT * FROM BS_LOCATION_TAG WHERE st_distance(point, :geometry) < :distance", nativeQuery = true)
List<LocationTag> findByDistance(@Param("geometry") Geometry geometry, @Param("distance") Integer distance);
}
......@@ -2,8 +2,10 @@
package com.yiring.app.domain.location;
import java.io.Serializable;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
/**
......@@ -14,4 +16,15 @@ import org.springframework.stereotype.Repository;
@Repository
public interface LocationTurnoverRepository
extends JpaRepository<LocationTurnover, Serializable>, JpaSpecificationExecutor<LocationTurnover> {}
extends JpaRepository<LocationTurnover, Serializable>, JpaSpecificationExecutor<LocationTurnover> {
/**
* 查询进入围栏状态为最新的所有
* @param fenceId 围栏id
* @param enter 是否是进入
* @return 所有信息
*/
@Query(
"SELECT l FROM LocationTurnover l WHERE l.sourceId = ?1 AND l.type = 'FENCE' AND l.enter = ?2 AND l.isLatest = true"
)
List<LocationTurnover> withinFence(Long fenceId, Boolean enter);
}
......@@ -49,7 +49,7 @@ public interface EvacuationZoneRepository
* @param name 名称
* @return 撤离区列表
*/
@Query("SELECT e FROM EvacuationZone e WHERE e.deleted = false AND e.name like %?1%")
@Query("SELECT e FROM EvacuationZone e WHERE e.deleted = false AND e.enable = true AND e.name like %?1%")
List<EvacuationZone> findLikeName(String name);
/**
......
......@@ -63,9 +63,6 @@ public class RehearsalPlan extends BasicEntity implements Serializable {
@Comment("演练时间")
private LocalDateTime rehearsalTime;
@Comment("推送信息")
private String pushMsg;
@Comment("演练计划的状态(1:未启动, 2:进行中, 3:已结束)")
private Integer status;
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.excel.location.fence;
import com.github.liaochong.myexcel.core.annotation.ExcelColumn;
import com.github.liaochong.myexcel.core.annotation.ExcelModel;
import com.yiring.app.constant.alarm.FenceTypeEnum;
import com.yiring.app.domain.location.LocationFenceAlarm;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author tml
* @version 1.0
* @date 2022/5/17 17:23
*/
@ExcelModel
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class FenceAlarmExcel implements Serializable {
@Serial
private static final long serialVersionUID = 4526095986813965381L;
@ExcelColumn(title = "地图名称")
private String mapName;
@ExcelColumn(title = "围栏名称")
private String fenceName;
@ExcelColumn(title = "围栏类别")
private String fenceTypeName;
@ExcelColumn(title = "报警人员")
private String realName;
@ExcelColumn(title = "标签号")
private String tagId;
@ExcelColumn(title = "报警开始时间")
private LocalDateTime startTime;
@ExcelColumn(title = "报警结束时间")
private LocalDateTime endTime;
@ExcelColumn(title = "报警类型")
private String alarmTypeName;
@ExcelColumn(title = "接收人")
private String recipient;
@ExcelColumn(title = "报警状态")
private String statusName;
public static FenceAlarmExcel transform(LocationFenceAlarm fenceAlarm) {
return FenceAlarmExcel
.builder()
.fenceName(fenceAlarm.getFence().getName())
.fenceTypeName(FenceTypeEnum.getByCode(fenceAlarm.getFence().getFenceType()))
.realName(fenceAlarm.getUser().getRealName())
.tagId(fenceAlarm.getTag().getCode())
.startTime(fenceAlarm.getStartTime())
.endTime(fenceAlarm.getEndTime())
.alarmTypeName(fenceAlarm.getType().getName())
//todo
//.recipient()
.statusName(fenceAlarm.getStatus().text())
.build();
}
}
......@@ -29,31 +29,28 @@ public class RehearsalPlanExcel implements Serializable {
@Serial
private static final long serialVersionUID = -2976618459214077036L;
@ExcelColumn(title = "演练主题")
@ExcelColumn(title = "演练主题", width = 10)
private String topical;
@ExcelColumn(title = "事故点")
@ExcelColumn(title = "事故点", width = 10)
private String accidentSpotName;
@ExcelColumn(title = "周边范围(m)")
@ExcelColumn(title = "周边范围(m)", width = 10)
private Integer scope;
@ExcelColumn(title = "撤离点")
@ExcelColumn(title = "撤离点", width = 10)
private String evacuationZoneName;
@ExcelColumn(title = "风险程度")
@ExcelColumn(title = "风险程度", width = 10)
private String riskLevelName;
@ExcelColumn(title = "事故信息")
@ExcelColumn(title = "事故信息", width = 10)
private String accidentMsg;
@ExcelColumn(title = "演练时间")
@ExcelColumn(title = "演练时间", width = 20)
private LocalDateTime rehearsalTime;
@ExcelColumn(title = "推送信息")
private String pushMsg;
@ExcelColumn(title = "状态")
@ExcelColumn(title = "状态", width = 10)
private String statusName;
public static RehearsalPlanExcel transform(RehearsalPlan rehearsalPlan) {
......@@ -66,7 +63,6 @@ public class RehearsalPlanExcel implements Serializable {
.riskLevelName(RiskLevelEnum.getByCode(rehearsalPlan.getRiskLevel()))
.accidentMsg(rehearsalPlan.getAccidentMsg())
.rehearsalTime(rehearsalPlan.getRehearsalTime())
.pushMsg(rehearsalPlan.getPushMsg())
.statusName(RehearsalPlanStatusEnum.getByCode(rehearsalPlan.getStatus()))
.build();
}
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.job;
import com.alibaba.fastjson.JSON;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.yiring.app.design.strategy.rule.ScanAlarmContext;
import com.yiring.app.domain.location.*;
import com.yiring.app.param.location.fence.LocationFenceJobParam;
import com.yiring.app.param.location.rule.RuleParam;
import com.yiring.app.vo.location.fence.LocationFenceJobVo;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
/**
* @author tml
* @version 1.0
* @date 2022/5/14 10:10
*/
@Slf4j
@Component
public class FenceAlarmJob {
@Resource
private LocationFenceRepository locationFenceRepository;
@Resource
private LocationFenceAlarmRepository locationFenceAlarmRepository;
@XxlJob("ScanAlarmHandler")
@Transactional(rollbackFor = Exception.class)
public void scanAlarmHandler() {
//查询出所有已启用的电子围栏信息和正在报警的报警信息
List<LocationFence> fenceList = locationFenceRepository.findAllByEnable(true);
List<LocationFenceAlarm> alarmList = locationFenceAlarmRepository.findAllByStatus(
LocationFenceAlarm.Status.ING
);
Map<Long, List<LocationFenceAlarm>> alarmMap = alarmList
.stream()
.collect(Collectors.groupingBy(e -> e.getFence().getId()));
LocationFenceJobVo jobVo = LocationFenceJobVo
.builder()
.addAlarm(new ArrayList<>())
.modifyAlarm(new ArrayList<>())
.build();
for (LocationFence fence : fenceList) {
//获取该围栏下的所有报警规则
Set<LocationFenceRule> fenceRuleSet = fence.getRules();
for (LocationFenceRule fenceRule : fenceRuleSet) {
RuleParam ruleParam = JSON.parseObject(fenceRule.getRule(), RuleParam.class);
List<LocationFenceAlarm> oldAlarms = alarmMap.get(fence.getId());
LocationFenceJobParam fenceJobParam = LocationFenceJobParam
.builder()
.rule(ruleParam)
.fenceId(fence.getId())
.alarmTypeId(fenceRule.getAlarmType().getId())
.tagSet(fence.getTags())
.mapId(fence.getMapId())
.geometry(fence.getGeometry())
.oldAlarms(oldAlarms)
.build();
LocationFenceJobVo locationFenceJobVo = ScanAlarmContext.scanAlarm(
fenceRule.getRelevanceParamType(),
fenceJobParam
);
jobVo.merge(locationFenceJobVo);
}
}
//添加报警和关闭报警
locationFenceAlarmRepository.saveAllAndFlush(jobVo.getAddAlarm());
List<Long> ids = jobVo.getModifyAlarm().stream().map(LocationFenceAlarm::getId).collect(Collectors.toList());
locationFenceAlarmRepository.batchOver(ids, LocalDateTime.now());
log.info(
"FenceAlarmJob.scanAlarmHandler: 添加的报警:[{}], 关闭的报警:[{}]",
JSON.toJSONString(jobVo.getAddAlarm()),
JSON.toJSONString(jobVo.getModifyAlarm())
);
}
}
......@@ -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();
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.param.location.fence;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author tml
* @version 1.0
* @date 2022/5/17 14:49
*/
@ApiModel("围栏报警数据管理查询")
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class FenceAlarmConditionParam implements Serializable {
@Serial
private static final long serialVersionUID = -2397459299914947087L;
@ApiModelProperty(value = "地图id", example = "1")
private Long mapId;
@ApiModelProperty(value = "围栏id", example = "1")
private Long fenceId;
@ApiModelProperty(value = "报警人员真名", example = "张三")
private String realName;
@ApiModelProperty(value = "报警状态", example = "true|false")
private Boolean status;
@ApiModelProperty(value = "报警开始时间", example = "2022-05-06 14:00:00")
private LocalDateTime beginTime;
@ApiModelProperty(value = "报警结束时间", example = "2022-05-7 14:00:00")
private LocalDateTime endTime;
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.param.location.fence;
import com.yiring.app.domain.location.LocationFenceAlarm;
import com.yiring.app.domain.location.LocationTag;
import com.yiring.app.param.location.rule.RuleParam;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.locationtech.jts.geom.Geometry;
/**
* 扫描围栏报警的param
* @author tml
* @version 1.0
* @date 2022/5/16 9:23
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class LocationFenceJobParam implements Serializable {
@Serial
private static final long serialVersionUID = -1078898654919721759L;
/**
* 围栏的报警规则
*/
private RuleParam rule;
/**
* 围栏id
*/
private Long fenceId;
/**
* 报警类别id
*/
private Long alarmTypeId;
/**
* 围栏中的定位标签
*/
private Set<LocationTag> tagSet;
/**
* 围栏所属的地图id
*/
private Long mapId;
/**
* 围栏的空间信息
*/
private Geometry geometry;
/**
* 属于该围栏当前正在报警的信息
*/
private List<LocationFenceAlarm> oldAlarms;
}
......@@ -55,10 +55,6 @@ public class RehearsalPlanAddParam implements Serializable {
@NotEmpty(message = "事故信息不能为空")
private String accidentMsg;
@ApiModelProperty(value = "推送信息", example = "气体泄露,请尽快逃离", required = true)
@NotEmpty(message = "推送信息不能为空")
private String pushMsg;
public RehearsalPlan transform() {
AccidentSpot accidentSpot = AccidentSpot.builder().id(accidentSpotId).build();
EvacuationZone evacuationZone = EvacuationZone.builder().id(evacuationZoneId).build();
......@@ -70,7 +66,6 @@ public class RehearsalPlanAddParam implements Serializable {
.evacuationZone(evacuationZone)
.riskLevel(riskLevel)
.accidentMsg(accidentMsg)
.pushMsg(pushMsg)
.status(RehearsalPlanStatusEnum.UN_START.getCode())
.deleted(false)
.build();
......
......@@ -51,9 +51,6 @@ public class RehearsalPlanModifyParam implements Serializable {
@ApiModelProperty(value = "事故信息", example = "气体泄露")
private String accidentMsg;
@ApiModelProperty(value = "推送信息", example = "气体泄露,请尽快逃离")
private String pushMsg;
public RehearsalPlan transform() {
AccidentSpot accidentSpot = AccidentSpot.builder().id(accidentSpotId).build();
EvacuationZone evacuationZone = EvacuationZone.builder().id(evacuationZoneId).build();
......@@ -66,7 +63,6 @@ public class RehearsalPlanModifyParam implements Serializable {
.evacuationZone(evacuationZone)
.riskLevel(riskLevel)
.accidentMsg(accidentMsg)
.pushMsg(pushMsg)
.build();
}
}
......@@ -13,6 +13,7 @@ import lombok.Data;
import lombok.NoArgsConstructor;
/**
*
* @author tml
* @version 1.0
* @date 2022/5/12 11:56
......@@ -21,7 +22,7 @@ import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ApiModel("演练计划查看回放param")
@ApiModel("RehearsalPlanPlaybackParam")
public class RehearsalPlanPlaybackParam implements Serializable {
@Serial
......@@ -31,6 +32,6 @@ public class RehearsalPlanPlaybackParam implements Serializable {
@NotNull(message = "演练计划id不能为空")
private Long id;
@ApiModelProperty(value = "看回放的开始时间(不传则默认演练开始的时间)")
@ApiModelProperty(value = "看回放的开始时间")
private LocalDateTime beginTime;
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.service.analysis.history.impl;
import com.alibaba.fastjson.JSONArray;
import com.github.liaochong.myexcel.core.DefaultStreamExcelBuilder;
import com.yiring.app.constant.RedisKey;
import com.yiring.app.domain.location.LocationLog;
import com.yiring.app.domain.location.LocationLogRepository;
import com.yiring.app.excel.analysis.history.HistoryRouteExcel;
import com.yiring.app.param.analysis.history.HistoryRouteConditionParam;
import com.yiring.app.service.analysis.history.HistoryRouteService;
import com.yiring.app.util.MapUtil;
import com.yiring.app.vo.analysis.history.HistoryRouteVo;
import com.yiring.app.vo.map.MapVo;
import com.yiring.common.core.Redis;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import com.yiring.common.vo.PageVo;
......@@ -45,26 +43,18 @@ public class HistoryRouteServiceImpl implements HistoryRouteService {
private LocationLogRepository locationLogRepository;
@Resource
private Redis redis;
private MapUtil mapUtil;
@Override
public Result<PageVo<HistoryRouteVo>> findByCondition(HistoryRouteConditionParam param) {
Specification<LocationLog> specification = getSpecification(param);
ArrayList<MapVo.MapVoReuslt> list1 = new ArrayList<>();
Object map = redis.get(RedisKey.ZY_MAP_AREAS);
String mapString = JSONArray.toJSONString(map);
List<MapVo.MapVoReuslt> mapVo = JSONArray.parseArray(mapString, MapVo.MapVoReuslt.class);
List<LocationLog> list = locationLogRepository.findAll(specification);
List<HistoryRouteVo> voList = list
.stream()
.map(e -> {
HistoryRouteVo routeVo = HistoryRouteVo.transform(e);
for (MapVo.MapVoReuslt item : mapVo) {
if (item.getId().equals(e.getAreaId().intValue())) {
routeVo.setMapName(item.getName());
break;
}
}
routeVo.setMapName(mapUtil.getMapName(e.getAreaId().intValue()));
return routeVo;
})
.collect(Collectors.toList());
......
......@@ -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;
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.service.location.fence;
import com.yiring.app.param.location.fence.FenceAlarmConditionParam;
import com.yiring.app.vo.IdNameVo;
import com.yiring.app.vo.location.fence.FenceAlarmVo;
import com.yiring.common.core.Result;
import com.yiring.common.param.PageParam;
import com.yiring.common.vo.PageVo;
import javax.servlet.http.HttpServletResponse;
/**
* @author tml
* @version 1.0
* @date 2022/5/17 16:24
*/
public interface FenceAlarmService {
/**
* 查询围栏报警数据列表
* @param param 查询条件
* @param pageParam 分页参数
* @return 报警数据
*/
Result<PageVo<FenceAlarmVo>> findList(FenceAlarmConditionParam param, PageParam pageParam);
/**
* 查询围栏下拉框
* @return 围栏id和名称
*/
Result<PageVo<IdNameVo>> findFenceList();
/**
* 导出围栏报警数据
* @param param 查询条件
*/
void export(FenceAlarmConditionParam param, HttpServletResponse response);
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.service.location.fence.impl;
import com.github.liaochong.myexcel.core.DefaultStreamExcelBuilder;
import com.yiring.app.domain.location.LocationFence;
import com.yiring.app.domain.location.LocationFenceAlarm;
import com.yiring.app.domain.location.LocationFenceAlarmRepository;
import com.yiring.app.domain.location.LocationFenceRepository;
import com.yiring.app.excel.location.fence.FenceAlarmExcel;
import com.yiring.app.param.location.fence.FenceAlarmConditionParam;
import com.yiring.app.service.location.fence.FenceAlarmService;
import com.yiring.app.util.MapUtil;
import com.yiring.app.vo.IdNameVo;
import com.yiring.app.vo.location.fence.FenceAlarmVo;
import com.yiring.auth.domain.user.User;
import com.yiring.common.core.Result;
import com.yiring.common.param.PageParam;
import com.yiring.common.vo.PageVo;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @author tml
* @version 1.0
* @date 2022/5/17 16:27
*/
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class FenceAlarmServiceImpl implements FenceAlarmService {
@Resource
private LocationFenceAlarmRepository locationFenceAlarmRepository;
@Resource
private LocationFenceRepository locationFenceRepository;
@Resource
private MapUtil mapUtil;
@Override
public Result<PageVo<FenceAlarmVo>> findList(FenceAlarmConditionParam param, PageParam pageParam) {
Pageable pageable = PageParam.toPageable(pageParam);
Specification<LocationFenceAlarm> specification = getSpecification(param);
Page<LocationFenceAlarm> page = locationFenceAlarmRepository.findAll(specification, pageable);
List<FenceAlarmVo> voList = page
.get()
.map(e -> {
FenceAlarmVo vo = FenceAlarmVo.transform(e);
vo.setMapName(mapUtil.getMapName(e.getAreaId().intValue()));
return vo;
})
.collect(Collectors.toList());
PageVo<FenceAlarmVo> pageVo = PageVo.build(voList, voList.size());
return Result.ok(pageVo);
}
@Override
public Result<PageVo<IdNameVo>> findFenceList() {
List<LocationFence> list = locationFenceRepository.findAll();
List<IdNameVo> voList = list
.stream()
.map(e -> new IdNameVo(e.getId(), e.getName()))
.collect(Collectors.toList());
PageVo<IdNameVo> pageVo = PageVo.build(voList, voList.size());
return Result.ok(pageVo);
}
@Override
public void export(FenceAlarmConditionParam param, HttpServletResponse response) {
Specification<LocationFenceAlarm> specification = getSpecification(param);
List<LocationFenceAlarm> list = locationFenceAlarmRepository.findAll(specification);
List<FenceAlarmExcel> excelList = list
.stream()
.map(e -> {
FenceAlarmExcel excel = FenceAlarmExcel.transform(e);
excel.setMapName(mapUtil.getMapName(e.getAreaId().intValue()));
return excel;
})
.collect(Collectors.toList());
try (
DefaultStreamExcelBuilder<FenceAlarmExcel> streamExcelBuilder = DefaultStreamExcelBuilder
.of(FenceAlarmExcel.class)
.threadPool(Executors.newFixedThreadPool(2))
.rowHeight(14)
.titleRowHeight(14)
.style(
"cell->vertical-align:center;text-align:center",
"title->vertical-align:center;text-align:center;font-weight:bold;font-family:等线"
)
.start()
) {
streamExcelBuilder.append(excelList);
String fileName = URLEncoder.encode("围栏报警数据列表.xlsx", StandardCharsets.UTF_8);
response.setContentType("application/octet-stream");
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
OutputStream out = response.getOutputStream();
Workbook workbook = streamExcelBuilder.fixedTitles().build();
workbook.write(out);
workbook.close();
out.flush();
out.close();
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new RuntimeException("报警类型列表导出失败: " + e.getMessage());
}
}
private Specification<LocationFenceAlarm> getSpecification(FenceAlarmConditionParam param) {
return (root, query, criteriaBuilder) -> {
ArrayList<Predicate> list = new ArrayList<>();
if (param.getMapId() != null) {
list.add(criteriaBuilder.equal(root.get(LocationFenceAlarm.Fields.areaId), param.getMapId()));
}
if (param.getFenceId() != null) {
LocationFence fence = LocationFence.builder().id(param.getFenceId()).build();
list.add(criteriaBuilder.equal(root.get(LocationFenceAlarm.Fields.fence), fence));
}
if (param.getRealName() != null) {
Join<Object, Object> join = root.join(LocationFenceAlarm.Fields.user, JoinType.LEFT);
list.add(criteriaBuilder.equal(join.get(User.Fields.realName), param.getRealName()));
}
if (param.getStatus() != null) {
list.add(
criteriaBuilder.equal(
root.get(LocationFenceAlarm.Fields.status),
LocationFenceAlarm.Status.get(param.getStatus())
)
);
}
if (param.getBeginTime() != null) {
list.add(
criteriaBuilder.greaterThanOrEqualTo(
root.get(LocationFenceAlarm.Fields.startTime),
param.getBeginTime()
)
);
}
if (param.getEndTime() != null) {
list.add(
criteriaBuilder.lessThanOrEqualTo(root.get(LocationFenceAlarm.Fields.endTime), param.getEndTime())
);
}
Predicate[] array = list.toArray(new Predicate[0]);
return criteriaBuilder.and(array);
};
}
}
......@@ -237,6 +237,7 @@ public class RehearsalPlanServiceImpl implements RehearsalPlanService {
return Result.no(Status.EXPECTATION_FAILED, "演练计划已经启动过了");
}
rehearsalPlan.setStatus(RehearsalPlanStatusEnum.RUNNING.getCode());
rehearsalPlan.setRehearsalTime(LocalDateTime.now());
//事故点信息
AccidentSpot accidentSpot = rehearsalPlan.getAccidentSpot();
Integer scope = rehearsalPlan.getScope();
......
/* (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;
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.util;
import com.alibaba.fastjson.JSONArray;
import com.yiring.app.constant.RedisKey;
import com.yiring.app.vo.map.MapVo;
import com.yiring.common.core.Redis;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
/**
* @author tml
* @version 1.0
* @date 2022/5/17 16:58
*/
@Component
public class MapUtil {
@Resource
private Redis redis;
public String getMapName(Integer mapId) {
Object map = redis.get(RedisKey.ZY_MAP_AREAS);
String mapString = JSONArray.toJSONString(map);
List<MapVo.MapVoReuslt> mapVo = JSONArray.parseArray(mapString, MapVo.MapVoReuslt.class);
for (MapVo.MapVoReuslt item : mapVo) {
if (item.getId().equals(mapId)) {
return item.getName();
}
}
return "未知地图";
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.util;
import com.yiring.common.constant.RegEx;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* @author tml
* @version 1.0
* @date 2022/5/14 14:06
*/
public class TimeUtil {
/**
* 判断一个时间是否在配置的时间内
* @param time 判断的时间
* @param beginTime 配置的开始时间
* @param endTime 配置的结束时间
* @return true:在 false:不在
*/
public static boolean judgeTime(LocalDateTime time, String beginTime, String endTime) {
if (!beginTime.matches(RegEx.TIME_RULE) || !endTime.matches(RegEx.TIME_RULE)) {
throw new IllegalArgumentException("时间格式不正确");
}
DateTimeFormatter pattern = DateTimeFormatter.ofPattern("E HH:mm:ss");
String source = time.format(pattern);
int beginWeek = transform(beginTime.charAt(2));
int endWeek = transform(endTime.charAt(2));
int nowWeek = transform(source.charAt(1));
if (nowWeek < beginWeek || nowWeek > endWeek) {
return false;
}
int beginHour = Integer.parseInt(beginTime.substring(4, 6));
int endHour = Integer.parseInt(endTime.substring(4, 6));
int nowHour = Integer.parseInt(beginTime.substring(3, 5));
if (nowHour < beginHour || nowHour > endHour) {
return false;
}
int beginMinute = Integer.parseInt(beginTime.substring(7, 9));
int endMinute = Integer.parseInt(endTime.substring(7, 9));
int nowMinute = Integer.parseInt(beginTime.substring(6, 8));
if (nowMinute < beginMinute || nowHour > endMinute) {
return false;
}
int beginSecond = Integer.parseInt(beginTime.substring(10));
int endSecond = Integer.parseInt(endTime.substring(10));
int nowSecond = Integer.parseInt(beginTime.substring(9));
if (nowSecond < beginSecond || nowSecond > endSecond) {
return false;
}
return true;
}
private static int transform(char source) {
return switch (source) {
case '一' -> 1;
case '二' -> 2;
case '三' -> 3;
case '四' -> 4;
case '五' -> 5;
case '六' -> 6;
case '日' -> 7;
default -> 1;
};
}
}
......@@ -35,7 +35,7 @@ public class HistoryRouteVo implements Serializable {
@ApiModelProperty(value = "工号", example = "ks2022")
private String uuid;
@ApiModelProperty(value = "经纬度")
@ApiModelProperty(value = "经纬度", dataType = "java.lang.String")
private Point point;
@ApiModelProperty(value = "地图名称", example = "总图")
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.vo.location.fence;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.yiring.app.constant.alarm.FenceTypeEnum;
import com.yiring.app.domain.location.LocationFenceAlarm;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author tml
* @version 1.0
* @date 2022/5/17 15:15
*/
@ApiModel("围栏报警数据管理")
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class FenceAlarmVo implements Serializable {
@Serial
private static final long serialVersionUID = 8259241388552022873L;
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty(value = "id", example = "1")
private Long id;
@ApiModelProperty(value = "地图id", example = "1")
private Long mapId;
@ApiModelProperty(value = "地图名称", example = "总图")
private String mapName;
@ApiModelProperty(value = "围栏名称", example = "一号围栏")
private String fenceName;
@ApiModelProperty(value = "围栏类别code", example = "1")
private Integer fenceType;
@ApiModelProperty(value = "围栏类别名称", example = "普通围栏")
private String fenceTypeName;
@ApiModelProperty(value = "报警人员名称", example = "张三")
private String realName;
@ApiModelProperty(value = "标签号", example = "BTT1")
private String tagId;
@ApiModelProperty(value = "报警开始时间", example = "2022-05-04 13:00:00")
private LocalDateTime startTime;
@ApiModelProperty(value = "报警结束时间", example = "2022-05-04 13:00:00")
private LocalDateTime endTime;
@ApiModelProperty(value = "报警类型", example = "超员报警")
private String alarmTypeName;
@ApiModelProperty(value = "接收人", example = "李四")
private String recipient;
@ApiModelProperty(value = "报警状态", example = "报警中")
private String statusName;
public static FenceAlarmVo transform(LocationFenceAlarm fenceAlarm) {
return FenceAlarmVo
.builder()
.id(fenceAlarm.getId())
.mapId(fenceAlarm.getAreaId())
.fenceName(fenceAlarm.getFence().getName())
.fenceType(fenceAlarm.getFence().getFenceType())
.fenceTypeName(FenceTypeEnum.getByCode(fenceAlarm.getFence().getFenceType()))
.realName(fenceAlarm.getUser().getRealName())
.tagId(fenceAlarm.getTag().getCode())
.startTime(fenceAlarm.getStartTime())
.endTime(fenceAlarm.getEndTime())
.alarmTypeName(fenceAlarm.getType().getName())
//todo
//.recipient()
.statusName(fenceAlarm.getStatus().text())
.build();
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.vo.location.fence;
import com.yiring.app.domain.location.LocationFenceAlarm;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 扫描围栏报警的vo
* @author tml
* @version 1.0
* @date 2022/5/16 9:17
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class LocationFenceJobVo implements Serializable {
@Serial
private static final long serialVersionUID = -594643836931827494L;
/**
* 需要添加的报警信息集合
*/
private List<LocationFenceAlarm> addAlarm;
/**
* 需要修改成取消报警的报警信息集合
*/
private List<LocationFenceAlarm> modifyAlarm;
/**
* 合并一个LocationFenceJobVo
* @param vo 目标LocationFenceJobVo
*/
public void merge(LocationFenceJobVo vo) {
addAlarm.addAll(vo.getAddAlarm());
modifyAlarm.addAll(vo.getModifyAlarm());
}
}
......@@ -43,7 +43,7 @@ public class AccidentSpotVo implements Serializable {
@ApiModelProperty(value = "地图名称", example = "总图")
private String mapName;
@ApiModelProperty(value = "空间信息")
@ApiModelProperty(value = "空间信息", dataType = "java.lang.String")
private Geometry geometry;
@ApiModelProperty(value = "摄像头id", example = "1")
......
......@@ -42,7 +42,7 @@ public class EvacuationZoneVo implements Serializable {
@ApiModelProperty(value = "地图名称", example = "总图")
private String mapName;
@ApiModelProperty(value = "空间信息")
@ApiModelProperty(value = "空间信息", dataType = "java.lang.String")
private Geometry geometry;
@ApiModelProperty(value = "摄像头id", example = "1")
......
......@@ -17,7 +17,7 @@ import lombok.NoArgsConstructor;
* @version 1.0
* @date 2022/5/12 11:40
*/
@ApiModel("演练计划实时数据VO")
@ApiModel("RehearsalPlanRealTimeVo")
@Data
@AllArgsConstructor
@NoArgsConstructor
......
......@@ -38,6 +38,7 @@ public class RehearsalPlanVo implements Serializable {
@ApiModelProperty(value = "演练主题", example = "红色演练")
private String topical;
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty(value = "事故点id", example = "1522844636060585984")
private Long accidentSpotId;
......@@ -47,6 +48,7 @@ public class RehearsalPlanVo implements Serializable {
@ApiModelProperty(value = "周边范围(事故点周围多少米)", example = "50")
private Integer scope;
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty(value = "撤离区id", example = "1523562795864428544")
private Long evacuationZoneId;
......@@ -65,9 +67,6 @@ public class RehearsalPlanVo implements Serializable {
@ApiModelProperty(value = "演练时间", example = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime rehearsalTime;
@ApiModelProperty(value = "推送信息", example = "气体泄露,请尽快逃离")
private String pushMsg;
@ApiModelProperty(value = "演练计划的状态code", example = "1")
private Integer status;
......@@ -88,7 +87,6 @@ public class RehearsalPlanVo implements Serializable {
.riskLevelName(RiskLevelEnum.getByCode(rehearsalPlan.getRiskLevel()))
.accidentMsg(rehearsalPlan.getAccidentMsg())
.rehearsalTime(rehearsalPlan.getRehearsalTime())
.pushMsg(rehearsalPlan.getPushMsg())
.status(rehearsalPlan.getStatus())
.statusName(RehearsalPlanStatusEnum.getByCode(rehearsalPlan.getStatus()))
.build();
......
......@@ -18,7 +18,7 @@ import org.locationtech.jts.geom.Point;
* @version 1.0
* @date 2022/5/12 11:48
*/
@ApiModel("员工位置信息VO")
@ApiModel("员工位置信息")
@Data
@AllArgsConstructor
@NoArgsConstructor
......@@ -35,6 +35,6 @@ public class UserLocationVo implements Serializable {
@ApiModelProperty(value = "员工姓名", example = "1")
private String realmName;
@ApiModelProperty(value = "员工坐标")
@ApiModelProperty(value = "员工坐标", dataType = "java.lang.String")
private 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));
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.web.location.fence;
import com.yiring.app.param.location.fence.FenceAlarmConditionParam;
import com.yiring.app.service.location.fence.FenceAlarmService;
import com.yiring.app.vo.IdNameVo;
import com.yiring.app.vo.location.fence.FenceAlarmVo;
import com.yiring.common.core.Result;
import com.yiring.common.domain.BasicEntity;
import com.yiring.common.param.PageParam;
import com.yiring.common.vo.PageVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.util.Objects;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import org.springframework.data.domain.Sort;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author tml
* @version 1.0
* @date 2022/5/17 14:41
*/
@Api(tags = "围栏报警数据管理")
@Validated
@RestController
@RequestMapping("/fence/alarm")
public class FenceAlarmController {
@Resource
private FenceAlarmService fenceAlarmService;
@ApiOperation("查询围栏报警数据列表")
@GetMapping("/findList")
public Result<PageVo<FenceAlarmVo>> findList(@Valid FenceAlarmConditionParam param, @Valid PageParam pageParam) {
if (Objects.isNull(pageParam.getSortField())) {
pageParam.setSortField(BasicEntity.Fields.createTime);
pageParam.setSortOrder(Sort.Direction.DESC);
}
return fenceAlarmService.findList(param, pageParam);
}
@ApiOperation("查询围栏下拉框")
@GetMapping("/findFenceList")
public Result<PageVo<IdNameVo>> findFenceList() {
return fenceAlarmService.findFenceList();
}
@ApiOperation(value = "导出围栏报警数据", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
@GetMapping("/export")
public void export(@Valid FenceAlarmConditionParam param, HttpServletResponse response) {
fenceAlarmService.export(param, response);
}
}
......@@ -33,7 +33,7 @@ import org.springframework.web.bind.annotation.*;
@Validated
@SuppressWarnings({ "deprecation" })
@Api(tags = "电子围栏报警规则,配置报警给谁", description = "AlarmRule")
@Api(tags = "报警规则", description = "AlarmRule")
@RestController
@RequestMapping("/alarm/rule")
public class LocationAlarmRuleController {
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.web.location.rule;
import com.yiring.app.design.check.rule.LocationFenceRuleContext;
import com.yiring.app.design.strategy.rule.LocationFenceRuleContext;
import com.yiring.app.param.location.rule.LocationFenceRuleAddParam;
import com.yiring.app.param.location.rule.LocationFenceRuleModifyParam;
import com.yiring.app.service.location.rule.impl.LocationFenceRuleServiceImpl;
......@@ -27,7 +27,7 @@ import org.springframework.web.bind.annotation.RestController;
@Validated
@SuppressWarnings({ "deprecation" })
@Api(tags = "电子围栏报警规则,什么情况下会报警", description = "FenceRule")
@Api(tags = "电子围栏报警规则", description = "FenceRule")
@RestController
@RequestMapping("/location/rule")
public class LocationFenceRuleController {
......
......@@ -84,7 +84,7 @@ public class AccidentSpotController {
}
@ApiOperation("事故点名下拉框")
@ApiImplicitParam(value = "事故点名(全模糊)", name = "name", example = "事故", required = true)
@ApiImplicitParam(value = "事故点名(全模糊)", name = "name", example = "事故")
@GetMapping("/findAccidentList")
public Result<PageVo<IdNameVo>> findAccidentList(String name) {
if (name == null) {
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.web.rehearsal;
import com.yiring.app.constant.rehearsal.RiskLevelEnum;
import com.yiring.app.domain.alarm.AlarmType;
import com.yiring.app.domain.location.LocationTag;
import com.yiring.app.domain.location.LocationTagRepository;
import com.yiring.app.domain.rehearsal.AccidentSpot;
import com.yiring.app.domain.rehearsal.AccidentSpotRepository;
import com.yiring.app.param.rehearsal.RehearsalPlanAddParam;
import com.yiring.app.param.rehearsal.RehearsalPlanConditionParam;
import com.yiring.app.param.rehearsal.RehearsalPlanModifyParam;
import com.yiring.app.param.rehearsal.RehearsalPlanPlaybackParam;
import com.yiring.app.service.rehearsal.RehearsalPlanService;
import com.yiring.app.vo.CodeNameVo;
import com.yiring.app.vo.rehearsal.RehearsalPlanRealTimeVo;
import com.yiring.app.vo.rehearsal.RehearsalPlanVo;
import com.yiring.common.core.Result;
......@@ -19,14 +17,11 @@ import com.yiring.common.param.PageParam;
import com.yiring.common.vo.PageVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import org.locationtech.jts.geom.Geometry;
import org.springframework.data.domain.Sort;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
......@@ -47,12 +42,6 @@ public class RehearsalPlanController {
@Resource
private RehearsalPlanService rehearsalPlanService;
@Resource
LocationTagRepository locationTagRepository;
@Resource
AccidentSpotRepository accidentSpotRepository;
@ApiOperation("添加一条演练计划")
@PostMapping("/addOne")
public Result<String> addOne(@Valid RehearsalPlanAddParam param) {
......@@ -90,6 +79,14 @@ public class RehearsalPlanController {
return rehearsalPlanService.findList(conditionParam, pageParam);
}
@ApiOperation(value = "查询风险等级")
@GetMapping("/findRiskLevel")
public Result<PageVo<CodeNameVo>> findRiskLevel() {
List<CodeNameVo> list = RiskLevelEnum.getAll();
PageVo<CodeNameVo> pageVo = PageVo.build(list, list.size());
return Result.ok(pageVo);
}
@ApiOperation(value = "导出演练计划", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
@GetMapping("/export")
public void export(@Valid RehearsalPlanConditionParam conditionParam, HttpServletResponse response) {
......@@ -108,30 +105,15 @@ public class RehearsalPlanController {
return rehearsalPlanService.stop(idParam);
}
@ApiOperation("查看演练(实时)")
@ApiOperation("实时查看演练")
@GetMapping("/findRealTime")
public Result<RehearsalPlanRealTimeVo> findRealTime(@Valid IdParam idParam) {
return rehearsalPlanService.findRealTime(idParam);
}
@ApiOperation("查看回放(每次查询一分钟的回放信息)")
@ApiOperation("查看回放")
@GetMapping("/findPlayback")
public Result<PageVo<RehearsalPlanRealTimeVo>> findPlayback(@Valid RehearsalPlanPlaybackParam param) {
return rehearsalPlanService.findPlayback(param);
}
@PostMapping("/test")
public Geometry test(@RequestBody Geometry geometry) {
double degree = 100 / (2 * Math.PI * 6371004) * 360;
return geometry.buffer(degree);
}
@GetMapping("/get")
public Result<ArrayList<LocationTag>> get() {
Optional<AccidentSpot> optional = accidentSpotRepository.findById(1524292027951353856L);
Geometry geometry = optional.get().getGeometry();
List<LocationTag> inArea = locationTagRepository.findInArea(geometry);
System.out.println(inArea);
return Result.ok(new ArrayList<>(inArea));
}
}
......@@ -3,6 +3,11 @@ spring:
pathmatch:
# 修复 swagger 插件在 2.6.x 接口路径匹配问题
matching-strategy: ant_path_matcher
jpa:
properties:
hibernate:
# 关闭 hibernate-types banner 日志信息
types.print.banner: false
logging:
level:
......
......@@ -33,7 +33,7 @@ knife4j:
username: admin
password: 123456
setting:
enableOpenApi: false
enableOpenApi: true
enableDebug: true
# minio
......
......@@ -5,7 +5,7 @@ server:
spring:
application:
name: "kshg-api"
name: "kshg-api-beta"
profiles:
include: auth, conf-patch
active: dev
......
/* (C) 2022 YiRing, Inc. */
package com.yiring;
/**
* @author Jim
* @version 0.1
* 2022/5/23 0:21
*/
public class Test {
public static void main(String[] args) {}
}
......@@ -32,4 +32,8 @@ dependencies {
implementation 'com.aliyun:aliyun-java-sdk-core:4.3.7'
implementation 'com.aliyun:aliyun-java-sdk-dysmsapi:1.1.0'
// https://github.com/vladmihalcea/hibernate-types
// hibernate-types-55
implementation "com.vladmihalcea:hibernate-types-55:${hibernateTypesVersion}"
}
......@@ -31,9 +31,10 @@ public class SaTokenConfigure implements WebMvcConfigurer {
.match("/**")
.notMatchMethod(SaHttpMethod.OPTIONS.name())
// 实现用户权限相关后应移除下行代码
// TODO
// .notMatch("/**")
// 示例接口
.notMatch("/hello/**")
.notMatch("/example/**")
// 授权相关接口(登录、登出、注册等)
.notMatch("/auth/**")
.notMatch("/visitor/saveVisitor")
......@@ -41,7 +42,7 @@ public class SaTokenConfigure implements WebMvcConfigurer {
.notMatch("/Car/saveCarInfo")
.notMatch("/Car/getCarInfo")
.notMatch("/favicon.ico", "/**/*.html", "/**/*.js", "/**/*.css")
.notMatch("/v2/api-docs", "/v3/api-docs", "/swagger-resources/**")
.notMatch("/v2/api-docs/**", "/v3/api-docs/**", "/swagger-resources/**")
.check(r -> StpUtil.checkLogin());
})
)
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.auth.domain.permission;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.vladmihalcea.hibernate.type.json.JsonType;
import com.yiring.common.domain.BasicEntity;
import java.io.Serial;
import java.io.Serializable;
import java.util.Objects;
import javax.persistence.*;
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants;
import lombok.experimental.SuperBuilder;
import org.hibernate.Hibernate;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.TypeDef;
/**
* 权限
......@@ -31,7 +30,7 @@ import org.hibernate.annotations.Comment;
@FieldNameConstants
@FieldDefaults(level = AccessLevel.PRIVATE)
@Entity
@Comment("系统权限")
@TypeDef(name = "json", typeClass = JsonType.class)
@Table(
name = "SYS_PERMISSION",
indexes = {
......@@ -41,6 +40,7 @@ import org.hibernate.annotations.Comment;
@Index(columnList = "uid", unique = true),
}
)
@Comment("系统权限")
public class Permission extends BasicEntity implements Serializable {
@Serial
......@@ -88,9 +88,9 @@ public class Permission extends BasicEntity implements Serializable {
* 可用于扩展一些前端可能用到的路由参数
*/
@Comment("扩展元数据信息")
@Lob
@Column(columnDefinition = "JSON")
String meta;
@org.hibernate.annotations.Type(type = "json")
@Column(columnDefinition = "json")
JSONObject meta;
@SuppressWarnings({ "unused" })
public enum Type {
......@@ -115,30 +115,14 @@ public class Permission extends BasicEntity implements Serializable {
* @return JSON 格式 Meta 元数据
*/
public JSONObject getMetaJson() {
JSONObject meta = new JSONObject();
JSONObject meta = new JSONObject(true);
meta.put("title", this.name);
meta.put("icon", this.icon);
meta.put("orderNo", this.serial);
meta.put("hideMenu", this.hidden);
try {
String raw = this.meta.replace("\\", "").replaceAll("^\"(.*)\"$", "$1");
meta.putAll(JSON.parseObject(raw));
} catch (Exception ignored) {}
if (this.meta != null) {
meta.putAll(this.meta);
}
return meta;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false;
Permission that = (Permission) o;
return this.getId() != null && Objects.equals(this.getId(), that.getId());
}
@Override
public int hashCode() {
return getClass().hashCode();
}
}
......@@ -8,14 +8,12 @@ import com.yiring.common.domain.BasicEntity;
import java.io.Serial;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import javax.persistence.*;
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants;
import lombok.experimental.SuperBuilder;
import org.hibernate.Hibernate;
import org.hibernate.annotations.Comment;
/**
......@@ -67,17 +65,4 @@ public class Role extends BasicEntity implements Serializable {
inverseJoinColumns = { @JoinColumn(name = "user_id") }
)
Set<User> users = new HashSet<>();
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false;
Role role = (Role) o;
return this.getId() != null && Objects.equals(this.getId(), role.getId());
}
@Override
public int hashCode() {
return getClass().hashCode();
}
}
......@@ -10,14 +10,13 @@ import com.yiring.auth.vo.permission.PermissionVo;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import com.yiring.common.param.IdParam;
import com.yiring.common.param.OptionalPidParam;
import com.yiring.common.param.PageParam;
import com.yiring.common.vo.PageVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import javax.annotation.Resource;
import javax.validation.Valid;
......@@ -25,9 +24,11 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 系统权限管理控制器
......@@ -121,12 +122,10 @@ public class PermissionController {
}
@ApiOperation(value = "树结构查询")
@GetMapping(value = "tree", headers = "Content-Type=" + MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public Result<ArrayList<PermissionVo>> tree(
@ApiParam(value = "父级 id", example = "0") @RequestParam(required = false) Long pid
) {
@GetMapping(value = "tree")
public Result<ArrayList<PermissionVo>> tree(OptionalPidParam param) {
List<Permission> permissions = permissionRepository.findAll();
List<PermissionVo> vos = Permissions.toTree(permissions, Objects.isNull(pid) ? 0L : pid);
List<PermissionVo> vos = Permissions.toTree(permissions, param.getPid() == null ? 0L : param.getPid());
return Result.ok((ArrayList<PermissionVo>) vos);
}
......
......@@ -7,13 +7,25 @@ dependencies {
// 本地依赖
implementation fileTree(dir: project.rootDir.getPath() + '\\libs', includes: ['*jar'])
// swagger annotations
implementation "io.swagger:swagger-annotations:${swaggerAnnotationsVersion}"
// swagger(knife4j)
implementation "com.github.xiaoymin:knife4j-spring-boot-starter:${knife4jVersion}"
implementation "cn.dev33:sa-token-dao-redis-jackson:${saTokenVersion}"
implementation fileTree(dir: project.rootDir.getPath() + '\\libs', includes: ['*jar'])
// 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'
exclude group: 'org.locationtech.jts'
}
// JTS 几何对象操作库
implementation "org.geolatte:geolatte-geom:${geolatteVersion}"
implementation("org.geolatte:geolatte-geojson:${geolatteVersion}") {
exclude group: 'com.fasterxml.jackson.core'
}
// JTS 几何对象操作库
implementation "org.locationtech.jts:jts-core:${jtsVersion}"
......
......@@ -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);
}
}
......@@ -17,7 +17,7 @@ import lombok.experimental.FieldDefaults;
* @version 0.1
* 2019/5/28 22:11
*/
@ApiModel("IdParam")
@ApiModel(value = "IdParam", description = "公共的 ID 查询参数")
@Valid
@Data
@Builder
......
/* (C) 2021 YiRing, Inc. */
package com.yiring.common.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serial;
import java.io.Serializable;
import javax.validation.Valid;
import lombok.*;
import lombok.experimental.FieldDefaults;
/**
* 公共的关键字查询参数类
*
* @author ifzm
* @version 0.1
* 2022/4/27 08:53
*/
@ApiModel(value = "KeywordParam", description = "公共的关键字查询参数")
@Valid
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
public class KeywordParam implements Serializable {
@Serial
private static final long serialVersionUID = -8690942241103456894L;
@ApiModelProperty(value = "关键字", example = "hi")
String keyword;
}
/* (C) 2021 YiRing, Inc. */
package com.yiring.common.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serial;
import java.io.Serializable;
import javax.validation.Valid;
import lombok.*;
import lombok.experimental.FieldDefaults;
/**
* 公共的可选父级 ID 查询参数
*
* @author ifzm
* @version 0.1
* 2019/5/28 22:11
*/
@ApiModel(value = "OptionalPidParam", description = "公共的可选父级 ID 查询参数")
@Valid
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
public class OptionalPidParam implements Serializable {
@Serial
private static final long serialVersionUID = -8690942241103456893L;
@ApiModelProperty(value = "pid", example = "0")
Long pid;
}
......@@ -19,13 +19,12 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
/**
* 分页查询参数公共类
* 公共的分页排序查询参数
*
* @author ifzm
* @version 0.1 2019/3/10 16:29
*/
@SuppressWarnings({ "unused" })
@ApiModel("分页查询参数公共类")
@ApiModel(value = "PageParam", description = "公共的分页排序查询参数")
@Data
@SuperBuilder
@NoArgsConstructor
......@@ -58,6 +57,7 @@ public class PageParam implements Serializable {
* @param param {@link PageParam}
* @return Pageable
*/
@SuppressWarnings({ "unused" })
public static Pageable toPageable(PageParam param) {
if (param == null) {
return Pageable.unpaged();
......
/* (C) 2021 YiRing, Inc. */
package com.yiring.common.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serial;
import java.io.Serializable;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import lombok.*;
import lombok.experimental.FieldDefaults;
/**
* 公共的父级 ID 查询参数类
*
* @author ifzm
* @version 0.1
* 2019/5/28 22:11
*/
@ApiModel(value = "PidParam", description = "公共的父级 ID 查询参数")
@Valid
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
public class PidParam implements Serializable {
@Serial
private static final long serialVersionUID = -8690942241103456893L;
@ApiModelProperty(value = "pid", example = "0", required = true)
@NotNull(message = "pid 不能为空")
Long pid;
}
......@@ -16,7 +16,7 @@ import lombok.experimental.FieldDefaults;
* @version 0.1
* 2022/3/23 16:47
*/
@ApiModel("DataVo")
@ApiModel(value = "DataVo", description = "公共数据响应输出")
@Data
@NoArgsConstructor
@AllArgsConstructor
......
......@@ -16,7 +16,7 @@ import lombok.experimental.FieldDefaults;
* 2022/3/24 17:29
*/
@ApiModel("KeyValueVo")
@ApiModel(value = "KeyValueVo", description = "键值对响应输出")
@Data
@Builder
@NoArgsConstructor
......
......@@ -16,7 +16,7 @@ import lombok.experimental.FieldDefaults;
* @author ifzm
* @version 0.1 2019/3/10 16:29
*/
@ApiModel("PageVo")
@ApiModel(value = "PageVo", description = "公共分页查询响应输出")
@Data
@NoArgsConstructor
@AllArgsConstructor
......@@ -26,10 +26,10 @@ public class PageVo<T extends Serializable> implements Serializable {
@Serial
private static final long serialVersionUID = 6103761701912769946L;
@ApiModelProperty(value = "数据")
@ApiModelProperty(value = "数据", required = true)
List<T> data;
@ApiModelProperty(value = "数据总数", example = "100")
@ApiModelProperty(value = "数据总数", example = "100", required = true)
Long total;
/**
......
......@@ -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)
......
......@@ -9,7 +9,6 @@ import java.io.File;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
......@@ -23,14 +22,7 @@ import org.springframework.web.multipart.MultipartFile;
@SuppressWarnings({ "unused" })
@Component
public class Minio {
@Resource
public MinioConfig config;
@Resource(name = "MinioClient")
public MinioClient client;
public record Minio(MinioConfig config, MinioClient client) {
/**
* 业务数据存储桶
*/
......@@ -38,6 +30,7 @@ public class Minio {
/**
* 获取文件访问地址
*
* @param object 文件相对地址(含路径)
* @return URI
*/
......@@ -47,9 +40,10 @@ public class Minio {
/**
* 上传文件流
* @param is 文件流
*
* @param is 文件流
* @param contentType 文件类型
* @param object 文件存储相对地址
* @param object 文件存储相对地址
* @return 上传结果
* @throws Exception 异常
*/
......@@ -66,6 +60,7 @@ public class Minio {
/**
* 将文件上传到当前日期文件夹
*
* @param file 文件 MultipartFile
* @return 上传结果
* @throws Exception 异常
......@@ -82,6 +77,7 @@ public class Minio {
/**
* 将文件上传到当前日期文件夹
*
* @param file 文件 MultipartFile
* @return 上传结果
* @throws Exception 异常
......@@ -97,6 +93,7 @@ public class Minio {
/**
* 删除文件
*
* @param object 文件相对地址
* @throws Exception 异常
*/
......@@ -107,6 +104,7 @@ public class Minio {
/**
* 获取文件
*
* @param object 文件相对地址
* @return 文件流
* @throws Exception 异常
......@@ -118,6 +116,7 @@ public class Minio {
/**
* 查询文件信息
*
* @param object 文件相对地址
* @return 文件信息
* @throws Exception 异常
......@@ -129,6 +128,7 @@ public class Minio {
/**
* 查询 list
*
* @param prefix 文件路径前缀
* @return 文件/文件夹集合
*/
......@@ -139,6 +139,7 @@ public class Minio {
/**
* 拷贝一个文件
*
* @param source 源文件 object
* @param target 目标文件 object
* @throws Exception 异常
......@@ -158,7 +159,8 @@ public class Minio {
/**
* 上传业务数据文件
* @param path 本地文件地址(通常是一个临时文件)
*
* @param path 本地文件地址(通常是一个临时文件)
* @param object 文件 object
* @return 上传结果
*/
......
......@@ -4,7 +4,8 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-aop'
// hutool-extra
// hutool
implementation "cn.hutool:hutool-core:${hutoolVersion}"
implementation "cn.hutool:hutool-extra:${hutoolVersion}"
// fastjson
implementation "com.alibaba:fastjson:${fastJsonVersion}"
......
......@@ -67,7 +67,8 @@ public class RequestAspect {
}
}
log.info(
"[Request] URL: {}, IP: {}, Times: {}{}",
"[Request] Method: {}, URL: {}, IP: {}, Times: {}{}",
request.getMethod(),
request.getRequestURL(),
Commons.getClientIpAddress(request),
times,
......
......@@ -84,6 +84,27 @@ public class Commons {
}
/**
* 对象 Copy
* @param source 源对象
* @param type 目标类型
* @param ignoreProperties 忽略属性
* @return 目标对象
* @param <T> 目标类型
*/
public <T> T transform(Object source, Class<T> type, String... ignoreProperties) {
try {
Constructor<T> declaredConstructor = type.getDeclaredConstructor();
// 实例化
T target = declaredConstructor.newInstance();
// 使用 BeanUtils 进行数据拷贝
BeanUtils.copyProperties(source, target, ignoreProperties);
return target;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 将集合通过 BeanUtils 反射转换成指定类型集合
* @param list 原始数据集合
* @param type 目标类型
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.common.util;
import cn.hutool.core.io.file.FileReader;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import javax.servlet.http.HttpServletResponse;
import lombok.experimental.UtilityClass;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
/**
* 文件工具类
*
* @author Jim
* @version 0.1
* 2022/4/22 13:54
*/
@UtilityClass
public class FileUtils {
/**
* 文件下载
* @param response HttpServletResponse
* @param file File
* @throws IOException IOException
*/
public void download(HttpServletResponse response, File file) throws IOException {
String filename = URLEncoder.encode(file.getName(), StandardCharsets.UTF_8);
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(file.length()));
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + filename);
FileReader.create(file).writeToStream(response.getOutputStream(), true);
}
}
......@@ -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
}
}
......@@ -11,7 +11,6 @@
```diff
+ @Resource
+ Redis redis;
+ Object value = redis.get(key);
```
......
{
"name": "basic-api-project",
"version": "0.0.1",
"scripts": {
"log": "conventional-changelog -p angular -i CHANGELOG.md -s"
},
"devDependencies": {
"cz-conventional-changelog": "^3.3.0"
"cz-conventional-changelog": "^3.3.0",
"conventional-changelog-cli": "^2.2.2"
},
"config": {
"commitizen": {
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论