优化记录日志功能

This commit is contained in:
wuweihua
2026-09-11 16:12:01 +08:00
parent 06211adaac
commit 719d8c7208
13 changed files with 346 additions and 161 deletions
@@ -8,6 +8,8 @@ public class BillSyncSnapshot
private String bizId;
private String requestJson;
private String responseJson;
private String status;
private String errorMessage;
private String updatedAt;
public String getDocId()
@@ -60,6 +62,26 @@ public class BillSyncSnapshot
this.responseJson = responseJson;
}
public String getStatus()
{
return status;
}
public void setStatus(String status)
{
this.status = status;
}
public String getErrorMessage()
{
return errorMessage;
}
public void setErrorMessage(String errorMessage)
{
this.errorMessage = errorMessage;
}
public String getUpdatedAt()
{
return updatedAt;
@@ -49,21 +49,25 @@ public class EsBillSearchStore implements IBillSearchStore
}
@Override
public void save(String logType, String bizId, String requestJson, String responseJson)
public void save(String logType, String bizId, String requestJson, String responseJson, String status,
String errorMessage)
{
if (StringUtils.isEmpty(logType) || StringUtils.isEmpty(bizId))
{
return;
}
String docId = EsLogType.docId(logType, bizId);
Date now = new Date();
String docId = EsLogType.docId(logType, bizId, now);
try
{
JSONObject doc = new JSONObject();
doc.put("logType", logType.trim());
doc.put("bizId", bizId.trim());
doc.put("status", StringUtils.isEmpty(status) ? EsBizLogSupport.STATUS_SUCCESS : status.trim());
doc.put("error", StringUtils.isEmpty(errorMessage) ? null : errorMessage);
doc.put("request", parseOrRaw(requestJson));
doc.put("response", parseOrRaw(responseJson));
doc.put("updatedAt", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
doc.put("updatedAt", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(now));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(doc.toJSONString(), headers);
@@ -82,7 +86,12 @@ public class EsBillSearchStore implements IBillSearchStore
{
return null;
}
return getByDocId(EsLogType.docId(logType, bizId));
BillSearchPage page = search(logType, bizId, null, 1, 1);
if (page.getRows() == null || page.getRows().isEmpty())
{
return null;
}
return page.getRows().get(0);
}
@Override
@@ -119,7 +128,7 @@ public class EsBillSearchStore implements IBillSearchStore
}
@Override
public BillSearchPage search(String logType, String bizId, int pageNum, int pageSize)
public BillSearchPage search(String logType, String bizId, String status, int pageNum, int pageSize)
{
BillSearchPage page = new BillSearchPage();
if (pageNum < 1)
@@ -143,7 +152,7 @@ public class EsBillSearchStore implements IBillSearchStore
sortItem.put("updatedAt.keyword", sortOpt);
sort.add(sortItem);
body.put("sort", sort);
body.put("query", buildQuery(logType, bizId));
body.put("query", buildQuery(logType, bizId, status));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(body.toJSONString(), headers);
@@ -210,14 +219,18 @@ public class EsBillSearchStore implements IBillSearchStore
snap.setRequestJson(toJsonString(source.get("request")));
snap.setResponseJson(toJsonString(source.get("response")));
snap.setUpdatedAt(source.getString("updatedAt"));
String status = source.getString("status");
snap.setStatus(StringUtils.isEmpty(status) ? EsBizLogSupport.STATUS_SUCCESS : status);
snap.setErrorMessage(source.getString("error"));
return snap;
}
private JSONObject buildQuery(String logType, String bizId)
private JSONObject buildQuery(String logType, String bizId, String status)
{
JSONArray filters = new JSONArray();
addTerm(filters, "logType", logType);
addWildcard(filters, "bizId", bizId);
addTerm(filters, "status", status);
if (filters.isEmpty())
{
JSONObject matchAll = new JSONObject();
@@ -0,0 +1,126 @@
package com.ruoyi.price.search;
import java.util.UUID;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.sign.Md5Utils;
import com.ruoyi.price.domain.vo.TmsPriceBillRequest;
import com.ruoyi.price.domain.vo.TmsPriceQuoteRequest;
/** Helpers for ES business logs (success / fail). */
public final class EsBizLogSupport
{
public static final String STATUS_SUCCESS = "SUCCESS";
public static final String STATUS_FAIL = "FAIL";
private static final int ERROR_MAX = 2000;
private EsBizLogSupport()
{
}
public static String requestJson(Object request)
{
if (request == null)
{
return null;
}
JSONObject obj = JSON.parseObject(JSON.toJSONString(request));
if (obj == null)
{
return null;
}
obj.remove("apiCode");
return obj.toJSONString();
}
public static String failResponseJson(String errorMessage)
{
JSONObject obj = new JSONObject();
obj.put("success", Boolean.FALSE);
obj.put("msg", errorMessage);
return obj.toJSONString();
}
public static String errorText(Throwable e)
{
if (e == null)
{
return "UNKNOWN_ERROR";
}
String msg = e.getMessage();
if (StringUtils.isEmpty(msg))
{
msg = e.getClass().getSimpleName();
}
Throwable cause = e.getCause();
if (cause != null && StringUtils.isNotEmpty(cause.getMessage())
&& (msg == null || !msg.contains(cause.getMessage())))
{
msg = msg + " | " + cause.getMessage();
}
return cut(msg);
}
public static String cut(String msg)
{
if (msg == null)
{
return null;
}
String text = msg.trim();
if (text.length() > ERROR_MAX)
{
return text.substring(0, ERROR_MAX);
}
return text;
}
public static String billBizId(TmsPriceBillRequest request)
{
if (request != null && StringUtils.isNotEmpty(request.getOrderNo()))
{
return request.getOrderNo().trim();
}
return "FAIL-" + UUID.randomUUID();
}
public static String billFailBizId(TmsPriceBillRequest request)
{
return billBizId(request);
}
public static String quoteFailBizId(TmsPriceQuoteRequest request)
{
if (request == null)
{
return "FAIL-" + UUID.randomUUID();
}
String raw = nvl(request.getCustomerCode()) + "|" + nvl(request.getCustomerId()) + "|"
+ nvl(request.getProductCode()) + "|" + nvl(request.getCountryCode()) + "|"
+ nvl(request.getCountryName()) + "|" + nvl(request.getWeight()) + "|"
+ nvl(request.getBizDate());
return "FAIL-" + Md5Utils.hash(raw);
}
public static void saveFail(IBillSearchStore store, String logType, String bizId, Object request, Throwable e)
{
saveFail(store, logType, bizId, request, errorText(e));
}
public static void saveFail(IBillSearchStore store, String logType, String bizId, Object request, String errorMessage)
{
if (store == null || StringUtils.isEmpty(logType) || StringUtils.isEmpty(bizId))
{
return;
}
String msg = cut(errorMessage);
store.save(logType, bizId, requestJson(request), failResponseJson(msg), STATUS_FAIL, msg);
}
private static String nvl(Object value)
{
return value == null ? "" : String.valueOf(value).trim();
}
}
@@ -1,5 +1,8 @@
package com.ruoyi.price.search;
import java.text.SimpleDateFormat;
import java.util.Date;
/** Common ES business-log types. */
public final class EsLogType
{
@@ -10,10 +13,23 @@ public final class EsLogType
{
}
/** One document per bizId + write time. */
public static String docId(String logType, String bizId)
{
return docId(logType, bizId, new Date());
}
public static String docId(String logType, String bizId, Date at)
{
String type = logType == null ? "" : logType.trim();
String id = bizId == null ? "" : bizId.trim();
return type + "_" + id;
Date time = at == null ? new Date() : at;
String ts = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(time);
String uniq = Long.toHexString(System.nanoTime());
if (uniq.length() > 6)
{
uniq = uniq.substring(uniq.length() - 6);
}
return type + "_" + id + "_" + ts + "_" + uniq;
}
}
@@ -5,11 +5,16 @@ package com.ruoyi.price.search;
*/
public interface IBillSearchStore
{
void save(String logType, String bizId, String requestJson, String responseJson);
default void save(String logType, String bizId, String requestJson, String responseJson)
{
save(logType, bizId, requestJson, responseJson, EsBizLogSupport.STATUS_SUCCESS, null);
}
void save(String logType, String bizId, String requestJson, String responseJson, String status, String errorMessage);
BillSyncSnapshot get(String logType, String bizId);
BillSyncSnapshot getByDocId(String docId);
BillSearchPage search(String logType, String bizId, int pageNum, int pageSize);
BillSearchPage search(String logType, String bizId, String status, int pageNum, int pageSize);
}
@@ -6,7 +6,8 @@ package com.ruoyi.price.search;
public class NoopBillSearchStore implements IBillSearchStore
{
@Override
public void save(String logType, String bizId, String requestJson, String responseJson)
public void save(String logType, String bizId, String requestJson, String responseJson, String status,
String errorMessage)
{
}
@@ -23,7 +24,7 @@ public class NoopBillSearchStore implements IBillSearchStore
}
@Override
public BillSearchPage search(String logType, String bizId, int pageNum, int pageSize)
public BillSearchPage search(String logType, String bizId, String status, int pageNum, int pageSize)
{
return new BillSearchPage();
}
@@ -23,7 +23,7 @@ import com.ruoyi.price.domain.vo.TmsPriceQuoteFeeLine;
import com.ruoyi.price.domain.vo.TmsPriceQuoteResult;
import com.ruoyi.price.mapper.PrcBillFeeMapper;
import com.ruoyi.price.mapper.PrcBillMapper;
import com.ruoyi.price.search.BillSyncSnapshot;
import com.ruoyi.price.search.EsBizLogSupport;
import com.ruoyi.price.search.EsLogType;
import com.ruoyi.price.search.IBillSearchStore;
import com.ruoyi.price.service.IPrcBillService;
@@ -48,20 +48,28 @@ public class PrcBillServiceImpl implements IPrcBillService
@Transactional(rollbackFor = Exception.class)
public TmsPriceQuoteResult bill(TmsPriceBillRequest request)
{
if (request == null || StringUtils.isEmpty(request.getOrderNo()))
try
{
throw new ServiceException(MessageUtils.message("price.bill.orderNoRequired"));
if (request == null || StringUtils.isEmpty(request.getOrderNo()))
{
throw new ServiceException(MessageUtils.message("price.bill.orderNoRequired"));
}
request.setOrderNo(request.getOrderNo().trim());
if (StringUtils.isEmpty(request.getBizDate()))
{
throw new ServiceException(MessageUtils.message("price.bill.bizDateRequired"));
}
Date bizDate = resolveBizDate(request.getBizDate());
BigDecimal weight = request.getWeight();
TmsPriceQuoteResult result = tmsPriceQuoteService.calculate(request);
persistBill(request, weight, bizDate, result);
return result;
}
request.setOrderNo(request.getOrderNo().trim());
if (StringUtils.isEmpty(request.getBizDate()))
catch (RuntimeException e)
{
throw new ServiceException(MessageUtils.message("price.bill.bizDateRequired"));
EsBizLogSupport.saveFail(billSearchStore, EsLogType.BILL, EsBizLogSupport.billFailBizId(request), request, e);
throw e;
}
Date bizDate = resolveBizDate(request.getBizDate());
BigDecimal weight = request.getWeight();
TmsPriceQuoteResult result = tmsPriceQuoteService.calculate(request);
persistBill(request, weight, bizDate, result);
return result;
}
@Override
@@ -261,31 +269,9 @@ public class PrcBillServiceImpl implements IPrcBillService
}
}
r.setFeeDetails(lines);
fillSnapshotFromSearch(r, bill);
return r;
}
private void fillSnapshotFromSearch(TmsPriceQuoteResult r, PrcBill bill)
{
BillSyncSnapshot snap = billSearchStore.get(EsLogType.BILL, bill.getOrderNo());
if (snap != null && StringUtils.isNotEmpty(snap.getRequestJson()))
{
r.setRequestJson(snap.getRequestJson());
}
else
{
r.setRequestJson(rebuildRequestJson(bill));
}
if (snap != null && StringUtils.isNotEmpty(snap.getResponseJson()))
{
r.setResponseJson(snap.getResponseJson());
}
else
{
r.setResponseJson(toResponseJson(r));
}
}
private void fillResultOrder(TmsPriceQuoteResult r, PrcBill bill)
{
r.setTrackingNo(bill.getTrackingNo());
@@ -328,42 +314,6 @@ public class PrcBillServiceImpl implements IPrcBillService
return obj.toJSONString();
}
private String rebuildRequestJson(PrcBill bill)
{
JSONObject obj = new JSONObject();
putIfNotNull(obj, "orderNo", bill.getOrderNo());
putIfNotNull(obj, "trackingNo", bill.getTrackingNo());
putIfNotNull(obj, "customerId", bill.getCustomerId());
putIfNotNull(obj, "customerCode", bill.getCustomerCode());
putIfNotNull(obj, "customerName", bill.getCustomerName());
putIfNotNull(obj, "productCode", bill.getProductCode());
putIfNotNull(obj, "countryCode", bill.getCountryCode());
putIfNotNull(obj, "countryName", bill.getCountryName());
putIfNotNull(obj, "weight", bill.getWeight());
if (bill.getBizDate() != null)
{
obj.put("bizDate", new SimpleDateFormat("yyyy-MM-dd").format(bill.getBizDate()));
}
putIfNotNull(obj, "tmsId", bill.getTmsId());
putIfNotNull(obj, "pieces", bill.getPieces());
putIfNotNull(obj, "actualWeight", bill.getActualWeight());
putIfNotNull(obj, "volume", bill.getVolume());
putIfNotNull(obj, "volumeWeight", bill.getVolumeWeight());
putIfNotNull(obj, "pkgLength", bill.getPkgLength());
putIfNotNull(obj, "pkgWidth", bill.getPkgWidth());
putIfNotNull(obj, "pkgHeight", bill.getPkgHeight());
putIfNotNull(obj, "shipperName", bill.getShipperName());
putIfNotNull(obj, "consigneeName", bill.getConsigneeName());
putIfNotNull(obj, "destPostcode", bill.getDestPostcode());
putIfNotNull(obj, "warehouseCode", bill.getWarehouseCode());
if (bill.getOrderTime() != null)
{
obj.put("orderTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(bill.getOrderTime()));
}
putIfNotNull(obj, "orderRemark", bill.getOrderRemark());
return obj.toJSONString();
}
private JSONObject parseJsonObject(String json)
{
if (StringUtils.isEmpty(json))
@@ -380,14 +330,6 @@ public class PrcBillServiceImpl implements IPrcBillService
}
}
private void putIfNotNull(JSONObject obj, String key, Object value)
{
if (value != null && !(value instanceof String && ((String) value).isEmpty()))
{
obj.put(key, value);
}
}
private Date resolveBizDate(String bizDate)
{
if (StringUtils.isEmpty(bizDate))
@@ -39,6 +39,7 @@ import com.ruoyi.price.mapper.PrcPriceSetMapper;
import com.ruoyi.price.mapper.PrcQuoteFeeMapper;
import com.ruoyi.price.mapper.PrcQuoteMapper;
import com.ruoyi.price.mapper.PrcSurchargeRelMapper;
import com.ruoyi.price.search.EsBizLogSupport;
import com.ruoyi.price.search.EsLogType;
import com.ruoyi.price.search.IBillSearchStore;
import com.ruoyi.price.service.ITmsPriceQuoteService;
@@ -92,6 +93,20 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
@Override
@Transactional(rollbackFor = Exception.class)
public TmsPriceQuoteResult quote(TmsPriceQuoteRequest request)
{
try
{
return quoteInternal(request);
}
catch (RuntimeException e)
{
EsBizLogSupport.saveFail(billSearchStore, EsLogType.QUOTE, EsBizLogSupport.quoteFailBizId(request),
request, e);
throw e;
}
}
private TmsPriceQuoteResult quoteInternal(TmsPriceQuoteRequest request)
{
validateRequest(request);
Date bizDate = resolveBizDate(request.getBizDate());