记录同步数据日志功能
This commit is contained in:
+53
@@ -0,0 +1,53 @@
|
||||
package com.ruoyi.web.controller.monitor;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.constant.HttpStatus;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.PageDomain;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.core.page.TableSupport;
|
||||
import com.ruoyi.price.search.BillSearchPage;
|
||||
import com.ruoyi.price.search.IBillSearchStore;
|
||||
|
||||
/**
|
||||
* Generic Elasticsearch business-log viewer.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/monitor/eslog")
|
||||
public class EsLogController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private IBillSearchStore billSearchStore;
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('monitor:eslog:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(
|
||||
@RequestParam(value = "logType", required = false) String logType,
|
||||
@RequestParam(value = "bizId", required = false) String bizId)
|
||||
{
|
||||
PageDomain pageDomain = TableSupport.buildPageRequest();
|
||||
int pageNum = pageDomain.getPageNum() == null ? 1 : pageDomain.getPageNum().intValue();
|
||||
int pageSize = pageDomain.getPageSize() == null ? 10 : pageDomain.getPageSize().intValue();
|
||||
BillSearchPage page = billSearchStore.search(logType, bizId, pageNum, pageSize);
|
||||
TableDataInfo rsp = new TableDataInfo();
|
||||
rsp.setCode(HttpStatus.SUCCESS);
|
||||
rsp.setMsg("\u67e5\u8be2\u6210\u529f");
|
||||
rsp.setRows(page.getRows());
|
||||
rsp.setTotal(page.getTotal());
|
||||
return rsp;
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('monitor:eslog:list')")
|
||||
@GetMapping("/{docId}")
|
||||
public AjaxResult getInfo(@PathVariable("docId") String docId)
|
||||
{
|
||||
return success(billSearchStore.getByDocId(docId));
|
||||
}
|
||||
}
|
||||
@@ -151,3 +151,9 @@ bms:
|
||||
tms:
|
||||
# Agreed API identification code for TMS callers
|
||||
api-code: BMS.TMS.ZYaOvlQzpcfau8TUaCFfO3Hp8ieHIqGw
|
||||
elasticsearch:
|
||||
enabled: true
|
||||
uris: http://127.0.0.1:9200
|
||||
username:
|
||||
password:
|
||||
index: bms_biz_log
|
||||
|
||||
@@ -74,4 +74,8 @@ public class TmsPriceQuoteResult implements Serializable
|
||||
private String orderRemark;
|
||||
/** true=hit stored quote */
|
||||
private Boolean fromCache;
|
||||
/** original TMS sync request JSON from Elasticsearch */
|
||||
private String requestJson;
|
||||
/** original billing response JSON from Elasticsearch */
|
||||
private String responseJson;
|
||||
}
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.ruoyi.price.search;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Bill sync search-store beans.
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(ElasticsearchProperties.class)
|
||||
public class BillSearchConfiguration
|
||||
{
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = "bms.elasticsearch", name = "enabled", havingValue = "true", matchIfMissing = true)
|
||||
public IBillSearchStore esBillSearchStore(ElasticsearchProperties properties)
|
||||
{
|
||||
return new EsBillSearchStore(properties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(IBillSearchStore.class)
|
||||
public IBillSearchStore noopBillSearchStore()
|
||||
{
|
||||
return new NoopBillSearchStore();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.ruoyi.price.search;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** Paginated ES search result. */
|
||||
public class BillSearchPage
|
||||
{
|
||||
private long total;
|
||||
private List<BillSyncSnapshot> rows = new ArrayList<BillSyncSnapshot>();
|
||||
|
||||
public long getTotal()
|
||||
{
|
||||
return total;
|
||||
}
|
||||
|
||||
public void setTotal(long total)
|
||||
{
|
||||
this.total = total;
|
||||
}
|
||||
|
||||
public List<BillSyncSnapshot> getRows()
|
||||
{
|
||||
return rows;
|
||||
}
|
||||
|
||||
public void setRows(List<BillSyncSnapshot> rows)
|
||||
{
|
||||
this.rows = rows == null ? new ArrayList<BillSyncSnapshot>() : rows;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.ruoyi.price.search;
|
||||
|
||||
/** Generic Elasticsearch business log. Distinguished by logType + bizId. */
|
||||
public class BillSyncSnapshot
|
||||
{
|
||||
private String docId;
|
||||
private String logType;
|
||||
private String bizId;
|
||||
private String requestJson;
|
||||
private String responseJson;
|
||||
private String updatedAt;
|
||||
|
||||
public String getDocId()
|
||||
{
|
||||
return docId;
|
||||
}
|
||||
|
||||
public void setDocId(String docId)
|
||||
{
|
||||
this.docId = docId;
|
||||
}
|
||||
|
||||
public String getLogType()
|
||||
{
|
||||
return logType;
|
||||
}
|
||||
|
||||
public void setLogType(String logType)
|
||||
{
|
||||
this.logType = logType;
|
||||
}
|
||||
|
||||
public String getBizId()
|
||||
{
|
||||
return bizId;
|
||||
}
|
||||
|
||||
public void setBizId(String bizId)
|
||||
{
|
||||
this.bizId = bizId;
|
||||
}
|
||||
|
||||
public String getRequestJson()
|
||||
{
|
||||
return requestJson;
|
||||
}
|
||||
|
||||
public void setRequestJson(String requestJson)
|
||||
{
|
||||
this.requestJson = requestJson;
|
||||
}
|
||||
|
||||
public String getResponseJson()
|
||||
{
|
||||
return responseJson;
|
||||
}
|
||||
|
||||
public void setResponseJson(String responseJson)
|
||||
{
|
||||
this.responseJson = responseJson;
|
||||
}
|
||||
|
||||
public String getUpdatedAt()
|
||||
{
|
||||
return updatedAt;
|
||||
}
|
||||
|
||||
public void setUpdatedAt(String updatedAt)
|
||||
{
|
||||
this.updatedAt = updatedAt;
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package com.ruoyi.price.search;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Elasticsearch connection for bill sync search store.
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "bms.elasticsearch")
|
||||
public class ElasticsearchProperties
|
||||
{
|
||||
/** false = skip ES write/read */
|
||||
private boolean enabled = true;
|
||||
|
||||
/** e.g. http://127.0.0.1:9200 */
|
||||
private String uris = "http://127.0.0.1:9200";
|
||||
|
||||
private String username;
|
||||
|
||||
private String password;
|
||||
|
||||
/** index name */
|
||||
private String index = "bms_biz_log";
|
||||
|
||||
public boolean isEnabled()
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getUris()
|
||||
{
|
||||
return uris;
|
||||
}
|
||||
|
||||
public void setUris(String uris)
|
||||
{
|
||||
this.uris = uris;
|
||||
}
|
||||
|
||||
public String getUsername()
|
||||
{
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username)
|
||||
{
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword()
|
||||
{
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password)
|
||||
{
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getIndex()
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
public void setIndex(String index)
|
||||
{
|
||||
this.index = index;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,330 @@
|
||||
package com.ruoyi.price.search;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
|
||||
/**
|
||||
* Persist / load generic business logs via Elasticsearch REST API.
|
||||
*/
|
||||
public class EsBillSearchStore implements IBillSearchStore
|
||||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(EsBillSearchStore.class);
|
||||
|
||||
private final ElasticsearchProperties properties;
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
public EsBillSearchStore(ElasticsearchProperties properties)
|
||||
{
|
||||
this.properties = properties;
|
||||
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
|
||||
factory.setConnectTimeout(3000);
|
||||
factory.setReadTimeout(5000);
|
||||
RestTemplate template = new RestTemplate(factory);
|
||||
if (StringUtils.isNotEmpty(properties.getUsername()))
|
||||
{
|
||||
String user = properties.getUsername();
|
||||
String pass = properties.getPassword() == null ? "" : properties.getPassword();
|
||||
template.getInterceptors().add((request, body, execution) -> {
|
||||
request.getHeaders().setBasicAuth(user, pass);
|
||||
return execution.execute(request, body);
|
||||
});
|
||||
}
|
||||
this.restTemplate = template;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(String logType, String bizId, String requestJson, String responseJson)
|
||||
{
|
||||
if (StringUtils.isEmpty(logType) || StringUtils.isEmpty(bizId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
String docId = EsLogType.docId(logType, bizId);
|
||||
try
|
||||
{
|
||||
JSONObject doc = new JSONObject();
|
||||
doc.put("logType", logType.trim());
|
||||
doc.put("bizId", bizId.trim());
|
||||
doc.put("request", parseOrRaw(requestJson));
|
||||
doc.put("response", parseOrRaw(responseJson));
|
||||
doc.put("updatedAt", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
HttpEntity<String> entity = new HttpEntity<String>(doc.toJSONString(), headers);
|
||||
restTemplate.exchange(docUrl(docId), HttpMethod.PUT, entity, String.class);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.warn("elasticsearch save {} / {} failed: {}", logType, bizId, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BillSyncSnapshot get(String logType, String bizId)
|
||||
{
|
||||
if (StringUtils.isEmpty(logType) || StringUtils.isEmpty(bizId))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return getByDocId(EsLogType.docId(logType, bizId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BillSyncSnapshot getByDocId(String docId)
|
||||
{
|
||||
if (StringUtils.isEmpty(docId))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
try
|
||||
{
|
||||
ResponseEntity<String> resp = restTemplate.exchange(docUrl(docId), HttpMethod.GET, HttpEntity.EMPTY, String.class);
|
||||
String body = resp.getBody();
|
||||
if (StringUtils.isEmpty(body))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
JSONObject root = JSON.parseObject(body);
|
||||
if (root == null || !Boolean.TRUE.equals(root.getBoolean("found")))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return toSnapshot(root.getJSONObject("_source"), root.getString("_id"));
|
||||
}
|
||||
catch (HttpClientErrorException.NotFound e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.warn("elasticsearch get {} failed: {}", docId, e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BillSearchPage search(String logType, String bizId, int pageNum, int pageSize)
|
||||
{
|
||||
BillSearchPage page = new BillSearchPage();
|
||||
if (pageNum < 1)
|
||||
{
|
||||
pageNum = 1;
|
||||
}
|
||||
if (pageSize < 1)
|
||||
{
|
||||
pageSize = 10;
|
||||
}
|
||||
try
|
||||
{
|
||||
JSONObject body = new JSONObject();
|
||||
body.put("from", Integer.valueOf((pageNum - 1) * pageSize));
|
||||
body.put("size", Integer.valueOf(pageSize));
|
||||
JSONArray sort = new JSONArray();
|
||||
JSONObject sortItem = new JSONObject();
|
||||
JSONObject sortOpt = new JSONObject();
|
||||
sortOpt.put("order", "desc");
|
||||
sortOpt.put("unmapped_type", "keyword");
|
||||
sortItem.put("updatedAt.keyword", sortOpt);
|
||||
sort.add(sortItem);
|
||||
body.put("sort", sort);
|
||||
body.put("query", buildQuery(logType, bizId));
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
HttpEntity<String> entity = new HttpEntity<String>(body.toJSONString(), headers);
|
||||
ResponseEntity<String> resp = restTemplate.exchange(searchUrl(), HttpMethod.POST, entity, String.class);
|
||||
JSONObject root = JSON.parseObject(resp.getBody());
|
||||
if (root == null)
|
||||
{
|
||||
return page;
|
||||
}
|
||||
JSONObject hits = root.getJSONObject("hits");
|
||||
if (hits == null)
|
||||
{
|
||||
return page;
|
||||
}
|
||||
page.setTotal(readTotal(hits.get("total")));
|
||||
JSONArray hitList = hits.getJSONArray("hits");
|
||||
if (hitList == null)
|
||||
{
|
||||
return page;
|
||||
}
|
||||
for (int i = 0; i < hitList.size(); i++)
|
||||
{
|
||||
JSONObject hit = hitList.getJSONObject(i);
|
||||
if (hit == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
BillSyncSnapshot snap = toSnapshot(hit.getJSONObject("_source"), hit.getString("_id"));
|
||||
if (snap != null)
|
||||
{
|
||||
page.getRows().add(snap);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (HttpClientErrorException.NotFound e)
|
||||
{
|
||||
return page;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.warn("elasticsearch search failed: {}", e.getMessage());
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
private BillSyncSnapshot toSnapshot(JSONObject source, String id)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
BillSyncSnapshot snap = new BillSyncSnapshot();
|
||||
snap.setDocId(id);
|
||||
snap.setLogType(source.getString("logType"));
|
||||
snap.setBizId(source.getString("bizId"));
|
||||
if (StringUtils.isEmpty(snap.getBizId()))
|
||||
{
|
||||
snap.setBizId(source.getString("orderNo"));
|
||||
}
|
||||
if (StringUtils.isEmpty(snap.getLogType()) && StringUtils.isNotEmpty(source.getString("billId")))
|
||||
{
|
||||
snap.setLogType(EsLogType.BILL);
|
||||
}
|
||||
snap.setRequestJson(toJsonString(source.get("request")));
|
||||
snap.setResponseJson(toJsonString(source.get("response")));
|
||||
snap.setUpdatedAt(source.getString("updatedAt"));
|
||||
return snap;
|
||||
}
|
||||
|
||||
private JSONObject buildQuery(String logType, String bizId)
|
||||
{
|
||||
JSONArray filters = new JSONArray();
|
||||
addTerm(filters, "logType", logType);
|
||||
addWildcard(filters, "bizId", bizId);
|
||||
if (filters.isEmpty())
|
||||
{
|
||||
JSONObject matchAll = new JSONObject();
|
||||
matchAll.put("match_all", new JSONObject());
|
||||
return matchAll;
|
||||
}
|
||||
JSONObject bool = new JSONObject();
|
||||
bool.put("must", filters);
|
||||
JSONObject query = new JSONObject();
|
||||
query.put("bool", bool);
|
||||
return query;
|
||||
}
|
||||
|
||||
private void addTerm(JSONArray filters, String field, String value)
|
||||
{
|
||||
if (StringUtils.isEmpty(value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
JSONObject term = new JSONObject();
|
||||
term.put(field + ".keyword", value.trim());
|
||||
JSONObject wrap = new JSONObject();
|
||||
wrap.put("term", term);
|
||||
filters.add(wrap);
|
||||
}
|
||||
|
||||
private void addWildcard(JSONArray filters, String field, String value)
|
||||
{
|
||||
if (StringUtils.isEmpty(value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
JSONObject wildcard = new JSONObject();
|
||||
JSONObject opts = new JSONObject();
|
||||
opts.put("value", "*" + escapeWildcard(value.trim()) + "*");
|
||||
opts.put("case_insensitive", Boolean.TRUE);
|
||||
wildcard.put(field + ".keyword", opts);
|
||||
JSONObject wrap = new JSONObject();
|
||||
wrap.put("wildcard", wildcard);
|
||||
filters.add(wrap);
|
||||
}
|
||||
|
||||
private String escapeWildcard(String value)
|
||||
{
|
||||
return value.replace("\\", "\\\\").replace("*", "\\*").replace("?", "\\?");
|
||||
}
|
||||
|
||||
private long readTotal(Object total)
|
||||
{
|
||||
if (total instanceof JSONObject)
|
||||
{
|
||||
return ((JSONObject) total).getLongValue("value");
|
||||
}
|
||||
if (total instanceof Number)
|
||||
{
|
||||
return ((Number) total).longValue();
|
||||
}
|
||||
return 0L;
|
||||
}
|
||||
|
||||
private String searchUrl()
|
||||
{
|
||||
return baseUrl() + "/" + properties.getIndex() + "/_search";
|
||||
}
|
||||
|
||||
private String docUrl(String docId)
|
||||
{
|
||||
String encodedId = URLEncoder.encode(docId, StandardCharsets.UTF_8);
|
||||
return baseUrl() + "/" + properties.getIndex() + "/_doc/" + encodedId;
|
||||
}
|
||||
|
||||
private String baseUrl()
|
||||
{
|
||||
String base = properties.getUris();
|
||||
if (base.endsWith("/"))
|
||||
{
|
||||
base = base.substring(0, base.length() - 1);
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
private Object parseOrRaw(String json)
|
||||
{
|
||||
if (StringUtils.isEmpty(json))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
try
|
||||
{
|
||||
return JSON.parse(json);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return json;
|
||||
}
|
||||
}
|
||||
|
||||
private String toJsonString(Object value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (value instanceof String)
|
||||
{
|
||||
return (String) value;
|
||||
}
|
||||
return JSON.toJSONString(value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.ruoyi.price.search;
|
||||
|
||||
/** Common ES business-log types. */
|
||||
public final class EsLogType
|
||||
{
|
||||
public static final String BILL = "BILL";
|
||||
public static final String QUOTE = "QUOTE";
|
||||
|
||||
private EsLogType()
|
||||
{
|
||||
}
|
||||
|
||||
public static String docId(String logType, String bizId)
|
||||
{
|
||||
String type = logType == null ? "" : logType.trim();
|
||||
String id = bizId == null ? "" : bizId.trim();
|
||||
return type + "_" + id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.ruoyi.price.search;
|
||||
|
||||
/**
|
||||
* Generic Elasticsearch store for business request/response logs.
|
||||
*/
|
||||
public interface IBillSearchStore
|
||||
{
|
||||
void save(String logType, String bizId, String requestJson, String responseJson);
|
||||
|
||||
BillSyncSnapshot get(String logType, String bizId);
|
||||
|
||||
BillSyncSnapshot getByDocId(String docId);
|
||||
|
||||
BillSearchPage search(String logType, String bizId, int pageNum, int pageSize);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.ruoyi.price.search;
|
||||
|
||||
/**
|
||||
* No-op when Elasticsearch is disabled.
|
||||
*/
|
||||
public class NoopBillSearchStore implements IBillSearchStore
|
||||
{
|
||||
@Override
|
||||
public void save(String logType, String bizId, String requestJson, String responseJson)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public BillSyncSnapshot get(String logType, String bizId)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BillSyncSnapshot getByDocId(String docId)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BillSearchPage search(String logType, String bizId, int pageNum, int pageSize)
|
||||
{
|
||||
return new BillSearchPage();
|
||||
}
|
||||
}
|
||||
+119
-5
@@ -10,6 +10,8 @@ import java.util.UUID;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.MessageUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
@@ -21,6 +23,9 @@ 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.EsLogType;
|
||||
import com.ruoyi.price.search.IBillSearchStore;
|
||||
import com.ruoyi.price.service.IPrcBillService;
|
||||
import com.ruoyi.price.service.ITmsPriceQuoteService;
|
||||
|
||||
@@ -36,6 +41,9 @@ public class PrcBillServiceImpl implements IPrcBillService
|
||||
@Autowired
|
||||
private PrcBillFeeMapper billFeeMapper;
|
||||
|
||||
@Autowired
|
||||
private IBillSearchStore billSearchStore;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public TmsPriceQuoteResult bill(TmsPriceBillRequest request)
|
||||
@@ -152,6 +160,11 @@ public class PrcBillServiceImpl implements IPrcBillService
|
||||
bill.setPayableTotal(result.getPayableTotal());
|
||||
bill.setCurrency(result.getCurrency());
|
||||
bill.setRoundMode(result.getRoundMode());
|
||||
result.setBillId(bill.getBillId());
|
||||
result.setOrderNo(orderNo);
|
||||
result.setCustomerCode(request.getCustomerCode());
|
||||
fillResultOrder(result, bill);
|
||||
result.setFromCache(Boolean.valueOf(existed != null));
|
||||
if (existed == null)
|
||||
{
|
||||
billMapper.insertPrcBill(bill);
|
||||
@@ -166,11 +179,7 @@ public class PrcBillServiceImpl implements IPrcBillService
|
||||
{
|
||||
billFeeMapper.insertBatch(fees);
|
||||
}
|
||||
result.setBillId(bill.getBillId());
|
||||
result.setOrderNo(orderNo);
|
||||
result.setCustomerCode(request.getCustomerCode());
|
||||
fillResultOrder(result, bill);
|
||||
result.setFromCache(Boolean.valueOf(existed != null));
|
||||
billSearchStore.save(EsLogType.BILL, orderNo, toRequestJson(request), toResponseJson(result));
|
||||
}
|
||||
|
||||
private List<PrcBillFee> toFeeRows(String billId, TmsPriceQuoteResult result)
|
||||
@@ -252,9 +261,31 @@ 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());
|
||||
@@ -274,6 +305,89 @@ public class PrcBillServiceImpl implements IPrcBillService
|
||||
r.setOrderRemark(bill.getOrderRemark());
|
||||
}
|
||||
|
||||
private String toRequestJson(TmsPriceBillRequest request)
|
||||
{
|
||||
JSONObject obj = parseJsonObject(JSON.toJSONString(request));
|
||||
if (obj == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
obj.remove("apiCode");
|
||||
return obj.toJSONString();
|
||||
}
|
||||
|
||||
private String toResponseJson(TmsPriceQuoteResult result)
|
||||
{
|
||||
JSONObject obj = parseJsonObject(JSON.toJSONString(result));
|
||||
if (obj == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
obj.remove("requestJson");
|
||||
obj.remove("responseJson");
|
||||
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))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
try
|
||||
{
|
||||
return JSON.parseObject(json);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
|
||||
+33
@@ -14,6 +14,8 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.MessageUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
@@ -37,6 +39,8 @@ 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.EsLogType;
|
||||
import com.ruoyi.price.search.IBillSearchStore;
|
||||
import com.ruoyi.price.service.ITmsPriceQuoteService;
|
||||
|
||||
/**
|
||||
@@ -82,6 +86,9 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
||||
@Autowired
|
||||
private PrcQuoteFeeMapper quoteFeeMapper;
|
||||
|
||||
@Autowired
|
||||
private IBillSearchStore billSearchStore;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public TmsPriceQuoteResult quote(TmsPriceQuoteRequest request)
|
||||
@@ -104,6 +111,7 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
||||
replaceQuoteFees(cached.getQuoteId(), refreshed);
|
||||
refreshed.setQuoteId(cached.getQuoteId());
|
||||
refreshed.setFromCache(false);
|
||||
billSearchStore.save(EsLogType.QUOTE, cached.getQuoteId(), toEsRequest(request), toEsResponse(refreshed));
|
||||
return refreshed;
|
||||
}
|
||||
|
||||
@@ -531,6 +539,7 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
||||
}
|
||||
result.setQuoteId(quote.getQuoteId());
|
||||
result.setFromCache(false);
|
||||
billSearchStore.save(EsLogType.QUOTE, quote.getQuoteId(), toEsRequest(request), toEsResponse(result));
|
||||
}
|
||||
|
||||
private boolean isStaleSurchargeFees(List<PrcQuoteFee> fees)
|
||||
@@ -580,6 +589,7 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
||||
for (TmsPriceQuoteFeeLine line : result.getFeeDetails())
|
||||
{
|
||||
PrcQuoteFee fee = new PrcQuoteFee();
|
||||
fee.setFeeId(UUID.randomUUID().toString());
|
||||
fee.setQuoteId(quoteId);
|
||||
fee.setFeeType(line.getFeeType());
|
||||
fee.setFeeName(line.getFeeName());
|
||||
@@ -832,6 +842,29 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
||||
return p == null ? null : p.getProductName();
|
||||
}
|
||||
|
||||
private String toEsRequest(TmsPriceQuoteRequest request)
|
||||
{
|
||||
JSONObject obj = JSON.parseObject(JSON.toJSONString(request));
|
||||
if (obj == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
obj.remove("apiCode");
|
||||
return obj.toJSONString();
|
||||
}
|
||||
|
||||
private String toEsResponse(TmsPriceQuoteResult result)
|
||||
{
|
||||
JSONObject obj = JSON.parseObject(JSON.toJSONString(result));
|
||||
if (obj == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
obj.remove("requestJson");
|
||||
obj.remove("responseJson");
|
||||
return obj.toJSONString();
|
||||
}
|
||||
|
||||
private static String emptyToNull(String s)
|
||||
{
|
||||
return StringUtils.isEmpty(s) ? null : s.trim();
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
-- ES log menu under system monitor (parent_id = 2)
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, route_name, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
|
||||
SELECT 2320, N'ES日志', 2, 7, 'eslog', 'monitor/eslog/index', '', 'EsLog', 1, 0, 'C', '0', '0', 'monitor:eslog:list', 'log', 'admin', sysdate(), N'查看Elasticsearch计费同步报文'
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2320);
|
||||
|
||||
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time)
|
||||
SELECT 2321, N'查询', 2320, 1, '', NULL, 1, 0, 'F', '0', '0', 'monitor:eslog:list', '#', 'admin', sysdate()
|
||||
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2321);
|
||||
|
||||
INSERT INTO sys_role_menu (role_id, menu_id)
|
||||
SELECT 1, m.menu_id FROM (SELECT 2320 AS menu_id UNION SELECT 2321) m
|
||||
WHERE NOT EXISTS (SELECT 1 FROM sys_role_menu rm WHERE rm.role_id = 1 AND rm.menu_id = m.menu_id);
|
||||
Reference in New Issue
Block a user