diff --git a/src/main/java/org/nl/apt15e/Apt15EApplication.java b/src/main/java/org/nl/apt15e/Apt15EApplication.java new file mode 100644 index 0000000..3a6c699 --- /dev/null +++ b/src/main/java/org/nl/apt15e/Apt15EApplication.java @@ -0,0 +1,34 @@ +package org.nl.apt15e; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@EnableAsync +@EnableScheduling +@SpringBootApplication +@EnableTransactionManagement +@RestController +@MapperScan("org.nl.apt15e.**.config") +public class Apt15EApplication { + + public static void main(String[] args) { + SpringApplication.run(Apt15EApplication.class, args); + } + + /** + * 访问首页提示 + * + * @return / + */ + @GetMapping("/") + public String index() { + return "Backend service started successfully"; + } + +} diff --git a/src/main/java/org/nl/apt15e/apt/dao/VehicleException.java b/src/main/java/org/nl/apt15e/apt/dao/VehicleException.java new file mode 100644 index 0000000..6825ec5 --- /dev/null +++ b/src/main/java/org/nl/apt15e/apt/dao/VehicleException.java @@ -0,0 +1,26 @@ +package org.nl.apt15e.apt.dao; + +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * @author dsh + * 2025/7/2 + */ +@Data +public class VehicleException implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 错误信息 + */ + private List exception; + + /** + * 错误码 + */ + private List exceptionCodes; + +} diff --git a/src/main/java/org/nl/apt15e/apt/dao/VehicleInfo.java b/src/main/java/org/nl/apt15e/apt/dao/VehicleInfo.java new file mode 100644 index 0000000..088a401 --- /dev/null +++ b/src/main/java/org/nl/apt15e/apt/dao/VehicleInfo.java @@ -0,0 +1,65 @@ +package org.nl.apt15e.apt.dao; + +import lombok.Data; + +import java.io.Serializable; + +/** + * @author dsh + * 2025/7/2 + */ +@Data +public class VehicleInfo implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 车辆 ID + */ + private String id; + + /** + * 车辆名称 + */ + private String name; + + /** + * 车辆 IP + */ + private String ip; + + /** + * 车辆所在地图 ID + */ + private Long mapId; + + /** + * 车辆所在地图 名称 + */ + private String mapName; + + /** + * 车辆状态 ID + */ + private Long stateId; + + /** + * 车辆状态名称 + */ + private String state; + + /** + * 区域 ID + */ + private Long areaId; + + /** + * 电量 + */ + private Long batteryPower; + + /** + * 异常信息 + */ + private VehicleException exceptionInfo; + +} diff --git a/src/main/java/org/nl/apt15e/apt/rest/VehicleInfoController.java b/src/main/java/org/nl/apt15e/apt/rest/VehicleInfoController.java new file mode 100644 index 0000000..8c4435c --- /dev/null +++ b/src/main/java/org/nl/apt15e/apt/rest/VehicleInfoController.java @@ -0,0 +1,30 @@ +package org.nl.apt15e.apt.rest; + +import lombok.extern.slf4j.Slf4j; +import org.nl.apt15e.apt.dao.VehicleInfo; +import org.nl.apt15e.apt.service.VehicleInfoService; +import org.nl.apt15e.common.logging.annotation.Log; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +/** + * @author dsh + * 2025/7/3 + */ +@Slf4j +@RestController +@RequestMapping("/vehicle") +public class VehicleInfoController { + + @Resource + private VehicleInfoService vehicleInfoService; + + @GetMapping("/getVehicleInfo") +// @Log("获取车辆信息") + public VehicleInfo getVehicleInfo() { + return vehicleInfoService.getVehicleInfo(); + } +} diff --git a/src/main/java/org/nl/apt15e/apt/service/VehicleInfoService.java b/src/main/java/org/nl/apt15e/apt/service/VehicleInfoService.java new file mode 100644 index 0000000..493b2f2 --- /dev/null +++ b/src/main/java/org/nl/apt15e/apt/service/VehicleInfoService.java @@ -0,0 +1,13 @@ +package org.nl.apt15e.apt.service; + +import org.nl.apt15e.apt.dao.VehicleInfo; + +/** + * @author dsh + * 2025/7/2 + */ +public interface VehicleInfoService { + + VehicleInfo getVehicleInfo(); + +} diff --git a/src/main/java/org/nl/apt15e/apt/service/impl/VehicleInfoServiceImpl.java b/src/main/java/org/nl/apt15e/apt/service/impl/VehicleInfoServiceImpl.java new file mode 100644 index 0000000..1df1033 --- /dev/null +++ b/src/main/java/org/nl/apt15e/apt/service/impl/VehicleInfoServiceImpl.java @@ -0,0 +1,98 @@ +package org.nl.apt15e.apt.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.nl.apt15e.apt.dao.VehicleException; +import org.nl.apt15e.apt.dao.VehicleInfo; +import org.nl.apt15e.apt.service.VehicleInfoService; +import org.nl.apt15e.apt.websocket.WebSocketVehicleServer; +import org.nl.apt15e.util.HTTPUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArraySet; + +/** + * @author dsh + * 2025/7/2 + */ +@Slf4j +@Service +public class VehicleInfoServiceImpl implements VehicleInfoService { + + @Resource + private TaskScheduler scheduler; + + public static VehicleInfo vehicleInfo = new VehicleInfo(); + + @Override + public VehicleInfo getVehicleInfo() { + return vehicleInfo; + } + + @Async("asynchronousTasks") + public void queryVehicleInfo() { + HttpResponse response = null; + try { + response = HTTPUtil.get("http://192.168.100.82:8081","/amr/onlineAmr",null); + // 检查响应状态码 + if (response!=null && response.isOk()) { + // 获取响应体内容 + String body = response.body(); + JSONArray jsonArray = JSONObject.parseObject(body).getJSONArray("data"); + if (jsonArray.isEmpty()) { + log.info("车辆数据为空"); + } + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject data = jsonArray.getJSONObject(i); + vehicleInfo = JSONObject.toJavaObject(data, VehicleInfo.class); + //电量 + vehicleInfo.setBatteryPower(data.getLong("batteryPercentile")); + //上报的异常信息 + VehicleException vehicleException = JSONObject.toJavaObject(data.getJSONObject("amrException"), VehicleException.class); + vehicleInfo.setExceptionInfo(vehicleException); + System.out.println("Response Body: " + data); + System.out.println("vehicleInfo: " + vehicleInfo); + } + } else { + log.info("查询调度车辆信息失败:{}",response); + } + } catch (Exception e) { + log.info("访问调度报错{}", e.getMessage()); + } + if (response != null) { + response.close(); + } + } + + @Async("asynchronousTasks") + public void sendVehicleInfo() { + CopyOnWriteArraySet webSocketSet = + WebSocketVehicleServer.getWebSocketSet(); + if (webSocketSet.size() > 0) { + webSocketSet.forEach(c -> { + Map vehicleInfoMap = new HashMap<>(); + vehicleInfoMap.put("data", vehicleInfo); + c.sendDataToClient(vehicleInfoMap); + }); + } + } + + @PostConstruct + public void init() { + scheduler.scheduleAtFixedRate(this::queryVehicleInfo,4000); + scheduler.scheduleAtFixedRate(this::sendVehicleInfo, 4000); + } +} 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 new file mode 100644 index 0000000..ec3a1dd --- /dev/null +++ b/src/main/java/org/nl/apt15e/apt/station/dao/Station.java @@ -0,0 +1,50 @@ +package org.nl.apt15e.apt.station.dao; + +import lombok.Data; + +import java.io.Serializable; + +/** + * @author dsh + * 2025/7/4 + */ +@Data +public class Station implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 站点标识 + */ + private String station_id; + + /** + * 站点编码 对应地图上站点 + */ + private String station_code; + + /** + * 站点别名 + */ + private String station_name; + + /** + * 动作类型 + */ + private String action_type; + + /** + * x坐标 + */ + private Double x; + + /** + * y坐标 + */ + private Double y; + + /** + * 角度 + */ + private Double angle; + +} 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 new file mode 100644 index 0000000..8e742b9 --- /dev/null +++ b/src/main/java/org/nl/apt15e/apt/teaching/rest/TeachingController.java @@ -0,0 +1,77 @@ +package org.nl.apt15e.apt.teaching.rest; + +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.annotations.Param; +import org.nl.apt15e.apt.teaching.service.TeachingService; +import org.nl.apt15e.common.logging.annotation.Log; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; + +/** + * @author dsh + * 2025/7/3 + */ +@Slf4j +@RestController +@RequestMapping("/teaching") +public class TeachingController { + + @Resource + private TeachingService teachingService; + + + @PostMapping("/startMapping") +// @Log("开始建图") + private ResponseEntity startMapping(@RequestParam("mapName") String mapName) { + return new ResponseEntity<>(teachingService.startMapping(mapName), HttpStatus.OK); + } + + @PostMapping("/stopMapping") + private ResponseEntity stopMapping() { + return new ResponseEntity<>(teachingService.stopMapping(), HttpStatus.OK); + } + + @PostMapping("/setStation") + private ResponseEntity setStation(@RequestParam("stationName") String stationName) { + return new ResponseEntity<>(teachingService.setStation(stationName), HttpStatus.OK); + } + + @PostMapping("/deployRunMap") + private ResponseEntity deployRunMap(@RequestParam("mapName") String mapName) { + return new ResponseEntity<>(teachingService.deployRunMap(mapName), HttpStatus.OK); + } + + @PostMapping("/changeCurrentRunMap") + private ResponseEntity changeCurrentRunMap(@RequestParam("mapName") String mapName) { + return new ResponseEntity<>(teachingService.changeCurrentRunMap(mapName), HttpStatus.OK); + } + + @PostMapping("/getLocalMaps") + private ResponseEntity getLocalMaps() { + return new ResponseEntity<>(teachingService.getLocalMaps(), HttpStatus.OK); + } + + @PostMapping("/getRunMapZip") + private ResponseEntity getRunMapZip(@RequestParam("mapName") String mapName) { + return new ResponseEntity<>(teachingService.getRunMapZip(mapName), HttpStatus.OK); + } + + @PostMapping("/synchronizeMap") + private ResponseEntity synchronizeMap(@RequestParam("mapName") String mapName) { + return new ResponseEntity<>(teachingService.synchronizeMap(mapName), HttpStatus.OK); + } + + @PostMapping("/restart") + private ResponseEntity restart() { + return new ResponseEntity<>(teachingService.restart(), HttpStatus.OK); + } + + @PostMapping("/relocate") + private ResponseEntity relocate(@RequestParam("x") Double x, @RequestParam("y") Double y, @RequestParam("angle") Double angle) { + return new ResponseEntity<>(teachingService.relocate(x, y, angle), 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 new file mode 100644 index 0000000..1fdf523 --- /dev/null +++ b/src/main/java/org/nl/apt15e/apt/teaching/service/TeachingService.java @@ -0,0 +1,81 @@ +package org.nl.apt15e.apt.teaching.service; + +import java.io.File; +import java.util.Map; + +/** + * @author dsh + * 2025/7/3 + */ +public interface TeachingService { + + /** + * 开始建图 + */ + Map startMapping(String mapName); + + /** + * 切手动 + */ + Map startManual(); + + /** + * 切自动 + */ + Map stopManual(); + + /** + * 结束建图 + */ + Map stopMapping(); + + /** + * 建图过程中设置站点 + */ + Map setStation(String stationName); + + /** + * 获取后台地图列表 + */ + Map getLocalMaps(); + + /** + * 部署地图 + * @param mapName + * @return + */ + Map deployRunMap(String mapName); + + /** + * 应用地图 + * @param mapName + * @return + */ + Map changeCurrentRunMap(String mapName); + + /** + * 获取主机地图包 + * @param mapName + * @return + */ + File getRunMapZip(String mapName); + + /** + * 同步地图到调度 + */ + Map synchronizeMap(String mapName); + + /** + * 重定位 + * @param x + * @param y + * @param angle + * @return + */ + Map relocate(Double x,Double y,Double angle); + + /** + * 重启车辆后台程序 + */ + Map restart(); +} 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 new file mode 100644 index 0000000..25f1243 --- /dev/null +++ b/src/main/java/org/nl/apt15e/apt/teaching/service/impl/TeachingServiceImpl.java @@ -0,0 +1,350 @@ +package org.nl.apt15e.apt.teaching.service.impl; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.ZipUtil; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.nl.apt15e.apt.dao.VehicleException; +import org.nl.apt15e.apt.dao.VehicleInfo; +import org.nl.apt15e.apt.teaching.service.TeachingService; +import org.nl.apt15e.common.BadRequestException; +import org.nl.apt15e.util.HTTPUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.nio.charset.Charset; +import java.util.Collections; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +/** + * @author dsh + * 2025/7/3 + */ +@Slf4j +@Service +public class TeachingServiceImpl implements TeachingService { + + @Override + public Map startMapping(String mapName) { + if ("".equals(mapName)){ + throw new BadRequestException("mapName is empty"); + } + JSONObject params = new JSONObject(); + params.put("name", mapName); + HttpResponse response = null; + try { + response = HTTPUtil.post("http://192.168.100.82:9998","/tool/rob/startMapping", params); + } catch (Exception e) { + log.info("访问车体开始建图接口报错:{}",e.getMessage()); + throw new BadRequestException("开始建图失败"); + } + // 检查响应状态码 + if (response.isOk()) { + // 获取响应体内容 + JSONObject body = JSON.parseObject(response.body()); + log.info("开始建图:{}",body); + if ("200".equals(body.getString("code"))){ + body =(JSONObject) this.startManual(); + } + return body; + } + log.info("开始建图失败"); + throw new BadRequestException("开始建图失败"); + } + + @Override + public Map startManual() { + HttpResponse response = null; + try { + response = HTTPUtil.post("http://192.168.100.82:9998","/tool/rob/startManual", new JSONObject()); + } catch (Exception e) { + log.info("访问车体切手动接口报错:{}",e.getMessage()); + throw new BadRequestException("切手动失败"); + } + // 检查响应状态码 + if (response.isOk()) { + // 获取响应体内容 + JSONObject body = JSON.parseObject(response.body()); + log.info("切手动:{}",body); + return body; + } + log.info("切手动失败"); + throw new BadRequestException("切手动失败"); + } + + @Override + public Map stopManual() { + HttpResponse response = null; + try { + response = HTTPUtil.post("http://192.168.100.82:9998","/tool/rob/stopManual", new JSONObject()); + } catch (Exception e) { + log.info("访问车体切自动接口报错:{}",e.getMessage()); + throw new BadRequestException("切自动失败"); + } + // 检查响应状态码 + if (response.isOk()) { + // 获取响应体内容 + JSONObject body = JSON.parseObject(response.body()); + log.info("切自动:{}",body); + return body; + } + log.info("切自动失败"); + throw new BadRequestException("切自动失败"); + } + + @Override + public Map stopMapping() { + HttpResponse response = null; + try { + response = HTTPUtil.post("http://192.168.100.82:9998","/tool/rob/stopMapping", new JSONObject()); + } catch (Exception e) { + log.info("访问车体结束建图接口报错:{}",e.getMessage()); + throw new BadRequestException("结束建图失败"); + } + // 检查响应状态码 + if (response.isOk()) { + // 获取响应体内容 + JSONObject body = JSON.parseObject(response.body()); + log.info("结束建图:{}",body); + if ("200".equals(body.getString("code"))){ + body =(JSONObject) this.stopManual(); + } + return body; + } + log.info("结束建图失败"); + throw new BadRequestException("结束建图失败"); + } + + @Override + public Map setStation(String stationName) { + if ("".equals(stationName)){ + throw new BadRequestException("spotCode is empty"); + } + JSONObject params = new JSONObject(); + params.put("spotCode", stationName); + HttpResponse response = null; + try { + response = HTTPUtil.post("http://192.168.100.82:9998","/tool/rob/setStates", params); + } catch (Exception e) { + log.info("访问车体设置站点接口报错:{}",e.getMessage()); + throw new BadRequestException("设置站点失败"); + } + // 检查响应状态码 + if (response.isOk()) { + // 获取响应体内容 + JSONObject body = JSON.parseObject(response.body()); + log.info("设置站点:{}",body); + return body; + } + log.info("设置站点失败"); + throw new BadRequestException("设置站点失败"); + } + + @Override + public Map getLocalMaps() { + HttpResponse response = null; + try { + response = HTTPUtil.get("http://192.168.100.82:9998","/tool/editor/getLocalMaps", new JSONObject()); + } catch (Exception e) { + log.info("访问车体地图列表接口报错:{}",e.getMessage()); + throw new BadRequestException("获取地图列表失败"); + } + // 检查响应状态码 + if (response.isOk()) { + // 获取响应体内容 + JSONObject body = JSON.parseObject(response.body()); + log.info("获取地图列表:{}",body); + return body; + } + log.info("获取地图列表失败"); + throw new BadRequestException("获取地图列表失败"); + } + + @Override + public Map deployRunMap(String mapName) { + if ("".equals(mapName)){ + throw new BadRequestException("mapName is empty"); + } + JSONObject params = new JSONObject(); + params.put("id", mapName); + HttpResponse response = null; + try { + response = HTTPUtil.post("http://192.168.100.82:9998","/tool/rob/deployRunMap", params); + } catch (Exception e) { + log.info("访问车体部署地图接口报错:{}",e.getMessage()); + throw new BadRequestException("部署地图失败"); + } + // 检查响应状态码 + if (response.isOk()) { + // 获取响应体内容 + JSONObject body = JSON.parseObject(response.body()); + log.info("部署地图:{}",body); + return body; + } + log.info("部署地图失败"); + throw new BadRequestException("部署地图失败"); + } + + @Override + public Map changeCurrentRunMap(String mapName) { + if ("".equals(mapName)){ + throw new BadRequestException("mapName is empty"); + } + JSONObject params = new JSONObject(); + params.put("name", mapName); + HttpResponse response = null; + try { + response = HTTPUtil.post("http://192.168.100.82:9998","/tool/rob/changeCurrentRunMap", params); + } catch (Exception e) { + log.info("访问车体应用地图接口报错:{}",e.getMessage()); + throw new BadRequestException("应用地图失败"); + } + // 检查响应状态码 + if (response.isOk()) { + // 获取响应体内容 + JSONObject body = JSON.parseObject(response.body()); + log.info("应用地图:{}",body); + return body; + } + log.info("应用地图失败"); + throw new BadRequestException("应用地图失败"); + } + + @Override + public File getRunMapZip(String mapName) { + if ("".equals(mapName)){ + throw new BadRequestException("mapName is empty"); + } + JSONObject params = new JSONObject(); + params.put("name", mapName); + HttpResponse response = null; + try { + response = HTTPUtil.post("http://192.168.100.82:9998","/tool/rob/getRunMapZip", params); + } catch (Exception e) { + log.info("访问车体地图包接口报错:{}",e.getMessage()); + throw new BadRequestException("获取地图包失败"); + } + // 检查响应状态码 + if (response.isOk()) { + // 获取响应体内容 +// JSONObject body = JSON.parseObject(response.body()); + // 3. 将响应体写入临时ZIP文件 + byte[] zipBytes = response.bodyBytes(); + File fileName = new File(mapName); + File tempZipFile = FileUtil.writeBytes(zipBytes, FileUtil.createTempFile(fileName)); + + // 4. 解压ZIP文件 +// File unzipDir = ZipUtil.unzip(tempZipFile, Charset.defaultCharset()); + + // 5. 处理解压后的文件 +// File[] files = unzipDir.listFiles(); +// if (files != null) { +// for (File file : files) { +// System.out.println("文件名: " + file.getName()); +// System.out.println("文件内容: "); +// System.out.println(FileUtil.readUtf8String(file)); // 读取文本内容 +// // 如果是二进制文件,使用:FileUtil.readBytes(file) +// } +// } + + // 6. 清理临时文件(可选) +// FileUtil.del(tempZipFile); +// FileUtil.del(unzipDir); + log.info("获取地图包"); + return tempZipFile; + } + log.info("获取地图包失败"); + throw new BadRequestException("获取地图包失败"); + } + + @Override + public Map synchronizeMap(String mapName) { + File zipFile = this.getRunMapZip(mapName); + HttpResponse response = null; + try { + response = HttpRequest.post("http://192.168.100.82:8081/map/uploadFile") + .setConnectionTimeout(3000) + .setReadTimeout(3000) + .header("token", "admin123") + .header("name", "lx-script") + .header("Content-Type", "multipart/form-data;charset=UTF-8") + .form("areaId",1) + .form("areaName","") + .form("data",zipFile) + .execute(); + } catch (Exception e) { + log.info("同步地图到调度接口报错:{}",e.getMessage()); + throw new BadRequestException("同步地图失败"); + } + // 检查响应状态码 + if (response.isOk()) { + // 获取响应体内容 + JSONObject body = JSON.parseObject(response.body()); + log.info("同步地图:{}",body); + return body; + } + log.info("同步地图失败"); + throw new BadRequestException("同步地图失败"); + } + + @Override + public Map relocate(Double x, Double y, Double angle) { + if (ObjectUtil.isEmpty(x) || ObjectUtil.isEmpty(y) || ObjectUtil.isEmpty(angle)){ + throw new BadRequestException("params is empty"); + } + JSONObject params = new JSONObject(); + params.put("x", x); + params.put("y", y); + params.put("angle", angle / 180.0 * Math.PI); + params.put("noisyX", 0.5); + params.put("noisyY", 0.5); + params.put("noisyAngle", Math.PI); + HttpResponse response = null; + try { + response = HTTPUtil.post("http://192.168.100.82:9998","/tool/rob/relocate", params); + } catch (Exception e) { + log.info("访问车体重定位接口报错:{}",e.getMessage()); + throw new BadRequestException("重定位失败"); + } + // 检查响应状态码 + if (response.isOk()) { + // 获取响应体内容 + JSONObject body = JSON.parseObject(response.body()); + log.info("重定位:{}",body); + return body; + } + log.info("重定位失败"); + throw new BadRequestException("重定位失败"); + } + + @Override + public Map restart() { + HttpResponse response = null; + try { + response = HTTPUtil.post("http://192.168.100.82:9998","/tool/rob/restart", new JSONObject()); + } catch (Exception e) { + log.info("访问车体程序重启接口报错:{}",e.getMessage()); + throw new BadRequestException("车体程序重启失败"); + } + // 检查响应状态码 + if (response.isOk()) { + // 获取响应体内容 + JSONObject body = JSON.parseObject(response.body()); + log.info("车体程序重启:{}",body); + return body; + } + log.info("车体程序重启失败"); + throw new BadRequestException("车体程序重启失败"); + } +} diff --git a/src/main/java/org/nl/apt15e/apt/websocket/WebSocketVehicleServer.java b/src/main/java/org/nl/apt15e/apt/websocket/WebSocketVehicleServer.java new file mode 100644 index 0000000..43149c2 --- /dev/null +++ b/src/main/java/org/nl/apt15e/apt/websocket/WebSocketVehicleServer.java @@ -0,0 +1,126 @@ +package org.nl.apt15e.apt.websocket; + +import cn.hutool.core.map.MapUtil; +import com.alibaba.fastjson.JSON; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.websocket.*; +import javax.websocket.server.PathParam; +import javax.websocket.server.ServerEndpoint; +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArraySet; + +/** + * @author dsh + * 2025/7/3 + */ +@Slf4j +@ServerEndpoint("/webSocket/VehicleInfo/{sid}") +@Component +public class WebSocketVehicleServer { + + /** + * concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。 + */ + private static CopyOnWriteArraySet webSocketSet = new CopyOnWriteArraySet<>(); + + /** + * 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。 + */ + private static int onlineCount = 0; + + + /** + * 与某个客户端的连接会话,需要通过它来给客户端发送数据 + */ + private Session session; + /** + * 接收userId + */ + private String sid = ""; + + /** + * 连接建立成功调用的方法 + */ + @OnOpen + public void onOpen(Session session, @PathParam("sid") String sid) { + this.session = session; + //如果存在就先删除一个,防止重复推送消息 + webSocketSet.removeIf(webSocket -> webSocket.sid.equals(sid)); + webSocketSet.add(this); + //在线数加1 + addOnlineCount(); + log.info("VehicleWS:sid{}连接成功,当前在线人数为{}", sid, getOnlineCount()); + this.sid = sid; + } + + /** + * 连接关闭调用的方法 + */ + @OnClose + public void onClose() { + webSocketSet.remove(this); + //在线数减1 + subOnlineCount(); + log.info("VehicleWS:sid{}关闭连接!当前在线人数为{}", sid, getOnlineCount()); + } + + /** + * 收到客户端消息后调用的方法 + * + * @param message 客户端发送过来的消息 + */ + @OnMessage + public void onMessage(String message, Session session) { + //System.out.println(webSocketSet.size() + "_接收到消息_" + session.getId()); + } + + @OnError + public void onError(Session session, Throwable error) { + //log.error("发生错误"); + webSocketSet.remove(session); + error.printStackTrace(); + } + + public Session getSession() { + return session; + } + + // 发送消息,在定时任务中会调用此方法 + public void sendMessage(String message) throws IOException { + this.session.getBasicRemote().sendText(message); + } + + + public void sendDataToClient(Map data) { + try { + if (this.session != null&& MapUtil.isNotEmpty(data)) { + this.session.getBasicRemote().sendText(JSON.toJSONString(data)); + } + } catch (IOException e) { + log.error("发送消息给客户端失败", e); + } + } + public static synchronized int getOnlineCount() { + return onlineCount; + } + + public static CopyOnWriteArraySet getWebSocketSet() { + return webSocketSet; + } + + + public void setSession(Session session) { + this.session = session; + } + + public static synchronized void addOnlineCount() { + WebSocketVehicleServer.onlineCount++; + } + + public static synchronized void subOnlineCount() { + WebSocketVehicleServer.onlineCount--; + } +} diff --git a/src/main/java/org/nl/apt15e/common/BadRequestException.java b/src/main/java/org/nl/apt15e/common/BadRequestException.java new file mode 100644 index 0000000..0b7ee89 --- /dev/null +++ b/src/main/java/org/nl/apt15e/common/BadRequestException.java @@ -0,0 +1,25 @@ +package org.nl.apt15e.common; + +import lombok.Getter; +import org.springframework.http.HttpStatus; + +import static org.springframework.http.HttpStatus.BAD_REQUEST; + +/** + * @author dsh + * 2025/7/3 + */ +@Getter +public class BadRequestException extends RuntimeException{ + + private Integer status = BAD_REQUEST.value(); + + public BadRequestException(String msg){ + super(msg); + } + + public BadRequestException(HttpStatus status, String msg){ + super(msg); + this.status = status.value(); + } +} diff --git a/src/main/java/org/nl/apt15e/common/exception/ApiError.java b/src/main/java/org/nl/apt15e/common/exception/ApiError.java new file mode 100644 index 0000000..96cb149 --- /dev/null +++ b/src/main/java/org/nl/apt15e/common/exception/ApiError.java @@ -0,0 +1,49 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.apt15e.common.exception; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +class ApiError { + + private Integer code = 400; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime Date; + private String message; + + private ApiError() { + Date = LocalDateTime.now(); + } + + public static ApiError error(String message){ + ApiError apiError = new ApiError(); + apiError.setMessage(message); + return apiError; + } + + public static ApiError error(Integer status, String message){ + ApiError apiError = new ApiError(); + apiError.setCode(status); + apiError.setMessage(message); + return apiError; + } +} + + diff --git a/src/main/java/org/nl/apt15e/common/exception/GlobalExceptionHandler.java b/src/main/java/org/nl/apt15e/common/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..e080f80 --- /dev/null +++ b/src/main/java/org/nl/apt15e/common/exception/GlobalExceptionHandler.java @@ -0,0 +1,78 @@ +package org.nl.apt15e.common.exception; + +import lombok.extern.slf4j.Slf4j; +import org.nl.apt15e.common.BadRequestException; +import org.nl.apt15e.util.ThrowableUtil; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.util.Objects; + + +/** + * @author liejiu + */ +@Slf4j +@RestControllerAdvice +public class GlobalExceptionHandler { + + /** + * 处理所有不可知的异常 + */ + @ExceptionHandler(Throwable.class) + public ResponseEntity handleException(Throwable e){ + // 打印堆栈信息 + log.error(ThrowableUtil.getStackTrace(e)); + return buildResponseEntity(ApiError.error(e.getMessage())); + } + + /** + * token 无效的异常拦截 + * @param e + * @return + */ +// @ExceptionHandler(value = NotLoginException.class) +// public ResponseEntity notLoginException(Exception e) { +//// log.error(ThrowableUtil.getStackTrace(e)); +// return buildResponseEntity(ApiError.error(401,"token 失效")); +// } + + + /** + * 处理自定义异常 + */ + @ExceptionHandler(value = BadRequestException.class) + public ResponseEntity badRequestException(BadRequestException e) { + // 打印堆栈信息 + log.error(ThrowableUtil.getStackTrace(e)); + log.info(e.getMessage()); + return buildResponseEntity(ApiError.error(e.getStatus(),e.getMessage())); + } + + + /** + * 处理所有接口数据验证异常 + */ + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException e){ + // 打印堆栈信息 + log.error(ThrowableUtil.getStackTrace(e)); + String[] str = Objects.requireNonNull(e.getBindingResult().getAllErrors().get(0).getCodes())[1].split("\\."); + String message = e.getBindingResult().getAllErrors().get(0).getDefaultMessage(); + String msg = "不能为空"; + if(msg.equals(message)){ + message = str[1] + ":" + message; + } + return buildResponseEntity(ApiError.error(message)); + } + + /** + * 统一返回 + */ + private ResponseEntity buildResponseEntity(ApiError apiError) { + return new ResponseEntity<>(apiError, HttpStatus.valueOf(apiError.getCode())); + } +} diff --git a/src/main/java/org/nl/apt15e/common/logging/annotation/Log.java b/src/main/java/org/nl/apt15e/common/logging/annotation/Log.java new file mode 100644 index 0000000..64be76a --- /dev/null +++ b/src/main/java/org/nl/apt15e/common/logging/annotation/Log.java @@ -0,0 +1,17 @@ +package org.nl.apt15e.common.logging.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author dsh + * 2025/7/3 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Log { + String value() default ""; + +} diff --git a/src/main/java/org/nl/apt15e/common/logging/aspect/LogAspect.java b/src/main/java/org/nl/apt15e/common/logging/aspect/LogAspect.java new file mode 100644 index 0000000..3f7e751 --- /dev/null +++ b/src/main/java/org/nl/apt15e/common/logging/aspect/LogAspect.java @@ -0,0 +1,66 @@ +package org.nl.apt15e.common.logging.aspect; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.Signature; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author dsh + * 2025/7/3 + */ +@Slf4j +@Aspect +@Component +public class LogAspect { + + /** + * 配置切入点 + */ + @Pointcut("@annotation(org.nl.apt15e.common.logging.annotation.Log)") + public void logPointCut(){} + + /** + * 环绕通知 + * @param joinPoint + * @return + * @throws Throwable + */ + @Around("logPointCut()") + public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { +// MethodSignature signature = (MethodSignature) joinPoint.getSignature(); +// Method method = signature.getMethod(); +// String className = joinPoint.getTarget().getClass().getName(); + // 方法路径 +// String methodName = joinPoint.getTarget().getClass().getName() + "." + signature.getName() + "()"; +// String params = JSONObject.toJSONString(joinPoint.getArgs()); + + + Object result; +// log.info("【日志注解】开始执行 -- {}:{} {}", className, "111", params); + result = joinPoint.proceed(); +// log.info("返回参数:{}" ,JSONObject.toJSONString(result)); + return result; + } + +} diff --git a/src/main/java/org/nl/apt15e/config/thread/AsyncTaskExecutePool.java b/src/main/java/org/nl/apt15e/config/thread/AsyncTaskExecutePool.java new file mode 100644 index 0000000..56ef0a8 --- /dev/null +++ b/src/main/java/org/nl/apt15e/config/thread/AsyncTaskExecutePool.java @@ -0,0 +1,86 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.nl.apt15e.config.thread; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.AsyncConfigurer; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * 异步任务线程池装配类 + * + * @author https://juejin.im/entry/5abb8f6951882555677e9da2 + * @date 2019年10月31日15:06:18 + */ +@Slf4j +@Configuration +@EnableAsync +public class AsyncTaskExecutePool implements AsyncConfigurer{ + + @Override + public Executor getAsyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + //核心线程池大小 + executor.setCorePoolSize(20); + //最大线程数 + executor.setMaxPoolSize(50); + //队列容量 + executor.setQueueCapacity(50); + //活跃时间 + executor.setKeepAliveSeconds(60); + //线程名字前缀 + executor.setThreadNamePrefix("Async-"); + // setRejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务 + // CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行 + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + executor.initialize(); + return executor; + } + + /** + * 线程池配置 + */ + @Bean(name = "asynchronousTasks") + public ThreadPoolTaskExecutor threadPoolTaskExecutor() { + ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); + // 核心线程池大小 + threadPoolTaskExecutor.setCorePoolSize(20); + // 最大线程数 + threadPoolTaskExecutor.setMaxPoolSize(50); + // 队列容量 + threadPoolTaskExecutor.setQueueCapacity(50); + // 活跃时间 + threadPoolTaskExecutor.setKeepAliveSeconds(60); + // 主线程等待子线程执行时间 + threadPoolTaskExecutor.setAwaitTerminationSeconds(50); + // threadPoolTaskExecutor.setAwaitTerminationSeconds(30); + // 线程名字前缀 + threadPoolTaskExecutor.setThreadNamePrefix("apt-thread-"); + // RejectedExecutionHandler:当pool已经达到max-size的时候,如何处理新任务 + // CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行 + threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + // 初始化 + threadPoolTaskExecutor.initialize(); + return threadPoolTaskExecutor; + } +} diff --git a/src/main/java/org/nl/apt15e/config/thread/WebSocketConfig.java b/src/main/java/org/nl/apt15e/config/thread/WebSocketConfig.java new file mode 100644 index 0000000..46e8240 --- /dev/null +++ b/src/main/java/org/nl/apt15e/config/thread/WebSocketConfig.java @@ -0,0 +1,19 @@ +package org.nl.apt15e.config.thread; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.server.standard.ServerEndpointExporter; + +/** + * @author dsh + * 2025/7/3 + */ +@Configuration +public class WebSocketConfig { + + @Bean + public ServerEndpointExporter serverEndpointExporter() { + return new ServerEndpointExporter(); + } + +} diff --git a/src/main/java/org/nl/apt15e/util/HTTPUtil.java b/src/main/java/org/nl/apt15e/util/HTTPUtil.java new file mode 100644 index 0000000..4013b6f --- /dev/null +++ b/src/main/java/org/nl/apt15e/util/HTTPUtil.java @@ -0,0 +1,40 @@ +package org.nl.apt15e.util; + +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; + +/** + * @author dsh + * 2025/7/2 + */ +@Slf4j +public class HTTPUtil { + + public static HttpResponse post(String url, String method, JSONObject params)throws Exception{ + String sendUrl = url + method; + return HttpRequest.post(sendUrl) + .setConnectionTimeout(3000) + .setReadTimeout(3000) + .header("token", "admin123") + .header("name", "lx-script") + .header("Content-Type", "application/json") + .body(String.valueOf(params)) + .execute(); + + } + + public static HttpResponse get(String url, String method, JSONObject params)throws Exception{ + String sendUrl = url + method; + return HttpRequest.get(sendUrl) + .setConnectionTimeout(3000) + .setReadTimeout(3000) + .header("token", "admin123") + .header("name", "lx-script") + .header("Content-Type", "application/json") + .form(params) + .execute(); + + } +} diff --git a/src/main/java/org/nl/apt15e/util/ThrowableUtil.java b/src/main/java/org/nl/apt15e/util/ThrowableUtil.java new file mode 100644 index 0000000..eb7780f --- /dev/null +++ b/src/main/java/org/nl/apt15e/util/ThrowableUtil.java @@ -0,0 +1,22 @@ +package org.nl.apt15e.util; + +import java.io.PrintWriter; +import java.io.StringWriter; + + +/** + * @author liejiu + */ +public class ThrowableUtil { + + /** + * 获取堆栈信息 + */ + public static String getStackTrace(Throwable throwable){ + StringWriter sw = new StringWriter(); + try (PrintWriter pw = new PrintWriter(sw)) { + throwable.printStackTrace(pw); + return sw.toString(); + } + } +} diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt new file mode 100644 index 0000000..cf45865 --- /dev/null +++ b/src/main/resources/banner.txt @@ -0,0 +1,8 @@ + _ _ ___________ _ _____ _ ___________ _____ +| \ | | _ | ___ \ | | ___| | | ___| ___|_ _| +| \| | | | | |_/ / | | |__ | | | |__ | |_ | | +| . ` | | | | ___ \ | | __|| | | __|| _| | | +| |\ \ \_/ / |_/ / |____| |___| |____| |___| | | | +\_| \_/\___/\____/\_____/\____/\_____/\____/\_| \_/ + + :: Spring Boot :: (v2.6.13.RELEASE) \ No newline at end of file diff --git a/src/main/resources/config/application-dev.yml b/src/main/resources/config/application-dev.yml new file mode 100644 index 0000000..e650843 --- /dev/null +++ b/src/main/resources/config/application-dev.yml @@ -0,0 +1,52 @@ +server: + # 端口 + port: 8081 +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 + username: root + password: 123456 + # 初始连接数 + initial-size: 5 + # 最小连接数 + min-idle: 15 + # 最大连接数 + max-active: 30 + # 超时时间(以秒数为单位) + remove-abandoned-timeout: 180 + # 获取连接超时时间 + max-wait: 3000 + # 连接有效性检测时间 + time-between-eviction-runs-millis: 60000 + # 连接在池中最小生存的时间 + min-evictable-idle-time-millis: 300000 + # 连接在池中最大生存的时间 + max-evictable-idle-time-millis: 900000 + # 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除 + test-while-idle: true + # 指明是否在从池中取出连接前进行检验,如果检验失败, 则从池中去除连接并尝试取出另一个 + test-on-borrow: true + # 是否在归还到池中前进行检验 + test-on-return: false + # 检测连接是否有效 + validation-query: select 1 + # 配置监控统计 + webStatFilter: + enabled: true + stat-view-servlet: + enabled: true + url-pattern: /druid/* + reset-enable: false + filter: + stat: + enabled: true + # 记录慢SQL + log-slow-sql: true + slow-sql-millis: 1000 + merge-sql: true + wall: + config: + multi-statement-allow: true \ No newline at end of file diff --git a/src/main/resources/config/application-pro.yml b/src/main/resources/config/application-pro.yml new file mode 100644 index 0000000..e650843 --- /dev/null +++ b/src/main/resources/config/application-pro.yml @@ -0,0 +1,52 @@ +server: + # 端口 + port: 8081 +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 + username: root + password: 123456 + # 初始连接数 + initial-size: 5 + # 最小连接数 + min-idle: 15 + # 最大连接数 + max-active: 30 + # 超时时间(以秒数为单位) + remove-abandoned-timeout: 180 + # 获取连接超时时间 + max-wait: 3000 + # 连接有效性检测时间 + time-between-eviction-runs-millis: 60000 + # 连接在池中最小生存的时间 + min-evictable-idle-time-millis: 300000 + # 连接在池中最大生存的时间 + max-evictable-idle-time-millis: 900000 + # 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除 + test-while-idle: true + # 指明是否在从池中取出连接前进行检验,如果检验失败, 则从池中去除连接并尝试取出另一个 + test-on-borrow: true + # 是否在归还到池中前进行检验 + test-on-return: false + # 检测连接是否有效 + validation-query: select 1 + # 配置监控统计 + webStatFilter: + enabled: true + stat-view-servlet: + enabled: true + url-pattern: /druid/* + reset-enable: false + filter: + stat: + enabled: true + # 记录慢SQL + log-slow-sql: true + slow-sql-millis: 1000 + merge-sql: true + wall: + config: + multi-statement-allow: true \ No newline at end of file diff --git a/src/main/resources/config/application.yml b/src/main/resources/config/application.yml new file mode 100644 index 0000000..1557389 --- /dev/null +++ b/src/main/resources/config/application.yml @@ -0,0 +1,18 @@ +spring: + profiles: + active: dev + jackson: + time-zone: GMT+8 + +mybatis-plus: + configuration: + map-underscore-to-camel-case: false + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl + mapper-locations: classpath*:/mapper/**/*.xml + global-config: + banner: false + +logging: + file: + path: logs + config: classpath:logback-spring.xml \ No newline at end of file diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..1a21870 --- /dev/null +++ b/src/main/resources/logback-spring.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + INFO + + + ${log.pattern} + ${log.charset} + + + + + + + + + + + ${LOG_HOME}/root/info.%d{yyyy-MM-dd}.log + + 30 + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n + ${log.charset} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/org/nl/apt15e/Apt15EApplicationTests.java b/src/test/java/org/nl/apt15e/Apt15EApplicationTests.java new file mode 100644 index 0000000..5f537f9 --- /dev/null +++ b/src/test/java/org/nl/apt15e/Apt15EApplicationTests.java @@ -0,0 +1,13 @@ +package org.nl.apt15e; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class Apt15EApplicationTests { + + @Test + void contextLoads() { + } + +}