29 changed files with 1178 additions and 275 deletions
@ -1,2 +1,18 @@ |
|||||
# ams-social |
# 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); |
||||
|
} |
||||
|
} |
@ -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