1. 启动默认调度,定时请求 databus api
2. 修复 databus 单元测试 3. 调整 iwork 回调业务编号
This commit is contained in:
@@ -2,6 +2,7 @@ package com.zt.plat.module.template;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
/**
|
||||
* 项目的启动类
|
||||
@@ -9,6 +10,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
* @author 周迪
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@EnableScheduling
|
||||
public class TemplateServerApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
package com.zt.plat.module.template.dal.dataobject.databus;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.zt.plat.framework.mybatis.core.dataobject.BaseDO;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* Databus 请求与响应日志表。
|
||||
*/
|
||||
@TableName("template_databus_request_log")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class TemplateDatabusRequestLogDO extends BaseDO {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 请求唯一标识。
|
||||
*/
|
||||
@TableField("REQUEST_ID")
|
||||
private String requestId;
|
||||
|
||||
/**
|
||||
* 实际请求 URL。
|
||||
*/
|
||||
@TableField("TARGET_URL")
|
||||
private String targetUrl;
|
||||
|
||||
/**
|
||||
* HTTP 方法。
|
||||
*/
|
||||
@TableField("HTTP_METHOD")
|
||||
private String httpMethod;
|
||||
|
||||
/**
|
||||
* Query 参数 JSON。
|
||||
*/
|
||||
@TableField("QUERY_PARAMS")
|
||||
private String queryParams;
|
||||
|
||||
/**
|
||||
* 请求头 JSON。
|
||||
*/
|
||||
@TableField("REQUEST_HEADERS")
|
||||
private String requestHeaders;
|
||||
|
||||
/**
|
||||
* 原始请求体。
|
||||
*/
|
||||
@TableField("REQUEST_BODY")
|
||||
private String requestBody;
|
||||
|
||||
/**
|
||||
* 加密后的请求体。
|
||||
*/
|
||||
@TableField("ENCRYPTED_REQUEST_BODY")
|
||||
private String encryptedRequestBody;
|
||||
|
||||
/**
|
||||
* 签名。
|
||||
*/
|
||||
@TableField("SIGNATURE")
|
||||
private String signature;
|
||||
|
||||
/**
|
||||
* 随机串。
|
||||
*/
|
||||
@TableField("NONCE")
|
||||
private String nonce;
|
||||
|
||||
/**
|
||||
* 时间戳。
|
||||
*/
|
||||
@TableField("ZT_TIMESTAMP")
|
||||
private String ztTimestamp;
|
||||
|
||||
/**
|
||||
* HTTP 返回状态码。
|
||||
*/
|
||||
@TableField("RESPONSE_STATUS")
|
||||
private Integer responseStatus;
|
||||
|
||||
/**
|
||||
* 加密响应体。
|
||||
*/
|
||||
@TableField("ENCRYPTED_RESPONSE_BODY")
|
||||
private String encryptedResponseBody;
|
||||
|
||||
/**
|
||||
* 解密后的响应体。
|
||||
*/
|
||||
@TableField("RESPONSE_BODY")
|
||||
private String responseBody;
|
||||
|
||||
/**
|
||||
* 是否调用成功。
|
||||
*/
|
||||
@TableField("SUCCESS")
|
||||
private Boolean success;
|
||||
|
||||
/**
|
||||
* 错误信息。
|
||||
*/
|
||||
@TableField("ERROR_MESSAGE")
|
||||
private String errorMessage;
|
||||
|
||||
/**
|
||||
* 调用耗时(毫秒)。
|
||||
*/
|
||||
@TableField("DURATION_MS")
|
||||
private Long durationMs;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.zt.plat.module.template.dal.mysql.databus;
|
||||
|
||||
import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.zt.plat.module.template.dal.dataobject.databus.TemplateDatabusRequestLogDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* Databus 请求日志 Mapper。
|
||||
*/
|
||||
@Mapper
|
||||
public interface TemplateDatabusRequestLogMapper extends BaseMapperX<TemplateDatabusRequestLogDO> {
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.zt.plat.module.template.job.databus;
|
||||
|
||||
import com.zt.plat.module.template.service.databus.TemplateDatabusInvokeService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 基于 Spring 的 Databus 调度任务。
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class TemplateDatabusScheduler {
|
||||
|
||||
private final TemplateDatabusInvokeService invokeService;
|
||||
|
||||
@Scheduled(cron = "0 0/10 * * * ?")
|
||||
public void execute() {
|
||||
invokeService.invokeAndRecord();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,304 @@
|
||||
package com.zt.plat.module.template.service.databus;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.zt.plat.framework.common.util.security.CryptoSignatureUtils;
|
||||
import com.zt.plat.framework.tenant.core.aop.TenantIgnore;
|
||||
import com.zt.plat.module.template.dal.dataobject.databus.TemplateDatabusRequestLogDO;
|
||||
import com.zt.plat.module.template.dal.mysql.databus.TemplateDatabusRequestLogMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 调用 Databus 接口并记录日志。
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class TemplateDatabusInvokeService {
|
||||
|
||||
private static final TypeReference<LinkedHashMap<String, Object>> MAP_TYPE = new TypeReference<>() {
|
||||
};
|
||||
private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
|
||||
private static final String HEADER_ZT_APP_ID = "ZT-App-Id";
|
||||
private static final String HEADER_ZT_TIMESTAMP = "ZT-Timestamp";
|
||||
private static final String HEADER_ZT_NONCE = "ZT-Nonce";
|
||||
private static final String HEADER_ZT_SIGNATURE = "ZT-Signature";
|
||||
private static final String HEADER_ZT_AUTH_TOKEN = "ZT-Auth-Token";
|
||||
private static final String HEADER_CONTENT_TYPE = "Content-Type";
|
||||
private static final String TARGET_URL = "http://172.16.46.63:30081/admin-api/databus/api/portal/callback/v1";
|
||||
private static final String APP_ID = "ztmy";
|
||||
private static final String APP_SECRET = "zFre/nTRGi7LpoFjN7oQkKeOT09x1fWTyIswrc702QQ=";
|
||||
private static final String AUTH_TOKEN = "a5d7cf609c0b47038ea405c660726ee9";
|
||||
private static final String DEFAULT_HTTP_METHOD = "POST";
|
||||
private static final String ENCRYPTION_TYPE = CryptoSignatureUtils.ENCRYPT_TYPE_AES;
|
||||
private static final Duration CONNECT_TIMEOUT = Duration.ofSeconds(5);
|
||||
private static final Duration READ_TIMEOUT = Duration.ofSeconds(10);
|
||||
private static final Map<String, String> BASE_QUERY_PARAMS = Map.of(
|
||||
"businessCode", "11",
|
||||
"fileId", "11"
|
||||
);
|
||||
private static final Map<String, String> EXTRA_HEADERS = Map.of();
|
||||
private static final String DEFAULT_REQUEST_BODY = """
|
||||
{
|
||||
}
|
||||
""";
|
||||
private static final HttpClient HTTP_CLIENT = HttpClient.newBuilder()
|
||||
.connectTimeout(CONNECT_TIMEOUT)
|
||||
.build();
|
||||
|
||||
private final TemplateDatabusRequestLogMapper requestLogMapper;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
@TenantIgnore
|
||||
public void invokeAndRecord() {
|
||||
TemplateDatabusRequestLogDO logDO = TemplateDatabusRequestLogDO.builder()
|
||||
.requestId(generateRequestId())
|
||||
.httpMethod(DEFAULT_HTTP_METHOD)
|
||||
.targetUrl(TARGET_URL)
|
||||
.success(Boolean.FALSE)
|
||||
.build();
|
||||
Instant start = Instant.now();
|
||||
try {
|
||||
Map<String, Object> queryParams = buildQueryParams();
|
||||
Map<String, Object> bodyParams = buildBodyParams(logDO.getRequestId());
|
||||
String requestBody = toJson(bodyParams);
|
||||
String serializedQuery = toJson(queryParams);
|
||||
logDO.setRequestBody(requestBody);
|
||||
logDO.setQueryParams(serializedQuery);
|
||||
|
||||
String timestamp = Long.toString(System.currentTimeMillis());
|
||||
logDO.setZtTimestamp(timestamp);
|
||||
String nonce = generateNonce();
|
||||
logDO.setNonce(nonce);
|
||||
String signature = generateSignature(queryParams, bodyParams, timestamp);
|
||||
logDO.setSignature(signature);
|
||||
|
||||
String encryptedBody = encryptPayload(requestBody);
|
||||
logDO.setEncryptedRequestBody(encryptedBody);
|
||||
|
||||
URI uri = buildUri(TARGET_URL, queryParams);
|
||||
logDO.setTargetUrl(uri.toString());
|
||||
Map<String, String> headers = buildHeaders(nonce, timestamp, signature);
|
||||
logDO.setRequestHeaders(toJson(headers));
|
||||
|
||||
HttpRequest request = buildHttpRequest(uri, headers, encryptedBody);
|
||||
HttpResponse<String> response = HTTP_CLIENT.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
|
||||
logDO.setResponseStatus(response.statusCode());
|
||||
logDO.setEncryptedResponseBody(response.body());
|
||||
logDO.setResponseBody(tryDecrypt(response.body()));
|
||||
boolean success = response.statusCode() >= 200 && response.statusCode() < 300;
|
||||
logDO.setSuccess(success);
|
||||
if (!success) {
|
||||
log.warn("Databus API 返回非 2xx 状态码: {}", response.statusCode());
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
logDO.setErrorMessage(truncate("Interrupted: " + ex.getMessage(), 1000));
|
||||
log.warn("Databus 调度被中断: {}", ex.getMessage());
|
||||
} catch (Exception ex) {
|
||||
logDO.setErrorMessage(truncate(ex.getMessage(), 1000));
|
||||
log.error("Databus 调度执行异常", ex);
|
||||
} finally {
|
||||
logDO.setDurationMs(Duration.between(start, Instant.now()).toMillis());
|
||||
requestLogMapper.insert(logDO);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Object> buildQueryParams() {
|
||||
Map<String, Object> params = new LinkedHashMap<>();
|
||||
BASE_QUERY_PARAMS.forEach(params::put);
|
||||
return params;
|
||||
}
|
||||
|
||||
private Map<String, Object> buildBodyParams(String requestId) {
|
||||
Map<String, Object> body = new LinkedHashMap<>(parseTemplateBody());
|
||||
body.put("__requestId__", requestId);
|
||||
body.put("datetime", DATETIME_FORMATTER.format(LocalDateTime.now()));
|
||||
body.putIfAbsent("system", "TEMPLATE");
|
||||
return body;
|
||||
}
|
||||
|
||||
private Map<String, Object> parseTemplateBody() {
|
||||
try {
|
||||
return objectMapper.readValue(DEFAULT_REQUEST_BODY, MAP_TYPE);
|
||||
} catch (JsonProcessingException ex) {
|
||||
throw new IllegalStateException("内置 Databus 请求体 JSON 解析失败", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, String> buildHeaders(String nonce, String timestamp, String signature) {
|
||||
Map<String, String> headers = new LinkedHashMap<>();
|
||||
headers.put(HEADER_ZT_APP_ID, APP_ID);
|
||||
headers.put(HEADER_ZT_TIMESTAMP, timestamp);
|
||||
headers.put(HEADER_ZT_NONCE, nonce);
|
||||
headers.put(HEADER_ZT_SIGNATURE, signature);
|
||||
if (StringUtils.hasText(AUTH_TOKEN)) {
|
||||
headers.put(HEADER_ZT_AUTH_TOKEN, AUTH_TOKEN);
|
||||
}
|
||||
headers.put(HEADER_CONTENT_TYPE, "application/json");
|
||||
EXTRA_HEADERS.forEach((key, value) -> {
|
||||
if (StringUtils.hasText(key) && value != null) {
|
||||
headers.put(key, value);
|
||||
}
|
||||
});
|
||||
return headers;
|
||||
}
|
||||
|
||||
private HttpRequest buildHttpRequest(URI uri, Map<String, String> headers, String encryptedBody) {
|
||||
HttpRequest.Builder builder = HttpRequest.newBuilder(uri)
|
||||
.timeout(READ_TIMEOUT);
|
||||
headers.forEach(builder::header);
|
||||
HttpRequest.BodyPublisher publisher = HttpRequest.BodyPublishers.ofString(encryptedBody, StandardCharsets.UTF_8);
|
||||
switch (DEFAULT_HTTP_METHOD) {
|
||||
case "GET":
|
||||
builder.GET();
|
||||
break;
|
||||
case "PUT":
|
||||
builder.PUT(publisher);
|
||||
break;
|
||||
case "PATCH":
|
||||
builder.method("PATCH", publisher);
|
||||
break;
|
||||
case "DELETE":
|
||||
builder.method("DELETE", publisher);
|
||||
break;
|
||||
default:
|
||||
builder.POST(publisher);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private String encryptPayload(String plaintext) {
|
||||
try {
|
||||
return CryptoSignatureUtils.encrypt(plaintext, APP_SECRET, ENCRYPTION_TYPE);
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalStateException("请求体加密失败", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private String tryDecrypt(String cipherText) {
|
||||
if (!StringUtils.hasText(cipherText)) {
|
||||
return cipherText;
|
||||
}
|
||||
try {
|
||||
return CryptoSignatureUtils.decrypt(cipherText, APP_SECRET, ENCRYPTION_TYPE);
|
||||
} catch (Exception ex) {
|
||||
return "<unable to decrypt> " + ex.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
private URI buildUri(String baseUrl, Map<String, Object> queryParams) {
|
||||
if (queryParams.isEmpty()) {
|
||||
return URI.create(baseUrl);
|
||||
}
|
||||
StringBuilder builder = new StringBuilder(baseUrl);
|
||||
builder.append(baseUrl.contains("?") ? '&' : '?');
|
||||
boolean first = true;
|
||||
for (Map.Entry<String, Object> entry : queryParams.entrySet()) {
|
||||
if (!first) {
|
||||
builder.append('&');
|
||||
}
|
||||
first = false;
|
||||
builder.append(encode(entry.getKey()))
|
||||
.append('=')
|
||||
.append(encode(Objects.toString(entry.getValue(), "")));
|
||||
}
|
||||
return URI.create(builder.toString());
|
||||
}
|
||||
|
||||
private String generateSignature(Map<String, Object> queryParams, Map<String, Object> bodyParams, String timestamp) {
|
||||
TreeMap<String, Object> sorted = new TreeMap<>();
|
||||
queryParams.forEach((key, value) -> sorted.put(key, normalizeValue(value)));
|
||||
bodyParams.forEach((key, value) -> sorted.put(key, normalizeValue(value)));
|
||||
sorted.put(HEADER_ZT_APP_ID, APP_ID);
|
||||
sorted.put(HEADER_ZT_TIMESTAMP, timestamp);
|
||||
StringBuilder canonical = new StringBuilder();
|
||||
sorted.forEach((key, value) -> {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
if (canonical.length() > 0) {
|
||||
canonical.append('&');
|
||||
}
|
||||
canonical.append(key).append('=').append(value);
|
||||
});
|
||||
return md5Hex(canonical.toString());
|
||||
}
|
||||
|
||||
private Object normalizeValue(Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Map || value instanceof Iterable) {
|
||||
try {
|
||||
return objectMapper.writeValueAsString(value);
|
||||
} catch (JsonProcessingException ex) {
|
||||
return value.toString();
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private String md5Hex(String source) {
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance("MD5");
|
||||
byte[] bytes = digest.digest(source.getBytes(StandardCharsets.UTF_8));
|
||||
StringBuilder builder = new StringBuilder(bytes.length * 2);
|
||||
for (byte aByte : bytes) {
|
||||
String part = Integer.toHexString(aByte & 0xFF);
|
||||
if (part.length() == 1) {
|
||||
builder.append('0');
|
||||
}
|
||||
builder.append(part);
|
||||
}
|
||||
return builder.toString();
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
throw new IllegalStateException("MD5 算法不可用", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private String encode(String value) {
|
||||
return URLEncoder.encode(value, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private String generateRequestId() {
|
||||
return UUID.randomUUID().toString().replace("-", "");
|
||||
}
|
||||
|
||||
private String generateNonce() {
|
||||
return UUID.randomUUID().toString().replace("-", "");
|
||||
}
|
||||
|
||||
private String toJson(Object value) {
|
||||
try {
|
||||
return objectMapper.writeValueAsString(value);
|
||||
} catch (JsonProcessingException ex) {
|
||||
return String.valueOf(value);
|
||||
}
|
||||
}
|
||||
|
||||
private String truncate(String value, int maxLength) {
|
||||
if (!StringUtils.hasText(value) || value.length() <= maxLength) {
|
||||
return value;
|
||||
}
|
||||
return value.substring(0, maxLength);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
CREATE TABLE template_databus_request_log (
|
||||
ID BIGINT NOT NULL,
|
||||
REQUEST_ID VARCHAR(64) NOT NULL,
|
||||
TARGET_URL VARCHAR(512) NOT NULL,
|
||||
HTTP_METHOD VARCHAR(16) NOT NULL,
|
||||
QUERY_PARAMS TEXT,
|
||||
REQUEST_HEADERS TEXT,
|
||||
REQUEST_BODY TEXT,
|
||||
ENCRYPTED_REQUEST_BODY TEXT,
|
||||
SIGNATURE VARCHAR(128),
|
||||
NONCE VARCHAR(64),
|
||||
ZT_TIMESTAMP VARCHAR(32),
|
||||
RESPONSE_STATUS INT,
|
||||
ENCRYPTED_RESPONSE_BODY TEXT,
|
||||
RESPONSE_BODY TEXT,
|
||||
SUCCESS BIT DEFAULT '0' NOT NULL,
|
||||
ERROR_MESSAGE TEXT,
|
||||
DURATION_MS BIGINT,
|
||||
CREATE_TIME DATETIME(6) DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
UPDATE_TIME DATETIME(6) DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
CREATOR VARCHAR(64),
|
||||
UPDATER VARCHAR(64),
|
||||
DELETED BIT DEFAULT '0' NOT NULL,
|
||||
PRIMARY KEY (ID)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE template_databus_request_log IS 'Databus 请求调度日志表';
|
||||
COMMENT ON COLUMN template_databus_request_log.ID IS '主键';
|
||||
COMMENT ON COLUMN template_databus_request_log.REQUEST_ID IS '请求唯一标识';
|
||||
COMMENT ON COLUMN template_databus_request_log.TARGET_URL IS '目标地址(含 Query)';
|
||||
COMMENT ON COLUMN template_databus_request_log.HTTP_METHOD IS 'HTTP 方法';
|
||||
COMMENT ON COLUMN template_databus_request_log.QUERY_PARAMS IS 'Query 参数 JSON';
|
||||
COMMENT ON COLUMN template_databus_request_log.REQUEST_HEADERS IS '请求头 JSON';
|
||||
COMMENT ON COLUMN template_databus_request_log.REQUEST_BODY IS '原始请求体';
|
||||
COMMENT ON COLUMN template_databus_request_log.ENCRYPTED_REQUEST_BODY IS '加密请求体';
|
||||
COMMENT ON COLUMN template_databus_request_log.SIGNATURE IS '签名';
|
||||
COMMENT ON COLUMN template_databus_request_log.NONCE IS '随机串';
|
||||
COMMENT ON COLUMN template_databus_request_log.ZT_TIMESTAMP IS '时间戳';
|
||||
COMMENT ON COLUMN template_databus_request_log.RESPONSE_STATUS IS '响应状态码';
|
||||
COMMENT ON COLUMN template_databus_request_log.ENCRYPTED_RESPONSE_BODY IS '加密响应体';
|
||||
COMMENT ON COLUMN template_databus_request_log.RESPONSE_BODY IS '解密后的响应体';
|
||||
COMMENT ON COLUMN template_databus_request_log.SUCCESS IS '是否成功';
|
||||
COMMENT ON COLUMN template_databus_request_log.ERROR_MESSAGE IS '错误信息';
|
||||
COMMENT ON COLUMN template_databus_request_log.DURATION_MS IS '耗时(毫秒)';
|
||||
COMMENT ON COLUMN template_databus_request_log.CREATE_TIME IS '创建时间';
|
||||
COMMENT ON COLUMN template_databus_request_log.UPDATE_TIME IS '更新时间';
|
||||
COMMENT ON COLUMN template_databus_request_log.CREATOR IS '创建人';
|
||||
COMMENT ON COLUMN template_databus_request_log.UPDATER IS '更新人';
|
||||
COMMENT ON COLUMN template_databus_request_log.DELETED IS '逻辑删除标记';
|
||||
Reference in New Issue
Block a user