| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417 |
- package com.ruoyi.web.controller.robot;
- import com.alibaba.fastjson2.JSON;
- import com.alibaba.fastjson2.JSONArray;
- import com.alibaba.fastjson2.JSONObject;
- import com.ruoyi.common.core.domain.AjaxResult;
- import com.ruoyi.common.core.redis.RedisCache;
- import com.ruoyi.mqtt.service.MqttSendService;
- import com.ruoyi.mqtt.util.MqttTopicUtil;
- import io.swagger.annotations.Api;
- import io.swagger.annotations.ApiOperation;
- import io.swagger.annotations.ApiParam;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.beans.factory.annotation.Value;
- import org.springframework.http.*;
- import org.springframework.util.LinkedMultiValueMap;
- import org.springframework.util.MultiValueMap;
- import org.springframework.web.bind.annotation.*;
- import org.springframework.web.client.RestTemplate;
- import java.util.*;
- import java.util.concurrent.TimeUnit;
- /**
- * 地图管理Controller
- * 提供地图列表、缩略图、路网数据、点云等API
- * 数据源:LD导航系统后端(http://192.168.0.102:8086)
- */
- @Api(tags = "地图管理")
- @RestController
- @RequestMapping("/robot/map")
- public class RobotMapController {
- @Value("${ld-nav.url:http://192.168.0.102:8086}")
- private String ldNavUrl;
- @Autowired
- private MqttSendService mqttSendService;
- @Autowired
- private RedisCache redisCache;
- private final RestTemplate restTemplate = new RestTemplate();
- // ==================== 导入导出API ====================
- @ApiOperation("压缩导出地图")
- @PostMapping("/export/compress")
- public AjaxResult compressMapExport(@RequestBody Map<String, Object> params) {
- try {
- String url = ldNavUrl + "/v1/map/export/compress";
- HttpHeaders headers = new HttpHeaders();
- headers.setContentType(MediaType.APPLICATION_JSON);
- HttpEntity<Map<String, Object>> request = new HttpEntity<>(params, headers);
-
- ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class);
-
- if (response.getStatusCode() == HttpStatus.OK) {
- return AjaxResult.success("压缩成功", JSON.parse(response.getBody()));
- }
- return AjaxResult.error("压缩失败");
- } catch (Exception e) {
- return AjaxResult.error("压缩异常: " + e.getMessage());
- }
- }
- @ApiOperation("下载地图导出包")
- @GetMapping("/export")
- public ResponseEntity<byte[]> downloadMapExport(
- @ApiParam("地图名称") @RequestParam("map") String mapName
- ) {
- try {
- String url = ldNavUrl + "/v1/map/export?map=" + mapName;
- ResponseEntity<byte[]> response = restTemplate.getForEntity(url, byte[].class);
-
- HttpHeaders headers = new HttpHeaders();
- headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
- headers.setContentDisposition(ContentDisposition.builder("attachment")
- .filename(mapName + ".zip")
- .build());
-
- return new ResponseEntity<>(response.getBody(), headers, HttpStatus.OK);
- } catch (Exception e) {
- return ResponseEntity.notFound().build();
- }
- }
- @ApiOperation("导入地图")
- @PostMapping("/import")
- public AjaxResult importMap(
- @ApiParam("地图文件") @RequestParam("file") org.springframework.web.multipart.MultipartFile file
- ) {
- try {
- String url = ldNavUrl + "/v1/map/import";
-
- MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
- body.add("filedata", file.getResource());
-
- HttpHeaders headers = new HttpHeaders();
- headers.setContentType(MediaType.MULTIPART_FORM_DATA);
-
- HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
-
- ResponseEntity<String> response = restTemplate.postForEntity(url, requestEntity, String.class);
-
- if (response.getStatusCode() == HttpStatus.OK) {
- return AjaxResult.success("导入成功", JSON.parse(response.getBody()));
- }
- return AjaxResult.error("导入失败");
- } catch (Exception e) {
- return AjaxResult.error("导入异常: " + e.getMessage());
- }
- }
- // ==================== 路网数据API ====================
- @ApiOperation("获取路网GeoJSON数据")
- @GetMapping("/roadmap/geojson")
- public AjaxResult getRoadMapGeoJson(
- @ApiParam("地图名称") @RequestParam("map") String mapName
- ) {
- try {
- String cacheKey = "ld:roadmap:" + mapName;
- Object cached = redisCache.getCacheObject(cacheKey);
- if (cached != null) {
- return AjaxResult.success("获取成功(缓存)", cached);
- }
- String url = ldNavUrl + "/v1/roadmap/geojson?map=" + mapName;
- ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
-
- if (response.getStatusCode() == HttpStatus.OK) {
- JSONObject geojson = JSON.parseObject(response.getBody());
- // 缓存10分钟
- redisCache.setCacheObject(cacheKey, geojson, 10, TimeUnit.MINUTES);
- return AjaxResult.success("获取成功", geojson);
- }
- return AjaxResult.error("获取路网数据失败");
- } catch (Exception e) {
- return AjaxResult.error("获取路网数据异常: " + e.getMessage());
- }
- }
- @ApiOperation("保存路网GeoJSON数据")
- @PostMapping("/roadmap/geojson")
- public AjaxResult saveRoadMapGeoJson(@RequestBody JSONObject geoJsonData) {
- try {
- String mapName = geoJsonData.getString("map");
- if (mapName == null) {
- return AjaxResult.error("缺少地图名称");
- }
- String url = ldNavUrl + "/v1/roadmap/geojson";
- HttpHeaders headers = new HttpHeaders();
- headers.setContentType(MediaType.APPLICATION_JSON);
- HttpEntity<JSONObject> request = new HttpEntity<>(geoJsonData, headers);
-
- ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class);
-
- if (response.getStatusCode() == HttpStatus.OK) {
- // 清除路网缓存
- redisCache.deleteObject("ld:roadmap:" + mapName);
- return AjaxResult.success("保存成功");
- }
- return AjaxResult.error("保存失败");
- } catch (Exception e) {
- return AjaxResult.error("保存异常: " + e.getMessage());
- }
- }
- // ==================== 任务路线API ====================
- @ApiOperation("获取任务路线列表")
- @GetMapping("/path/list")
- public AjaxResult listPath(
- @ApiParam("地图名称") @RequestParam("map") String mapName
- ) {
- try {
- String url = ldNavUrl + "/v1/path/list?map=" + mapName;
- ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
-
- if (response.getStatusCode() == HttpStatus.OK) {
- return AjaxResult.success("获取成功", JSON.parse(response.getBody()));
- }
- return AjaxResult.error("获取路线列表失败");
- } catch (Exception e) {
- return AjaxResult.error("获取路线列表异常: " + e.getMessage());
- }
- }
- @ApiOperation("获取任务路线详情")
- @GetMapping("/path")
- public AjaxResult getPath(
- @ApiParam("地图名称") @RequestParam("map") String mapName,
- @ApiParam("路线名称") @RequestParam("path") String pathName
- ) {
- try {
- String url = ldNavUrl + "/v1/path?map=" + mapName + "&path=" + pathName;
- ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
-
- if (response.getStatusCode() == HttpStatus.OK) {
- return AjaxResult.success("获取成功", JSON.parse(response.getBody()));
- }
- return AjaxResult.error("获取路线详情失败");
- } catch (Exception e) {
- return AjaxResult.error("获取路线详情异常: " + e.getMessage());
- }
- }
- @ApiOperation("添加任务路线")
- @PostMapping("/path")
- public AjaxResult addPath(@RequestBody Map<String, Object> params) {
- try {
- String url = ldNavUrl + "/v1/path";
- HttpHeaders headers = new HttpHeaders();
- headers.setContentType(MediaType.APPLICATION_JSON);
- HttpEntity<Map<String, Object>> request = new HttpEntity<>(params, headers);
-
- ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class);
-
- if (response.getStatusCode() == HttpStatus.OK) {
- return AjaxResult.success("添加成功");
- }
- return AjaxResult.error("添加失败");
- } catch (Exception e) {
- return AjaxResult.error("添加异常: " + e.getMessage());
- }
- }
- @ApiOperation("删除任务路线")
- @DeleteMapping("/path")
- public AjaxResult deletePath(@RequestBody Map<String, String> params) {
- try {
- String map = params.get("map");
- String path = params.get("path");
-
- String url = ldNavUrl + "/v1/path?map=" + map + "&path=" + path;
- HttpHeaders headers = new HttpHeaders();
- HttpEntity<String> request = new HttpEntity<>(headers);
-
- ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.DELETE, request, String.class);
-
- if (response.getStatusCode() == HttpStatus.OK) {
- return AjaxResult.success("删除成功");
- }
- return AjaxResult.error("删除失败");
- } catch (Exception e) {
- return AjaxResult.error("删除异常: " + e.getMessage());
- }
- }
- // ==================== 标定API ====================
- @ApiOperation("获取标定历史")
- @GetMapping("/calibration/history")
- public AjaxResult getCalibrationHistory(
- @ApiParam("地图名称") @RequestParam("map") String mapName
- ) {
- try {
- String url = ldNavUrl + "/v1/map/file/" + mapName + "/shapefile/calibration.json";
- ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
-
- if (response.getStatusCode() == HttpStatus.OK) {
- return AjaxResult.success("获取成功", JSON.parse(response.getBody()));
- }
- return AjaxResult.error("获取标定历史失败");
- } catch (Exception e) {
- return AjaxResult.error("获取标定历史异常: " + e.getMessage());
- }
- }
- // ==================== VSLAM API ====================
- @ApiOperation("获取VSLAM统计信息")
- @GetMapping("/vslam/statistics")
- public AjaxResult getVSlamStatistics(
- @ApiParam("地图名称") @RequestParam("map") String mapName
- ) {
- try {
- String url = ldNavUrl + "/v1/vslam/statistics?map=" + mapName;
- ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
-
- if (response.getStatusCode() == HttpStatus.OK) {
- return AjaxResult.success("获取成功", JSON.parse(response.getBody()));
- }
- return AjaxResult.error("获取VSLAM统计信息失败");
- } catch (Exception e) {
- return AjaxResult.error("获取VSLAM统计信息异常: " + e.getMessage());
- }
- }
- @ApiOperation("获取关键帧点云")
- @GetMapping("/vslam/keyframe/cloud")
- public ResponseEntity<byte[]> getKeyframeCloud(
- @ApiParam("地图名称") @RequestParam("map") String mapName,
- @ApiParam("关键帧索引") @RequestParam("idx") int idx
- ) {
- try {
- String url = ldNavUrl + "/v1/vslam/keyframe/cloud?map=" + mapName + "&idx=" + idx;
- ResponseEntity<byte[]> response = restTemplate.getForEntity(url, byte[].class);
- return ResponseEntity.ok()
- .headers(headers -> headers.setContentType(MediaType.APPLICATION_OCTET_STREAM))
- .body(response.getBody());
- } catch (Exception e) {
- return ResponseEntity.notFound().build();
- }
- }
- @ApiOperation("获取关键帧变换矩阵")
- @GetMapping("/vslam/keyframe/trans")
- public ResponseEntity<byte[]> getKeyframeTrans(
- @ApiParam("地图名称") @RequestParam("map") String mapName,
- @ApiParam("关键帧索引") @RequestParam("idx") int idx
- ) {
- try {
- String url = ldNavUrl + "/v1/vslam/keyframe/trans?map=" + mapName + "&idx=" + idx;
- ResponseEntity<byte[]> response = restTemplate.getForEntity(url, byte[].class);
- return ResponseEntity.ok()
- .headers(headers -> headers.setContentType(MediaType.APPLICATION_OCTET_STREAM))
- .body(response.getBody());
- } catch (Exception e) {
- return ResponseEntity.notFound().build();
- }
- }
- @ApiOperation("获取闭环详情")
- @GetMapping("/vslam/closure/details")
- public AjaxResult getClosureDetails(
- @ApiParam("地图名称") @RequestParam("map") String mapName,
- @ApiParam("闭环索引") @RequestParam("idx") int idx
- ) {
- try {
- String url = ldNavUrl + "/v1/vslam/closure/details?map=" + mapName + "&idx=" + idx;
- ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
-
- if (response.getStatusCode() == HttpStatus.OK) {
- return AjaxResult.success("获取成功", JSON.parse(response.getBody()));
- }
- return AjaxResult.error("获取闭环详情失败");
- } catch (Exception e) {
- return AjaxResult.error("获取闭环详情异常: " + e.getMessage());
- }
- }
- // ==================== 传感器API ====================
- @ApiOperation("获取点云数据")
- @GetMapping("/sensor/pointcloud")
- public ResponseEntity<byte[]> getPointcloud() {
- try {
- String url = ldNavUrl + "/v1/sensor/pointcloud/3d";
- ResponseEntity<byte[]> response = restTemplate.getForEntity(url, byte[].class);
- return ResponseEntity.ok()
- .headers(headers -> headers.setContentType(MediaType.APPLICATION_OCTET_STREAM))
- .body(response.getBody());
- } catch (Exception e) {
- return ResponseEntity.notFound().build();
- }
- }
- // ==================== 地图瓦片API ====================
- @ApiOperation("获取地图配置信息")
- @GetMapping("/tilemap/details")
- public AjaxResult getTilemapDetails(
- @ApiParam("地图名称") @RequestParam("map") String mapName
- ) {
- try {
- String url = ldNavUrl + "/v1/tilemap/details?map=" + mapName;
- ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
-
- if (response.getStatusCode() == HttpStatus.OK) {
- return AjaxResult.success("获取成功", JSON.parse(response.getBody()));
- }
- return AjaxResult.error("获取地图配置失败");
- } catch (Exception e) {
- return AjaxResult.error("获取地图配置异常: " + e.getMessage());
- }
- }
- // ==================== 设备状态API ====================
- @ApiOperation("获取机器人实时位姿(从Redis缓存)")
- @GetMapping("/robot/pose")
- public AjaxResult getRobotPose(
- @ApiParam("设备ID") @RequestParam(required = false) String deviceId
- ) {
- try {
- String cacheKey = "ld:pose:" + (deviceId != null ? deviceId : "default");
- Object cached = redisCache.getCacheObject(cacheKey);
- if (cached != null) {
- return AjaxResult.success("获取成功(实时)", cached);
- }
- return AjaxResult.error("未获取到位姿数据");
- } catch (Exception e) {
- return AjaxResult.error("获取位姿异常: " + e.getMessage());
- }
- }
- @ApiOperation("获取任务实时信息(从Redis缓存)")
- @GetMapping("/robot/task")
- public AjaxResult getTaskRealtimeInfo(
- @ApiParam("设备ID") @RequestParam(required = false) String deviceId
- ) {
- try {
- String cacheKey = "ld:task:realtime:" + (deviceId != null ? deviceId : "default");
- Object cached = redisCache.getCacheObject(cacheKey);
- if (cached != null) {
- return AjaxResult.success("获取成功(实时)", cached);
- }
- return AjaxResult.error("未获取到任务数据");
- } catch (Exception e) {
- return AjaxResult.error("获取任务信息异常: " + e.getMessage());
- }
- }
- }
|