refactor: 全框架 JSON 操作迁移到 simapi_serialization
- 依赖:新增 simapi_serialization path 依赖(保留 soulsoft_serialization 供 soulsoft web 栈传递使用) - SimApiJson.json / SimApiUtil.json → JsonSerializer.Serialize - SimApiUtil.fromJson / base64DecodeTo → JsonSerializer.Deserialize(去 ISerialization 约束) - SimApiHttpClient signQuery/aesQuery/aesSignQuery/query → 去约束,反序列化换新库 - SimApiBaseResponse/SimApiDataResponse/SimApiLoginItem/AesBodyRequest/AuthSDK DTO → 去 @Serialization 宏/去 soulsoft 接口,改纯 POCO(simapi_serialization 反射) - SimApiBaseResponse 标 @SerializerParent:子类响应序列化包含 _code/_message - SimApiResultWriter / SimApiExceptionMiddleware → 响应输出走 simapi_serialization(统一 _code/_message 格式) - SimApiRequestLogMiddleware 截断 → Deserialize<HashMap<String,Any>> + 重序列化 - SimApiAuthDto JsonValue 字段 → HashMap<String,Any>;SimApiCache.get<T> 去约束 - webdemo:AuthController readFromJson 换 Deserialize;cjpm.toml 补依赖 - 验证:webdemo 启动正常,GET/POST 接口响应格式统一,S3 存储全链路 OK
This commit is contained in:
@@ -7,8 +7,7 @@ package simapi.helpers
|
||||
|
||||
import std.collection.*
|
||||
import std.io.*
|
||||
import soulsoft_serialization.*
|
||||
import soulsoft_serialization.macros.*
|
||||
import simapi_serialization.*
|
||||
import soulsoft_web_http.*
|
||||
import simapi.communications.*
|
||||
import simapi.exceptions.*
|
||||
@@ -16,7 +15,6 @@ import simapi.exceptions.*
|
||||
/**
|
||||
* AES body 请求({"data": "密文"},对齐 C# SimApiOneFieldRequest<string>)。
|
||||
*/
|
||||
@Serialization
|
||||
public class AesBodyRequest {
|
||||
public var _data: String = ""
|
||||
|
||||
@@ -48,7 +46,7 @@ public open class AesBodyProviderBase {
|
||||
*
|
||||
* 仓颉无 ModelBinder 机制,按项目惯例由控制器在方法开头调用:
|
||||
* let jsonStr = SimApiAesBodyChecker.decryptBody(context, provider)
|
||||
* let request = JsonSerializer.deserializeObject<XxxRequest>(jsonStr)
|
||||
* let request = JsonSerializer.Deserialize<XxxRequest>(jsonStr)
|
||||
*
|
||||
* 流程(与 C# 一致):
|
||||
* 1. 读取 body 并反序列化为 {"data": "密文"}
|
||||
@@ -75,7 +73,7 @@ public class SimApiAesBodyChecker {
|
||||
}
|
||||
|
||||
// 2. 反序列化 {"data": "密文"}
|
||||
let req = JsonSerializer.deserializeObject<AesBodyRequest>(body)
|
||||
let req = JsonSerializer.Deserialize<AesBodyRequest>(body)
|
||||
if (req._data.isEmpty()) {
|
||||
SimApiError.error(code: 400, message: "请求体缺少密文Data字段")
|
||||
}
|
||||
|
||||
@@ -9,8 +9,7 @@ import std.collection.*
|
||||
import std.collection.concurrent.*
|
||||
import std.convert.*
|
||||
import std.time.*
|
||||
import stdx.encoding.json.*
|
||||
import soulsoft_serialization.*
|
||||
import simapi_serialization.*
|
||||
import redis.client.*
|
||||
import simapi.communications.*
|
||||
import simapi.configurations.*
|
||||
@@ -287,11 +286,11 @@ public class SimApiAuth {
|
||||
|
||||
private static func loginItemJson(item: SimApiLoginItem): String {
|
||||
// 统一 JSON 序列化:对齐 .NET JsonSerializer.Serialize(item)
|
||||
JsonSerializer.serializeObject<SimApiLoginItem>(item)
|
||||
JsonSerializer.Serialize(item)
|
||||
}
|
||||
|
||||
private static func parseLoginItem(json: String): SimApiLoginItem {
|
||||
// 统一 JSON 反序列化:对齐 .NET JsonSerializer.Deserialize<SimApiLoginItem>(json)
|
||||
JsonSerializer.deserializeObject<SimApiLoginItem>(json)
|
||||
JsonSerializer.Deserialize<SimApiLoginItem>(json)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import std.collection.concurrent.*
|
||||
import std.convert.*
|
||||
import std.time.*
|
||||
import redis.client.*
|
||||
import soulsoft_serialization.*
|
||||
import simapi_serialization.*
|
||||
import simapi.configurations.*
|
||||
import simapi.exceptions.*
|
||||
|
||||
@@ -100,11 +100,11 @@ public class SimApiCache {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取特定类型缓存(对齐 C# Get<T>:从 JSON 反序列化)。
|
||||
* 获取特定类型缓存(对齐 C# Get<T>:从 JSON 反序列化,使用 simapi_serialization)。
|
||||
*/
|
||||
public func get<T>(key: String): ?T where T <: ISerialization<T> {
|
||||
public func get<T>(key: String): ?T {
|
||||
match (getString(key)) {
|
||||
case Some(json) => Some(JsonSerializer.deserializeObject<T>(json))
|
||||
case Some(json) => Some(JsonSerializer.Deserialize<T>(json))
|
||||
case None => None
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import stdx.net.tls.*
|
||||
import stdx.net.tls.common.*
|
||||
import soulsoft_net_http.{HttpClient, HttpRequestMessage, JsonContent}
|
||||
import soulsoft_net_http.{HttpMethod as NetHttpMethod}
|
||||
import soulsoft_serialization.*
|
||||
import simapi_serialization.*
|
||||
import simapi.communications.*
|
||||
import simapi.configurations.*
|
||||
import simapi.exceptions.*
|
||||
@@ -21,7 +21,7 @@ import simapi.exceptions.*
|
||||
* 对齐 C# 的 SimApi.Helpers.SimApiHttpClient:
|
||||
* - 内部使用 soulsoft_net_http 的 HttpClient(等价 .NET 的 System.Net.Http.HttpClient)
|
||||
* - 返回泛型 T(反序列化响应 body 的 data 字段),不再返回 String
|
||||
* @param T 响应 data 的数据类型(需实现 ISerialization<T>,如 SimApiLoginItem、String、Int64 等)。
|
||||
* @param T 响应 data 的数据类型(任意类,simapi_serialization 反射反序列化)。
|
||||
*/
|
||||
public open class SimApiHttpClient {
|
||||
public var server: String
|
||||
@@ -48,7 +48,7 @@ public open class SimApiHttpClient {
|
||||
* @param queries 额外查询参数(可选)。
|
||||
* @return 响应 data 字段反序列化后的 T。
|
||||
*/
|
||||
public func signQuery<T>(url: String, body!: String = "", queries!: HashMap<String, String> = HashMap<String, String>()): T where T <: ISerialization<T> {
|
||||
public func signQuery<T>(url: String, body!: String = "", queries!: HashMap<String, String> = HashMap<String, String>()): T {
|
||||
var queryUrl = StringBuilder()
|
||||
for (field in signFields) {
|
||||
queryUrl.append("${field}=")
|
||||
@@ -80,7 +80,7 @@ public open class SimApiHttpClient {
|
||||
* @param body 请求体 JSON 字符串。
|
||||
* @return 响应 data 字段反序列化后的 T。
|
||||
*/
|
||||
public func aesQuery<T>(url: String, body: String): T where T <: ISerialization<T> {
|
||||
public func aesQuery<T>(url: String, body: String): T {
|
||||
var target = "${server}${url}"
|
||||
if (let Some(name) <- appIdName) {
|
||||
target = "${target}?${name}=${appId}"
|
||||
@@ -98,19 +98,20 @@ public open class SimApiHttpClient {
|
||||
* @param queries 额外查询参数(可选)。
|
||||
* @return 响应 data 字段反序列化后的 T。
|
||||
*/
|
||||
public func aesSignQuery<T>(url: String, body: String, queries!: HashMap<String, String> = HashMap<String, String>()): T where T <: ISerialization<T> {
|
||||
public func aesSignQuery<T>(url: String, body: String, queries!: HashMap<String, String> = HashMap<String, String>()): T {
|
||||
let encrypted = aesEncrypt(body)
|
||||
let req = "{\"data\":\"${encrypted}\"}"
|
||||
return signQuery<T>(url, body: req, queries: queries)
|
||||
}
|
||||
|
||||
/**
|
||||
* 发起 POST 请求并反序列化 SimApiBaseResponse<T>,返回 data 字段。
|
||||
* 发起 POST 请求并反序列化 SimApiResponse<T>,返回 data 字段。
|
||||
* 对齐 C# Query<T>:
|
||||
* ErrorWhenFalse(IsSuccessStatusCode) → ReadFromJsonAsync<SimApiBaseResponse<T>> → ErrorWhen(Code != 200) → return Data。
|
||||
* ErrorWhenFalse(IsSuccessStatusCode) → ReadFromJsonAsync<SimApiResponse<T>> → ErrorWhen(Code != 200) → return Data。
|
||||
* 注意:必须 noProxy(),否则会走系统代理(192.168.0.250:8118)导致连接被拒。
|
||||
* 反序列化使用 simapi_serialization(Deserialize<T> 免约束)。
|
||||
*/
|
||||
private func query<T>(url: String, body: String): T where T <: ISerialization<T> {
|
||||
private func query<T>(url: String, body: String): T {
|
||||
let client = HttpClient.create { builder =>
|
||||
builder.noProxy()
|
||||
// 支持 https:配置 TLS(信任所有证书 + SNI 域名)
|
||||
@@ -128,7 +129,8 @@ public open class SimApiHttpClient {
|
||||
let response = client.send(request)
|
||||
try {
|
||||
SimApiError.errorWhenFalse(response.isSuccessStatusCode, code: response.statusCode, message: "HTTP ERROR: ${response.statusCode}")
|
||||
let result = response.content.readFromJson<SimApiResponse<T>>()
|
||||
let json = response.content.readAsString()
|
||||
let result = JsonSerializer.Deserialize<SimApiResponse<T>>(json)
|
||||
SimApiError.errorWhen(result._code != 200, code: result._code, message: result._message)
|
||||
return result._data.getOrThrow()
|
||||
} finally {
|
||||
|
||||
@@ -7,6 +7,7 @@ package simapi.helpers
|
||||
|
||||
import soulsoft_web_http.*
|
||||
import soulsoft_web_mvc.core.*
|
||||
import simapi_serialization.*
|
||||
import simapi.communications.*
|
||||
|
||||
/**
|
||||
@@ -16,6 +17,8 @@ import simapi.communications.*
|
||||
* - String → SimApiResponse<String>(data 为字符串)
|
||||
* - Unit(void)→ SimApiBaseResponse()({code:200, message:成功})
|
||||
* - 其他对象(DTO/数组/动态结构)→ SimApiDataResponse(data 内嵌为对象)
|
||||
*
|
||||
* 输出使用 simapi_serialization 序列化后直接写响应体(不走 soulsoft formatter)。
|
||||
*/
|
||||
public class SimApiResultWriter {
|
||||
private init() {}
|
||||
@@ -26,17 +29,22 @@ public class SimApiResultWriter {
|
||||
result.invoke(context)
|
||||
} else if (let result: SimApiBaseResponse <- actionResult) {
|
||||
// 已是 SimApiBaseResponse(含子类)→ 原样输出
|
||||
ObjectResult<Any>(result).invoke(context)
|
||||
writeJson(context, result)
|
||||
} else if (let result: String <- actionResult) {
|
||||
// String → SimApiResponse<String>(data 为字符串)
|
||||
ObjectResult<Any>(SimApiResponse<String>(result)).invoke(context)
|
||||
writeJson(context, SimApiResponse<String>(result))
|
||||
} else if (let result: Unit <- actionResult) {
|
||||
// void/无返回 → SimApiBaseResponse()({code:200, message:成功})
|
||||
context.response.writeAsJson(SimApiBaseResponse())
|
||||
writeJson(context, SimApiBaseResponse())
|
||||
} else {
|
||||
// 其他对象(DTO/数组/动态结构)→ SimApiDataResponse
|
||||
// data 由 SimApiDataResponse.serializeObject 内嵌为对象
|
||||
ObjectResult<Any>(SimApiDataResponse(actionResult)).invoke(context)
|
||||
writeJson(context, SimApiDataResponse(actionResult))
|
||||
}
|
||||
}
|
||||
|
||||
/// simapi_serialization 序列化后直接写响应体
|
||||
private static func writeJson(context: HttpContext, obj: Any): Unit {
|
||||
context.response.contentType = "application/json; charset=utf-8"
|
||||
context.response.write(JsonSerializer.Serialize(obj))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,9 +11,8 @@ import std.random.*
|
||||
import stdx.crypto.digest.*
|
||||
import stdx.encoding.hex.*
|
||||
import stdx.encoding.base64.*
|
||||
import stdx.encoding.json.*
|
||||
import std.regex.*
|
||||
import soulsoft_serialization.*
|
||||
import simapi_serialization.*
|
||||
import simapi.communications.*
|
||||
import simapi.macros.*
|
||||
|
||||
@@ -181,12 +180,12 @@ public class SimApiUtil {
|
||||
|
||||
/**
|
||||
* 从 JSON 字符串反序列化为 T(对齐 C# SimApiUtil.FromJson<T>)。
|
||||
* @param T 目标类型(需实现 ISerialization<T>,如 @Serialization DTO、基础类型等)。
|
||||
* @param T 目标类型(任意类,无需接口/宏约束)。
|
||||
* @param jsonString JSON 字符串。
|
||||
* @return 反序列化结果。
|
||||
*/
|
||||
public static func fromJson<T>(jsonString: String): T where T <: ISerialization<T> {
|
||||
JsonSerializer.deserializeObject<T>(jsonString)
|
||||
public static func fromJson<T>(jsonString: String): T {
|
||||
JsonSerializer.Deserialize<T>(jsonString)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -195,21 +194,17 @@ public class SimApiUtil {
|
||||
* @return Base64 字符串。
|
||||
*/
|
||||
public static func base64Encode(obj: Any): String {
|
||||
let json = if (let ser: ISerializable <- obj) {
|
||||
ser.serializeObject().toJson().toString()
|
||||
} else {
|
||||
SimApiJson.json(Some(obj))
|
||||
}
|
||||
let json = SimApiJson.json(Some(obj))
|
||||
base64Encode(json)
|
||||
}
|
||||
|
||||
/**
|
||||
* Base64 → JSON → T 反序列化(对齐 C# Base64Decode<T>)。
|
||||
* @param T 目标类型(需实现 ISerialization<T>)。
|
||||
* @param T 目标类型(任意类,无需接口/宏约束)。
|
||||
* @param base64Str Base64 字符串。
|
||||
* @return 反序列化结果。
|
||||
*/
|
||||
public static func base64DecodeTo<T>(base64Str: String): T where T <: ISerialization<T> {
|
||||
public static func base64DecodeTo<T>(base64Str: String): T {
|
||||
fromJson<T>(base64Decode(base64Str))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user