diff --git a/navigate-8432/pom.xml b/navigate-8432/pom.xml
new file mode 100644
index 0000000..a381a9a
--- /dev/null
+++ b/navigate-8432/pom.xml
@@ -0,0 +1,102 @@
+
+
+ 4.0.0
+
+ com.ivmiku.tutorial
+ first-tutorial
+ 1.0-SNAPSHOT
+
+
+ navigate-8432
+
+
+ 21
+ 21
+ UTF-8
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ com.baomidou
+ mybatis-plus-spring-boot3-starter
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
+
+ com.mysql
+ mysql-connector-j
+ runtime
+
+
+ org.projectlombok
+ lombok
+ provided
+
+
+
+ cn.dev33
+ sa-token-spring-boot3-starter
+
+
+
+ com.alibaba.fastjson2
+ fastjson2
+
+
+
+ cn.dev33
+ sa-token-redis-jackson
+ 1.38.0
+
+
+ org.apache.commons
+ commons-pool2
+
+
+
+ org.apache.dubbo
+ dubbo-spring-boot-starter
+
+
+
+ org.apache.dubbo
+ dubbo-registry-nacos
+
+
+ org.springframework.cloud
+ spring-cloud-starter-loadbalancer
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-sentinel
+
+
+ com.ivmiku.tutorial
+ commons
+ 1.0-SNAPSHOT
+
+
+
+ cn.hutool
+ hutool-http
+ 5.8.29
+
+
+ com.tencentcloudapi
+ tencentcloud-sdk-java-ocr
+ 3.1.1076
+
+
+
\ No newline at end of file
diff --git a/navigate-8432/src/main/java/com/ivmiku/tutorial/Main8432.java b/navigate-8432/src/main/java/com/ivmiku/tutorial/Main8432.java
new file mode 100644
index 0000000..9401c6a
--- /dev/null
+++ b/navigate-8432/src/main/java/com/ivmiku/tutorial/Main8432.java
@@ -0,0 +1,13 @@
+package com.ivmiku.tutorial;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+@MapperScan("com.ivmiku.tutorial.mapper")
+public class Main8432 {
+ public static void main(String[] args) {
+ SpringApplication.run(Main8432.class, args);
+ }
+}
\ No newline at end of file
diff --git a/navigate-8432/src/main/java/com/ivmiku/tutorial/controller/NavigateController.java b/navigate-8432/src/main/java/com/ivmiku/tutorial/controller/NavigateController.java
new file mode 100644
index 0000000..927d070
--- /dev/null
+++ b/navigate-8432/src/main/java/com/ivmiku/tutorial/controller/NavigateController.java
@@ -0,0 +1,62 @@
+package com.ivmiku.tutorial.controller;
+
+import cn.dev33.satoken.annotation.SaCheckLogin;
+import cn.dev33.satoken.stp.StpUtil;
+import com.alibaba.fastjson2.JSON;
+import com.ivmiku.tutorial.entity.RouteStep;
+import com.ivmiku.tutorial.response.Result;
+import com.ivmiku.tutorial.service.NavigateService;
+import jakarta.annotation.Resource;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+@RestController
+@RequestMapping("/navigate")
+@SaCheckLogin
+public class NavigateController {
+ @Resource
+ private NavigateService navigateService;
+
+ private static final ConcurrentHashMap> STEPS_MAP = new ConcurrentHashMap<>();
+
+ @GetMapping("/route")
+ public Object getRoute(@RequestParam(defaultValue = "") String origin,
+ @RequestParam(defaultValue = "") String destination,
+ @RequestParam(defaultValue = "-1") int step) {
+ String userId = (String) StpUtil.getLoginId();
+ if (!origin.isEmpty() && !destination.isEmpty()) {
+ Map route = navigateService.getRoute(origin, destination);
+ List stepsList = (List) route.get("steps");
+ STEPS_MAP.put(userId, stepsList);
+ Map map = new HashMap<>();
+ map.put("total", stepsList.size());
+ map.put("distance", Integer.parseInt((String) route.get("distance")));
+ map.put("duration", Integer.parseInt((String) route.get("duration")));
+ map.put("step", stepsList.getFirst());
+ return JSON.toJSON(Result.ok(map));
+ } else if (step >0) {
+ if (!STEPS_MAP.containsKey(userId)) {
+ return JSON.toJSON(Result.error("请先获取路线!"));
+ }
+ Map map = new HashMap<>();
+ map.put("step", STEPS_MAP.get(userId).get(step-1));
+ return JSON.toJSON(Result.ok(map));
+ }
+ return JSON.toJSON(Result.error("非法的请求参数"));
+ }
+
+ @PostMapping("/ticket")
+ public Object scanTicket(@RequestPart MultipartFile file) throws IOException {
+ BufferedImage image = ImageIO.read(file.getInputStream());
+ Map map = navigateService.scanTicket(image);
+ return JSON.toJSON(Result.ok(map));
+ }
+}
diff --git a/navigate-8432/src/main/java/com/ivmiku/tutorial/entity/RouteStep.java b/navigate-8432/src/main/java/com/ivmiku/tutorial/entity/RouteStep.java
new file mode 100644
index 0000000..b42e3bc
--- /dev/null
+++ b/navigate-8432/src/main/java/com/ivmiku/tutorial/entity/RouteStep.java
@@ -0,0 +1,16 @@
+package com.ivmiku.tutorial.entity;
+
+import lombok.Data;
+
+@Data
+public class RouteStep {
+ private String instruction;
+ private String orientation;
+ private String road;
+ private Integer distance;
+ private Integer duration;
+ private String polyline;
+ private String action;
+ private String assistant_action;
+ private Integer walk_type;
+}
diff --git a/navigate-8432/src/main/java/com/ivmiku/tutorial/service/NavigateService.java b/navigate-8432/src/main/java/com/ivmiku/tutorial/service/NavigateService.java
new file mode 100644
index 0000000..32ba49d
--- /dev/null
+++ b/navigate-8432/src/main/java/com/ivmiku/tutorial/service/NavigateService.java
@@ -0,0 +1,84 @@
+package com.ivmiku.tutorial.service;
+
+import cn.hutool.core.img.ImgUtil;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.ivmiku.tutorial.entity.RouteStep;
+import com.tencentcloudapi.common.Credential;
+import com.tencentcloudapi.common.exception.TencentCloudSDKException;
+import com.tencentcloudapi.common.profile.ClientProfile;
+import com.tencentcloudapi.common.profile.HttpProfile;
+import com.tencentcloudapi.ocr.v20181119.OcrClient;
+import com.tencentcloudapi.ocr.v20181119.models.*;
+import org.springframework.stereotype.Service;
+
+import java.awt.image.BufferedImage;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Service
+public class NavigateService {
+ private final String key = "d3aa1b75aff468a5ca5384d2b4b6bfef";
+ private final String secretId = "AKID09INNYxYEFFJH3g9VhljVF3qbDiFdx50";
+ private final String secretKey = "KajjcNyNaaUCqQroqpzNoMtTHNj4Lbil";
+
+ public Map getRoute(String origin, String destination) {
+ Map params = new HashMap<>();
+ params.put("key", key);
+ params.put("origin", origin);
+ params.put("destination", destination);
+ HttpResponse response = HttpRequest.get("https://restapi.amap.com/v3/direction/walking")
+ .form(params)
+ .execute();
+ String result = response.body();
+ response.close();
+ JSONObject route = JSONObject.parseObject(JSONObject.parseObject(result).getString("route"));
+ JSONArray paths = JSONArray.parseArray(route.getString("paths"));
+ JSONObject path = paths.getJSONObject(0);
+ String distance = path.getString("distance");
+ String duration = path.getString("duration");
+ Map map = new HashMap<>();
+ map.put("distance", distance);
+ map.put("duration", duration);
+ map.put("steps", JSONArray.parseArray(path.getString("steps"), RouteStep.class));
+ return map;
+ }
+
+ public Map scanTicket(BufferedImage image) {
+ String base64Img = ImgUtil.toBase64(image, "jpg");
+ SmartStructuralOCRV2Response resp;
+ try {
+ Credential cred = new Credential(secretId, secretKey);
+ HttpProfile httpProfile = new HttpProfile();
+ httpProfile.setEndpoint("ocr.tencentcloudapi.com");
+ ClientProfile clientProfile = new ClientProfile();
+ clientProfile.setHttpProfile(httpProfile);
+ OcrClient client = new OcrClient(cred, "ap-shanghai", clientProfile);
+ SmartStructuralOCRV2Request req = new SmartStructuralOCRV2Request();
+ req.setImageBase64(base64Img);
+ String[] itemNames1 = {"登机口", "检票口"};
+ req.setItemNames(itemNames1);
+ resp = client.SmartStructuralOCRV2(req);
+ } catch (TencentCloudSDKException e) {
+ throw new RuntimeException(e.getMessage());
+ }
+ Map result = new HashMap<>();
+ List groupInfoList = Arrays.stream(resp.getStructuralList()).toList();
+ for (GroupInfo groupInfo : groupInfoList) {
+ List lineList = Arrays.stream(groupInfo.getGroups()).toList();
+ for (LineInfo lineInfo : lineList) {
+ List itemList = Arrays.stream(lineInfo.getLines()).toList();
+ for (ItemInfo info : itemList) {
+ if (info.getKey() != null && info.getValue() != null) {
+ result.put(String.valueOf(info.getKey().getAutoName()), info.getValue().getAutoContent());
+ }
+ }
+ }
+ }
+ return result;
+ }
+}
diff --git a/navigate-8432/src/main/java/com/ivmiku/tutorial/utils/GlobalExceptionHandler.java b/navigate-8432/src/main/java/com/ivmiku/tutorial/utils/GlobalExceptionHandler.java
new file mode 100644
index 0000000..bc0f099
--- /dev/null
+++ b/navigate-8432/src/main/java/com/ivmiku/tutorial/utils/GlobalExceptionHandler.java
@@ -0,0 +1,61 @@
+package com.ivmiku.tutorial.utils;
+
+import cn.dev33.satoken.exception.SaTokenException;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.fastjson2.JSON;
+import com.ivmiku.tutorial.response.Result;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+import java.sql.SQLException;
+import java.text.ParseException;
+
+/**
+ * @author Aurora
+ */
+@Slf4j
+@ControllerAdvice
+public class GlobalExceptionHandler {
+ @ExceptionHandler(value = SaTokenException.class)
+ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+ @ResponseBody
+ public Object SaTokenExceptionHandler(SaTokenException e) {
+ log.error("SaTokenException:" + e.getLocalizedMessage());
+ return JSON.toJSON(Result.error("身份认证错误:" + e.getMessage()));
+ }
+
+ @ExceptionHandler(value = ParseException.class)
+ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+ @ResponseBody
+ public Object parseExceptionHandler(ParseException e) {
+
+ log.error("ParseException:" + e.getLocalizedMessage());
+ return JSON.toJSON(Result.error("请检查日期是否合法"));
+ }
+
+ @ExceptionHandler(value = SQLException.class)
+ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+ @ResponseBody
+ public Object SQLExceptionHandler(SQLException e) {
+ log.error("SQLException:" + e.getLocalizedMessage());
+ return JSON.toJSON(Result.error("数据库出错!(内部错误)\n" + e.getMessage()));
+ }
+
+ @ExceptionHandler(value = BlockException.class)
+ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+ @ResponseBody
+ public Object sentinelHandler(BlockException e) {
+ return JSON.toJSON(Result.error("系统繁忙,请稍后再试"));
+ }
+
+ @ExceptionHandler(value = Exception.class)
+ @ResponseBody
+ public Object exceptionHandler(Exception e) {
+ log.error("Exception:" + e.getLocalizedMessage());
+ return JSON.toJSON(Result.error("服务器内部错误:" + e.getClass() + ":" + e.getMessage()));
+ }
+}
diff --git a/navigate-8432/src/main/resources/application-dep.properties b/navigate-8432/src/main/resources/application-dep.properties
new file mode 100644
index 0000000..c84c07e
--- /dev/null
+++ b/navigate-8432/src/main/resources/application-dep.properties
@@ -0,0 +1,19 @@
+spring.data.redis.host=redis
+spring.data.redis.port=6379
+spring.data.redis.database=0
+spring.data.redis.password=Shuodedaoli114514
+
+spring.application.name=navigate
+
+server.port=8432
+
+spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
+spring.datasource.username=root
+spring.datasource.password=Shuodedaoli114514
+spring.datasource.url=jdbc:mysql://mysql:4514/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&ServerTimezone=Asia/Shanghai
+
+spring.cloud.nacos.discovery.server-addr=nacos:8848
+spring.cloud.nacos.discovery.enabled=true
+
+management.zipkin.tracing.endpoint=http://zipkin:9411/api/v2/spans
+management.tracing.sampling.probability=1.0
\ No newline at end of file
diff --git a/navigate-8432/src/main/resources/application-dev.properties b/navigate-8432/src/main/resources/application-dev.properties
new file mode 100644
index 0000000..cc170df
--- /dev/null
+++ b/navigate-8432/src/main/resources/application-dev.properties
@@ -0,0 +1,14 @@
+spring.data.redis.host=localhost
+spring.data.redis.port=6379
+spring.data.redis.database=0
+
+spring.application.name=navigate
+
+server.port=8432
+
+dubbo.application.qos-enable=false
+
+spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
+spring.datasource.username=root
+spring.datasource.password=12345abcde
+spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&ServerTimezone=Asia/Shanghai
diff --git a/navigate-8432/src/main/resources/application.properties b/navigate-8432/src/main/resources/application.properties
new file mode 100644
index 0000000..257b306
--- /dev/null
+++ b/navigate-8432/src/main/resources/application.properties
@@ -0,0 +1 @@
+spring.profiles.active=dev
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 8db85ab..f405644 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,6 +12,7 @@
gateway-8133
user-8072
commons
+ navigate-8432