feat(core): 新增向量数据库与Apple支付支持
This commit is contained in:
45
pom.xml
45
pom.xml
@@ -55,7 +55,50 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- <dependency>-->
|
<!-- qdrant向量数据库 sdk -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.qdrant</groupId>
|
||||||
|
<artifactId>client</artifactId>
|
||||||
|
<version>1.15.0</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<version>33.2.0-jre</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.protobuf</groupId>
|
||||||
|
<artifactId>protobuf-java</artifactId>
|
||||||
|
<version>4.28.2</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- gRPC API(包含 ManagedChannel)-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.grpc</groupId>
|
||||||
|
<artifactId>grpc-api</artifactId>
|
||||||
|
<version>1.65.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- gRPC Stub(一般也会用到,间接依赖 grpc-api)-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.grpc</groupId>
|
||||||
|
<artifactId>grpc-stub</artifactId>
|
||||||
|
<version>1.65.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- gRPC Netty 传输实现(QdrantGrpcClient 底层需要)-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.grpc</groupId>
|
||||||
|
<artifactId>grpc-netty-shaded</artifactId>
|
||||||
|
<version>1.65.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- <dependency>-->
|
||||||
<!-- <groupId>com.alibaba.cloud.ai</groupId>-->
|
<!-- <groupId>com.alibaba.cloud.ai</groupId>-->
|
||||||
<!-- <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>-->
|
<!-- <artifactId>spring-ai-alibaba-starter-dashscope</artifactId>-->
|
||||||
<!-- <version>1.0.0.4</version>-->
|
<!-- <version>1.0.0.4</version>-->
|
||||||
|
|||||||
@@ -3,12 +3,17 @@ package com.yolo.keyborad.config;
|
|||||||
|
|
||||||
import org.springframework.ai.chat.client.ChatClient;
|
import org.springframework.ai.chat.client.ChatClient;
|
||||||
import org.springframework.ai.chat.model.ChatModel;
|
import org.springframework.ai.chat.model.ChatModel;
|
||||||
|
import org.springframework.ai.document.MetadataMode;
|
||||||
import org.springframework.ai.openai.OpenAiChatOptions;
|
import org.springframework.ai.openai.OpenAiChatOptions;
|
||||||
|
import org.springframework.ai.openai.OpenAiEmbeddingModel;
|
||||||
|
import org.springframework.ai.openai.OpenAiEmbeddingOptions;
|
||||||
import org.springframework.ai.openai.api.OpenAiApi;
|
import org.springframework.ai.openai.api.OpenAiApi;
|
||||||
|
import org.springframework.ai.retry.RetryUtils;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @author: ziin
|
* @author: ziin
|
||||||
* @date: 2025/11/11 20:37
|
* @date: 2025/11/11 20:37
|
||||||
@@ -39,4 +44,19 @@ public class LLMConfig {
|
|||||||
.build())
|
.build())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public OpenAiEmbeddingModel embeddingModel() {
|
||||||
|
return new OpenAiEmbeddingModel(
|
||||||
|
this.openAiApi(),
|
||||||
|
MetadataMode.EMBED,
|
||||||
|
OpenAiEmbeddingOptions.builder()
|
||||||
|
.model("qwen/qwen3-embedding-8b")
|
||||||
|
.user("user-6")
|
||||||
|
.build(),
|
||||||
|
RetryUtils.DEFAULT_RETRY_TEMPLATE);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.yolo.keyborad.config;
|
||||||
|
|
||||||
|
import io.qdrant.client.QdrantClient;
|
||||||
|
import io.qdrant.client.QdrantGrpcClient;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @author: ziin
|
||||||
|
* @date: 2025/11/13 20:28
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class QdrantClientConfig {
|
||||||
|
|
||||||
|
private final String qdrantHost = "b0c7f1ee-0eb9-469e-83e0-654249d9bd04.us-east4-0.gcp.cloud.qdrant.io";
|
||||||
|
|
||||||
|
private final Integer qdrantPort = 6334;
|
||||||
|
|
||||||
|
private final String apiKey = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3MiOiJtIn0.HX_GxjXCrnhw2DQbMnMFzvDeaHbmNpI2tj2hoUjkvVU";
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public QdrantClient qdrantClient() {
|
||||||
|
return new QdrantClient(
|
||||||
|
QdrantGrpcClient.newBuilder(
|
||||||
|
qdrantHost,
|
||||||
|
qdrantPort,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
.withApiKey(apiKey)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,7 +36,9 @@ public class SaTokenConfigure implements WebMvcConfigurer {
|
|||||||
"/demo/test",
|
"/demo/test",
|
||||||
"/error",
|
"/error",
|
||||||
"/demo/talk",
|
"/demo/talk",
|
||||||
"/user/appleLogin"
|
"/user/appleLogin",
|
||||||
|
"/demo/embed",
|
||||||
|
"/demo/testSaveEmbed"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@Bean
|
@Bean
|
||||||
|
|||||||
@@ -1,23 +1,26 @@
|
|||||||
package com.yolo.keyborad.controller;
|
package com.yolo.keyborad.controller;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
|
||||||
import com.yolo.keyborad.common.BaseResponse;
|
import com.yolo.keyborad.common.BaseResponse;
|
||||||
import com.yolo.keyborad.common.ErrorCode;
|
|
||||||
import com.yolo.keyborad.common.ResultUtils;
|
import com.yolo.keyborad.common.ResultUtils;
|
||||||
|
|
||||||
import com.yolo.keyborad.exception.BusinessException;
|
|
||||||
import com.yolo.keyborad.model.dto.IosPayVerifyReq;
|
import com.yolo.keyborad.model.dto.IosPayVerifyReq;
|
||||||
|
import com.yolo.keyborad.service.impl.QdrantVectorService;
|
||||||
|
import io.qdrant.client.QdrantClient;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.ai.chat.client.ChatClient;
|
import org.springframework.ai.chat.client.ChatClient;
|
||||||
|
import org.springframework.ai.embedding.Embedding;
|
||||||
|
import org.springframework.ai.embedding.EmbeddingResponse;
|
||||||
|
import org.springframework.ai.openai.OpenAiEmbeddingModel;
|
||||||
import org.springframework.boot.context.properties.bind.DefaultValue;
|
import org.springframework.boot.context.properties.bind.DefaultValue;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @author: ziin
|
* @author: ziin
|
||||||
* @date: 2025/10/28 20:42
|
* @date: 2025/10/28 20:42
|
||||||
@@ -32,6 +35,14 @@ public class DemoController {
|
|||||||
@Resource
|
@Resource
|
||||||
private ChatClient client;
|
private ChatClient client;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private OpenAiEmbeddingModel embeddingModel;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private QdrantVectorService qdrantVectorService;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@GetMapping("/test")
|
@GetMapping("/test")
|
||||||
@Operation(summary = "测试接口", description = "测试接口")
|
@Operation(summary = "测试接口", description = "测试接口")
|
||||||
public BaseResponse<String> testDemo(){
|
public BaseResponse<String> testDemo(){
|
||||||
@@ -53,9 +64,26 @@ public class DemoController {
|
|||||||
.content();
|
.content();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/embed")
|
||||||
|
@Operation(summary = "测试向量接口", description = "测试向量接口")
|
||||||
|
@Parameter(name = "userInput",required = true,description = "测试向量接口",example = "you are so cute!")
|
||||||
|
public BaseResponse<Embedding> testEmbed(@DefaultValue("you are so cute!") @RequestBody List<String> userInput){
|
||||||
|
EmbeddingResponse response = embeddingModel.embedForResponse(userInput);
|
||||||
|
return ResultUtils.success(response.getResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Operation(summary = "IOS内购凭证校验", description = "IOS内购凭证校验")
|
@Operation(summary = "IOS内购凭证校验", description = "IOS内购凭证校验")
|
||||||
public BaseResponse<String> iosPay(@RequestBody IosPayVerifyReq req) {
|
public BaseResponse<String> iosPay(@RequestBody IosPayVerifyReq req) {
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/testSaveEmbed")
|
||||||
|
@Operation(summary = "测试存储向量接口", description = "测试存储向量接口")
|
||||||
|
@Parameter(name = "userInput",required = true,description = "测试存储向量接口")
|
||||||
|
public BaseResponse<Boolean> testSaveEmbed( @RequestBody List<Float> userInput) throws Exception {
|
||||||
|
qdrantVectorService.upsertPoint(1L, userInput, null);
|
||||||
|
return ResultUtils.success(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,17 @@
|
|||||||
package com.yolo.keyborad.controller;
|
package com.yolo.keyborad.controller;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.yolo.keyborad.common.BaseResponse;
|
import com.yolo.keyborad.common.BaseResponse;
|
||||||
import com.yolo.keyborad.common.ResultUtils;
|
import com.yolo.keyborad.common.ResultUtils;
|
||||||
import com.yolo.keyborad.model.dto.AppleLoginReq;
|
import com.yolo.keyborad.model.dto.AppleLoginReq;
|
||||||
import com.yolo.keyborad.service.impl.IAppleService;
|
import com.yolo.keyborad.service.IAppleService;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.BeanUtils;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户前端控制器
|
* 用户前端控制器
|
||||||
*
|
*
|
||||||
|
|||||||
12
src/main/java/com/yolo/keyborad/model/dto/AppleLoginReq.java
Normal file
12
src/main/java/com/yolo/keyborad/model/dto/AppleLoginReq.java
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package com.yolo.keyborad.model.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @author: ziin
|
||||||
|
* @date: 2025/11/13 16:15
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class AppleLoginReq {
|
||||||
|
private String identityToken;
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.yolo.keyborad.model.dto;
|
||||||
|
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class IosPayVerifyReq {
|
||||||
|
|
||||||
|
@Schema(description = "商家订单id")
|
||||||
|
private String orderId;
|
||||||
|
|
||||||
|
@Schema(description = "用户id")
|
||||||
|
private String userId;
|
||||||
|
|
||||||
|
@Schema(description = "验证凭据")
|
||||||
|
private String receiptDate;
|
||||||
|
|
||||||
|
@Schema(description = "ios选项值")
|
||||||
|
private String productId;
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.yolo.keyborad.service.impl;
|
package com.yolo.keyborad.service;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apple相关API
|
* Apple相关API
|
||||||
@@ -3,6 +3,7 @@ package com.yolo.keyborad.service.impl;
|
|||||||
import cn.hutool.http.HttpUtil;
|
import cn.hutool.http.HttpUtil;
|
||||||
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONArray;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.yolo.keyborad.service.IAppleService;
|
||||||
import io.jsonwebtoken.*;
|
import io.jsonwebtoken.*;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package com.yolo.keyborad.service.impl;
|
||||||
|
|
||||||
|
import com.yolo.keyborad.utils.ProtoUtils;
|
||||||
|
import io.qdrant.client.QdrantClient;
|
||||||
|
import io.qdrant.client.grpc.Collections;
|
||||||
|
import io.qdrant.client.grpc.JsonWithInt;
|
||||||
|
import io.qdrant.client.grpc.Points;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static io.qdrant.client.PointIdFactory.id;
|
||||||
|
import static io.qdrant.client.ValueFactory.value;
|
||||||
|
import static io.qdrant.client.VectorsFactory.vectors;
|
||||||
|
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class QdrantVectorService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private QdrantClient qdrantClient;
|
||||||
|
|
||||||
|
private static final String COLLECTION_NAME = "test_document";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插入/更新一条向量数据
|
||||||
|
*
|
||||||
|
* @param id 向量ID(可以是 Long / String,自行约定)
|
||||||
|
* @param vector 向量(和 collection 中定义的 size 一致)
|
||||||
|
* @param payload 额外信息,例如原文、标题、userId 等
|
||||||
|
*/
|
||||||
|
public void upsertPoint(long id, List<Float> vector, Map<String, JsonWithInt.Value> payload) throws Exception {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 1. 确保 collection 存在(没有就创建一次即可)
|
||||||
|
qdrantClient.createCollectionAsync(
|
||||||
|
COLLECTION_NAME,
|
||||||
|
Collections.VectorParams.newBuilder()
|
||||||
|
.setSize(vector.size()) // 向量维度
|
||||||
|
.setDistance(Collections.Distance.Cosine) // 相似度度量
|
||||||
|
.build()
|
||||||
|
).get(); // 简单起见直接 get(),生产建议在启动时提前创建好
|
||||||
|
|
||||||
|
|
||||||
|
qdrantClient.upsertAsync(
|
||||||
|
COLLECTION_NAME,
|
||||||
|
List.of(
|
||||||
|
Points.PointStruct.newBuilder()
|
||||||
|
.setId(id(id))
|
||||||
|
.setVectors(vectors(vector))
|
||||||
|
.putAllPayload(Map.of("payload",value("testInfo")))
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
).get();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
85
src/main/java/com/yolo/keyborad/utils/ApplePayUtil.java
Normal file
85
src/main/java/com/yolo/keyborad/utils/ApplePayUtil.java
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
package com.yolo.keyborad.utils;
|
||||||
|
|
||||||
|
import javax.net.ssl.*;
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
|
||||||
|
public class ApplePayUtil {
|
||||||
|
|
||||||
|
private static class TrustAnyTrustManager implements X509TrustManager {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public X509Certificate[] getAcceptedIssuers() {
|
||||||
|
return new X509Certificate[]{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TrustAnyHostnameVerifier implements HostnameVerifier {
|
||||||
|
@Override
|
||||||
|
public boolean verify(String hostname, SSLSession session) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String url_sandbox = "https://sandbox.itunes.apple.com/verifyReceipt";
|
||||||
|
private static final String url_verify = "https://buy.itunes.apple.com/verifyReceipt";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 苹果服务器验证
|
||||||
|
*
|
||||||
|
* @param receipt 账单
|
||||||
|
* @return null 或返回结果 沙盒 https://sandbox.itunes.apple.com/verifyReceipt
|
||||||
|
* @url 要验证的地址
|
||||||
|
*/
|
||||||
|
public static String buyAppVerify(String receipt, int type) throws Exception {
|
||||||
|
//环境判断 线上/开发环境用不同的请求链接
|
||||||
|
String url = "";
|
||||||
|
if (type == 0) {
|
||||||
|
url = url_sandbox; //沙盒测试
|
||||||
|
} else {
|
||||||
|
url = url_verify; //线上测试
|
||||||
|
}
|
||||||
|
SSLContext sc = SSLContext.getInstance("SSL");
|
||||||
|
sc.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new java.security.SecureRandom());
|
||||||
|
URL console = new URL(url);
|
||||||
|
HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
|
||||||
|
conn.setSSLSocketFactory(sc.getSocketFactory());
|
||||||
|
conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
|
||||||
|
conn.setRequestMethod("POST");
|
||||||
|
conn.setRequestProperty("content-type", "text/json");
|
||||||
|
conn.setRequestProperty("Proxy-Connection", "Keep-Alive");
|
||||||
|
conn.setDoInput(true);
|
||||||
|
conn.setDoOutput(true);
|
||||||
|
BufferedOutputStream hurlBufOus = new BufferedOutputStream(conn.getOutputStream());
|
||||||
|
//拼成固定的格式传给平台
|
||||||
|
String str = String.format(Locale.CHINA, "{\"receipt-data\":\"" + receipt + "\"}");
|
||||||
|
hurlBufOus.write(str.getBytes());
|
||||||
|
hurlBufOus.flush();
|
||||||
|
|
||||||
|
InputStream is = conn.getInputStream();
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
|
||||||
|
String line = null;
|
||||||
|
StringBuffer sb = new StringBuffer();
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
sb.append(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
32
src/main/java/com/yolo/keyborad/utils/ProtoUtils.java
Normal file
32
src/main/java/com/yolo/keyborad/utils/ProtoUtils.java
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package com.yolo.keyborad.utils;
|
||||||
|
|
||||||
|
import com.google.protobuf.Struct;
|
||||||
|
import com.google.protobuf.Value;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class ProtoUtils {
|
||||||
|
|
||||||
|
public static Struct mapToStruct(Map<String, Object> map) {
|
||||||
|
Struct.Builder structBuilder = Struct.newBuilder();
|
||||||
|
map.forEach((key, value) -> structBuilder.putFields(key, toValue(value)));
|
||||||
|
return structBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Value toValue(Object obj) {
|
||||||
|
Value.Builder valueBuilder = Value.newBuilder();
|
||||||
|
|
||||||
|
if (obj instanceof String) {
|
||||||
|
valueBuilder.setStringValue((String) obj);
|
||||||
|
} else if (obj instanceof Number) {
|
||||||
|
valueBuilder.setNumberValue(((Number) obj).doubleValue());
|
||||||
|
} else if (obj instanceof Boolean) {
|
||||||
|
valueBuilder.setBoolValue((Boolean) obj);
|
||||||
|
} else {
|
||||||
|
// 复杂类型你自己扩展,也可以转 string 存
|
||||||
|
valueBuilder.setStringValue(obj.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return valueBuilder.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ spring:
|
|||||||
username: root
|
username: root
|
||||||
password: 123asd
|
password: 123asd
|
||||||
|
|
||||||
|
|
||||||
knife4j:
|
knife4j:
|
||||||
enable: true
|
enable: true
|
||||||
openapi:
|
openapi:
|
||||||
|
|||||||
Reference in New Issue
Block a user