Merge remote-tracking branch 'base-version/main' into dev

This commit is contained in:
chenbowen
2025-11-24 15:53:49 +08:00
2 changed files with 128 additions and 61 deletions

View File

@@ -17,10 +17,9 @@ import lombok.RequiredArgsConstructor;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import okio.Buffer;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import javax.crypto.Cipher;
@@ -128,9 +127,8 @@ public class IWorkIntegrationServiceImpl implements IWorkIntegrationService {
String operatorUserId = resolveOperatorUserId(reqVO.getOperatorUserId());
IWorkSession session = ensureSession(appId, clientKeyPair, operatorUserId, Boolean.TRUE.equals(reqVO.getForceRefreshToken()));
MultiValueMap<String, String> formData = buildCreateForm(reqVO);
appendFormExtras(formData, reqVO.getFormExtras());
String responseBody = executeFormRequest(properties.getPaths().getCreateWorkflow(), appId, session, formData);
Map<String, Object> payload = buildCreatePayload(reqVO);
String responseBody = executeJsonRequest(properties.getPaths().getCreateWorkflow(), null, appId, session, payload);
return buildOperationResponse(responseBody);
}
@@ -145,9 +143,8 @@ public class IWorkIntegrationServiceImpl implements IWorkIntegrationService {
}
IWorkSession session = ensureSession(appId, clientKeyPair, operatorUserId, Boolean.TRUE.equals(reqVO.getForceRefreshToken()));
MultiValueMap<String, String> formData = buildVoidForm(reqVO);
appendFormExtras(formData, reqVO.getFormExtras());
String responseBody = executeFormRequest(properties.getPaths().getVoidWorkflow(), appId, session, formData);
Map<String, Object> payload = buildVoidPayload(reqVO);
String responseBody = executeJsonRequest(properties.getPaths().getVoidWorkflow(), null, appId, session, payload);
return buildOperationResponse(responseBody);
}
@@ -327,24 +324,6 @@ public class IWorkIntegrationServiceImpl implements IWorkIntegrationService {
return executeRequest(request, IWORK_REMOTE_REQUEST_FAILED);
}
private String executeFormRequest(String path,
String appId,
IWorkSession session,
MultiValueMap<String, String> formData) {
FormBody.Builder builder = new FormBody.Builder();
formData.forEach((key, values) -> {
if (values != null) {
values.forEach(value -> builder.add(key, value));
}
});
Request request = new Request.Builder()
.url(resolveUrl(path))
.headers(authHeaders(appId, session).build())
.post(builder.build())
.build();
return executeRequest(request, IWORK_REMOTE_REQUEST_FAILED);
}
private Headers.Builder authHeaders(String appId, IWorkSession session) {
return new Headers.Builder()
.set(properties.getHeaders().getAppId(), appId)
@@ -361,18 +340,19 @@ public class IWorkIntegrationServiceImpl implements IWorkIntegrationService {
return payload;
}
private MultiValueMap<String, String> buildCreateForm(IWorkWorkflowCreateReqVO reqVO) {
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.add("requestName", reqVO.getRequestName());
formData.add("workflowId", String.valueOf(resolveWorkflowId(reqVO.getWorkflowId())));
formData.add("mainData", toJsonString(convertFormFields(reqVO.getMainFields())));
private Map<String, Object> buildCreatePayload(IWorkWorkflowCreateReqVO reqVO) {
Map<String, Object> payload = new LinkedHashMap<>();
payload.put("requestName", reqVO.getRequestName());
payload.put("workflowId", resolveWorkflowId(reqVO.getWorkflowId()));
payload.put("mainData", convertFormFields(reqVO.getMainFields()));
if (reqVO.getDetailTables() != null && !reqVO.getDetailTables().isEmpty()) {
formData.add("detailData", toJsonString(convertDetailTables(reqVO.getDetailTables())));
payload.put("detailData", convertDetailTables(reqVO.getDetailTables()));
}
if (reqVO.getOtherParams() != null && !reqVO.getOtherParams().isEmpty()) {
formData.add("otherParams", toJsonString(reqVO.getOtherParams()));
payload.put("otherParams", reqVO.getOtherParams());
}
return formData;
appendPayloadExtras(payload, reqVO.getFormExtras());
return payload;
}
private long resolveWorkflowId(Long requestWorkflowId) {
@@ -385,29 +365,26 @@ public class IWorkIntegrationServiceImpl implements IWorkIntegrationService {
throw ServiceExceptionUtil.exception(IWORK_WORKFLOW_ID_MISSING);
}
private MultiValueMap<String, String> buildVoidForm(IWorkWorkflowVoidReqVO reqVO) {
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.add("requestId", reqVO.getRequestId());
private Map<String, Object> buildVoidPayload(IWorkWorkflowVoidReqVO reqVO) {
Map<String, Object> payload = new LinkedHashMap<>();
payload.put("requestId", reqVO.getRequestId());
if (StringUtils.hasText(reqVO.getReason())) {
formData.add("remark", reqVO.getReason());
payload.put("remark", reqVO.getReason());
}
if (reqVO.getExtraParams() != null && !reqVO.getExtraParams().isEmpty()) {
reqVO.getExtraParams().forEach((key, value) -> {
if (value != null) {
formData.add(key, String.valueOf(value));
payload.putAll(reqVO.getExtraParams());
}
});
}
return formData;
appendPayloadExtras(payload, reqVO.getFormExtras());
return payload;
}
private void appendFormExtras(MultiValueMap<String, String> formData, Map<String, String> extras) {
private void appendPayloadExtras(Map<String, Object> payload, Map<String, String> extras) {
if (extras == null || extras.isEmpty()) {
return;
}
extras.forEach((key, value) -> {
if (StringUtils.hasText(key) && value != null) {
formData.add(key, value);
payload.put(key, value);
}
});
}
@@ -632,6 +609,7 @@ public class IWorkIntegrationServiceImpl implements IWorkIntegrationService {
}
private String executeRequest(Request request, ErrorCode errorCode) {
logCurlCommand(request);
try (Response response = okHttpClient().newCall(request).execute()) {
String responseBody = response.body() != null ? response.body().string() : null;
if (!response.isSuccessful()) {
@@ -645,6 +623,49 @@ public class IWorkIntegrationServiceImpl implements IWorkIntegrationService {
}
}
private void logCurlCommand(Request request) {
if (request == null || !log.isInfoEnabled()) {
return;
}
try {
StringBuilder curl = new StringBuilder("curl");
curl.append(" -X ").append(request.method());
curl.append(" '").append(request.url()).append("'");
Headers headers = request.headers();
for (int i = 0; i < headers.size(); i++) {
curl.append(" -H '")
.append(escapeSingleQuotes(headers.name(i)))
.append(": ")
.append(escapeSingleQuotes(headers.value(i)))
.append("'");
}
RequestBody body = request.body();
if (body != null) {
Buffer buffer = new Buffer();
body.writeTo(buffer);
String bodyString = buffer.readUtf8();
if (StringUtils.hasText(bodyString)) {
curl.append(" --data '")
.append(escapeSingleQuotes(bodyString))
.append("'");
}
}
log.info("[iWork] -> {}", curl);
} catch (Exception ex) {
log.warn("[iWork] failed to build curl log for {}: {}", request.url(), ex.getMessage());
}
}
private String escapeSingleQuotes(String value) {
if (value == null) {
return "";
}
return value.replace("'", "'\"'\"'");
}
private record RegistrationState(String secret, String spk, ClientKeyPair clientKeyPair) {
}

View File

@@ -15,11 +15,11 @@ import com.zt.plat.module.system.controller.admin.integration.iwork.vo.IWorkUser
import com.zt.plat.module.system.framework.integration.iwork.config.IWorkProperties;
import com.zt.plat.module.system.service.integration.iwork.IWorkOrgRestService;
import lombok.extern.slf4j.Slf4j;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.Buffer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
@@ -46,6 +46,7 @@ public class IWorkOrgRestServiceImpl implements IWorkOrgRestService {
private static final TypeReference<Map<String, Object>> MAP_TYPE = new TypeReference<>() {
};
private static final okhttp3.MediaType JSON_MEDIA_TYPE = okhttp3.MediaType.get("application/json; charset=UTF-8");
private final IWorkProperties properties;
private final ObjectMapper objectMapper;
@@ -179,30 +180,34 @@ public class IWorkOrgRestServiceImpl implements IWorkOrgRestService {
}
private IWorkOrgRespVO invokeParamsEndpoint(String path, Map<String, Object> params) {
String payload = toJson(params);
return executeForm(path, "params", payload);
Map<String, Object> payload = new HashMap<>();
payload.put("params", params == null ? Collections.emptyMap() : params);
return executeJson(path, payload);
}
private IWorkOrgRespVO invokeDataEndpoint(String path, Object data) {
String payload = toJson(data);
return executeForm(path, "data", payload);
Map<String, Object> payload = new HashMap<>();
payload.put("data", data == null ? Collections.emptyMap() : data);
return executeJson(path, payload);
}
private IWorkOrgRespVO executeForm(String path, String fieldName, String jsonPayload) {
private IWorkOrgRespVO executeJson(String path, Map<String, Object> payload) {
assertOrgConfigured(path);
FormBody.Builder formBuilder = new FormBody.Builder(StandardCharsets.UTF_8);
if (StringUtils.hasText(fieldName) && StringUtils.hasText(jsonPayload)) {
formBuilder.add(fieldName, jsonPayload);
Map<String, Object> body = new HashMap<>();
if (payload != null && !payload.isEmpty()) {
body.putAll(payload);
}
formBuilder.add("token", buildTokenJson());
body.put("token", buildTokenPayload());
String jsonBody = toJson(body);
RequestBody requestBody = formBuilder.build();
RequestBody requestBody = RequestBody.create(JSON_MEDIA_TYPE, jsonBody);
Request request = new Request.Builder()
.url(resolveUrl(path))
.header("Content-Type", MediaType.APPLICATION_FORM_URLENCODED_VALUE)
.header("Content-Type", MediaType.APPLICATION_JSON_VALUE)
.post(requestBody)
.build();
logCurlCommand(request);
try (Response response = okHttpClient().newCall(request).execute()) {
String responseBody = response.body() != null ? response.body().string() : null;
if (!response.isSuccessful()) {
@@ -216,7 +221,7 @@ public class IWorkOrgRestServiceImpl implements IWorkOrgRestService {
}
}
private String buildTokenJson() {
private Map<String, String> buildTokenPayload() {
String tokenSeed = StringUtils.trimWhitespace(orgConfig().getTokenSeed());
if (!StringUtils.hasText(tokenSeed)) {
throw ServiceExceptionUtil.exception(IWORK_ORG_IDENTIFIER_MISSING);
@@ -225,11 +230,10 @@ public class IWorkOrgRestServiceImpl implements IWorkOrgRestService {
String raw = tokenSeed + ts;
// 通过 MD5(tokenSeed + ts) 计算 key并转为大写以符合 PDF 约定
String hashed = md5Upper(raw);
Map<String, String> token = Map.of(
return Map.of(
"key", hashed,
"ts", String.valueOf(ts)
);
return toJson(token);
}
private String md5Upper(String raw) {
@@ -368,4 +372,46 @@ public class IWorkOrgRestServiceImpl implements IWorkOrgRestService {
}
return baseUrl + path;
}
private void logCurlCommand(Request request) {
if (request == null || !log.isInfoEnabled()) {
return;
}
try {
StringBuilder curl = new StringBuilder("curl");
curl.append(" -X ").append(request.method());
curl.append(" '").append(request.url()).append("'");
for (int i = 0; i < request.headers().size(); i++) {
curl.append(" -H '")
.append(escapeSingleQuotes(request.headers().name(i)))
.append(": ")
.append(escapeSingleQuotes(request.headers().value(i)))
.append("'");
}
RequestBody body = request.body();
if (body != null) {
Buffer buffer = new Buffer();
body.writeTo(buffer);
String bodyString = buffer.readUtf8();
if (StringUtils.hasText(bodyString)) {
curl.append(" --data '")
.append(escapeSingleQuotes(bodyString))
.append("'");
}
}
log.info("[iWork-Org] -> {}", curl);
} catch (Exception ex) {
log.warn("[iWork-Org] 构建 curl 日志失败 {}: {}", request.url(), ex.getMessage());
}
}
private String escapeSingleQuotes(String value) {
if (value == null) {
return "";
}
return value.replace("'", "'\"'\"'");
}
}