29 changed files with 1178 additions and 275 deletions
@ -1,2 +1,18 @@ |
|||
# ams-social |
|||
|
|||
- 框架/依赖说明 |
|||
- JDK17 |
|||
- SpringBoot 3.1.7 |
|||
- sa-token 登陆认证 |
|||
- mapstruct、orika 对象拷贝 |
|||
- mybatis-plus 数据持久化 |
|||
- easy-excel excel导入导出 |
|||
- hikari 数据库连接池 |
|||
- openapi 注解生成接口文档 |
|||
- rabbitmq 消息队列 |
|||
- redis 缓存 |
|||
- actuator/prometheus 监控 |
|||
- huawei obs 对象存储 |
|||
- fastjson2/gson/jackson json |
|||
- maven-pmd-plugin 静态代码检查插件 |
|||
- 功能说明 |
@ -0,0 +1,48 @@ |
|||
package com.jiagutech.ams.controller; |
|||
|
|||
import com.alibaba.fastjson2.JSONObject; |
|||
import com.jiagutech.ams.model.common.R; |
|||
import com.jiagutech.ams.model.request.MachImage; |
|||
import com.jiagutech.ams.model.request.RealTimeData; |
|||
import com.jiagutech.ams.model.request.WorkRecord; |
|||
import com.jiagutech.ams.service.MessageDataService; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.web.bind.annotation.*; |
|||
|
|||
import java.util.List; |
|||
|
|||
@Slf4j |
|||
@RestController |
|||
@RequiredArgsConstructor |
|||
@RequestMapping("/MessageDataService") |
|||
public class MessageDataController { |
|||
|
|||
private final MessageDataService messageDataService; |
|||
|
|||
@PostMapping("/machineryRealtimeData") |
|||
public R addRealTimeData(@RequestBody List<RealTimeData> realTimeDatas) { |
|||
//if (checkSign(request,response)) {
|
|||
log.info("RealTimeData:{}", JSONObject.toJSONString(realTimeDatas)); |
|||
messageDataService.addRealTimeData(realTimeDatas); |
|||
return R.ok("success"); |
|||
|
|||
} |
|||
|
|||
@PostMapping(value = "/machineryImage", consumes = "multipart/form-data") |
|||
public R machineryImage(@ModelAttribute MachImage machImage) { |
|||
|
|||
log.info("workRecord:{}", machImage.getVehicleId()); |
|||
messageDataService.machineryImage(machImage); |
|||
return R.ok("success"); |
|||
|
|||
} |
|||
|
|||
@PostMapping("/machineryAreaDataList") |
|||
public R addWorkData(@RequestBody List<WorkRecord> workRecords) { |
|||
log.info("WorkRecord:{}", JSONObject.toJSONString(workRecords)); |
|||
messageDataService.addWorkData(workRecords); |
|||
|
|||
return R.ok("success"); |
|||
} |
|||
} |
@ -0,0 +1,15 @@ |
|||
package com.jiagutech.ams.model; |
|||
|
|||
import com.jiagutech.ams.model.request.MachImage; |
|||
import org.mapstruct.Mapper; |
|||
import org.mapstruct.factory.Mappers; |
|||
|
|||
@Mapper |
|||
public interface TrackImageMapping { |
|||
|
|||
TrackImageMapping INTANCE = Mappers.getMapper(TrackImageMapping.class); |
|||
|
|||
|
|||
TrackImageVO convertByMachImage(MachImage machImage); |
|||
|
|||
} |
@ -0,0 +1,20 @@ |
|||
package com.jiagutech.ams.model; |
|||
|
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class ZhongNongTrack { |
|||
|
|||
private String simNo; |
|||
|
|||
private String sendTime; |
|||
|
|||
private Float velocity; |
|||
|
|||
private Double latitude; |
|||
|
|||
private Double longitude; |
|||
|
|||
private Integer direction; |
|||
|
|||
} |
@ -0,0 +1,21 @@ |
|||
package com.jiagutech.ams.model.request; |
|||
|
|||
import lombok.Data; |
|||
import org.springframework.web.multipart.MultipartFile; |
|||
|
|||
@Data |
|||
public class MachImage { |
|||
|
|||
// 设备Id
|
|||
private String vehicleId; |
|||
// 时间戳
|
|||
private long timestamp; |
|||
// 纬度,最多保留7位小数(CGCS2000 坐标系)
|
|||
private double lat; |
|||
// 经度,最多保留7位小数(CGCS2000 坐标系)
|
|||
private double lng; |
|||
|
|||
private MultipartFile image; |
|||
|
|||
private String imageUrl; |
|||
} |
@ -0,0 +1,29 @@ |
|||
package com.jiagutech.ams.model.request; |
|||
|
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class RealTimeData { |
|||
|
|||
// 设备Id
|
|||
private String vehicleId; |
|||
// 时间戳
|
|||
private long timestamp; |
|||
// 纬度,最多保留7位小数(CGCS2000 坐标系)
|
|||
private double lat; |
|||
// 经度,最多保留7位小数(CGCS2000 坐标系)
|
|||
private double lng; |
|||
// 状态[1位数字](0=不工作,1=工作,3=合格)
|
|||
private int status; |
|||
// 幅宽(米)[浮点数,最多保留两位小数]
|
|||
private Double breadth; // 可选字段
|
|||
// 速度(千米/小时<km/h>)[浮点数,最多保留一位小数]
|
|||
private Double velocity; // 可选字段
|
|||
// 耕深(厘米)[浮点数,最多保留一位小数]
|
|||
private Double deep; // 可选字段
|
|||
// 流量(脉冲值)[浮点数,最多保留一位小数]
|
|||
// 流量(脉冲值)[浮点数,最多保留一位小数]
|
|||
private Double flow; // 可选字段
|
|||
// 播种速度 粒/s转对应实体类
|
|||
private Double seeding; // 可选字段
|
|||
} |
@ -0,0 +1,41 @@ |
|||
package com.jiagutech.ams.model.request; |
|||
|
|||
import com.jiagutech.ams.model.Locus; |
|||
import lombok.Data; |
|||
|
|||
import java.util.List; |
|||
|
|||
// 主要的作业记录类
|
|||
@Data |
|||
public class WorkRecord { |
|||
// 达标面积(亩)
|
|||
private Double qualifiedWorkArea; |
|||
// 重复作业面积(亩)
|
|||
private Double repeatWorkArea; |
|||
// 作业面积(亩)
|
|||
private Double workArea; |
|||
// 开始时间,毫秒时间戳
|
|||
private Long startAt; |
|||
// 结束时间,毫秒时间戳
|
|||
private Long endAt; |
|||
// 设备Id
|
|||
private String vehicleId; |
|||
// 作业地点经度
|
|||
private Double longitude; |
|||
// 作业地点纬度
|
|||
private Double latitude; |
|||
// 耕深(厘米)
|
|||
private Double avgDeep; |
|||
// 合格率
|
|||
private Double qualifiedRate; |
|||
// 行驶里程(米)
|
|||
private Double distance; |
|||
// 作业类型,编码见附表1
|
|||
private Long module; |
|||
// 总流量(单位:L)
|
|||
private Double sumFlow; |
|||
// 总播种量 (单位:粒)
|
|||
private Integer seedingNumber; |
|||
// 地块轨迹
|
|||
private List<Locus> locus; |
|||
} |
@ -0,0 +1,75 @@ |
|||
package com.jiagutech.ams.rest; |
|||
|
|||
import com.alibaba.fastjson2.JSON; |
|||
import com.alibaba.fastjson2.JSONObject; |
|||
import com.jiagutech.ams.model.ZhongNongTrack; |
|||
import io.swagger.v3.core.util.Json; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.http.HttpEntity; |
|||
import org.springframework.http.HttpHeaders; |
|||
import org.springframework.http.MediaType; |
|||
import org.springframework.http.ResponseEntity; |
|||
import org.springframework.stereotype.Component; |
|||
import org.springframework.web.client.RestTemplate; |
|||
|
|||
import java.time.Instant; |
|||
import java.time.ZoneId; |
|||
import java.time.format.DateTimeFormatter; |
|||
import java.util.List; |
|||
|
|||
@Slf4j |
|||
@Component |
|||
@RequiredArgsConstructor |
|||
public class ZhongNongRestClient { |
|||
|
|||
|
|||
private final RestTemplate restTemplate; |
|||
|
|||
|
|||
@Value("${zhong-nong.client.base_url}") |
|||
private String baseUrl; |
|||
|
|||
public String getAccessToken(String keyId, String signature, long timestamp) { |
|||
// 设置请求头和请求体
|
|||
HttpHeaders headers = new HttpHeaders(); |
|||
headers.setContentType(MediaType.APPLICATION_JSON); |
|||
JSONObject body = new JSONObject(); |
|||
body.put("keyId", keyId); |
|||
body.put("signature", signature); |
|||
body.put("timestamp", timestamp); |
|||
HttpEntity<String> requestEntity = new HttpEntity<>(body.toJSONString(), headers); |
|||
ResponseEntity<String> response = restTemplate.postForEntity(baseUrl + "/ThirdParty/sso", requestEntity, String.class); |
|||
if (response.getStatusCode().is2xxSuccessful()) { |
|||
return response.getBody(); |
|||
} else { |
|||
log.error("获取token失败:{}", response); |
|||
return null; |
|||
} |
|||
|
|||
} |
|||
|
|||
|
|||
public List<ZhongNongTrack> getTracks(String accessToken, String simNo, long startTime, long endTime) { |
|||
// 设置请求头和请求体
|
|||
HttpHeaders headers = new HttpHeaders(); |
|||
headers.setContentType(MediaType.APPLICATION_JSON); |
|||
headers.set("concrete-token-id", accessToken); |
|||
JSONObject body = new JSONObject(); |
|||
body.put("simNo", simNo); |
|||
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") |
|||
.withZone(ZoneId.of("Asia/Shanghai")); |
|||
body.put("startTime", df.format(Instant.ofEpochMilli(startTime))); |
|||
body.put("endTime", df.format(Instant.ofEpochMilli(endTime))); |
|||
log.info(" get tracks params :{}", body); |
|||
HttpEntity<String> requestEntity = new HttpEntity<>(body.toJSONString(), headers); |
|||
ResponseEntity<String> response = restTemplate.postForEntity(baseUrl + "/MessageDataService/vehicleLocusList", requestEntity, String.class); |
|||
if (response.getStatusCode().is2xxSuccessful()) { |
|||
return JSON.parseArray(response.getBody(), ZhongNongTrack.class); |
|||
} else { |
|||
log.error("获取轨迹失败:{}", response); |
|||
return null; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,16 @@ |
|||
package com.jiagutech.ams.service; |
|||
|
|||
import com.jiagutech.ams.model.request.MachImage; |
|||
import com.jiagutech.ams.model.request.RealTimeData; |
|||
import com.jiagutech.ams.model.request.WorkRecord; |
|||
|
|||
import java.util.List; |
|||
|
|||
public interface MessageDataService { |
|||
|
|||
void addRealTimeData(List<RealTimeData> realTimeDatas); |
|||
|
|||
void machineryImage(MachImage machImage); |
|||
|
|||
void addWorkData(List<WorkRecord> workRecords); |
|||
} |
@ -0,0 +1,72 @@ |
|||
package com.jiagutech.ams.service; |
|||
|
|||
import com.alibaba.fastjson2.JSONObject; |
|||
import com.jiagutech.ams.model.Locus; |
|||
import com.jiagutech.ams.model.TrackDataJG; |
|||
import com.jiagutech.ams.model.TrackImageMapping; |
|||
import com.jiagutech.ams.model.UavSortie; |
|||
import com.jiagutech.ams.model.request.MachImage; |
|||
import com.jiagutech.ams.model.request.RealTimeData; |
|||
import com.jiagutech.ams.model.request.WorkRecord; |
|||
import com.jiagutech.ams.rest.TrackRestClient; |
|||
import com.jiagutech.ams.utils.HuaweiObs; |
|||
import lombok.Data; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.SneakyThrows; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.data.redis.core.StringRedisTemplate; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import java.util.List; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
@Slf4j |
|||
@Service |
|||
@RequiredArgsConstructor |
|||
public class MessageDataServiceImpl implements MessageDataService { |
|||
private final StringRedisTemplate stringRedisTemplate; |
|||
private final HuaweiObs huaweiObs; |
|||
|
|||
private final JobService jobService; |
|||
|
|||
private final TrackRestClient trackRestClient; |
|||
|
|||
public void addRealTimeData(List<RealTimeData> realTimeDatas) { |
|||
for (RealTimeData realTimeData : realTimeDatas) { |
|||
TrackDataJG uavTrackDataRVO = new TrackDataJG(); |
|||
uavTrackDataRVO.setLat(realTimeData.getLat()); |
|||
uavTrackDataRVO.setLng(realTimeData.getLng()); |
|||
uavTrackDataRVO.setDroneId(realTimeData.getVehicleId()); |
|||
uavTrackDataRVO.setHvel(Float.parseFloat(String.valueOf(realTimeData.getVelocity()))); |
|||
uavTrackDataRVO.setTimeStamp(realTimeData.getTimestamp()); |
|||
String s = JSONObject.toJSONString(uavTrackDataRVO); |
|||
stringRedisTemplate.opsForValue().set("mtrack:" + realTimeData.getVehicleId(), s, 2, TimeUnit.MINUTES); |
|||
} |
|||
} |
|||
|
|||
|
|||
@SneakyThrows |
|||
public void machineryImage(MachImage machImage) { |
|||
String upload = huaweiObs.upload(machImage.getImage()); |
|||
if (upload != null) { |
|||
log.info("保存图片到ams,图片链接:{}", upload); |
|||
machImage.setImageUrl(upload); |
|||
machImage.setImage(null); |
|||
TrackImageMapping mapping = TrackImageMapping.INTANCE; |
|||
jobService.saveJobImages(mapping.convertByMachImage(machImage)); |
|||
} |
|||
|
|||
} |
|||
|
|||
@Override |
|||
public void addWorkData(List<WorkRecord> workRecords) { |
|||
for (WorkRecord workRecord : workRecords) { |
|||
List<Locus> locus = workRecord.getLocus(); |
|||
//轨迹插入
|
|||
if (locus.size() > 0) { |
|||
trackRestClient.saveTractor(locus); |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
@ -0,0 +1,264 @@ |
|||
package com.jiagutech.ams.utils; |
|||
|
|||
import cn.hutool.core.util.IdUtil; |
|||
import com.alibaba.fastjson2.JSON; |
|||
import com.obs.services.ObsClient; |
|||
import com.obs.services.model.*; |
|||
import jakarta.annotation.Resource; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.commons.io.IOUtils; |
|||
import org.springframework.stereotype.Component; |
|||
import org.springframework.web.multipart.MultipartFile; |
|||
|
|||
import java.io.ByteArrayInputStream; |
|||
import java.io.IOException; |
|||
import java.io.InputStream; |
|||
import java.util.Calendar; |
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* @author Lenovo |
|||
*/ |
|||
@Slf4j |
|||
@Component |
|||
public class HuaweiObs { |
|||
|
|||
//Access Key Id
|
|||
//private String ak = "Access Key Id";
|
|||
|
|||
//Secret Access Key
|
|||
//private String sk = "Secret Access Key";
|
|||
|
|||
//桶名称
|
|||
private String bucketName = "jg-iot"; |
|||
|
|||
// 终端节点访问Endpoint
|
|||
//private String endpoint = "Endpoint";
|
|||
|
|||
// 文件目录
|
|||
private String prifix = "/farm"; |
|||
|
|||
// 访问域名 在域名后面或文件目录前加“/”
|
|||
private String path = "/farm/"; |
|||
|
|||
|
|||
@Resource |
|||
private ObsClient obsClient; |
|||
|
|||
/** |
|||
* 文件上传 |
|||
* |
|||
* @param file |
|||
* @return |
|||
* @throws IOException |
|||
*/ |
|||
public String upload(MultipartFile file) throws IOException { |
|||
//ObsClient obsClient = null;
|
|||
|
|||
Calendar cal = Calendar.getInstance(); |
|||
int year = cal.get(Calendar.YEAR); |
|||
int month = cal.get(Calendar.MONTH); |
|||
int day = cal.get(Calendar.DATE); |
|||
String fileName = IdUtil.simpleUUID() + file.getOriginalFilename().substring(file.getOriginalFilename().indexOf(".")); |
|||
String objectName = prifix + "/" + year + "/" + month + "/" + day + "/" + fileName; |
|||
//obsClient = new ObsClient(ak, sk, endpoint);
|
|||
PutObjectResult response = obsClient.putObject(bucketName, objectName, file.getInputStream()); |
|||
log.info(JSON.toJSONString(response)); |
|||
// 可选:调用成功后,记录调用成功的HTTP状态码和服务端请求ID
|
|||
int statusCode = response.getStatusCode(); |
|||
|
|||
if (200 == statusCode) { |
|||
|
|||
return response.getObjectUrl(); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
/** |
|||
* 上传文件--流式 |
|||
* |
|||
* @param fileName 上传文件名称 |
|||
* @param is 文件流 |
|||
* @return |
|||
*/ |
|||
public String uploadFile(String fileName, InputStream is) throws IOException { |
|||
//ObsClient obsClient = null;
|
|||
try { |
|||
Calendar cal = Calendar.getInstance(); |
|||
int year = cal.get(Calendar.YEAR); |
|||
int month = cal.get(Calendar.MONTH); |
|||
int day = cal.get(Calendar.DATE); |
|||
String objectName = prifix + "/" + year + "/" + month + "/" + day + "/" + fileName; |
|||
//obsClient = new ObsClient(ak, sk, endpoint);
|
|||
HeaderResponse response = obsClient.putObject(bucketName, objectName, is); |
|||
log.info(JSON.toJSONString(response)); |
|||
// 可选:调用成功后,记录调用成功的HTTP状态码和服务端请求ID
|
|||
int statusCode = response.getStatusCode(); |
|||
if (200 == statusCode) { |
|||
String objectUrl = path + objectName; |
|||
return objectUrl; |
|||
} |
|||
} finally { |
|||
obsClient.close(); |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
/** |
|||
* 上传文件--字节数组 |
|||
* |
|||
* @param fileName 上传文件名称 |
|||
* @param fileType 文件路径 |
|||
* @param is 文件流 |
|||
* @return |
|||
*/ |
|||
public boolean uploadFileByte(String fileName, FileType fileType, byte[] is) { |
|||
//ObsClient obsClient = null;
|
|||
try { |
|||
String objectName = fileType.getType().concat("/").concat(fileName); |
|||
//obsClient = new ObsClient(ak, sk, endpoint);
|
|||
HeaderResponse response = obsClient.putObject(bucketName, objectName, new ByteArrayInputStream(is)); |
|||
// 可选:调用成功后,记录调用成功的HTTP状态码和服务端请求ID
|
|||
int statusCode = response.getStatusCode(); |
|||
if (200 == statusCode) { |
|||
return true; |
|||
} |
|||
obsClient.close(); |
|||
} catch (IOException e) { |
|||
log.info("文件上传失败:{}", e.getMessage(), e); |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* 下载文件 |
|||
* |
|||
* @param fileName 文件名称 |
|||
* @param fileType 文件路径 |
|||
* @return |
|||
*/ |
|||
public String getDownloadUrl(String fileName, FileType fileType) { |
|||
//ObsClient obsClient = null;
|
|||
//obsClient = new ObsClient(ak, sk, endpoint);
|
|||
// URL有效期,3600秒.5分钟
|
|||
long expireSeconds = 3600L; |
|||
String objectName = fileType.getType().concat("/").concat(fileName); |
|||
TemporarySignatureRequest request = new TemporarySignatureRequest(HttpMethodEnum.GET, expireSeconds); |
|||
request.setBucketName(bucketName); |
|||
request.setObjectKey(objectName); |
|||
TemporarySignatureResponse response = obsClient.createTemporarySignature(request); |
|||
return response.getSignedUrl(); |
|||
} |
|||
|
|||
/** |
|||
* 获取上传地址 |
|||
* |
|||
* @param fileName 文件名称 |
|||
* @param fileType 文件路径 |
|||
* @return |
|||
*/ |
|||
public String getUploadUrl(String fileName, FileType fileType) { |
|||
try { |
|||
// 创建ObsClient实例
|
|||
//ObsClient obsClient = new ObsClient(ak, sk, endpoint);
|
|||
// URL有效期,3600秒
|
|||
long expireSeconds = 3600L; |
|||
Map<String, String> headers = new HashMap<String, String>(); |
|||
headers.put("Content-Type", "application/octet-stream"); |
|||
String objectName = fileType.getType().concat("/").concat(fileName); |
|||
TemporarySignatureRequest request = new TemporarySignatureRequest(HttpMethodEnum.PUT, expireSeconds); |
|||
request.setBucketName(bucketName); |
|||
request.setObjectKey(objectName); |
|||
request.setHeaders(headers); |
|||
TemporarySignatureResponse response = obsClient.createTemporarySignature(request); |
|||
return response.getSignedUrl(); |
|||
} catch (Exception e) { |
|||
log.error("获取上传地址异常:{}", e.getMessage(), e); |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
/** |
|||
* 下载文件返回字节数组 |
|||
* |
|||
* @param fileName 文件名称 |
|||
* @param fileType 文件路径 |
|||
* @return |
|||
*/ |
|||
public byte[] downloadFile(String fileName, FileType fileType) { |
|||
try { |
|||
InputStream inputStream = downloadFileInputStream(fileName, fileType); |
|||
byte[] bytes = IOUtils.toByteArray(inputStream); |
|||
return bytes; |
|||
} catch (Exception e) { |
|||
log.error("下载文件异常:{}", e.getMessage(), e); |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
/** |
|||
* 上传视频 |
|||
* |
|||
* @param fileName 文件名称 |
|||
* @param fileType 文件路径 |
|||
* @return |
|||
*/ |
|||
public boolean uploadFileVideo(String fileName, FileType fileType, InputStream is) { |
|||
try { |
|||
String objectName = fileType.getType().concat("/").concat(fileName); |
|||
//ObsClient obsClient = new ObsClient(ak, sk, endpoint);
|
|||
// 添加 ContentType (添加后可在浏览器中直接浏览,而非下载链接)
|
|||
obsClient.putObject(bucketName, objectName, is); |
|||
obsClient.close(); |
|||
return true; |
|||
} catch (Exception e) { |
|||
log.error("上传视频文件异常:{}", e.getMessage(), e); |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* 下载文件返回流式 |
|||
* |
|||
* @param fileName 文件名称 |
|||
* @param fileType 文件路径 |
|||
* @return |
|||
*/ |
|||
public InputStream downloadFileInputStream(String fileName, FileType fileType) { |
|||
try { |
|||
String objectName = fileType.getType().concat("/").concat(fileName); |
|||
// 用户拿到STS临时凭证后,通过其中的安全令牌(SecurityToken)和临时访问密钥(AccessKeyId和AccessKeySecret)生成OSSClient。
|
|||
//ObsClient obsClient = new ObsClient(ak, sk, endpoint);
|
|||
ObsObject obsObject = obsClient.getObject(bucketName, objectName); |
|||
obsClient.close(); |
|||
return obsObject.getObjectContent(); |
|||
} catch (Exception e) { |
|||
log.error("下载文件异常:{}", e.getMessage(), e); |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
|
|||
public enum FileType { |
|||
TEST("TEST", "测试"); |
|||
|
|||
private String type; |
|||
private String desc; |
|||
|
|||
FileType(String type, String desc) { |
|||
this.type = type; |
|||
this.desc = desc; |
|||
} |
|||
|
|||
public String getType() { |
|||
return type; |
|||
} |
|||
|
|||
public String getDesc() { |
|||
return desc; |
|||
} |
|||
} |
|||
} |
|||
|
@ -0,0 +1,104 @@ |
|||
package com.jiagutech.ams.utils; |
|||
|
|||
import cn.hutool.core.collection.CollectionUtil; |
|||
import com.jiagutech.ams.model.TrackItem; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
|
|||
import java.time.Instant; |
|||
import java.time.LocalDateTime; |
|||
import java.time.ZoneId; |
|||
import java.util.List; |
|||
import java.util.concurrent.atomic.AtomicReference; |
|||
|
|||
@Slf4j |
|||
public class TrackUtil { |
|||
|
|||
public static float calculateArea(List<TrackItem> trackList) { |
|||
try { |
|||
if (CollectionUtil.isEmpty(trackList)) { |
|||
return 0.0f; |
|||
} |
|||
List<FlightTrackerUtils.PointTemp> pointTemps = trackList.stream().map(item -> { |
|||
LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(item.getTimestamp()), ZoneId.systemDefault()); |
|||
int speed = Math.round(item.getVelocity() * 5 / 18); |
|||
return new FlightTrackerUtils.PointTemp(localDateTime, item.getLat(), item.getLng(), speed); |
|||
}).toList(); |
|||
if (CollectionUtil.isEmpty(pointTemps)) { |
|||
return 0.0f; |
|||
} |
|||
return (float) FlightTrackerUtils.calculateArea(pointTemps); |
|||
} catch (Exception e) { |
|||
log.error("calculate area error", e); |
|||
return 0.0f; |
|||
} |
|||
} |
|||
|
|||
private static final double EARTH_RADIUS = 6371000; |
|||
|
|||
// 计算总作业面积
|
|||
public static double calculateArea(List<double[]> coordinates, double width) { |
|||
double totalDistance = 0.0; |
|||
|
|||
// 累加轨迹点之间的距离
|
|||
for (int i = 1; i < coordinates.size(); i++) { |
|||
double[] start = coordinates.get(i - 1); |
|||
double[] end = coordinates.get(i); |
|||
|
|||
totalDistance += haversineDistance(start[1], start[0], end[1], end[0]); |
|||
} |
|||
|
|||
// 作业面积 = 作业宽度 * 总距离 * 作业效率系数
|
|||
return width * totalDistance * 0.7 * 0.0015; // Convert to mu (亩)
|
|||
|
|||
} |
|||
|
|||
public static double haversineDistance(double lat1, double lon1, double lat2, double lon2) { |
|||
// 将纬度和经度从度转换为弧度
|
|||
double lat1Rad = Math.toRadians(lat1); |
|||
double lon1Rad = Math.toRadians(lon1); |
|||
double lat2Rad = Math.toRadians(lat2); |
|||
double lon2Rad = Math.toRadians(lon2); |
|||
|
|||
// 计算差值
|
|||
double deltaLat = lat2Rad - lat1Rad; |
|||
double deltaLon = lon2Rad - lon1Rad; |
|||
|
|||
// 应用Haversine公式
|
|||
double a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) |
|||
+ Math.cos(lat1Rad) * Math.cos(lat2Rad) |
|||
* Math.sin(deltaLon / 2) * Math.sin(deltaLon / 2); |
|||
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); |
|||
|
|||
// 返回距离(米)
|
|||
return EARTH_RADIUS * c; |
|||
} |
|||
// // Haversine公式计算两点之间的距离
|
|||
// public static double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
|
|||
// double dLat = Math.toRadians(lat2 - lat1);
|
|||
// double dLon = Math.toRadians(lon2 - lon1);
|
|||
// double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
|
|||
// + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))
|
|||
// * Math.sin(dLon / 2) * Math.sin(dLon / 2);
|
|||
// double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|||
// return EARTH_RADIUS * c;
|
|||
// }
|
|||
|
|||
|
|||
public static float calcAreaByBlockData(List<TrackItem> pointTemps) { |
|||
AtomicReference<Double> breadth = new AtomicReference<>((double) 0); |
|||
List<double[]> coordinates = pointTemps.stream() |
|||
.filter(p -> p.getVelocity() > 0) |
|||
.filter(p -> p.getBreadth()!=null && p.getBreadth() > 0) |
|||
.map(item -> { |
|||
breadth.set(item.getBreadth()); |
|||
return new double[]{item.getLng(), item.getLat()}; |
|||
}).toList(); |
|||
return (float) calculateArea(coordinates, breadth.get()); |
|||
} |
|||
|
|||
public static float calcAreaByBlockDataNoFilter(List<TrackItem> pointTemps,double breadth) { |
|||
List<double[]> coordinates = pointTemps.stream() |
|||
.map(item -> new double[]{item.getLng(), item.getLat()}).toList(); |
|||
return (float) calculateArea(coordinates, breadth); |
|||
} |
|||
} |
@ -1,208 +1,214 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
<parent> |
|||
<groupId>com.jiagutech</groupId> |
|||
<artifactId>ams-social</artifactId> |
|||
<version>${revision}</version> |
|||
</parent> |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
<parent> |
|||
<groupId>com.jiagutech</groupId> |
|||
<artifactId>ams-social</artifactId> |
|||
<version>${revision}</version> |
|||
</parent> |
|||
|
|||
<artifactId>web</artifactId> |
|||
<packaging>jar</packaging> |
|||
<name>ams-social</name> |
|||
<artifactId>web</artifactId> |
|||
<packaging>jar</packaging> |
|||
<name>ams-social</name> |
|||
|
|||
<properties> |
|||
<maven.compiler.source>17</maven.compiler.source> |
|||
<maven.compiler.target>17</maven.compiler.target> |
|||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
|||
</properties> |
|||
<properties> |
|||
<maven.compiler.source>17</maven.compiler.source> |
|||
<maven.compiler.target>17</maven.compiler.target> |
|||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
|||
</properties> |
|||
|
|||
<profiles> |
|||
<profile> |
|||
<id>dev</id> |
|||
<properties> |
|||
<!-- 环境标识,需要与配置文件的名称相对应 --> |
|||
<profiles.active>dev</profiles.active> |
|||
<logging.level>info</logging.level> |
|||
</properties> |
|||
<activation> |
|||
<!-- 默认环境 --> |
|||
<activeByDefault>true</activeByDefault> |
|||
</activation> |
|||
</profile> |
|||
<profile> |
|||
<id>zyg</id> |
|||
<properties> |
|||
<profiles.active>zyg</profiles.active> |
|||
<logging.level>info</logging.level> |
|||
</properties> |
|||
</profile> |
|||
<profile> |
|||
<id>prod</id> |
|||
<properties> |
|||
<profiles.active>prod</profiles.active> |
|||
<logging.level>info</logging.level> |
|||
</properties> |
|||
</profile> |
|||
</profiles> |
|||
<dependencies> |
|||
<dependency> |
|||
<groupId>com.jiagutech</groupId> |
|||
<artifactId>system</artifactId> |
|||
<version>1.0.0-SNAPSHOT</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.jiagutech</groupId> |
|||
<artifactId>social</artifactId> |
|||
<version>1.0.0-SNAPSHOT</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-data-jdbc</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>mysql</groupId> |
|||
<artifactId>mysql-connector-java</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springdoc</groupId> |
|||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> |
|||
<profiles> |
|||
<profile> |
|||
<id>dev</id> |
|||
<properties> |
|||
<!-- 环境标识,需要与配置文件的名称相对应 --> |
|||
<profiles.active>dev</profiles.active> |
|||
<logging.level>info</logging.level> |
|||
</properties> |
|||
<activation> |
|||
<!-- 默认环境 --> |
|||
<activeByDefault>true</activeByDefault> |
|||
</activation> |
|||
</profile> |
|||
<profile> |
|||
<id>zyg</id> |
|||
<properties> |
|||
<profiles.active>zyg</profiles.active> |
|||
<logging.level>info</logging.level> |
|||
</properties> |
|||
</profile> |
|||
<profile> |
|||
<id>prod</id> |
|||
<properties> |
|||
<profiles.active>prod</profiles.active> |
|||
<logging.level>info</logging.level> |
|||
</properties> |
|||
</profile> |
|||
</profiles> |
|||
<dependencies> |
|||
<dependency> |
|||
<groupId>com.jiagutech</groupId> |
|||
<artifactId>system</artifactId> |
|||
<version>1.0.0-SNAPSHOT</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.jiagutech</groupId> |
|||
<artifactId>social</artifactId> |
|||
<version>1.0.0-SNAPSHOT</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-data-jdbc</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>mysql</groupId> |
|||
<artifactId>mysql-connector-java</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springdoc</groupId> |
|||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> |
|||
|
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springdoc</groupId> |
|||
<artifactId>springdoc-openapi-starter-webmvc-api</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.apache.commons</groupId> |
|||
<artifactId>commons-pool2</artifactId> |
|||
<version>2.12.0</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>cn.dev33</groupId> |
|||
<artifactId>sa-token-spring-boot3-starter</artifactId> |
|||
</dependency> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springdoc</groupId> |
|||
<artifactId>springdoc-openapi-starter-webmvc-api</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.apache.commons</groupId> |
|||
<artifactId>commons-pool2</artifactId> |
|||
<version>2.12.0</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>cn.dev33</groupId> |
|||
<artifactId>sa-token-spring-boot3-starter</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>cn.dev33</groupId> |
|||
<artifactId>sa-token-redis-jackson</artifactId> |
|||
</dependency> |
|||
<!-- 添加 MapStruct 依赖 --> |
|||
<dependency> |
|||
<groupId>org.mapstruct</groupId> |
|||
<artifactId>mapstruct</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework.amqp</groupId> |
|||
<artifactId>spring-rabbit</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework.amqp</groupId> |
|||
<artifactId>spring-amqp</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-actuator</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>cn.dev33</groupId> |
|||
<artifactId>sa-token-redis-jackson</artifactId> |
|||
</dependency> |
|||
<!-- 添加 MapStruct 依赖 --> |
|||
<dependency> |
|||
<groupId>org.mapstruct</groupId> |
|||
<artifactId>mapstruct</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework.amqp</groupId> |
|||
<artifactId>spring-rabbit</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework.amqp</groupId> |
|||
<artifactId>spring-amqp</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-actuator</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>io.micrometer</groupId> |
|||
<artifactId>micrometer-registry-prometheus</artifactId> |
|||
</dependency> |
|||
</dependencies> |
|||
<build> |
|||
<finalName>${project.parent.artifactId}</finalName> |
|||
<resources> |
|||
<resource> |
|||
<directory>src/main/resources</directory> |
|||
<filtering>true</filtering> |
|||
<includes> |
|||
<include>application.yml</include> |
|||
<include>application-${profiles.active}.yml</include> |
|||
<include>*.xml</include> |
|||
</includes> |
|||
</resource> |
|||
</resources> |
|||
<plugins> |
|||
<plugin> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-maven-plugin</artifactId> |
|||
<version>${spring-boot.version}</version> |
|||
<executions> |
|||
<execution> |
|||
<goals> |
|||
<goal>repackage</goal> |
|||
</goals> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
<!-- 添加 MapStruct 插件 --> |
|||
<plugin> |
|||
<groupId>org.apache.maven.plugins</groupId> |
|||
<artifactId>maven-compiler-plugin</artifactId> |
|||
<version>${maven-compiler-plugin.version}</version> |
|||
<configuration> |
|||
<source>17</source> |
|||
<target>17</target> |
|||
<annotationProcessorPaths> |
|||
<!-- 添加 Lombok 注解处理器 --> |
|||
<path> |
|||
<groupId>org.projectlombok</groupId> |
|||
<artifactId>lombok</artifactId> |
|||
<version>${lombok.version}</version> |
|||
</path> |
|||
</annotationProcessorPaths> |
|||
</configuration> |
|||
</plugin> |
|||
<!-- 添加 maven-pmd-plugin --> |
|||
<plugin> |
|||
<groupId>org.apache.maven.plugins</groupId> |
|||
<artifactId>maven-pmd-plugin</artifactId> |
|||
<version>3.15.0</version> |
|||
<dependencies> |
|||
<dependency> |
|||
<groupId>net.sourceforge.pmd</groupId> |
|||
<artifactId>pmd-core</artifactId> |
|||
<version>6.38.0</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>net.sourceforge.pmd</groupId> |
|||
<artifactId>pmd-java</artifactId> |
|||
<version>6.38.0</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.ow2.asm</groupId> |
|||
<artifactId>asm</artifactId> |
|||
<version>9.2</version> |
|||
</dependency> |
|||
</dependencies> |
|||
<configuration> |
|||
<linkXRef>false</linkXRef> |
|||
<sourceEncoding>UTF-8</sourceEncoding> |
|||
<minimumTokens>100</minimumTokens> |
|||
<targetJdk>17</targetJdk> |
|||
<analysisCache>true</analysisCache> |
|||
<analysisCacheLocation>${project.build.directory}/pmd/pmd.cache</analysisCacheLocation> |
|||
<outputDirectory>${project.build.directory}/pmd</outputDirectory> |
|||
<format>html</format> |
|||
<failOnViolation>false</failOnViolation> |
|||
</configuration> |
|||
<executions> |
|||
<execution> |
|||
<id>pmd-check</id> |
|||
<phase>verify</phase> |
|||
<goals> |
|||
<goal>check</goal> |
|||
<goal>cpd-check</goal> |
|||
<goal>pmd</goal> |
|||
</goals> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
</plugins> |
|||
<dependency> |
|||
<groupId>io.micrometer</groupId> |
|||
<artifactId>micrometer-registry-prometheus</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.huaweicloud</groupId> |
|||
<artifactId>esdk-obs-java</artifactId> |
|||
<version>3.20.6.1</version> |
|||
<scope>compile</scope> |
|||
</dependency> |
|||
</dependencies> |
|||
<build> |
|||
<finalName>${project.parent.artifactId}</finalName> |
|||
<resources> |
|||
<resource> |
|||
<directory>src/main/resources</directory> |
|||
<filtering>true</filtering> |
|||
<includes> |
|||
<include>application.yml</include> |
|||
<include>application-${profiles.active}.yml</include> |
|||
<include>*.xml</include> |
|||
</includes> |
|||
</resource> |
|||
</resources> |
|||
<plugins> |
|||
<plugin> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-maven-plugin</artifactId> |
|||
<version>${spring-boot.version}</version> |
|||
<executions> |
|||
<execution> |
|||
<goals> |
|||
<goal>repackage</goal> |
|||
</goals> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
<!-- 添加 MapStruct 插件 --> |
|||
<plugin> |
|||
<groupId>org.apache.maven.plugins</groupId> |
|||
<artifactId>maven-compiler-plugin</artifactId> |
|||
<version>${maven-compiler-plugin.version}</version> |
|||
<configuration> |
|||
<source>17</source> |
|||
<target>17</target> |
|||
<annotationProcessorPaths> |
|||
<!-- 添加 Lombok 注解处理器 --> |
|||
<path> |
|||
<groupId>org.projectlombok</groupId> |
|||
<artifactId>lombok</artifactId> |
|||
<version>${lombok.version}</version> |
|||
</path> |
|||
</annotationProcessorPaths> |
|||
</configuration> |
|||
</plugin> |
|||
<!-- 添加 maven-pmd-plugin --> |
|||
<plugin> |
|||
<groupId>org.apache.maven.plugins</groupId> |
|||
<artifactId>maven-pmd-plugin</artifactId> |
|||
<version>3.15.0</version> |
|||
<dependencies> |
|||
<dependency> |
|||
<groupId>net.sourceforge.pmd</groupId> |
|||
<artifactId>pmd-core</artifactId> |
|||
<version>6.38.0</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>net.sourceforge.pmd</groupId> |
|||
<artifactId>pmd-java</artifactId> |
|||
<version>6.38.0</version> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.ow2.asm</groupId> |
|||
<artifactId>asm</artifactId> |
|||
<version>9.2</version> |
|||
</dependency> |
|||
</dependencies> |
|||
<configuration> |
|||
<linkXRef>false</linkXRef> |
|||
<sourceEncoding>UTF-8</sourceEncoding> |
|||
<minimumTokens>100</minimumTokens> |
|||
<targetJdk>17</targetJdk> |
|||
<analysisCache>true</analysisCache> |
|||
<analysisCacheLocation>${project.build.directory}/pmd/pmd.cache</analysisCacheLocation> |
|||
<outputDirectory>${project.build.directory}/pmd</outputDirectory> |
|||
<format>html</format> |
|||
<failOnViolation>false</failOnViolation> |
|||
</configuration> |
|||
<executions> |
|||
<execution> |
|||
<id>pmd-check</id> |
|||
<phase>verify</phase> |
|||
<goals> |
|||
<goal>check</goal> |
|||
<goal>cpd-check</goal> |
|||
<goal>pmd</goal> |
|||
</goals> |
|||
</execution> |
|||
</executions> |
|||
</plugin> |
|||
</plugins> |
|||
|
|||
</build> |
|||
</build> |
|||
|
|||
</project> |
@ -0,0 +1,30 @@ |
|||
package com.jiagutech.ams.config; |
|||
|
|||
|
|||
import com.obs.services.ObsClient; |
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
import org.springframework.boot.context.properties.ConfigurationProperties; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
|
|||
@Data |
|||
@Configuration |
|||
@NoArgsConstructor |
|||
@ConfigurationProperties(prefix = "huawei.obs") |
|||
public class ObsConfig { |
|||
|
|||
|
|||
private String endPoint; |
|||
private String ak; |
|||
private String sk; |
|||
|
|||
private String bucketName; |
|||
private String pathPrefix; |
|||
|
|||
@Bean |
|||
public ObsClient obsClient() { |
|||
ObsClient obsClient= new ObsClient(ak, sk, endPoint); |
|||
return obsClient; |
|||
} |
|||
} |
Loading…
Reference in new issue