feat: 添加路径规划和票面信息识别api

This commit is contained in:
ivmiku
2024-08-08 19:09:25 +08:00
parent dc534d7ee6
commit a282b97442
10 changed files with 373 additions and 0 deletions

102
navigate-8432/pom.xml Normal file
View File

@@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.ivmiku.tutorial</groupId>
<artifactId>first-tutorial</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>navigate-8432</artifactId>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!-- Sa-Token 权限认证在线文档https://sa-token.cc -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot3-starter</artifactId>
</dependency>
<!-- fastjson2 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
</dependency>
<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redis-jackson</artifactId>
<version>1.38.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-registry-nacos -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.ivmiku.tutorial</groupId>
<artifactId>commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-http -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-http</artifactId>
<version>5.8.29</version>
</dependency>
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java-ocr</artifactId>
<version>3.1.1076</version>
</dependency>
</dependencies>
</project>

View File

@@ -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);
}
}

View File

@@ -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<String, List<RouteStep>> 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<String, Object> route = navigateService.getRoute(origin, destination);
List<RouteStep> stepsList = (List<RouteStep>) route.get("steps");
STEPS_MAP.put(userId, stepsList);
Map<String, Object> 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<String, Object> 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<String, Object> map = navigateService.scanTicket(image);
return JSON.toJSON(Result.ok(map));
}
}

View File

@@ -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;
}

View File

@@ -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<String, Object> getRoute(String origin, String destination) {
Map<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> result = new HashMap<>();
List<GroupInfo> groupInfoList = Arrays.stream(resp.getStructuralList()).toList();
for (GroupInfo groupInfo : groupInfoList) {
List<LineInfo> lineList = Arrays.stream(groupInfo.getGroups()).toList();
for (LineInfo lineInfo : lineList) {
List<ItemInfo> 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;
}
}

View File

@@ -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()));
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1 @@
spring.profiles.active=dev

View File

@@ -12,6 +12,7 @@
<module>gateway-8133</module> <module>gateway-8133</module>
<module>user-8072</module> <module>user-8072</module>
<module>commons</module> <module>commons</module>
<module>navigate-8432</module>
</modules> </modules>
<properties> <properties>