提交 f04af0b6 作者: 方治民

feat: 增加 xxl-job 任务调度配置、定位日志表采用时序分区标签联合主键、增加实时消息数据 Mock 配置、xyz 转经纬度工具引入、springcloud 统一版本管理、其他细节调整

上级 e21e94dc
......@@ -38,3 +38,4 @@ out/
node_modules
logs/
.jpb/
......@@ -29,9 +29,8 @@
- [x] [conventional-changelog](https://www.cnblogs.com/mengfangui/p/12634845.html)
- [x] 用户及权限模块(目录/菜单/按钮),预览初始化权限配置 [SQL 脚本](./basic-auth/src/main/resources/init-test-mysql.sql)
- [x] 通用文件上传模块
- [ ] 通用字典管理模块
- [ ] XXL-JOB 定时任务模块
- [x] @Convert 处理 Raw JSON 数据格式转换
- [x] 通用字典管理模块
- [x] XXL-JOB 定时任务模块
- [ ] 扩展 PostgresDialect 实现时序查询函数
---
......
......@@ -13,6 +13,8 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-amqp'
implementation "org.springframework.boot:spring-boot-starter-websocket"
implementation "org.springframework.boot:spring-boot-starter-reactor-netty"
implementation "org.springframework.cloud:spring-cloud-starter-openfeign"
implementation "org.springframework.cloud:spring-cloud-commons"
// 💬 Mock/Test Env
runtimeOnly 'com.h2database:h2'
// 💬 Prod/Dev Env
......@@ -70,10 +72,10 @@ dependencies {
// myexcel
implementation "com.github.liaochong:myexcel:${myexcelVersion}"
// https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign
implementation "org.springframework.cloud:spring-cloud-starter-openfeign:${openfeignVersion}"
// feign-okhttp
implementation "io.github.openfeign:feign-okhttp:${feignOkhttpVersion}"
// xxl-job
implementation "com.xuxueli:xxl-job-core:${xxlJobVersion}"
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.config;
import cn.hutool.core.util.StrUtil;
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import javax.annotation.Resource;
import lombok.AccessLevel;
import lombok.Data;
import lombok.experimental.FieldDefaults;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.commons.util.InetUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* xxl-job 配置
*/
@Slf4j
@Data
@FieldDefaults(level = AccessLevel.PRIVATE)
@Configuration
@ConfigurationProperties(prefix = "xxl.job")
public class XxlJobConfig {
@Resource
InetUtils inetUtils;
String adminAddresses;
String accessToken;
String executorAppName;
String executorAddress;
String executorIp;
Integer executorPort = 9999;
String executorLogPath;
Integer executorLogRetentionDays = 30;
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
log.info(">>>>>>>>>>> xxl-job init: {}", adminAddresses);
if (StrUtil.isBlank(executorIp)) {
executorIp = inetUtils.findFirstNonLoopbackAddress().getHostAddress();
}
if (StrUtil.isBlank(executorAddress)) {
executorAddress = "http://" + executorIp + ":" + executorPort;
}
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
xxlJobSpringExecutor.setAppname(executorAppName);
xxlJobSpringExecutor.setAddress(executorAddress);
xxlJobSpringExecutor.setIp(executorIp);
xxlJobSpringExecutor.setPort(executorPort);
xxlJobSpringExecutor.setAccessToken(accessToken);
xxlJobSpringExecutor.setLogPath(executorLogPath);
xxlJobSpringExecutor.setLogRetentionDays(executorLogRetentionDays);
return xxlJobSpringExecutor;
}
}
......@@ -8,16 +8,13 @@ import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
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;
import org.hibernate.annotations.Type;
import org.locationtech.jts.geom.Point;
/**
......@@ -83,8 +80,6 @@ public class LocationBeacon extends BasicEntity implements Serializable {
Double distance;
@Comment("坐标点信息")
@Type(type = "jts_geometry")
@Column(columnDefinition = "point")
Point point;
@FieldMapping
......@@ -103,17 +98,4 @@ public class LocationBeacon extends BasicEntity implements Serializable {
@ManyToMany
@ToString.Exclude
Set<LocationFence> fences = new HashSet<>(0);
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false;
LocationBeacon that = (LocationBeacon) o;
return getId() != null && Objects.equals(getId(), that.getId());
}
@Override
public int hashCode() {
return getClass().hashCode();
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.location;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.vladmihalcea.hibernate.type.json.JsonType;
import com.vladmihalcea.hibernate.type.json.JsonBinaryType;
import com.yiring.auth.domain.user.User;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.*;
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import org.locationtech.jts.geom.Point;
......@@ -40,19 +38,17 @@ import org.locationtech.jts.geom.Point;
@FieldNameConstants
@FieldDefaults(level = AccessLevel.PRIVATE)
@Entity
@TypeDef(name = "json", typeClass = JsonType.class)
@Table(name = "BS_LOCATION_LOG")
@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
@Table(name = "BS_LOCATION_LOG", indexes = { @Index(name = "idx_time", columnList = "time") })
@Comment("定位数据")
public class LocationLog implements Serializable {
@Serial
private static final long serialVersionUID = 3467455881020691989L;
@Id
@Comment("时间")
@Column(nullable = false, columnDefinition = "timestamp without time zone")
@CreationTimestamp
LocalDateTime time;
@Comment("定位标签时序复合主键")
@EmbeddedId
TagTimeId id;
@Comment("地图 ID")
Long areaId;
......@@ -64,7 +60,7 @@ public class LocationLog implements Serializable {
* 来源于定位数据产生时刻标签所属的人员
*/
@Comment("用户")
@ManyToOne
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
User user;
......@@ -72,29 +68,20 @@ public class LocationLog implements Serializable {
* 来源于定位标签定位时刻的人员状态
*/
@Comment("用户状态")
String status;
@Comment("标签")
@ManyToOne
@JoinColumn(name = "tag_id")
LocationTag tag;
User.Status status;
@Comment("坐标点信息")
@Type(type = "jts_geometry")
@Column(columnDefinition = "point")
Point point;
@Comment("信标集合")
@Builder.Default
@OneToMany
@ToString.Exclude
Set<LocationBeacon> beacons = new HashSet<>(0);
@Type(type = "jsonb")
@Column(columnDefinition = "jsonb")
JSONArray beacons;
@Comment("围栏集合")
@Builder.Default
@OneToMany
@ToString.Exclude
Set<LocationFence> fences = new HashSet<>(0);
@Type(type = "jsonb")
@Column(columnDefinition = "jsonb")
JSONArray fences;
@Comment("静止/运动")
Boolean silent;
......@@ -106,8 +93,8 @@ public class LocationLog implements Serializable {
String voltUnit;
@Comment("原始数据")
@org.hibernate.annotations.Type(type = "json")
@Column(columnDefinition = "json")
@Type(type = "jsonb")
@Column(columnDefinition = "jsonb")
JSONObject raw;
@Comment("定位时间")
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.location;
import java.io.Serializable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
......@@ -14,4 +13,4 @@ import org.springframework.stereotype.Repository;
@Repository
public interface LocationLogRepository
extends JpaRepository<LocationLog, Serializable>, JpaSpecificationExecutor<LocationLog> {}
extends JpaRepository<LocationLog, TagTimeId>, JpaSpecificationExecutor<LocationLog> {}
......@@ -6,7 +6,6 @@ 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.*;
......@@ -15,6 +14,7 @@ import lombok.experimental.FieldNameConstants;
import lombok.experimental.SuperBuilder;
import org.hibernate.Hibernate;
import org.hibernate.annotations.Comment;
import org.locationtech.jts.geom.Point;
/**
* 定位标签
......@@ -82,8 +82,7 @@ public class LocationTag extends BasicEntity implements Serializable {
@Comment("静止/运动")
Boolean silent;
@OneToOne
@JoinColumn(name = "user_id")
@ManyToOne
@Comment("绑定用户")
User user;
......@@ -103,12 +102,8 @@ public class LocationTag extends BasicEntity implements Serializable {
@Comment("类型(1:内部/2:访客/3:承包商)")
Integer category;
@FieldMapping(value = "raiseTimestamp", desc = "更新时间戳", type = Long.class)
@Comment("更新时间")
LocalDateTime updateTime;
@Comment("创建时间")
LocalDateTime createTime;
@Comment("最后定位坐标")
Point point;
@SuppressWarnings({ "unused" })
public enum Type {
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.domain.location;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.FetchType;
import javax.persistence.OneToOne;
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants;
import org.hibernate.annotations.Comment;
/**
* 定位标签时序联合主键
* @author Jim
* @version 0.1
* 2022/5/10 10:24
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@FieldNameConstants
@FieldDefaults(level = AccessLevel.PRIVATE)
@Embeddable
public class TagTimeId implements Serializable {
@Serial
private static final long serialVersionUID = -5254861902659471641L;
@Comment("定位标签")
@OneToOne(fetch = FetchType.LAZY)
LocationTag tag;
@Comment("定位时间")
@Column(nullable = false, columnDefinition = "timestamp without time zone")
LocalDateTime time;
public TagTimeId(LocationTag tag) {
this.tag = tag;
this.time = LocalDateTime.now();
}
}
......@@ -11,7 +11,8 @@ import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
/**
......@@ -45,10 +46,11 @@ public class ZyRealtimeLog implements Serializable {
@Serial
private static final long serialVersionUID = 5545864821082386L;
@Id
@Comment("时间")
@Id
@GeneratedValue(generator = "time-id")
@GenericGenerator(name = "time-id", strategy = "com.yiring.app.util.TimeIdGenerator")
@Column(nullable = false, columnDefinition = "timestamp without time zone")
@CreationTimestamp
LocalDateTime time;
@Comment("类型")
......@@ -56,7 +58,7 @@ public class ZyRealtimeLog implements Serializable {
String method;
@Comment("内容")
@org.hibernate.annotations.Type(type = "jsonb")
@Type(type = "jsonb")
@Column(nullable = false, columnDefinition = "jsonb")
JSONObject raw;
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.job;
import com.alibaba.fastjson.JSONObject;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.yiring.app.domain.location.LocationLog;
import com.yiring.app.domain.location.LocationLogRepository;
import com.yiring.app.rabbit.config.ZyRabbitConfig;
import com.yiring.app.util.GeoUtils;
import com.yiring.common.constant.DateFormatter;
import java.time.LocalDateTime;
import java.util.List;
import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.Point;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;
/**
* 模拟真源消息日志推送
*
* @author Jim
* @version 0.1
* 2022/5/7 15:26
*/
@SuppressWarnings("unused")
@Slf4j
@Component
public class MockZyMessageJob {
@Resource
RabbitTemplate rabbitTemplate;
@Resource
LocationLogRepository locationLogRepository;
@XxlJob("MockZyMessageHandler")
public void mockMessageHandler() {
log.info("MockZyMessageHandler: {}", LocalDateTime.now().format(DateFormatter.DATE_TIME));
log.info("[Mock] Position: {}", mockPositionMessage());
log.info("[Mock] LowPower: {}", mockLowPowerMessage());
log.info("[Mock] DeviceStatus: {}", mockDeviceStatusMessage());
log.info("[Mock] KeyWarning: {}", mockKeyWarningMessage());
}
@XxlJob("QueryMessageHandler")
public void queryMessageHandler() {
log.info("QueryZyMessageHandler: {}", LocalDateTime.now().format(DateFormatter.DATE_TIME));
try {
Specification<LocationLog> spec = (root, query, cb) -> {
Predicate predicate = cb.conjunction();
predicate.getExpressions().add(cb.lessThanOrEqualTo(root.get("id").get("time"), LocalDateTime.now()));
return predicate;
};
List<LocationLog> logs = locationLogRepository.findAll(spec);
log.info("QueryZyMessageHandler: {}", logs.size());
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
public JSONObject send(JSONObject body) {
rabbitTemplate.convertAndSend(ZyRabbitConfig.MESSAGE_QUEUES_NAME, body.toJSONString());
return body;
}
private String mockTag() {
return "BTT33333331";
}
private Long mockAreaId() {
return 10019L;
}
private JSONObject mockPositionMessage() {
// 随机生成一个坐标点
Point point = GeoUtils.randomPoint(GeoUtils.defaultBounds(), 0);
// 模拟定位数据
JSONObject params = new JSONObject();
params.put("tagId", mockTag());
params.put("areaId", mockAreaId());
params.put("silent", false);
params.put("beacons", "BTI22085237,BTI22085238");
params.put("longitude", point.getCoordinate().getX());
params.put("latitude", point.getCoordinate().getY());
params.put("altitude", point.getCoordinate().getZ());
params.put("locationTime", System.currentTimeMillis());
params.put("volt", 3650);
params.put("voltUnit", "mV");
params.put("floor", 1);
JSONObject body = new JSONObject();
body.put("method", "position");
body.put("params", params);
return send(body);
}
private JSONObject mockLowPowerMessage() {
JSONObject params = new JSONObject();
params.put("tagId", mockTag());
params.put("volt", 3650);
params.put("voltUnit", "mV");
JSONObject body = new JSONObject();
body.put("method", "lowPower");
body.put("params", params);
return send(body);
}
private JSONObject mockDeviceStatusMessage() {
JSONObject params = new JSONObject();
params.put("deviceId", mockTag());
params.put("areaId", mockAreaId());
params.put("deviceType", "BTI");
params.put("volt", 3650);
params.put("field_21", "mV");
params.put("updateTime", System.currentTimeMillis());
JSONObject body = new JSONObject();
body.put("method", "deviceStatus");
body.put("params", params);
return send(body);
}
private JSONObject mockKeyWarningMessage() {
JSONObject params = new JSONObject();
params.put("tagId", mockTag());
params.put("entityId", "1522770547178475520");
params.put("areaId", mockAreaId());
params.put("raiseTime", System.currentTimeMillis());
params.put("x", 100);
params.put("y", 100);
params.put("z", 0);
params.put("floor", 1);
JSONObject body = new JSONObject();
body.put("method", "keyWarning");
body.put("params", params);
return send(body);
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.rabbit.config;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 模拟真源 rabbitmq 消息队列配置
*
* @author ifzm
* 2019/8/21 15:44
*/
@Configuration
public class MockZyRabbitConfig {
/**
* 消息交换机
*/
public static final String ZY_TOPIC_EXCHANGE = "zy.topic.exchange";
/**
* 订阅模式
*
* @return TopicExchange
*/
@Bean(ZY_TOPIC_EXCHANGE)
TopicExchange exchange() {
return new TopicExchange(ZY_TOPIC_EXCHANGE, true, false);
}
@Bean(ZyRabbitConfig.MESSAGE_QUEUES_NAME)
public Queue mockMessageQueue() {
return new Queue(ZyRabbitConfig.MESSAGE_QUEUES_NAME, true, false, false);
}
@Bean
Binding bindingExchangeMock(
@Qualifier(ZyRabbitConfig.MESSAGE_QUEUES_NAME) Queue queue,
@Qualifier(ZY_TOPIC_EXCHANGE) TopicExchange exchange
) {
return BindingBuilder.bind(queue).to(exchange).with(ZyRabbitConfig.MESSAGE_QUEUES_NAME);
}
}
......@@ -2,6 +2,7 @@
package com.yiring.app.rabbit.config;
import javax.annotation.Resource;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
......@@ -9,6 +10,7 @@ import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.amqp.RabbitProperties;
import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
......@@ -25,7 +27,7 @@ public class RabbitConfig {
@Resource
RabbitProperties rabbitProperties;
private static final String CONNECTION_FACTORY_NAME = "rabbitConnectionFactory";
public static final String CONNECTION_FACTORY_NAME = "rabbitConnectionFactory";
@Bean(CONNECTION_FACTORY_NAME)
@Primary
......@@ -42,10 +44,13 @@ public class RabbitConfig {
@Bean
@Primary
public RabbitListenerContainerFactory<?> rabbitListenerContainerFactory(
SimpleRabbitListenerContainerFactoryConfigurer configurer,
@Qualifier(CONNECTION_FACTORY_NAME) ConnectionFactory connectionFactory
) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
// 手动确认消息模式
factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
configurer.configure(factory, connectionFactory);
return factory;
}
......
......@@ -6,6 +6,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer;
......@@ -35,6 +36,7 @@ public class ZyRabbitConfig {
public static final String CONNECTION_FACTORY_NAME = "zyRabbitConnectionFactory";
public static final String LISTENER_FACTORY_NAME = "zyRabbitListenerFactory";
public static final String TEMPLATE_NAME = "zyRabbitTemplate";
/**
* 消息队列名称(必须要与配置文件中的 queue-name 完全一致)
......@@ -72,4 +74,9 @@ public class ZyRabbitConfig {
configurer.configure(factory, connectionFactory);
return factory;
}
@Bean(TEMPLATE_NAME)
public RabbitTemplate rabbitTemplate(@Qualifier(CONNECTION_FACTORY_NAME) ConnectionFactory connectionFactory) {
return new RabbitTemplate(connectionFactory);
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.rabbit.receiver;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.rabbitmq.client.Channel;
import com.yiring.app.domain.location.*;
import com.yiring.app.domain.log.ZyRealtimeLog;
import com.yiring.app.domain.log.ZyRealtimeLogRepository;
import com.yiring.app.rabbit.config.ZyRabbitConfig;
import com.yiring.app.util.GeoUtils;
import com.yiring.app.service.message.ZyMessageService;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.Point;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.Example;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
/**
* 真源 RabbitMQ 消息监听(消息消费者)
......@@ -48,19 +34,7 @@ public class ZyRabbitReceiver {
// 3. 订阅 position(定位数据)、lowPower(低电量报警)、deviceStatus(设备状态)、keyWarning(按键报警)
@Resource
LocationTagRepository locationTagRepository;
@Resource
LocationBeaconRepository locationBeaconRepository;
@Resource
LocationLogRepository locationLogRepository;
@Resource
SimpMessagingTemplate simpMessagingTemplate;
@Resource
ZyRealtimeLogRepository zyRealtimeLogRepository;
ZyMessageService zyMessageService;
/**
* 订阅真源定位系统 RabbitMQ 推送过来的消息(主动订阅的一些消息类别)
......@@ -71,158 +45,15 @@ public class ZyRabbitReceiver {
* @throws IOException 消息确认异常
*/
@RabbitHandler
@RabbitListener(
queues = ZyRabbitConfig.MESSAGE_QUEUES_NAME,
containerFactory = ZyRabbitConfig.LISTENER_FACTORY_NAME
)
// @RabbitListener(
// queues = ZyRabbitConfig.MESSAGE_QUEUES_NAME,
// containerFactory = ZyRabbitConfig.LISTENER_FACTORY_NAME
// )
@RabbitListener(queues = ZyRabbitConfig.MESSAGE_QUEUES_NAME, containerFactory = "rabbitListenerContainerFactory")
public void listen(String msg, Channel channel, Message message) throws IOException {
// 消费消息
zyMessageService.consume(msg);
// 手动确认消息已收到
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
try {
// 将消息转换成 JSON 格式
JSONObject info = JSON.parseObject(msg);
log.info("Receiver Message: {}", info);
// 解构消息内容
JSONObject data = info.getJSONObject("params");
String method = info.getString("method");
// 记录日志
ZyRealtimeLog realtimeLog = ZyRealtimeLog.builder().method(method).raw(info).build();
zyRealtimeLogRepository.save(realtimeLog);
// 业务处理
switch (method) {
// 实时定位
case "position" -> processPositionMessage(data);
// 设备低电量
case "lowPower" -> processLowPowerMessage(data);
// 设备状态变更
case "deviceStatus" -> processDeviceStatusMessage(data);
// 按键报警
case "keyWarning" -> processKeyWarningMessage(data);
// 围栏报警
case "enclosure" -> log.warn("Ignore Message Type [enclosure]: {}", info);
default -> log.warn("Unknown Message Type: {}", info);
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
/**
* 处理定位消息
* @param data 消息内容
*/
@Transactional(rollbackFor = Exception.class)
public void processPositionMessage(JSONObject data) {
// TODO
log.info("Position Message: {}", data);
// 包装消息
// TODO
// 1. 解析消息内容,进行围栏、出入标识判断等处理,将定位记录录入数据库
// 2. 创建一条需要进行消息推送的记录
// 3. 将记录推送的消息推送模块
// 4. 检查是否触发围栏告警,记录告警数据,并推送消息
// 定位时间
Instant instant = Instant.ofEpochMilli(data.getLongValue("locationTime"));
LocalDateTime time = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
// 定位的基本信息
LocationLog locationLog = LocationLog
.builder()
.raw(data)
.locationTime(time)
.areaId(data.getLong("areaId"))
.silent(data.getBoolean("silent"))
.volt(data.getInteger("volt"))
.voltUnit(data.getString("voltUnit"))
.build();
// 设置空间点位信息
Point point = GeoUtils.createPoint(
data.getDoubleValue("longitude"),
data.getDoubleValue("latitude"),
data.getDoubleValue("altitude")
);
locationLog.setPoint(point);
// 查询定位标签
Example<LocationTag> example = Example.of(LocationTag.builder().code(data.getString("tagId")).build());
Optional<LocationTag> optional = locationTagRepository.findOne(example);
if (optional.isPresent()) {
LocationTag tag = optional.get();
// 设置定位标签
locationLog.setTag(tag);
// 定位标签当时所属的用户
locationLog.setUser(tag.getUser());
// 查询当前用户的状态
// TODO
}
// 查询定位信标
Set<String> codes = Arrays
.stream(data.getString("beacons").split(","))
.map(beacon -> beacon.replaceAll("\\(.*\\)", ""))
.collect(Collectors.toSet());
Set<LocationBeacon> beacons = locationBeaconRepository.findByCodeIn(codes);
locationLog.setBeacons(beacons);
// 查询定位所在围栏信息
Set<LocationFence> fences = locationLog
.getBeacons()
.stream()
.map(LocationBeacon::getFences)
.flatMap(Set::stream)
.collect(Collectors.toSet());
locationLog.setFences(fences);
// TODO
// 并计算出入标记(围栏、区域)
// 写入数据
locationLogRepository.saveAndFlush(locationLog);
// 更新定位标签卡电量信息
// TODO
// WebSocket 推送定位消息
// 消息内容需要确定 TODO
simpMessagingTemplate.convertAndSend("/topic/position", "{}");
// TODO
// 判断围栏告警是否触发,触发写入告警记录,并推送消息
}
/**
* 处理低电量报警消息
* @param data 消息内容
*/
@Transactional(rollbackFor = Exception.class)
public void processLowPowerMessage(JSONObject data) {
// TODO
log.info("LowPower Message: {}", data);
}
/**
* 处理设备状态更新消息
* @param data 消息内容
*/
@Transactional(rollbackFor = Exception.class)
public void processDeviceStatusMessage(JSONObject data) {
// TODO
log.info("DeviceStatus Message: {}", data);
}
/**
* 处理按键报警消息
* @param data 消息内容
*/
@Transactional(rollbackFor = Exception.class)
public void processKeyWarningMessage(JSONObject data) {
// TODO
log.info("KeyWarning Message: {}", data);
}
}
......@@ -16,7 +16,10 @@ import com.yiring.app.domain.location.LocationTagRepository;
import com.yiring.app.excel.location.tag.LocationTagExportExcel;
import com.yiring.app.excel.location.tag.LocationTagImportExcel;
import com.yiring.app.feign.zy.location.tag.LocationTagClient;
import com.yiring.app.param.location.tag.*;
import com.yiring.app.param.location.tag.LocationTagAddParam;
import com.yiring.app.param.location.tag.LocationTagDeleteParam;
import com.yiring.app.param.location.tag.LocationTagExportParam;
import com.yiring.app.param.location.tag.LocationTagFindParam;
import com.yiring.app.param.zy.location.tag.ZyLocationTagAddParam;
import com.yiring.app.service.location.tag.LocationTagService;
import com.yiring.app.util.zy.ZyUtil;
......@@ -24,6 +27,7 @@ import com.yiring.app.vo.location.tag.LocationTagIndexVo;
import com.yiring.app.vo.location.tag.LocationTagVo;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import com.yiring.common.domain.BasicEntity;
import com.yiring.common.param.IdParam;
import com.yiring.common.param.IndexParam;
import com.yiring.common.param.PageParam;
......@@ -33,7 +37,10 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import javax.annotation.Resource;
......@@ -42,7 +49,10 @@ 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.*;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
......@@ -120,7 +130,7 @@ public class LocationTagServiceImpl implements LocationTagService {
predicates.add(cb.equal(root.get(LocationTag.Fields.silent), locationTagFindParam.getSilent()));
}
Order order = cb.desc(root.get(LocationTag.Fields.createTime));
Order order = cb.desc(root.get(BasicEntity.Fields.createTime));
return cq.orderBy(order).where(predicates.toArray(new Predicate[0])).getRestriction();
};
......@@ -183,7 +193,7 @@ public class LocationTagServiceImpl implements LocationTagService {
predicates.add(cb.equal(root.get(LocationTag.Fields.silent), locationTagExportParam.getSilent()));
}
Order order = cb.desc(root.get(LocationTag.Fields.createTime));
Order order = cb.desc(root.get(BasicEntity.Fields.createTime));
return cq.orderBy(order).where(predicates.toArray(new Predicate[0])).getRestriction();
};
......@@ -318,7 +328,7 @@ public class LocationTagServiceImpl implements LocationTagService {
predicates.add(cb.like(root.get(LocationTag.Fields.code), "%" + indexParam.getStr() + "%"));
}
Order order = cb.desc(root.get(LocationTag.Fields.createTime));
Order order = cb.desc(root.get(BasicEntity.Fields.createTime));
return cq.orderBy(order).where(predicates.toArray(new Predicate[0])).getRestriction();
};
......@@ -348,7 +358,7 @@ public class LocationTagServiceImpl implements LocationTagService {
predicates.add(cb.equal(root.get(LocationTag.Fields.silent), locationTagFindParam.getSilent()));
}
Order order = cb.desc(root.get(LocationTag.Fields.createTime));
Order order = cb.desc(root.get(BasicEntity.Fields.createTime));
return cq.orderBy(order).where(predicates.toArray(new Predicate[0])).getRestriction();
};
......
......@@ -71,7 +71,7 @@ public class LocationTagTypeServiceImpl implements LocationTagTypeService {
predicates.add(cb.equal(root.get(LocationTag.Fields.category), locationTagTypeFindParam.getCategory()));
}
Order order = cb.desc(root.get(LocationTag.Fields.createTime));
Order order = cb.desc(root.get(BasicEntity.Fields.createTime));
return cq.orderBy(order).where(predicates.toArray(new Predicate[0])).getRestriction();
};
......@@ -118,7 +118,7 @@ public class LocationTagTypeServiceImpl implements LocationTagTypeService {
predicates.add(cb.and(in));
}
Order order = cb.desc(root.get(LocationTag.Fields.createTime));
Order order = cb.desc(root.get(BasicEntity.Fields.createTime));
return cq.orderBy(order).where(predicates.toArray(new Predicate[0])).getRestriction();
};
List<LocationTag> locationTags = locationTagRepository.findAll(specification);
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.service.message;
/**
* 真源消息处理 Service
*
* @author Jim
* @version 0.1
* 2022/5/9 10:16
*/
public interface ZyMessageService {
/**
* 消费消息
* @param message 消息内容
*/
void consume(String message);
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.service.message.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yiring.app.domain.location.*;
import com.yiring.app.domain.log.ZyRealtimeLog;
import com.yiring.app.domain.log.ZyRealtimeLogRepository;
import com.yiring.app.service.message.ZyMessageService;
import com.yiring.app.util.GeoUtils;
import com.yiring.auth.domain.user.User;
import com.yiring.common.annotation.Times;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Arrays;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.Point;
import org.springframework.data.domain.Example;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* 真源消息处理实现类
*
* @author Jim
* @version 0.1
* 2022/5/9 10:22
*/
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class ZyMessageServiceImpl implements ZyMessageService {
@Resource
LocationTagRepository locationTagRepository;
@Resource
LocationLogRepository locationLogRepository;
@Resource
SimpMessagingTemplate simpMessagingTemplate;
@Resource
ZyRealtimeLogRepository zyRealtimeLogRepository;
@Times
@Override
public void consume(String message) {
// 将消息转换成 JSON 格式
JSONObject info = JSON.parseObject(message);
log.info("Receiver Message: {}", info);
// 解构消息内容
JSONObject data = info.getJSONObject("params");
String method = info.getString("method");
// 记录日志
ZyRealtimeLog realtimeLog = ZyRealtimeLog.builder().method(method).raw(info).build();
zyRealtimeLogRepository.save(realtimeLog);
// 业务处理
switch (method) {
// 实时定位
case "position" -> processPositionMessage(data);
// 设备低电量
case "lowPower" -> processLowPowerMessage(data);
// 设备状态变更
case "deviceStatus" -> processDeviceStatusMessage(data);
// 按键报警
case "keyWarning" -> processKeyWarningMessage(data);
// 围栏报警
case "enclosure" -> log.warn("Ignore Message Type [enclosure]: {}", info);
default -> log.warn("Unknown Message Type: {}", info);
}
}
/**
* 处理定位消息
* @param data 消息内容
*/
public void processPositionMessage(JSONObject data) {
// TODO
log.info("Position Message: {}", data);
// 包装消息
// TODO
// 1. 解析消息内容,进行围栏、出入标识判断等处理,将定位记录录入数据库
// 2. 创建一条需要进行消息推送的记录
// 3. 将记录推送的消息推送模块
// 4. 检查是否触发围栏告警,记录告警数据,并推送消息
// 查询定位标签
String tagId = data.getString("tagId");
Example<LocationTag> example = Example.of(LocationTag.builder().code(tagId).build());
Optional<LocationTag> optional = locationTagRepository.findOne(example);
if (optional.isEmpty()) {
log.warn("Tag Not Found: {}", tagId);
return;
}
// 构建复合主键
LocationTag tag = optional.get();
TagTimeId id = new TagTimeId(tag);
// 定位时间
Instant instant = Instant.ofEpochMilli(data.getLongValue("locationTime"));
LocalDateTime locationTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
// 定位的基本信息
LocationLog locationLog = LocationLog
.builder()
.id(id)
.locationTime(locationTime)
.areaId(data.getLong("areaId"))
.floor(data.getString("floor"))
.silent(data.getBoolean("silent"))
.volt(data.getInteger("volt"))
.voltUnit(data.getString("voltUnit"))
.raw(data)
.build();
// 获取定位卡当前绑定的用户
User user = tag.getUser();
if (user != null) {
// 定位标签当时所属的用户
locationLog.setUser(user);
// 查询当前用户的状态
locationLog.setStatus(user.getStatus());
}
// 设置空间点位信息
Point point = GeoUtils.createPoint(
data.getDoubleValue("longitude"),
data.getDoubleValue("latitude"),
data.getDoubleValue("altitude")
);
locationLog.setPoint(point);
// 定位信标
Set<String> codes = Arrays
.stream(data.getString("beacons").split(","))
.map(beacon -> beacon.replaceAll("\\(.*\\)", ""))
.collect(Collectors.toSet());
locationLog.setBeacons(new JSONArray().fluentAddAll(codes));
// TODO
// 并计算出入标记(围栏、区域)
// 写入数据
locationLogRepository.saveAndFlush(locationLog);
// 更新定位标签卡状态信息
tag.setPoint(locationLog.getPoint());
tag.setVolt(locationLog.getVolt());
tag.setVoltUnit(locationLog.getVoltUnit());
tag.setSilent(locationLog.getSilent());
locationTagRepository.save(tag);
// WebSocket 推送定位消息
// 消息内容需要确定 TODO
simpMessagingTemplate.convertAndSend("/topic/position", "{}");
// TODO
// 判断围栏告警是否触发,触发写入告警记录,并推送消息
}
/**
* 处理低电量报警消息
* @param data 消息内容
*/
public void processLowPowerMessage(JSONObject data) {
// TODO
log.info("LowPower Message: {}", data);
}
/**
* 处理设备状态更新消息
* @param data 消息内容
*/
public void processDeviceStatusMessage(JSONObject data) {
// TODO
log.info("DeviceStatus Message: {}", data);
}
/**
* 处理按键报警消息
* @param data 消息内容
*/
public void processKeyWarningMessage(JSONObject data) {
// TODO
log.info("KeyWarning Message: {}", data);
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.util;
import com.alibaba.fastjson.JSONObject;
import com.yiring.app.util.zy.LonLatUtil;
import lombok.experimental.UtilityClass;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
......@@ -53,6 +55,61 @@ public class GeoUtils {
// TODO
// 根据真源定位系统设置的坐标系,转换为经纬度
// 根据北向的地图左下角坐标点,矩形长宽距离,结合二维图片的像素比,计算经纬度
// 左下角经纬度信息(基准点)
// TODO: 需要从真源获取后更新
JSONObject root = LonLatUtil.getRoot();
// 计算经纬度
JSONObject result = LonLatUtil.ComputeLonLat(
root.getDoubleValue("lon"),
root.getDoubleValue("lat"),
root.getDoubleValue("x"),
root.getDoubleValue("y"),
x,
y
);
// 构建经纬度坐标信息
Coordinate coordinate = new Coordinate(
result.getDoubleValue("lon"),
result.getDoubleValue("lat"),
root.getDoubleValue("altitude") + z
);
return factory.createPoint(coordinate);
}
/**
* 获取经纬度边界
* @return 经纬度边界
*/
public static double[] defaultBounds() {
// 数据来源于 2D 正射影像图转 mbtiles 描述文件
return new double[] { 112.858891, 30.473306, 112.866217, 30.481243 };
}
/**
* 根据经纬度边界随机生成一个坐标点
* @param bounds 经纬度边界
* @param z 高度
* @return 坐标点
*/
public Point randomPoint(double[] bounds, double z) {
return randomPoint(bounds[0], bounds[1], bounds[2], bounds[3], z);
}
/**
* 根据经纬度边界随机生成一个坐标点
* @param minX 最小经度
* @param minY 最小纬度
* @param maxX 最大经度
* @param maxY 最大纬度
* @param z 高度
* @return 坐标点
*/
public Point randomPoint(double minX, double minY, double maxX, double maxY, double z) {
double x = minX + (maxX - minX) * Math.random();
double y = minY + (maxY - minY) * Math.random();
return factory.createPoint(new Coordinate(x, y, z));
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.util;
import java.io.Serializable;
import java.time.LocalDateTime;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.IdentifierGenerator;
import org.springframework.stereotype.Component;
/**
* @author Jim
* @version 0.1
* 2022/5/10 18:26
*/
@Component
public class TimeIdGenerator implements IdentifierGenerator {
public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
return LocalDateTime.now();
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.app.util.zy;
import com.alibaba.fastjson.JSONObject;
/**
* @author Jim
* @version 0.1
* 2022/5/9 16:41
*/
public class LonLatUtil {
static final long LonLat_A = 6378137;
static final double LonLat_B = 6356752.3142;
static final double LonLat_F = 1 / 298.257223563;
public static JSONObject getRoot() {
JSONObject root = new JSONObject();
root.put("lon", 0D);
root.put("lat", 0D);
root.put("x", 0D);
root.put("y", 0D);
root.put("altitude", 0D);
return root;
}
// lon:基准点经度
// lat:基准点纬度
// distance:目标点离基准点距离
// angle:目标点与基准点连线和正北方向夹角
public static JSONObject ComputeLonLat(
double lon,
double lat,
double rootX,
double rootY,
double postX,
double postY
) {
double distance = getDistance(rootX, rootY, postX, postY);
double alpha1 = (Math.PI / 2) - Math.atan2(postY - rootY, postX - rootX);
double sinAlpha1 = Math.sin(alpha1);
double cosAlpha1 = Math.cos(alpha1);
double tanU1 = (1 - LonLat_F) * Math.tan(Rad(lat));
double cosU1 = 1 / Math.sqrt((1 + tanU1 * tanU1));
double sinU1 = tanU1 * cosU1;
double sigma1 = Math.atan2(tanU1, cosAlpha1);
double sinAlpha = cosU1 * sinAlpha1;
double cosSqAlpha = 1 - sinAlpha * sinAlpha;
double uSq = cosSqAlpha * ((LonLat_A * LonLat_A) - LonLat_B * LonLat_B) / (LonLat_B * LonLat_B);
double A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
double B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
double sigma = distance / (LonLat_B * A);
double sigmaP = 2 * Math.PI;
double cos2SigmaM = Math.cos(2 * sigma1 + sigma);
double sinSigma = Math.sin(sigma);
double cosSigma = Math.cos(sigma);
while (Math.abs(sigma - sigmaP) > 1e-12) {
cos2SigmaM = Math.cos(2 * sigma1 + sigma);
sinSigma = Math.sin(sigma);
cosSigma = Math.cos(sigma);
double deltaSigma =
B *
sinSigma *
(
cos2SigmaM +
B /
4 *
(
cosSigma *
(-1 + 2 * cos2SigmaM * cos2SigmaM) -
B /
6 *
cos2SigmaM *
(-3 + 4 * sinSigma * sinSigma) *
(-3 + 4 * cos2SigmaM * cos2SigmaM)
)
);
sigmaP = sigma;
sigma = distance / (LonLat_B * A) + deltaSigma;
}
double tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1;
double lat2 = Math.atan2(
sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1,
(1 - LonLat_F) * Math.sqrt(sinAlpha * sinAlpha + tmp * tmp)
);
double lambda = Math.atan2(sinSigma * sinAlpha1, cosU1 * cosSigma - sinU1 * sinSigma * cosAlpha1);
double C = LonLat_F / 16 * cosSqAlpha * (4 + LonLat_F * (4 - 3 * cosSqAlpha));
double L =
lambda -
(1 - C) *
LonLat_F *
sinAlpha *
(sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));
// double revAz = Math.atan2(sinAlpha, -tmp); // final bearing4
JSONObject lonLat = new JSONObject();
lonLat.put("lon", lon + Deg(L));
lonLat.put("lat", Deg(lat2));
return lonLat;
}
public static double Rad(double d) {
return d * Math.PI / 180.0;
}
public static double Deg(double d) {
return d * 180 / Math.PI;
}
public static double getDistance(double rootX, double rootY, double postX, double postY) {
double dx2 = Math.pow((rootX - postX), 2);
double dy2 = Math.pow((rootY - postY), 2);
double dz2 = Math.pow((0), 2);
return Math.sqrt(dx2 + dy2 + dz2);
}
}
......@@ -12,6 +12,10 @@ import java.util.Arrays;
import java.util.List;
import javax.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKTReader;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
......@@ -52,4 +56,14 @@ public class HelloController {
public Result<String> test() {
return Result.ok(ZyUtil.manageLogin());
}
@GetMapping("test2")
public Result<Geometry> 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);
}
}
......@@ -5,8 +5,8 @@ import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yiring.app.feign.MapClient;
import com.yiring.app.util.zy.ZyUtil;
import com.yiring.app.vo.map.MapVo;
import com.yiring.auth.util.ZyUtil;
import com.yiring.common.core.Result;
import com.yiring.common.core.Status;
import io.swagger.annotations.Api;
......@@ -41,7 +41,7 @@ public class MapController {
@GetMapping("/mapSelect")
@ApiImplicitParams({ @ApiImplicitParam(value = "orgId", required = true, name = "orgId") })
public Result<MapVo> mapSelect(String orgId) {
String login = ZyUtil.login();
String login = ZyUtil.clientLogin();
JSONObject jsonObject = mapClient.selectMap(orgId, "bearer " + login);
// if (ObjectUtil.isNotNull(jsonObject.getJSONArray("data"))) {
// List<MapVo.MapVoReuslt> data = jsonObject.getJSONArray("data").toJavaList(MapVo.MapVoReuslt.class);
......
......@@ -3,6 +3,11 @@ env:
host: 192.168.0.156
spring:
servlet:
multipart:
enabled: true
max-file-size: 50MB
max-request-size: 100MB
datasource:
url: jdbc:postgresql://${env.host}:5432/kshg_app
username: admin
......@@ -26,24 +31,16 @@ spring:
username: admin
password: 123456
virtual-host: /
# 开启发送端确认
publisher-confirm-type: correlated
# 开启接收端确认
publisher-returns: true
template:
# 消息抵达队列,异步回调 confirm
mandatory: true
listener:
simple:
# 手动确认消息
acknowledge-mode: manual
servlet:
multipart:
enabled: true
max-file-size: 50MB
max-request-size: 100MB
data:
redis:
repositories:
enabled: false
# 处理多网卡选举
cloud:
inetutils:
preferred-networks: 192.168.0
# knife4j
# knife4j(swagger)
knife4j:
enable: true
basic:
......@@ -62,10 +59,33 @@ minio:
bucket: kshg
domain: ${minio.endpoint}/${minio.bucket}
# 任务调度
xxl:
job:
### 调度中心部署跟地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册;
admin-addresses: http://${env.host}:8080/xxl-job-admin
### 执行器通讯TOKEN [选填]:非空时启用;
access-token: local
### 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
executor-app-name: kshg-app
### 执行器注册 [选填]:优先使用该配置作为注册地址,为空时使用内嵌服务 ”IP:PORT“ 作为注册地址。从而更灵活的支持容器类型执行器动态IP和动态映射端口问题。
executor-address:
### 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务";
executor-ip:
### 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
executor-port:
### 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
executor-log-path: /data/applogs/xxl-job/jobhandler
### 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能;
executor-log-retention-days: 30
# 日志
logging:
level:
# sql bind parameter
org.hibernate.type.descriptor.sql.BasicBinder: trace
# org.hibernate.type.descriptor.sql.BasicBinder: trace
org.hibernate.type.descriptor.sql.BasicBinder: error
# 真源定位系统相关配置
zy-config:
host: project.yz-online.com
......
......@@ -17,9 +17,11 @@ dependencies {
// JTS 几何对象操作库
implementation "org.locationtech.jts:jts-core:${jtsVersion}"
// https://mvnrepository.com/artifact/com.graphhopper.external/jackson-datatype-jts
implementation("com.graphhopper.external:jackson-datatype-jts:1.0-2.7") {
// https://mvnrepository.com/artifact/org.n52.jackson/jackson-datatype-jts/1.2.10
implementation("org.n52.jackson:jackson-datatype-jts:1.2.10") {
exclude group: 'com.fasterxml.jackson.core', module: 'jackson-databind'
exclude group: 'com.fasterxml.jackson.core', module: 'jackson-annotations'
exclude group: 'com.fasterxml.jackson.core', module: 'jackson-core'
exclude group: 'org.locationtech.jts', module: 'jts-core'
}
......
/* (C) 2022 YiRing, Inc. */
package com.yiring.common.config;
import com.bedatadriven.jackson.datatype.jts.JtsModule;
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.n52.jackson.datatype.jts.JtsModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
......
......@@ -2,7 +2,6 @@
package com.yiring.common.domain;
import java.time.LocalDateTime;
import java.util.Objects;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
......@@ -11,7 +10,6 @@ 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.CreationTimestamp;
import org.hibernate.annotations.GenericGenerator;
......@@ -52,17 +50,4 @@ public abstract class BasicEntity {
@Column(nullable = false)
@UpdateTimestamp
LocalDateTime updateTime;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false;
BasicEntity that = (BasicEntity) o;
return id != null && Objects.equals(id, that.id);
}
@Override
public int hashCode() {
return getClass().hashCode();
}
}
/* (C) 2022 YiRing, Inc. */
package com.yiring.common.annotation;
import java.lang.annotation.*;
/**
* 耗时计算注解
*
* @author Jim
* @version 0.1
* 2022/4/7 15:21
*/
@SuppressWarnings({ "unused" })
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Times {
/**
* 描述
*/
String value() default "";
}
......@@ -3,6 +3,7 @@ package com.yiring.common.aspect;
import cn.hutool.extra.servlet.ServletUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.yiring.common.constant.DateFormatter;
import com.yiring.common.core.Result;
import com.yiring.common.util.Commons;
......@@ -34,7 +35,7 @@ public class RequestAspect {
Boolean debug;
@Pointcut(
"@annotation(org.springframework.web.bind.annotation.PostMapping) || @annotation(org.springframework.web.bind.annotation.GetMapping) || @annotation(org.springframework.web.bind.annotation.ExceptionHandler)"
"@annotation(org.springframework.web.bind.annotation.PostMapping) || @annotation(org.springframework.web.bind.annotation.GetMapping) || @annotation(org.springframework.web.bind.annotation.PutMapping) || @annotation(org.springframework.web.bind.annotation.DeleteMapping) || @annotation(org.springframework.web.bind.annotation.PatchMapping) || @annotation(org.springframework.web.bind.annotation.ExceptionHandler)"
)
public void apiPointCut() {}
......@@ -52,8 +53,10 @@ public class RequestAspect {
// Print Request Log (Optional Replace: MDC)
String extra = "";
if (Boolean.TRUE.equals(debug)) {
extra += String.format("\nHeaders: %s", JSONObject.toJSONString(ServletUtil.getHeaderMap(request), true));
extra += String.format("\nParams: %s", JSONObject.toJSONString(ServletUtil.getParamMap(request), true));
String headers = JSONObject.toJSONString(ServletUtil.getHeaderMap(request), SerializerFeature.PrettyFormat);
String params = JSONObject.toJSONString(ServletUtil.getParamMap(request), SerializerFeature.PrettyFormat);
extra += String.format("\nHeaders: %s", headers);
extra += String.format("\nParams: %s", params);
if (result instanceof Result) {
extra +=
String.format(
......
/* (C) 2021 YiRing, Inc. */
package com.yiring.common.aspect;
import cn.hutool.core.util.StrUtil;
import com.yiring.common.annotation.Times;
import java.lang.reflect.Method;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
/**
* 耗时计算注解切面
*
* @author ifzm
* @version 0.1
*/
@Slf4j
@Aspect
@Component
public class TimesAspect {
@Pointcut("@annotation(com.yiring.common.annotation.Times)")
public void pointCut() {}
@Around("pointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
long start = System.currentTimeMillis();
Object result = point.proceed();
long end = System.currentTimeMillis();
log.info("[Times] {}: {} ms", getTimesValue(point), end - start);
return result;
}
public String getTimesValue(JoinPoint joinPoint) {
// 获取切入点的目标类
Class<?> targetClass = joinPoint.getTarget().getClass();
// 获取切入方法名
String methodName = joinPoint.getSignature().getName();
// 获取切入方法参数
Object[] arguments = joinPoint.getArgs();
// 获取目标类的所有方法
Method[] methods = targetClass.getMethods();
String timesValue = methodName;
for (Method method : methods) {
// 方法名相同、包含目标注解、方法参数个数相同(避免有重载)
if (
method.getName().equals(methodName) &&
method.isAnnotationPresent(Times.class) &&
method.getParameterTypes().length == arguments.length
) {
String value = method.getAnnotation(Times.class).value();
if (StrUtil.isNotEmpty(value)) {
timesValue = value;
}
}
}
return timesValue;
}
}
......@@ -3,6 +3,8 @@ buildscript {
maven { url "https://plugins.gradle.org/m2/" }
}
ext {
// https://start.spring.io/
springCloudVersion = '2021.0.2'
// https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-spring-boot-starter
knife4jVersion = '2.0.9'
// https://mvnrepository.com/artifact/io.swagger/swagger-annotations
......@@ -26,11 +28,9 @@ buildscript {
// https://mvnrepository.com/artifact/org.locationtech.jts/jts-core
jtsVersion = '1.18.2'
// https://mvnrepository.com/artifact/com.vladmihalcea/hibernate-types-55
hibernateTypesVersion = '2.16.1'
hibernateTypesVersion = '2.16.2'
// https://mvnrepository.com/artifact/com.github.liaochong/myexcel
myexcelVersion = '4.1.1'
// https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign
openfeignVersion = '3.1.1'
// https://mvnrepository.com/artifact/io.github.openfeign/feign-okhttp
feignOkhttpVersion= '11.8'
}
......@@ -38,7 +38,7 @@ buildscript {
plugins {
id 'java'
id 'org.springframework.boot' version '2.6.6'
id 'org.springframework.boot' version '2.6.7'
// https://plugins.gradle.org/plugin/io.spring.dependency-management
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
// https://plugins.gradle.org/plugin/com.diffplug.spotless
......@@ -81,6 +81,12 @@ subprojects {
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
[compileJava, compileTestJava, javadoc]*.options*.encoding = 'UTF-8'
tasks.withType(JavaCompile) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论