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

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