diff --git a/src/main/java/org/nl/apt15e/apt/map/dao/MapInfo.java b/src/main/java/org/nl/apt15e/apt/map/dao/MapInfo.java index 1624a7a..f14f5f7 100644 --- a/src/main/java/org/nl/apt15e/apt/map/dao/MapInfo.java +++ b/src/main/java/org/nl/apt15e/apt/map/dao/MapInfo.java @@ -23,6 +23,11 @@ public class MapInfo { */ private String mapName; + /** + * 地图图片地址 + */ + private String mapImageAddress; + /** * 图片像素宽 */ diff --git a/src/main/java/org/nl/apt15e/apt/map/rest/MapInfoController.java b/src/main/java/org/nl/apt15e/apt/map/rest/MapInfoController.java index 992d43d..b2316e5 100644 --- a/src/main/java/org/nl/apt15e/apt/map/rest/MapInfoController.java +++ b/src/main/java/org/nl/apt15e/apt/map/rest/MapInfoController.java @@ -4,6 +4,7 @@ import org.nl.apt15e.apt.map.dao.MapInfo; import org.nl.apt15e.apt.map.service.MapInfoService; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -21,8 +22,8 @@ public class MapInfoController { @Resource private MapInfoService mapInfoService; - @RequestMapping("/getMapInfoByCode") - public ResponseEntity getMapInfoByCode(@RequestParam("mapCode") String mapCode) { - return new ResponseEntity<>(mapInfoService.getMapInfoByCode(mapCode), HttpStatus.OK); + @GetMapping("/getMapInfoByCode") + public ResponseEntity getMapInfoByCode() { + return new ResponseEntity<>(mapInfoService.getMapInfoByCode(), HttpStatus.OK); } } diff --git a/src/main/java/org/nl/apt15e/apt/map/service/MapInfoService.java b/src/main/java/org/nl/apt15e/apt/map/service/MapInfoService.java index bcb0fc1..aa86b19 100644 --- a/src/main/java/org/nl/apt15e/apt/map/service/MapInfoService.java +++ b/src/main/java/org/nl/apt15e/apt/map/service/MapInfoService.java @@ -4,12 +4,17 @@ import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.extension.service.IService; import org.nl.apt15e.apt.map.dao.MapInfo; +import java.util.List; + /** * @author dsh * 2025/7/17 */ public interface MapInfoService extends IService { - JSONObject getMapInfoByCode(String mapCode); + /** + * 返回当前正在使用的地图数据 + */ + MapInfo getMapInfoByCode(); } diff --git a/src/main/java/org/nl/apt15e/apt/map/service/impl/MapInfoServiceImpl.java b/src/main/java/org/nl/apt15e/apt/map/service/impl/MapInfoServiceImpl.java index 213fd23..4eba9f5 100644 --- a/src/main/java/org/nl/apt15e/apt/map/service/impl/MapInfoServiceImpl.java +++ b/src/main/java/org/nl/apt15e/apt/map/service/impl/MapInfoServiceImpl.java @@ -13,6 +13,8 @@ import org.nl.apt15e.common.BadRequestException; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; +import java.util.List; + /** * @author dsh * 2025/7/17 @@ -22,13 +24,7 @@ import org.springframework.stereotype.Service; public class MapInfoServiceImpl extends ServiceImpl implements MapInfoService { @Override - public JSONObject getMapInfoByCode(String mapCode) { - if (StrUtil.isEmpty(mapCode)) { - throw new BadRequestException("mapCode is null"); - } - JSONObject jsonObject = new JSONObject(); - jsonObject.put("code", HttpStatus.OK.value()); - jsonObject.put("data", this.getOne(new LambdaQueryWrapper<>(MapInfo.class).eq(MapInfo::getMapCode,mapCode))); - return jsonObject; + public MapInfo getMapInfoByCode() { + return this.getOne(new LambdaQueryWrapper<>(MapInfo.class)); } } diff --git a/src/main/java/org/nl/apt15e/apt/route/dao/RouteInfo.java b/src/main/java/org/nl/apt15e/apt/route/dao/RouteInfo.java index 2d8fa3a..f313a73 100644 --- a/src/main/java/org/nl/apt15e/apt/route/dao/RouteInfo.java +++ b/src/main/java/org/nl/apt15e/apt/route/dao/RouteInfo.java @@ -51,11 +51,11 @@ public class RouteInfo { /** * 导航模式 前进模式, 后退模式 ,无头模式 */ - private Integer navigation_mode; + private String navigation_mode; /** * 路线类型 直行,转弯 */ - private Integer route_type; + private String route_type; } diff --git a/src/main/java/org/nl/apt15e/apt/route/service/RouteInfoService.java b/src/main/java/org/nl/apt15e/apt/route/service/RouteInfoService.java index a914167..291908f 100644 --- a/src/main/java/org/nl/apt15e/apt/route/service/RouteInfoService.java +++ b/src/main/java/org/nl/apt15e/apt/route/service/RouteInfoService.java @@ -4,11 +4,13 @@ import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.extension.service.IService; import org.nl.apt15e.apt.route.dao.RouteInfo; +import java.util.List; + /** * @author dsh * 2025/7/18 */ public interface RouteInfoService extends IService { - JSONObject getAllRouteInfo(); + List getAllRouteInfo(); } diff --git a/src/main/java/org/nl/apt15e/apt/route/service/impl/RouteInfoServiceImpl.java b/src/main/java/org/nl/apt15e/apt/route/service/impl/RouteInfoServiceImpl.java index 5827a6f..35d0cbb 100644 --- a/src/main/java/org/nl/apt15e/apt/route/service/impl/RouteInfoServiceImpl.java +++ b/src/main/java/org/nl/apt15e/apt/route/service/impl/RouteInfoServiceImpl.java @@ -12,6 +12,7 @@ import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; import javax.annotation.Resource; +import java.util.List; /** * @author dsh @@ -24,10 +25,7 @@ public class RouteInfoServiceImpl extends ServiceImpl getAllRouteInfo() { + return routeInfoMapper.selectList(null); } } diff --git a/src/main/java/org/nl/apt15e/apt/route/service/rest/RouteInfoController.java b/src/main/java/org/nl/apt15e/apt/route/service/rest/RouteInfoController.java index 003e787..757e26e 100644 --- a/src/main/java/org/nl/apt15e/apt/route/service/rest/RouteInfoController.java +++ b/src/main/java/org/nl/apt15e/apt/route/service/rest/RouteInfoController.java @@ -3,6 +3,7 @@ package org.nl.apt15e.apt.route.service.rest; import org.nl.apt15e.apt.route.service.RouteInfoService; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -19,7 +20,7 @@ public class RouteInfoController { @Resource private RouteInfoService routeInfoService; - @RequestMapping("/getRouteInfo") + @GetMapping("/getRouteInfo") public ResponseEntity getRouteInfo(){ return new ResponseEntity<>(routeInfoService.getAllRouteInfo(), HttpStatus.OK); } diff --git a/src/main/java/org/nl/apt15e/apt/station/StationTypeEnum.java b/src/main/java/org/nl/apt15e/apt/station/StationTypeEnum.java index b00725c..bc5a81b 100644 --- a/src/main/java/org/nl/apt15e/apt/station/StationTypeEnum.java +++ b/src/main/java/org/nl/apt15e/apt/station/StationTypeEnum.java @@ -12,18 +12,19 @@ import lombok.Getter; public enum StationTypeEnum { //站点类型 Station工位点 Charge充电点 Breaks休息点 Docking对接点 System系统自动生成点 - STATION(1, "STATION", "工位点"), - CHARGE(2, "CHARGE", "充电点"), - BREAKS(3, "BREAKS", "休息点"), - DOCKING(4, "DOCKING", "对接点"), - SYSTEM(5, "SYSTEM", "系统自动生成点"), + STATION(1, "Station", "工位点"), + CHARGE(2, "Charge", "充电点"), + BREAKS(3, "Breaks", "休息点"), + DOCKING(4, "Docking", "对接点"), + SYSTEM(5, "System", "系统自动生成点"), - //动作类型 Ascend升叉 Descend降叉 Move移动 Customize自定义 + //动作类型 Ascend升叉 Descend降叉 Move移动 Customize自定义 Return返回 ASCEND(1, "Ascend", "升叉"), DESCEND(2, "Descend", "降叉"), MOVE(3, "Move", "移动"), - CUSTOMIZE(4, "Customize", "自定义"); + CUSTOMIZE(4, "Customize", "自定义"), + RETURN(5, "Return", "返回"); /** diff --git a/src/main/java/org/nl/apt15e/apt/station/dao/Station.java b/src/main/java/org/nl/apt15e/apt/station/dao/Station.java index 4c700b9..1c6793c 100644 --- a/src/main/java/org/nl/apt15e/apt/station/dao/Station.java +++ b/src/main/java/org/nl/apt15e/apt/station/dao/Station.java @@ -35,7 +35,7 @@ public class Station implements Serializable { private String station_type; /** - * 动作类型 (Ascend升叉 Descend降叉 Move移动 Customize自定义) + * 动作类型 (Ascend升叉 Descend降叉 Move移动 Customize自定义 Return返回) */ private String action_type; diff --git a/src/main/java/org/nl/apt15e/apt/station/service/StationService.java b/src/main/java/org/nl/apt15e/apt/station/service/StationService.java index 5dcf948..c977a94 100644 --- a/src/main/java/org/nl/apt15e/apt/station/service/StationService.java +++ b/src/main/java/org/nl/apt15e/apt/station/service/StationService.java @@ -14,4 +14,7 @@ public interface StationService extends IService { List queryAllStation(); + List queryMapAllStation(); + + Station queryStationById(Integer id); } diff --git a/src/main/java/org/nl/apt15e/apt/station/service/impl/StationServiceImpl.java b/src/main/java/org/nl/apt15e/apt/station/service/impl/StationServiceImpl.java index dd2788b..62aa659 100644 --- a/src/main/java/org/nl/apt15e/apt/station/service/impl/StationServiceImpl.java +++ b/src/main/java/org/nl/apt15e/apt/station/service/impl/StationServiceImpl.java @@ -27,7 +27,17 @@ public class StationServiceImpl extends ServiceImpl impl @Override public List queryAllStation() { - return stationMapper.selectList(stationMapper.selectList(new LambdaQueryWrapper<>(Station.class) - .eq(Station::getStation_type, StationTypeEnum.STATION.getCode()))); + return stationMapper.selectList(new LambdaQueryWrapper<>(Station.class) + .eq(Station::getStation_type, StationTypeEnum.STATION.getCode())); + } + + @Override + public List queryMapAllStation() { + return stationMapper.selectList(null); + } + + @Override + public Station queryStationById(Integer id) { + return stationMapper.selectOne(new LambdaQueryWrapper().eq(Station::getStation_id, id)); } } diff --git a/src/main/java/org/nl/apt15e/apt/station/service/rest/StationController.java b/src/main/java/org/nl/apt15e/apt/station/service/rest/StationController.java index cb15eb0..123e8bf 100644 --- a/src/main/java/org/nl/apt15e/apt/station/service/rest/StationController.java +++ b/src/main/java/org/nl/apt15e/apt/station/service/rest/StationController.java @@ -21,8 +21,17 @@ public class StationController { private StationService stationService; @GetMapping("/queryAllStation") - private ResponseEntity startMapping() { + private ResponseEntity queryAllStation() { return new ResponseEntity<>(stationService.queryAllStation(), HttpStatus.OK); } + @GetMapping("/queryMapAllStation") + private ResponseEntity queryMapAllStation() { + return new ResponseEntity<>(stationService.queryMapAllStation(), HttpStatus.OK); + } + + @GetMapping("/queryStationById") + private ResponseEntity queryStationById(@RequestParam("station_id") Integer station_id) { + return new ResponseEntity<>(stationService.queryStationById(station_id), HttpStatus.OK); + } } diff --git a/src/main/java/org/nl/apt15e/apt/teaching/rest/TeachingController.java b/src/main/java/org/nl/apt15e/apt/teaching/rest/TeachingController.java index e65526d..6c4a43e 100644 --- a/src/main/java/org/nl/apt15e/apt/teaching/rest/TeachingController.java +++ b/src/main/java/org/nl/apt15e/apt/teaching/rest/TeachingController.java @@ -82,4 +82,9 @@ public class TeachingController { private ResponseEntity oneClickDeployment(@RequestParam("mapName") String mapName) { return new ResponseEntity<>(teachingService.oneClickDeployment(mapName), HttpStatus.OK); } + + @PostMapping("/abandonMapping") + private ResponseEntity abandonMapping() { + return new ResponseEntity<>(teachingService.abandonMapping(),HttpStatus.OK); + } } diff --git a/src/main/java/org/nl/apt15e/apt/teaching/service/TeachingService.java b/src/main/java/org/nl/apt15e/apt/teaching/service/TeachingService.java index 776adba..ac56596 100644 --- a/src/main/java/org/nl/apt15e/apt/teaching/service/TeachingService.java +++ b/src/main/java/org/nl/apt15e/apt/teaching/service/TeachingService.java @@ -86,4 +86,10 @@ public interface TeachingService { * @return */ Map oneClickDeployment(String mapName); + + /** + * 放弃当前示教建图 + * @return + */ + Map abandonMapping(); } diff --git a/src/main/java/org/nl/apt15e/apt/teaching/service/impl/TeachingServiceImpl.java b/src/main/java/org/nl/apt15e/apt/teaching/service/impl/TeachingServiceImpl.java index 9afaf1a..047c802 100644 --- a/src/main/java/org/nl/apt15e/apt/teaching/service/impl/TeachingServiceImpl.java +++ b/src/main/java/org/nl/apt15e/apt/teaching/service/impl/TeachingServiceImpl.java @@ -264,6 +264,8 @@ public class TeachingServiceImpl implements TeachingService { if (response.isOk() && response.body() != null) { // 获取zip包 byte[] zipBytes = response.bodyBytes(); + File fileName = new File(mapName); + File tempZipFile = FileUtil.writeBytes(zipBytes, FileUtil.createTempFile(fileName)); log.info("解析地图包数据"); processZip.processZipResponse(zipBytes); return zipBytes; @@ -409,4 +411,34 @@ public class TeachingServiceImpl implements TeachingService { // } return response; } + + @Override + public Map abandonMapping() { + JSONObject params = new JSONObject(); + String attach = "{"+ + "'sub_command':0,"+ + "'param':''"+ + "}"; + params.put("cmd", 906); + params.put("attach", JSON.parseObject(attach)); + HttpResponse response = null; + try { + response = HTTPUtil.post("http://192.168.100.82:9998","/tool/rob/sendCMD", params); + } catch (Exception e) { + log.info("访问车体放弃示教建图接口报错:{}",e.getMessage()); + throw new BadRequestException("车体放弃示教建图失败"); + } + // 检查响应状态码 + if (response.isOk() && response.body() != null) { + // 获取响应体内容 + JSONObject body = JSON.parseObject(response.body()); + log.info("放弃示教建图:{}",body); + if ("200".equals(body.getString("code"))){ + body.put("message","放弃示教建图成功"); + return body; + } + } + log.info("放弃示教建图失败"); + throw new BadRequestException("放弃示教建图失败"); + } } diff --git a/src/main/java/org/nl/apt15e/apt/vehicle/ProcessZip.java b/src/main/java/org/nl/apt15e/apt/vehicle/ProcessZip.java index 7d492e1..a86b773 100644 --- a/src/main/java/org/nl/apt15e/apt/vehicle/ProcessZip.java +++ b/src/main/java/org/nl/apt15e/apt/vehicle/ProcessZip.java @@ -13,12 +13,15 @@ import org.nl.apt15e.apt.station.dao.Station; import org.nl.apt15e.apt.station.service.StationService; import org.nl.apt15e.apt.station.service.impl.StationServiceImpl; import org.nl.apt15e.common.BadRequestException; +import org.nl.apt15e.config.file.FileProperties; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.yaml.snakeyaml.Yaml; import javax.annotation.Resource; import javax.imageio.ImageIO; +import java.awt.*; import java.awt.image.BufferedImage; import java.awt.image.DataBufferByte; import java.io.*; @@ -48,9 +51,11 @@ public class ProcessZip { @Resource private RouteInfoService routeInfoService; + @Resource + private FileProperties properties; + private static final String PGM_MAGIC_NUMBER = "P5"; - private static final String OUTPUT_DIR = "/logs"; @Transactional(rollbackFor = Exception.class) public void processZipResponse(byte[] zipBytes) { @@ -59,6 +64,11 @@ public class ProcessZip { MapInfo mapInfo = new MapInfo(); + //存储之前先清除站点表中数据和路径表中的数据 + stationService.remove(new LambdaQueryWrapper<>()); + routeInfoService.remove(new LambdaQueryWrapper<>()); + mapInfoService.remove(new LambdaQueryWrapper<>()); + ZipEntry entry; // 遍历ZIP文件中的每个条目 while ((entry = zis.getNextEntry()) != null) { @@ -72,10 +82,6 @@ public class ProcessZip { BufferedReader reader = new BufferedReader( new InputStreamReader(zis, StandardCharsets.UTF_8)); - //存储站点之前先清除站点表中数据和路径表中的数据 - stationService.remove(new LambdaQueryWrapper<>()); - routeInfoService.remove(new LambdaQueryWrapper<>()); - String line; int lineNumber = 0; while ((line = reader.readLine()) != null) { @@ -110,11 +116,15 @@ public class ProcessZip { throw new BadRequestException("地图PGM转换失败: "); } + // 将灰度图转换为透明背景图 + pngImage = convertToTransparentBackground(pngImage); + // 保存PNG文件 String pngFileName = entryName.substring(0, entryName.lastIndexOf('.')) + ".png"; // 记录地图编码、名称 mapInfo.setMapCode(pngFileName); mapInfo.setMapName(pngFileName); + mapInfo.setMapImageAddress("/file/"+pngFileName); savePngImage(pngImage, pngFileName); } } @@ -173,6 +183,71 @@ public class ProcessZip { } } + // 将灰度图像转换为透明背景图像 + private BufferedImage convertToTransparentBackground(BufferedImage grayImage) { + try { + + // 创建支持透明度的ARGB图像 + BufferedImage transparentImage = new BufferedImage( + grayImage.getWidth(), + grayImage.getHeight(), + BufferedImage.TYPE_INT_ARGB + ); + + // 获取灰度图像的像素数据 + byte[] grayPixels = ((DataBufferByte) grayImage.getRaster().getDataBuffer()).getData(); + int width = grayImage.getWidth(); + int height = grayImage.getHeight(); + + // 创建ARGB像素数组 + int[] argbPixels = new int[width * height]; + +// // 转换每个像素 +// for (int y = 0; y < height; y++) { +// for (int x = 0; x < width; x++) { +// int index = y * width + x; +// // 灰度值(0-255),0=黑,255=白 +// int grayValue = grayPixels[index] & 0xFF; +// +// // 创建ARGB像素(Alpha, Red, Green, Blue) +// // 白色背景(>=250)设为完全透明,其他保持黑色但完全不透明 +// if (grayValue >= 250) { +// // 完全透明 (Alpha=0) +// argbPixels[index] = 0x00FFFFFF; +// } else { +// // 完全不透明 (Alpha=255) + 灰度值转为RGB +// int rgb = grayValue << 16 | grayValue << 8 | grayValue; +// argbPixels[index] = 0xFF000000 | rgb; +// } +// } +// } + // 转换每个像素 + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + int index = y * width + x; + // 灰度值(0-255),0=黑,255=白 + int grayValue = grayPixels[index] & 0xFF; + + // 创建ARGB像素(Alpha, Red, Green, Blue) + if (grayValue >= 250) { + // 白色背景(>=250)设为完全透明 + argbPixels[index] = 0x00FFFFFF; // 透明 + } else { + // 黑色点云转为白色点云(完全不透明) + argbPixels[index] = 0xFFFFFFFF; // 不透明的白色 + } + } + } + + // 设置ARGB像素数据 + transparentImage.setRGB(0, 0, width, height, argbPixels, 0, width); + return transparentImage; + }catch (Exception e) { + log.info(".png点云图将灰度图像转换为透明背景图像失败:{}",e.getMessage()); + throw new BadRequestException(".png点云图将灰度图像转换为透明背景图像失败:"+e.getMessage()); + } + } + public void processLine(String line, int lineNumber) { // 跳过空行 if (line.trim().isEmpty()) { @@ -211,7 +286,7 @@ public class ProcessZip { stationService.save(station); System.out.printf("行号 %d - 有效数据: %s%n", lineNumber, station); //Route路径标识 - }else if ("Route".equals(processData[0]) && processData.length > 23){ + }else if ("Route".equals(processData[0]) && processData.length >22 ){ System.out.printf("行号 %d - 有效路径数据: %s%n", lineNumber, Arrays.toString(processData)); RouteInfo routeInfo = new RouteInfo(); routeInfo.setRoute_id(Integer.valueOf(processData[1])); @@ -221,8 +296,8 @@ public class ProcessZip { routeInfo.setStart_y(Double.valueOf(processData[5])); routeInfo.setEnd_x(Double.valueOf(processData[6])); routeInfo.setEnd_y(Double.valueOf(processData[7])); - routeInfo.setNavigation_mode(Integer.valueOf(processData[16])); - routeInfo.setRoute_type(Integer.valueOf(processData[17])); + routeInfo.setNavigation_mode(processData[16].replaceAll("^\"|\"$", "")); + routeInfo.setRoute_type(processData[17].replaceAll("^\"|\"$", "")); routeInfoService.save(routeInfo); System.out.printf("行号 %d - 有效数据: %s%n", lineNumber, routeInfo); @@ -287,7 +362,7 @@ public class ProcessZip { private void savePngImage(BufferedImage image, String fileName) { try { // 确保输出目录存在 - File outputDir = new File(OUTPUT_DIR); + File outputDir = new File(properties.getPath().getPath()); if (!outputDir.exists()) { outputDir.mkdirs(); } diff --git a/src/main/java/org/nl/apt15e/apt/vehicle/dao/VehicleInfo.java b/src/main/java/org/nl/apt15e/apt/vehicle/dao/VehicleInfo.java index dc92c5a..3b00bdf 100644 --- a/src/main/java/org/nl/apt15e/apt/vehicle/dao/VehicleInfo.java +++ b/src/main/java/org/nl/apt15e/apt/vehicle/dao/VehicleInfo.java @@ -55,7 +55,7 @@ public class VehicleInfo implements Serializable { /** * 电量 */ - private Long batteryPower; + private Double batteryPower; /** * 异常信息 @@ -76,4 +76,9 @@ public class VehicleInfo implements Serializable { * 车辆角度 */ private Double theta; + + /** + * 是否是手动模式 + */ + private Boolean isManual; } diff --git a/src/main/java/org/nl/apt15e/apt/vehicle/service/VehicleInfoService.java b/src/main/java/org/nl/apt15e/apt/vehicle/service/VehicleInfoService.java index ab90ff4..5329cbf 100644 --- a/src/main/java/org/nl/apt15e/apt/vehicle/service/VehicleInfoService.java +++ b/src/main/java/org/nl/apt15e/apt/vehicle/service/VehicleInfoService.java @@ -10,4 +10,6 @@ public interface VehicleInfoService { VehicleInfo getVehicleInfo(); + void setVehicleInfo(VehicleInfo vehicleInfo); + } diff --git a/src/main/java/org/nl/apt15e/apt/vehicle/service/impl/VehicleInfoServiceImpl.java b/src/main/java/org/nl/apt15e/apt/vehicle/service/impl/VehicleInfoServiceImpl.java index dd824d3..04b14bd 100644 --- a/src/main/java/org/nl/apt15e/apt/vehicle/service/impl/VehicleInfoServiceImpl.java +++ b/src/main/java/org/nl/apt15e/apt/vehicle/service/impl/VehicleInfoServiceImpl.java @@ -37,6 +37,11 @@ public class VehicleInfoServiceImpl implements VehicleInfoService { return vehicleInfo; } + @Override + public void setVehicleInfo(VehicleInfo vehicleInfo) { + + } + @Async("asynchronousTasks") public void queryVehicleInfo() { HttpResponse response = null; @@ -52,18 +57,17 @@ public class VehicleInfoServiceImpl implements VehicleInfoService { } for (int i = 0; i < jsonArray.size(); i++) { JSONObject data = jsonArray.getJSONObject(i); - vehicleInfo = JSONObject.toJavaObject(data, VehicleInfo.class); - //电量 - vehicleInfo.setBatteryPower(data.getLong("batteryPercentile")); + vehicleInfo.setId(data.getString("id")); + vehicleInfo.setName(data.getString("name")); + vehicleInfo.setIp(data.getString("ip")); + vehicleInfo.setMapId(data.getLong("mapId")); + vehicleInfo.setMapName(data.getString("mapName")); + vehicleInfo.setStateId(data.getLong("stateId")); + vehicleInfo.setState(data.getString("state")); + vehicleInfo.setAreaId(data.getLong("areaId")); //上报的异常信息 VehicleException vehicleException = JSONObject.toJavaObject(data.getJSONObject("amrException"), VehicleException.class); vehicleInfo.setExceptionInfo(vehicleException); - //x,y,theta - JSONObject coordinate = data.getJSONObject("coordinate"); - vehicleInfo.setX(coordinate.getDouble("x")); - vehicleInfo.setY(coordinate.getDouble("y")); - vehicleInfo.setTheta(coordinate.getDouble("theta")); - System.out.println("Response Body: " + data); System.out.println("vehicleInfo: " + vehicleInfo); } } else { diff --git a/src/main/java/org/nl/apt15e/config/CorsConfig.java b/src/main/java/org/nl/apt15e/config/CorsConfig.java index 9801aa1..5bae32c 100644 --- a/src/main/java/org/nl/apt15e/config/CorsConfig.java +++ b/src/main/java/org/nl/apt15e/config/CorsConfig.java @@ -1,8 +1,11 @@ package org.nl.apt15e.config; +import org.nl.apt15e.config.file.FileProperties; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** @@ -10,7 +13,27 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; * 2025/7/14 */ @Configuration +@EnableWebMvc public class CorsConfig implements WebMvcConfigurer { + + /** 文件配置 */ + private final FileProperties properties; + + public CorsConfig(FileProperties properties) { + this.properties = properties; + } + + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + FileProperties.ElPath path = properties.getPath(); + String avatarUtl = "file:" + path.getAvatar().replace("\\","/"); + String pathUtl = "file:" + path.getPath().replace("\\","/"); + registry.addResourceHandler("/avatar/**").addResourceLocations(avatarUtl).setCachePeriod(0); + registry.addResourceHandler("/file/**").addResourceLocations(pathUtl).setCachePeriod(0); + registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/").setCachePeriod(0); + } + @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") diff --git a/src/main/java/org/nl/apt15e/config/file/FileProperties.java b/src/main/java/org/nl/apt15e/config/file/FileProperties.java new file mode 100644 index 0000000..24989bc --- /dev/null +++ b/src/main/java/org/nl/apt15e/config/file/FileProperties.java @@ -0,0 +1,45 @@ +package org.nl.apt15e.config.file; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * @author dsh + * 2025/7/24 + */ +@Data +@Configuration +@ConfigurationProperties(prefix = "file") +public class FileProperties { + + /** 文件大小限制 */ + private Long maxSize; + + /** 头像大小限制 */ + private Long avatarMaxSize; + + private ElPath mac; + + private ElPath linux; + + private ElPath windows; + + public ElPath getPath(){ + String os = System.getProperty("os.name"); + if(os.toLowerCase().startsWith("win")) { + return windows; + } else if(os.toLowerCase().startsWith("mac")){ + return mac; + } + return linux; + } + + @Data + public static class ElPath{ + + private String path; + + private String avatar; + } +} diff --git a/src/main/java/org/nl/apt15e/config/thread/ProtobufWebSocketHandler.java b/src/main/java/org/nl/apt15e/config/thread/ProtobufWebSocketHandler.java index d28ea4a..1d93d08 100644 --- a/src/main/java/org/nl/apt15e/config/thread/ProtobufWebSocketHandler.java +++ b/src/main/java/org/nl/apt15e/config/thread/ProtobufWebSocketHandler.java @@ -1,73 +1,111 @@ -//package org.nl.apt15e.config.thread; -// -//import comm_protocol.Robottype; -//import comm_protocol.Uidata; -//import lombok.extern.slf4j.Slf4j; -//import org.springframework.stereotype.Component; -//import org.springframework.web.socket.BinaryMessage; -//import org.springframework.web.socket.CloseStatus; -//import org.springframework.web.socket.TextMessage; -//import org.springframework.web.socket.WebSocketSession; -//import org.springframework.web.socket.handler.BinaryWebSocketHandler; -// -//import static comm_protocol.Uidata.UiDatagram.ItemCase.*; -// -///** -// * @author dsh -// * 2025/7/9 -// */ -//@Slf4j -//@Component -//public class ProtobufWebSocketHandler extends BinaryWebSocketHandler { -// -// @Override -// protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) { -// try { -// // 解析Protobuf数据 -// byte[] payload = message.getPayload().array(); -// Uidata.UiDatagram datagram = Uidata.UiDatagram.parseFrom(payload); -// -// switch (datagram.getItemCase()) { -// case ONLINE_INFO: -// Uidata.UiOnline online = datagram.getOnlineInfo(); -// System.out.println("Received online_info: " + online); -// break; -// -// case HEARTBEAT: -// Uidata.UiHeartbeat heartbeat = datagram.getHeartbeat(); -// System.out.println("Received heartbeat: " + heartbeat); -// break; -// -// case LASER_SCAN: +package org.nl.apt15e.config.thread; + +import comm_protocol.Robottype; +import comm_protocol.Uidata; +import lombok.extern.slf4j.Slf4j; +import org.nl.apt15e.apt.vehicle.service.impl.VehicleInfoServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.BinaryMessage; +import org.springframework.web.socket.CloseStatus; +import org.springframework.web.socket.TextMessage; +import org.springframework.web.socket.WebSocketSession; +import org.springframework.web.socket.client.WebSocketConnectionManager; +import org.springframework.web.socket.handler.BinaryWebSocketHandler; + +import javax.annotation.Resource; +import java.util.concurrent.atomic.AtomicBoolean; + +import static comm_protocol.Uidata.UiDatagram.ItemCase.*; + +/** + * @author dsh + * 2025/7/9 + */ +@Slf4j +@Component +@EnableScheduling +public class ProtobufWebSocketHandler extends BinaryWebSocketHandler { + + private static Boolean isConnected = false; + @Autowired + private WebSocketConnectionManager connectionManager; + private WebSocketSession currentSession; + + + @Override + protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) { + try { + // 解析Protobuf数据 + byte[] payload = message.getPayload().array(); + Uidata.UiDatagram datagram = Uidata.UiDatagram.parseFrom(payload); + + switch (datagram.getItemCase()) { + case ROBOT_BASE: + Robottype.RobotBase robotBase = datagram.getRobotBase(); + // 电量 + VehicleInfoServiceImpl.vehicleInfo.setBatteryPower(robotBase.getBatteryInfo().getSoc()); + //x,y,theta + VehicleInfoServiceImpl.vehicleInfo.setX(robotBase.getLocate().getCurrentState().getX()); + VehicleInfoServiceImpl.vehicleInfo.setY(robotBase.getLocate().getCurrentState().getY()); + VehicleInfoServiceImpl.vehicleInfo.setTheta(robotBase.getLocate().getCurrentState().getTheta()); + // 手自动模式 + VehicleInfoServiceImpl.vehicleInfo.setIsManual(robotBase.getRobotInactive()); +// System.out.println("vehicleInfo2: " + VehicleInfoServiceImpl.vehicleInfo); + break; + + case HEARTBEAT: + Uidata.UiHeartbeat heartbeat = datagram.getHeartbeat(); + System.out.println("Received heartbeat: " + heartbeat); + break; + + case LASER_SCAN: // Robottype.LaserData laser = datagram.getLaserScan(); -// System.out.println("Received laser_scan: " + laser); -// break; -// -// case IMAGE: -// // 处理图像数据 -// break; -// -// case CONTROL_SPEED: -// // 处理速度控制 -// break; -// -// case ITEM_NOT_SET: -// System.err.println("UiDatagram item not set!"); -// break; -// } -// session.close(); -// } catch (Exception e) { -// log.error("Error processing protobuf message", e); -// } -// } -// -// @Override -// public void afterConnectionEstablished(WebSocketSession session) { -// log.info("Connected to WebSocket server: {}", session.getUri()); -// } -// -// @Override -// public void afterConnectionClosed(WebSocketSession session, CloseStatus status) { -// log.info("Connection closed: {}", status); -// } -//} +// System.out.println("Received laser_scan: " + laser.getScanList()); + break; + } + } catch (Exception e) { + log.error("Error processing protobuf message", e); + } + } + + @Override + public void afterConnectionEstablished(WebSocketSession session) { + log.info("Connected to WebSocket server: {}", session.getUri()); + isConnected = true; + currentSession = session; + } + + @Override + public void afterConnectionClosed(WebSocketSession session, CloseStatus status) { + log.info("Connection closed: {}", status); + isConnected = false; + currentSession = null; + } + + @Override + public void handleTransportError(WebSocketSession session, Throwable exception) { + log.info("传输错误: {}", exception.getMessage()); + isConnected = false; + currentSession = null; + } + + @Scheduled(fixedDelay = 5000) + public synchronized void reconnectTask() { + if (!isConnected) { + try { + log.info("websocket 正在进行重连.."); + // 先停止当前连接(如果正在运行) + if (connectionManager.isRunning()) { + connectionManager.stop(); + } + // 启动新连接 + connectionManager.start(); + }catch (Exception e) { + log.error("websocket重连失败:{}",e.getMessage()); + } + } + } +} diff --git a/src/main/java/org/nl/apt15e/config/thread/WebsocketClientConfig.java b/src/main/java/org/nl/apt15e/config/thread/WebsocketClientConfig.java index 3a9296c..66fac17 100644 --- a/src/main/java/org/nl/apt15e/config/thread/WebsocketClientConfig.java +++ b/src/main/java/org/nl/apt15e/config/thread/WebsocketClientConfig.java @@ -1,45 +1,52 @@ -//package org.nl.apt15e.config.thread; -// -//import lombok.extern.slf4j.Slf4j; -//import org.springframework.context.annotation.Bean; -//import org.springframework.context.annotation.Configuration; -//import org.springframework.stereotype.Component; -//import org.springframework.web.socket.client.WebSocketClient; -//import org.springframework.web.socket.client.WebSocketConnectionManager; -//import org.springframework.web.socket.client.standard.StandardWebSocketClient; -// -//import javax.websocket.ContainerProvider; -//import javax.websocket.WebSocketContainer; -// -///** -// * @author dsh -// * 2025/7/9 -// */ -//@Slf4j -//@Configuration -//public class WebsocketClientConfig { -// -// @Bean -// public WebSocketClient webSocketClient() { -// // 创建WebSocket容器并配置缓冲区大小 -// WebSocketContainer container = ContainerProvider.getWebSocketContainer(); -// // 256KB -// container.setDefaultMaxBinaryMessageBufferSize(100 * 1024); -// container.setDefaultMaxTextMessageBufferSize(100 * 1024); -// -// return new StandardWebSocketClient(container); -// } -// -// @Bean -// public WebSocketConnectionManager webSocketConnectionManager() { -// String serverUrl = "ws://192.168.100.82:9998/ws/AGVInfo"; -// -// WebSocketConnectionManager manager = new WebSocketConnectionManager( -// this.webSocketClient(), -// new ProtobufWebSocketHandler(), -// serverUrl -// ); -// manager.setAutoStartup(true); -// return manager; -// } -//} +package org.nl.apt15e.config.thread; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.WebSocketHandler; +import org.springframework.web.socket.client.WebSocketClient; +import org.springframework.web.socket.client.WebSocketConnectionManager; +import org.springframework.web.socket.client.standard.StandardWebSocketClient; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.websocket.ContainerProvider; +import javax.websocket.WebSocketContainer; + +/** + * @author dsh + * 2025/7/9 + */ +@Slf4j +@Configuration +public class WebsocketClientConfig { + + @Bean + public WebSocketClient webSocketClient() { + // 创建WebSocket容器并配置缓冲区大小 + WebSocketContainer container = ContainerProvider.getWebSocketContainer(); + // 256KB + container.setDefaultMaxBinaryMessageBufferSize(100 * 1024); + container.setDefaultMaxTextMessageBufferSize(100 * 1024); + + return new StandardWebSocketClient(container); + } + + @Bean + public WebSocketConnectionManager webSocketConnectionManager() { + String serverUrl = "ws://192.168.100.82:9998/ws/AGVInfo"; + + WebSocketConnectionManager manager = new WebSocketConnectionManager( + this.webSocketClient(), + new ProtobufWebSocketHandler(), + serverUrl + ); + manager.setAutoStartup(false); + return manager; + } + + +} diff --git a/src/main/java/org/nl/apt15e/util/URLConstant.java b/src/main/java/org/nl/apt15e/util/URLConstant.java index ff1147c..b292f7e 100644 --- a/src/main/java/org/nl/apt15e/util/URLConstant.java +++ b/src/main/java/org/nl/apt15e/util/URLConstant.java @@ -13,7 +13,7 @@ public class URLConstant { /** * RCS调度IP及端口 */ - public final static String RCS_IP_PORT = "127.0.0.1:8011"; + public final static String RCS_IP_PORT = "192.168.100.82:8081"; /** * 下发任务URL diff --git a/src/main/resources/config/application-dev.yml b/src/main/resources/config/application-dev.yml index e650843..b3d8bf9 100644 --- a/src/main/resources/config/application-dev.yml +++ b/src/main/resources/config/application-dev.yml @@ -1,12 +1,12 @@ server: # 端口 - port: 8081 + port: 8011 spring: datasource: druid: db-type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://localhost:3306/apt_data?serverTimezone=GMT%2B8&characterEncoding=utf-8&userSSL=false + url: jdbc:mysql://localhost:3306/nl_apt15e?serverTimezone=GMT%2B8&characterEncoding=utf-8&userSSL=false username: root password: 123456 # 初始连接数 @@ -49,4 +49,19 @@ spring: merge-sql: true wall: config: - multi-statement-allow: true \ No newline at end of file + multi-statement-allow: true + +# 文件存储路径 +file: + mac: + path: ~/file/ + avatar: ~/avatar/ + linux: + path: /home/eladmin/file/ + avatar: /home/eladmin/avatar/ + windows: + path: C:\eladmin\file\ + avatar: C:\eladmin\avatar\ + # 文件大小 /M + maxSize: 100 + avatarMaxSize: 5 \ No newline at end of file diff --git a/src/main/resources/config/application-pro.yml b/src/main/resources/config/application-pro.yml index e650843..97b9e65 100644 --- a/src/main/resources/config/application-pro.yml +++ b/src/main/resources/config/application-pro.yml @@ -49,4 +49,19 @@ spring: merge-sql: true wall: config: - multi-statement-allow: true \ No newline at end of file + multi-statement-allow: true + +# 文件存储路径 +file: + mac: + path: ~/file/ + avatar: ~/avatar/ + linux: + path: /home/eladmin/file/ + avatar: /home/eladmin/avatar/ + windows: + path: C:\eladmin\file\ + avatar: C:\eladmin\avatar\ + # 文件大小 /M + maxSize: 100 + avatarMaxSize: 5 \ No newline at end of file