From 35d8c09fd1ea3f72684c5921939fa20c92bd330b Mon Sep 17 00:00:00 2001
From: cl <1442464845@qq.com>
Date: 星期二, 12 五月 2026 13:18:29 +0800
Subject: [PATCH] #

---
 rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/HttpAuditLogSink.java                            |   11 
 rsf-server/src/main/java/com/vincent/rsf/server/common/datasource/HttpAuditDataSourceAspect.java                |   15 
 rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/common/Cools.java                                        |   57 ++++
 rsf-http-audit/src/main/resources/META-INF/spring.factories                                                     |    2 
 rsf-http-audit/src/main/resources/META-INF/rsf-http-audit/defaults.yml                                          |    4 
 rsf-open-api/src/main/java/com/vincent/rsf/openApi/common/datasource/HttpAuditDataSourceAspect.java             |   15 
 rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/HttpAuditAsyncRecorder.java                      |   48 ---
 rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/config/HttpAuditOpenSearchConfiguration.java             |   73 ++++++
 rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/admin/HttpAuditSysConfigAdminController.java             |    4 
 rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/config/HttpAuditJarDefaultsEnvironmentPostProcessor.java |   51 ++++
 rsf-server/src/main/java/com/vincent/rsf/server/manager/service/CusBarcodeSyncViewQueryService.java             |   53 ++-
 rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/admin/HttpAuditLogAdminController.java                   |    4 
 rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/open/HttpAuditOpenLogController.java                     |    4 
 rsf-server/src/main/resources/application-dev.yml                                                               |    6 
 rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/props/HttpAuditProperties.java                           |   39 +++
 rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/MysqlHttpAuditLogSink.java                       |   54 ++++
 rsf-http-audit/pom.xml                                                                                          |    7 
 rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/config/OnOpenSearchLogStorageEnabled.java                |   18 +
 rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/common/BaseRes.java                                      |   13 +
 rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/common/R.java                                            |   58 ++++
 rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/admin/HttpAuditRuleAdminController.java                  |    4 
 rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/config/HttpAuditAutoConfiguration.java                   |   44 +++
 rsf-server/src/main/resources/application-prod.yml                                                              |    5 
 rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/web/util/HttpAuditAdminQueryHelper.java                  |    2 
 rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/HttpAuditCleanupService.java                     |   55 ++++
 rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/OpenSearchHttpAuditLogSink.java                  |   72 ++++++
 26 files changed, 616 insertions(+), 102 deletions(-)

diff --git a/rsf-http-audit/pom.xml b/rsf-http-audit/pom.xml
index 365ffa4..78141cd 100644
--- a/rsf-http-audit/pom.xml
+++ b/rsf-http-audit/pom.xml
@@ -41,11 +41,13 @@
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
         </dependency>
+        <!--
         <dependency>
             <groupId>com.vincent</groupId>
             <artifactId>rsf-framework</artifactId>
             <version>1.0.0</version>
         </dependency>
+        -->
         <dependency>
             <groupId>org.springframework.security</groupId>
             <artifactId>spring-security-core</artifactId>
@@ -59,6 +61,11 @@
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-lang3</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.opensearch.client</groupId>
+            <artifactId>opensearch-rest-client</artifactId>
+            <version>2.19.1</version>
+        </dependency>
     </dependencies>
     <build>
         <plugins>
diff --git a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/admin/HttpAuditLogAdminController.java b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/admin/HttpAuditLogAdminController.java
index 7b51bea..adf22be 100644
--- a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/admin/HttpAuditLogAdminController.java
+++ b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/admin/HttpAuditLogAdminController.java
@@ -2,8 +2,8 @@
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.vincent.rsf.framework.common.Cools;
-import com.vincent.rsf.framework.common.R;
+import com.vincent.rsf.httpaudit.common.Cools;
+import com.vincent.rsf.httpaudit.common.R;
 import com.vincent.rsf.httpaudit.entity.HttpAuditLog;
 import com.vincent.rsf.httpaudit.service.HttpAuditLogCrudService;
 import com.vincent.rsf.httpaudit.web.util.HttpAuditAdminQueryHelper;
diff --git a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/admin/HttpAuditRuleAdminController.java b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/admin/HttpAuditRuleAdminController.java
index 4f29154..f5abcdf 100644
--- a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/admin/HttpAuditRuleAdminController.java
+++ b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/admin/HttpAuditRuleAdminController.java
@@ -2,8 +2,8 @@
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.vincent.rsf.framework.common.Cools;
-import com.vincent.rsf.framework.common.R;
+import com.vincent.rsf.httpaudit.common.Cools;
+import com.vincent.rsf.httpaudit.common.R;
 import com.vincent.rsf.httpaudit.entity.HttpAuditRule;
 import com.vincent.rsf.httpaudit.service.HttpAuditRuleService;
 import com.vincent.rsf.httpaudit.web.util.HttpAuditAdminQueryHelper;
diff --git a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/admin/HttpAuditSysConfigAdminController.java b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/admin/HttpAuditSysConfigAdminController.java
index 3127986..1709f6e 100644
--- a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/admin/HttpAuditSysConfigAdminController.java
+++ b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/admin/HttpAuditSysConfigAdminController.java
@@ -3,8 +3,8 @@
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.vincent.rsf.framework.common.Cools;
-import com.vincent.rsf.framework.common.R;
+import com.vincent.rsf.httpaudit.common.Cools;
+import com.vincent.rsf.httpaudit.common.R;
 import com.vincent.rsf.httpaudit.entity.HttpAuditSysConfig;
 import com.vincent.rsf.httpaudit.service.HttpAuditDbConfigService;
 import com.vincent.rsf.httpaudit.service.HttpAuditSysConfigService;
diff --git a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/common/BaseRes.java b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/common/BaseRes.java
new file mode 100644
index 0000000..71bb04d
--- /dev/null
+++ b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/common/BaseRes.java
@@ -0,0 +1,13 @@
+package com.vincent.rsf.httpaudit.common;
+
+public interface BaseRes {
+
+    String OK = "200-Success";
+    String EMPTY = "201-Empty Data";
+    String LIMIT = "202-No Authority";
+    String PARAM = "203-Parameters Cannot Be Empty";
+    String DENIED = "403-Please Re-Login";
+    String REPEAT = "407-Already Exist";
+    String NO_ACTIVATION = "409-Please Activate The System First";
+    String ERROR = "500-Internal Server Error";
+}
diff --git a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/common/Cools.java b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/common/Cools.java
new file mode 100644
index 0000000..05e6b64
--- /dev/null
+++ b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/common/Cools.java
@@ -0,0 +1,57 @@
+package com.vincent.rsf.httpaudit.common;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public final class Cools {
+
+    private Cools() {
+    }
+
+    public static boolean isEmpty(Object... objects) {
+        for (Object obj : objects) {
+            if (isEmpty(obj)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @SuppressWarnings("rawtypes")
+    public static boolean isEmpty(Object o) {
+        if (o == null) {
+            return true;
+        }
+        if (o instanceof String) {
+            if (o.toString().trim().equals("")) {
+                return true;
+            }
+        } else if (o instanceof List) {
+            if (((List) o).size() == 0) {
+                return true;
+            }
+        } else if (o instanceof Map) {
+            if (((Map) o).size() == 0) {
+                return true;
+            }
+        } else if (o instanceof Set) {
+            if (((Set) o).size() == 0) {
+                return true;
+            }
+        } else if (o instanceof Object[]) {
+            if (((Object[]) o).length == 0) {
+                return true;
+            }
+        } else if (o instanceof int[]) {
+            if (((int[]) o).length == 0) {
+                return true;
+            }
+        } else if (o instanceof long[]) {
+            if (((long[]) o).length == 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/common/R.java b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/common/R.java
new file mode 100644
index 0000000..9147f89
--- /dev/null
+++ b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/common/R.java
@@ -0,0 +1,58 @@
+package com.vincent.rsf.httpaudit.common;
+
+import java.util.HashMap;
+
+public class R extends HashMap<String, Object> {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final String CODE = "code";
+    private static final String MSG = "msg";
+    private static final String DATA = "data";
+
+    public R(Integer code, String msg) {
+        super.put(CODE, code);
+        super.put(MSG, msg);
+    }
+
+    public static R ok() {
+        return parse(BaseRes.OK);
+    }
+
+    public static R ok(String msg) {
+        R r = ok();
+        r.put(MSG, msg);
+        return r;
+    }
+
+    public static R ok(Object obj) {
+        return parse(BaseRes.OK).add(obj);
+    }
+
+    public static R error() {
+        return parse(BaseRes.ERROR);
+    }
+
+    public static R error(String msg) {
+        R r = error();
+        r.put(MSG, msg);
+        return r;
+    }
+
+    public R add(Object obj) {
+        this.put(DATA, obj);
+        return this;
+    }
+
+    public static R parse(String message) {
+        if (Cools.isEmpty(message)) {
+            return parse(BaseRes.ERROR);
+        }
+        String[] msg = message.split("-");
+        if (msg.length == 2) {
+            return new R(Integer.parseInt(msg[0].replaceAll(" ", "")), msg[1]);
+        } else {
+            return parse("500-".concat(message));
+        }
+    }
+}
diff --git a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/config/HttpAuditAutoConfiguration.java b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/config/HttpAuditAutoConfiguration.java
index aa2c83e..1c4bc76 100644
--- a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/config/HttpAuditAutoConfiguration.java
+++ b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/config/HttpAuditAutoConfiguration.java
@@ -7,16 +7,22 @@
 import com.vincent.rsf.httpaudit.service.HttpAuditAsyncRecorder;
 import com.vincent.rsf.httpaudit.service.HttpAuditCleanupService;
 import com.vincent.rsf.httpaudit.service.HttpAuditDbConfigService;
-import com.vincent.rsf.httpaudit.service.HttpAuditOutboundRecorder;
 import com.vincent.rsf.httpaudit.service.HttpAuditLogCrudService;
 import com.vincent.rsf.httpaudit.service.HttpAuditLogCrudServiceImpl;
+import com.vincent.rsf.httpaudit.service.HttpAuditLogSink;
+import com.vincent.rsf.httpaudit.service.HttpAuditOutboundRecorder;
 import com.vincent.rsf.httpaudit.service.HttpAuditRuleService;
 import com.vincent.rsf.httpaudit.service.HttpAuditRuleServiceImpl;
 import com.vincent.rsf.httpaudit.service.HttpAuditSysConfigService;
 import com.vincent.rsf.httpaudit.service.HttpAuditSysConfigServiceImpl;
+import com.vincent.rsf.httpaudit.service.MysqlHttpAuditLogSink;
+import com.vincent.rsf.httpaudit.service.OpenSearchHttpAuditLogSink;
 import com.vincent.rsf.httpaudit.web.HttpAuditFilter;
 import com.vincent.rsf.httpaudit.web.OutboundHttpAuditInterceptor;
 import org.mybatis.spring.annotation.MapperScan;
+import org.opensearch.client.RestClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.boot.web.servlet.FilterRegistrationBean;
@@ -27,8 +33,12 @@
 import org.springframework.core.env.Environment;
 import org.springframework.scheduling.annotation.EnableAsync;
 import org.springframework.scheduling.annotation.EnableScheduling;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.Executor;
 
 /**
@@ -40,8 +50,10 @@
 @EnableConfigurationProperties(HttpAuditProperties.class)
 @ConditionalOnProperty(prefix = "http-audit", name = "enabled", havingValue = "true", matchIfMissing = true)
 @MapperScan("com.vincent.rsf.httpaudit.mapper")
-@Import({HttpAuditAdminApiAutoConfiguration.class, HttpAuditOpenUiAutoConfiguration.class})
+@Import({HttpAuditAdminApiAutoConfiguration.class, HttpAuditOpenUiAutoConfiguration.class, HttpAuditOpenSearchConfiguration.class})
 public class HttpAuditAutoConfiguration {
+
+    private static final Logger log = LoggerFactory.getLogger(HttpAuditAutoConfiguration.class);
 
     @Bean
     public HttpAuditSysConfigService httpAuditSysConfigService(HttpAuditConfigMapper httpAuditConfigMapper) {
@@ -59,13 +71,33 @@
     }
 
     @Bean
-    public HttpAuditAsyncRecorder httpAuditAsyncRecorder(HttpAuditLogMapper httpAuditLogMapper) {
-        return new HttpAuditAsyncRecorder(httpAuditLogMapper);
+    public HttpAuditAsyncRecorder httpAuditAsyncRecorder(
+            HttpAuditProperties props,
+            HttpAuditLogMapper httpAuditLogMapper,
+            @Autowired(required = false) OpenSearchHttpAuditLogSink openSearchHttpAuditLogSink) {
+        List<HttpAuditLogSink> sinks = new ArrayList<>();
+        if (props.usesMysqlLogStorage()) {
+            sinks.add(new MysqlHttpAuditLogSink(httpAuditLogMapper));
+        }
+        if (props.usesOpenSearchLogStorage()) {
+            if (openSearchHttpAuditLogSink == null) {
+                log.warn("http_audit_warn code=opensearch_sink_missing log_storage_mode={}", props.resolveLogStorageMode());
+            } else {
+                sinks.add(openSearchHttpAuditLogSink);
+            }
+        }
+        if (sinks.isEmpty()) {
+            log.warn("http_audit_warn code=no_log_sinks log_storage_mode={}", props.resolveLogStorageMode());
+        }
+        return new HttpAuditAsyncRecorder(sinks);
     }
 
     @Bean
-    public HttpAuditCleanupService httpAuditCleanupService(HttpAuditLogMapper httpAuditLogMapper, HttpAuditProperties props) {
-        return new HttpAuditCleanupService(httpAuditLogMapper, props);
+    public HttpAuditCleanupService httpAuditCleanupService(
+            HttpAuditLogMapper httpAuditLogMapper,
+            HttpAuditProperties props,
+            @Autowired(required = false) @Qualifier("httpAuditOpenSearchRestClient") RestClient httpAuditOpenSearchRestClient) {
+        return new HttpAuditCleanupService(httpAuditLogMapper, props, httpAuditOpenSearchRestClient);
     }
 
     @Bean
diff --git a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/config/HttpAuditJarDefaultsEnvironmentPostProcessor.java b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/config/HttpAuditJarDefaultsEnvironmentPostProcessor.java
new file mode 100644
index 0000000..bcd6072
--- /dev/null
+++ b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/config/HttpAuditJarDefaultsEnvironmentPostProcessor.java
@@ -0,0 +1,51 @@
+package com.vincent.rsf.httpaudit.config;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.env.EnvironmentPostProcessor;
+import org.springframework.boot.env.YamlPropertySourceLoader;
+import org.springframework.core.Ordered;
+import org.springframework.core.env.ConfigurableEnvironment;
+import org.springframework.core.env.PropertySource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * jar 鍐呴粯璁ら厤缃紝鏈�浣庝紭鍏堢骇锛涘紩鐢ㄥ伐绋嬭鐩栥��
+ */
+public class HttpAuditJarDefaultsEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
+
+    private static final Logger log = LoggerFactory.getLogger(HttpAuditJarDefaultsEnvironmentPostProcessor.class);
+
+    private static final String RESOURCE = "META-INF/rsf-http-audit/defaults.yml";
+    private static final String NAME = "httpAuditJarDefaults";
+
+    @Override
+    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
+        if (environment.getPropertySources().contains(NAME)) {
+            return;
+        }
+        Resource resource = new ClassPathResource(RESOURCE);
+        if (!resource.exists()) {
+            return;
+        }
+        try {
+            YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
+            List<PropertySource<?>> loaded = loader.load(NAME, resource);
+            for (PropertySource<?> ps : loaded) {
+                environment.getPropertySources().addLast(ps);
+            }
+        } catch (IOException e) {
+            log.warn("http_audit_warn code=jar_defaults_load_failed", e);
+        }
+    }
+
+    @Override
+    public int getOrder() {
+        return Ordered.LOWEST_PRECEDENCE;
+    }
+}
diff --git a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/config/HttpAuditOpenSearchConfiguration.java b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/config/HttpAuditOpenSearchConfiguration.java
new file mode 100644
index 0000000..a92903c
--- /dev/null
+++ b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/config/HttpAuditOpenSearchConfiguration.java
@@ -0,0 +1,73 @@
+package com.vincent.rsf.httpaudit.config;
+
+import com.vincent.rsf.httpaudit.props.HttpAuditProperties;
+import com.vincent.rsf.httpaudit.service.OpenSearchHttpAuditLogSink;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.HttpHost;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.impl.client.BasicCredentialsProvider;
+import org.opensearch.client.RestClient;
+import org.opensearch.client.RestClientBuilder;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * log-storage-mode 涓� 2 鎴� 3 鏃跺姞杞�
+ */
+@Configuration
+@Conditional(OnOpenSearchLogStorageEnabled.class)
+public class HttpAuditOpenSearchConfiguration {
+
+    @Bean(destroyMethod = "close")
+    public RestClient httpAuditOpenSearchRestClient(HttpAuditProperties props) {
+        HttpAuditProperties.OpenSearch oc = props.getOpenSearch();
+        RestClientBuilder builder = RestClient.builder(buildHosts(oc));
+        builder.setRequestConfigCallback(rc -> rc
+                .setConnectTimeout((int) oc.getConnectTimeout().toMillis())
+                .setSocketTimeout((int) oc.getSocketTimeout().toMillis()));
+        if (StringUtils.isNotBlank(oc.getUsername())) {
+            CredentialsProvider cp = new BasicCredentialsProvider();
+            cp.setCredentials(AuthScope.ANY,
+                    new UsernamePasswordCredentials(oc.getUsername(), oc.getPassword() == null ? "" : oc.getPassword()));
+            builder.setHttpClientConfigCallback(hcb -> hcb.setDefaultCredentialsProvider(cp));
+        }
+        return builder.build();
+    }
+
+    @Bean
+    public OpenSearchHttpAuditLogSink openSearchHttpAuditLogSink(
+            @Qualifier("httpAuditOpenSearchRestClient") RestClient httpAuditOpenSearchRestClient,
+            HttpAuditProperties props) {
+        return new OpenSearchHttpAuditLogSink(httpAuditOpenSearchRestClient, props);
+    }
+
+    private static HttpHost[] buildHosts(HttpAuditProperties.OpenSearch oc) {
+        String scheme = oc.getScheme() == null ? "http" : oc.getScheme();
+        List<HttpHost> hosts = new ArrayList<>();
+        for (String raw : oc.getUris()) {
+            if (raw == null || raw.trim().isEmpty()) {
+                continue;
+            }
+            String s = raw.trim();
+            int colon = s.lastIndexOf(':');
+            if (colon > 0 && colon < s.length() - 1) {
+                String h = s.substring(0, colon);
+                int port = Integer.parseInt(s.substring(colon + 1));
+                hosts.add(new HttpHost(h, port, scheme));
+            } else {
+                hosts.add(new HttpHost(s, 9200, scheme));
+            }
+        }
+        if (hosts.isEmpty()) {
+            hosts.add(new HttpHost("localhost", 9200, scheme));
+        }
+        return hosts.toArray(new HttpHost[0]);
+    }
+}
diff --git a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/config/OnOpenSearchLogStorageEnabled.java b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/config/OnOpenSearchLogStorageEnabled.java
new file mode 100644
index 0000000..73f1c46
--- /dev/null
+++ b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/config/OnOpenSearchLogStorageEnabled.java
@@ -0,0 +1,18 @@
+package com.vincent.rsf.httpaudit.config;
+
+import org.springframework.context.annotation.Condition;
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+
+/**
+ * log-storage-mode 涓� 2 鎴� 3
+ */
+public class OnOpenSearchLogStorageEnabled implements Condition {
+
+    @Override
+    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
+        Integer mode = context.getEnvironment().getProperty("http-audit.log-storage-mode", Integer.class, 1);
+        int m = (mode != null && (mode == 2 || mode == 3)) ? mode : 1;
+        return m == 2 || m == 3;
+    }
+}
diff --git a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/open/HttpAuditOpenLogController.java b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/open/HttpAuditOpenLogController.java
index 6c0c3af..379d6bc 100644
--- a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/open/HttpAuditOpenLogController.java
+++ b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/open/HttpAuditOpenLogController.java
@@ -2,8 +2,8 @@
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.vincent.rsf.framework.common.Cools;
-import com.vincent.rsf.framework.common.R;
+import com.vincent.rsf.httpaudit.common.Cools;
+import com.vincent.rsf.httpaudit.common.R;
 import com.vincent.rsf.httpaudit.entity.HttpAuditLog;
 import com.vincent.rsf.httpaudit.props.HttpAuditProperties;
 import com.vincent.rsf.httpaudit.service.HttpAuditLogCrudService;
diff --git a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/props/HttpAuditProperties.java b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/props/HttpAuditProperties.java
index 912ee46..b744b41 100644
--- a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/props/HttpAuditProperties.java
+++ b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/props/HttpAuditProperties.java
@@ -3,7 +3,9 @@
 import lombok.Data;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 
+import java.time.Duration;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -16,6 +18,15 @@
 public class HttpAuditProperties {
 
     private boolean enabled = true;
+
+    /** 1 鏁版嵁搴� 2 OpenSearch 3 鍙屽啓锛涙湭濉垨鍏跺畠鍊煎悓 1 */
+    private int logStorageMode = 1;
+
+    /** 浠� 2銆�3 浣跨敤 */
+    private OpenSearch openSearch = new OpenSearch();
+
+    /** 浠� 1銆�3锛涙棤澶氭暟鎹簮鍙渷鐣� */
+    private String datasource = "primary";
 
     /** 鏄惁娉ㄥ唽 /httpAuditRule銆�/httpAuditLog銆�/httpAuditSysConfig 绛夌鐞嗘帴鍙� */
     private boolean adminApiEnabled = true;
@@ -115,6 +126,34 @@
         return HttpAuditDbConfigHolder.getPathDescriptions(pathDescriptions);
     }
 
+    public int resolveLogStorageMode() {
+        if (logStorageMode == 2 || logStorageMode == 3) {
+            return logStorageMode;
+        }
+        return 1;
+    }
+
+    public boolean usesMysqlLogStorage() {
+        int m = resolveLogStorageMode();
+        return m == 1 || m == 3;
+    }
+
+    public boolean usesOpenSearchLogStorage() {
+        int m = resolveLogStorageMode();
+        return m == 2 || m == 3;
+    }
+
+    @Data
+    public static class OpenSearch {
+        private List<String> uris = new ArrayList<>(Collections.singletonList("localhost:9200"));
+        private String scheme = "http";
+        private String username = "";
+        private String password = "";
+        private String indexName = "http_audit_log";
+        private Duration connectTimeout = Duration.ofSeconds(5);
+        private Duration socketTimeout = Duration.ofSeconds(30);
+    }
+
     private static List<String> defaultExcludes() {
         List<String> list = new ArrayList<>();
         list.add("/actuator");
diff --git a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/HttpAuditAsyncRecorder.java b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/HttpAuditAsyncRecorder.java
index 3a1756f..f182cbd 100644
--- a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/HttpAuditAsyncRecorder.java
+++ b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/HttpAuditAsyncRecorder.java
@@ -1,55 +1,25 @@
 package com.vincent.rsf.httpaudit.service;
 
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.vincent.rsf.httpaudit.entity.HttpAuditLog;
-import com.vincent.rsf.httpaudit.mapper.HttpAuditLogMapper;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
 import org.springframework.scheduling.annotation.Async;
 
-import java.util.LinkedHashMap;
-import java.util.Map;
+import java.util.List;
 
 /**
- * 寮傛钀藉簱锛涘け璐ユ椂鎵撳叏閲忔棩蹇楋紝涓嶅悜涓氬姟鎶涢敊
+ * 寮傛鍐欏叆宸查厤缃殑鏃ュ織鐩爣锛涘崟璺け璐ヤ笉褰卞搷鍏朵粬璺笌涓氬姟
  */
-@Slf4j
-@RequiredArgsConstructor
 public class HttpAuditAsyncRecorder {
 
-    private final HttpAuditLogMapper httpAuditLogMapper;
-    private final ObjectMapper objectMapper = new ObjectMapper();
+    private final List<HttpAuditLogSink> sinks;
+
+    public HttpAuditAsyncRecorder(List<HttpAuditLogSink> sinks) {
+        this.sinks = sinks;
+    }
 
     @Async("httpAuditExecutor")
     public void save(HttpAuditLog entity) {
-        try {
-            httpAuditLogMapper.insert(entity);
-        } catch (Throwable t) {
-            try {
-                Map<String, Object> dump = new LinkedHashMap<>();
-                dump.put("serviceName", entity.getServiceName());
-                dump.put("scopeType", entity.getScopeType());
-                dump.put("uri", entity.getUri());
-                dump.put("method", entity.getMethod());
-                dump.put("functionDesc", entity.getFunctionDesc());
-                dump.put("queryString", entity.getQueryString());
-                dump.put("requestBody", entity.getRequestBody());
-                dump.put("responseBody", entity.getResponseBody());
-                dump.put("httpStatus", entity.getHttpStatus());
-                dump.put("okFlag", entity.getOkFlag());
-                dump.put("spendMs", entity.getSpendMs());
-                dump.put("clientIp", entity.getClientIp());
-                dump.put("errorMessage", entity.getErrorMessage());
-                String json = objectMapper.writeValueAsString(dump);
-                log.error("http-audit 钀藉簱澶辫触锛屽叏閲廕SON濡備笅锛歿}", json, t);
-            } catch (JsonProcessingException je) {
-                log.error("http-audit 钀藉簱澶辫触涓斿簭鍒楀寲瀹¤鍐呭澶辫触锛宺equestBody.length={}, responseBody.length={}",
-                        entity.getRequestBody() == null ? -1 : entity.getRequestBody().length(),
-                        entity.getResponseBody() == null ? -1 : entity.getResponseBody().length(),
-                        t);
-                log.error("搴忓垪鍖栧紓甯�", je);
-            }
+        for (HttpAuditLogSink sink : sinks) {
+            sink.write(entity);
         }
     }
 }
diff --git a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/HttpAuditCleanupService.java b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/HttpAuditCleanupService.java
index f95c567..5aacd79 100644
--- a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/HttpAuditCleanupService.java
+++ b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/HttpAuditCleanupService.java
@@ -1,14 +1,20 @@
 package com.vincent.rsf.httpaudit.service;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.vincent.rsf.httpaudit.entity.HttpAuditLog;
 import com.vincent.rsf.httpaudit.mapper.HttpAuditLogMapper;
 import com.vincent.rsf.httpaudit.props.HttpAuditProperties;
 import lombok.extern.slf4j.Slf4j;
+import org.opensearch.client.Request;
+import org.opensearch.client.ResponseException;
+import org.opensearch.client.RestClient;
 import org.springframework.scheduling.annotation.Scheduled;
 
 import java.time.LocalDateTime;
 import java.time.ZoneId;
+import java.time.ZoneOffset;
 import java.util.Date;
 
 /**
@@ -19,10 +25,14 @@
 
     private final HttpAuditLogMapper httpAuditLogMapper;
     private final HttpAuditProperties props;
+    private final RestClient openSearchRestClient;
+    private final ObjectMapper objectMapper = new ObjectMapper();
 
-    public HttpAuditCleanupService(HttpAuditLogMapper httpAuditLogMapper, HttpAuditProperties props) {
+    public HttpAuditCleanupService(HttpAuditLogMapper httpAuditLogMapper, HttpAuditProperties props,
+                                   RestClient openSearchRestClient) {
         this.httpAuditLogMapper = httpAuditLogMapper;
         this.props = props;
+        this.openSearchRestClient = openSearchRestClient;
     }
 
     @Scheduled(cron = "${http-audit.cleanup-cron:0 30 2 * * ?}")
@@ -35,16 +45,51 @@
             log.warn("http-audit 娓呯悊宸茶烦杩囷紝retentionDays 閰嶇疆鏃犳晥锛歿}", retentionDays);
             return;
         }
+        LocalDateTime cutoff = LocalDateTime.now().minusDays(retentionDays);
+        Date cutoffDate = Date.from(cutoff.atZone(ZoneId.systemDefault()).toInstant());
+        if (props.usesMysqlLogStorage()) {
+            cleanupMysql(cutoffDate, retentionDays);
+        }
+        if (props.usesOpenSearchLogStorage() && openSearchRestClient != null) {
+            cleanupOpenSearch(cutoffDate, retentionDays);
+        }
+    }
+
+    private void cleanupMysql(Date cutoffDate, int retentionDays) {
         try {
-            LocalDateTime cutoff = LocalDateTime.now().minusDays(retentionDays);
-            Date cutoffDate = Date.from(cutoff.atZone(ZoneId.systemDefault()).toInstant());
             int count = httpAuditLogMapper.delete(new LambdaQueryWrapper<HttpAuditLog>()
                     .lt(HttpAuditLog::getCreateTime, cutoffDate));
             if (count > 0) {
-                log.info("http-audit 娓呯悊瀹屾垚锛屽垹闄� {} 鏉★紝淇濈暀澶╂暟 {}", count, retentionDays);
+                log.info("http-audit MySQL 娓呯悊瀹屾垚锛屽垹闄� {} 鏉★紝淇濈暀澶╂暟 {}", count, retentionDays);
             }
         } catch (Exception e) {
-            log.warn("http-audit 娓呯悊澶辫触", e);
+            log.warn("http-audit MySQL 娓呯悊澶辫触", e);
+        }
+    }
+
+    private void cleanupOpenSearch(Date cutoffDate, int retentionDays) {
+        try {
+            String index = props.getOpenSearch().getIndexName();
+            String cutoffIso = cutoffDate.toInstant().atOffset(ZoneOffset.UTC).toString();
+            ObjectNode body = objectMapper.createObjectNode();
+            ObjectNode query = objectMapper.createObjectNode();
+            ObjectNode range = objectMapper.createObjectNode();
+            range.set("create_time", objectMapper.createObjectNode().put("lt", cutoffIso));
+            query.set("range", range);
+            body.set("query", query);
+            Request request = new Request("POST", "/" + index + "/_delete_by_query?refresh=false&conflicts=proceed");
+            request.setJsonEntity(objectMapper.writeValueAsString(body));
+            openSearchRestClient.performRequest(request);
+            log.debug("http-audit OpenSearch delete_by_query 宸叉彁浜� retentionDays={}", retentionDays);
+        } catch (ResponseException ex) {
+            int code = ex.getResponse() != null ? ex.getResponse().getStatusLine().getStatusCode() : -1;
+            if (code == 404) {
+                log.debug("http-audit OpenSearch 娓呯悊璺宠繃锛岀储寮曚笉瀛樺湪");
+            } else {
+                log.warn("http-audit OpenSearch 娓呯悊澶辫触 status={}", code, ex);
+            }
+        } catch (Exception e) {
+            log.warn("http-audit OpenSearch 娓呯悊澶辫触", e);
         }
     }
 }
diff --git a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/HttpAuditLogSink.java b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/HttpAuditLogSink.java
new file mode 100644
index 0000000..780e0ca
--- /dev/null
+++ b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/HttpAuditLogSink.java
@@ -0,0 +1,11 @@
+package com.vincent.rsf.httpaudit.service;
+
+import com.vincent.rsf.httpaudit.entity.HttpAuditLog;
+
+/**
+ * 瀹¤鏃ュ織鍐欏叆鐩爣锛涘崟璺け璐ヤ笉褰卞搷鍏朵粬璺笌涓氬姟
+ */
+public interface HttpAuditLogSink {
+
+    void write(HttpAuditLog entity);
+}
diff --git a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/MysqlHttpAuditLogSink.java b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/MysqlHttpAuditLogSink.java
new file mode 100644
index 0000000..07259cf
--- /dev/null
+++ b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/MysqlHttpAuditLogSink.java
@@ -0,0 +1,54 @@
+package com.vincent.rsf.httpaudit.service;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.vincent.rsf.httpaudit.entity.HttpAuditLog;
+import com.vincent.rsf.httpaudit.mapper.HttpAuditLogMapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * 鍐欏叆 MySQL sys_http_audit_log
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class MysqlHttpAuditLogSink implements HttpAuditLogSink {
+
+    private final HttpAuditLogMapper httpAuditLogMapper;
+    private final ObjectMapper objectMapper = new ObjectMapper();
+
+    @Override
+    public void write(HttpAuditLog entity) {
+        try {
+            httpAuditLogMapper.insert(entity);
+        } catch (Throwable t) {
+            try {
+                Map<String, Object> dump = new LinkedHashMap<>();
+                dump.put("serviceName", entity.getServiceName());
+                dump.put("scopeType", entity.getScopeType());
+                dump.put("uri", entity.getUri());
+                dump.put("method", entity.getMethod());
+                dump.put("functionDesc", entity.getFunctionDesc());
+                dump.put("queryString", entity.getQueryString());
+                dump.put("requestBody", entity.getRequestBody());
+                dump.put("responseBody", entity.getResponseBody());
+                dump.put("httpStatus", entity.getHttpStatus());
+                dump.put("okFlag", entity.getOkFlag());
+                dump.put("spendMs", entity.getSpendMs());
+                dump.put("clientIp", entity.getClientIp());
+                dump.put("errorMessage", entity.getErrorMessage());
+                String json = objectMapper.writeValueAsString(dump);
+                log.error("http-audit 钀藉簱澶辫触锛屽叏閲廕SON濡備笅锛歿}", json, t);
+            } catch (JsonProcessingException je) {
+                log.error("http-audit 钀藉簱澶辫触涓斿簭鍒楀寲瀹¤鍐呭澶辫触锛宺equestBody.length={}, responseBody.length={}",
+                        entity.getRequestBody() == null ? -1 : entity.getRequestBody().length(),
+                        entity.getResponseBody() == null ? -1 : entity.getResponseBody().length(),
+                        t);
+                log.error("搴忓垪鍖栧紓甯�", je);
+            }
+        }
+    }
+}
diff --git a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/OpenSearchHttpAuditLogSink.java b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/OpenSearchHttpAuditLogSink.java
new file mode 100644
index 0000000..d134104
--- /dev/null
+++ b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/service/OpenSearchHttpAuditLogSink.java
@@ -0,0 +1,72 @@
+package com.vincent.rsf.httpaudit.service;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.vincent.rsf.httpaudit.entity.HttpAuditLog;
+import com.vincent.rsf.httpaudit.props.HttpAuditProperties;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.opensearch.client.Request;
+import org.opensearch.client.ResponseException;
+import org.opensearch.client.RestClient;
+
+import java.time.ZoneOffset;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * 鍐欏叆 OpenSearch 绱㈠紩
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class OpenSearchHttpAuditLogSink implements HttpAuditLogSink {
+
+    private static final ObjectMapper JSON = new ObjectMapper()
+            .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+
+    private final RestClient restClient;
+    private final HttpAuditProperties props;
+
+    @Override
+    public void write(HttpAuditLog entity) {
+        try {
+            String index = props.getOpenSearch().getIndexName();
+            String docId = entity.getId() != null ? String.valueOf(entity.getId()) : UUID.randomUUID().toString();
+            String path = "/" + index + "/_doc/" + docId + "?refresh=false";
+            Request request = new Request("PUT", path);
+            request.setJsonEntity(JSON.writeValueAsString(toDocument(entity)));
+            restClient.performRequest(request);
+        } catch (ResponseException ex) {
+            int code = ex.getResponse() != null ? ex.getResponse().getStatusLine().getStatusCode() : -1;
+            log.error("http-audit OpenSearch 鍐欏叆澶辫触 uri={} status={}", entity.getUri(), code, ex);
+        } catch (Throwable t) {
+            log.error("http-audit OpenSearch 鍐欏叆澶辫触 uri={}", entity.getUri(), t);
+        }
+    }
+
+    private static Map<String, Object> toDocument(HttpAuditLog e) {
+        Map<String, Object> m = new LinkedHashMap<>();
+        m.put("id", e.getId());
+        m.put("service_name", e.getServiceName());
+        m.put("scope_type", e.getScopeType());
+        m.put("uri", e.getUri());
+        m.put("io_direction", e.getIoDirection());
+        m.put("method", e.getMethod());
+        m.put("function_desc", e.getFunctionDesc());
+        m.put("query_string", e.getQueryString());
+        m.put("request_body", e.getRequestBody());
+        m.put("response_body", e.getResponseBody());
+        m.put("response_truncated", e.getResponseTruncated());
+        m.put("http_status", e.getHttpStatus());
+        m.put("ok_flag", e.getOkFlag());
+        m.put("spend_ms", e.getSpendMs());
+        m.put("client_ip", e.getClientIp());
+        m.put("error_message", e.getErrorMessage());
+        if (e.getCreateTime() != null) {
+            m.put("create_time", e.getCreateTime().toInstant().atOffset(ZoneOffset.UTC).toString());
+        }
+        m.put("deleted", e.getDeleted());
+        return m;
+    }
+}
diff --git a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/web/util/HttpAuditAdminQueryHelper.java b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/web/util/HttpAuditAdminQueryHelper.java
index f417a34..78f1311 100644
--- a/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/web/util/HttpAuditAdminQueryHelper.java
+++ b/rsf-http-audit/src/main/java/com/vincent/rsf/httpaudit/web/util/HttpAuditAdminQueryHelper.java
@@ -2,7 +2,7 @@
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.vincent.rsf.framework.common.Cools;
+import com.vincent.rsf.httpaudit.common.Cools;
 
 import java.util.HashMap;
 import java.util.Map;
diff --git a/rsf-http-audit/src/main/resources/META-INF/rsf-http-audit/defaults.yml b/rsf-http-audit/src/main/resources/META-INF/rsf-http-audit/defaults.yml
new file mode 100644
index 0000000..a5d18de
--- /dev/null
+++ b/rsf-http-audit/src/main/resources/META-INF/rsf-http-audit/defaults.yml
@@ -0,0 +1,4 @@
+http-audit:
+  enabled: true
+  log-storage-mode: 1
+  datasource: primary
diff --git a/rsf-http-audit/src/main/resources/META-INF/spring.factories b/rsf-http-audit/src/main/resources/META-INF/spring.factories
index 65c20b4..0d703ca 100644
--- a/rsf-http-audit/src/main/resources/META-INF/spring.factories
+++ b/rsf-http-audit/src/main/resources/META-INF/spring.factories
@@ -1,2 +1,4 @@
 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
 com.vincent.rsf.httpaudit.config.HttpAuditAutoConfiguration
+org.springframework.boot.env.EnvironmentPostProcessor=\
+com.vincent.rsf.httpaudit.config.HttpAuditJarDefaultsEnvironmentPostProcessor
diff --git a/rsf-open-api/src/main/java/com/vincent/rsf/openApi/common/datasource/HttpAuditDataSourceAspect.java b/rsf-open-api/src/main/java/com/vincent/rsf/openApi/common/datasource/HttpAuditDataSourceAspect.java
index 6499384..feebb64 100644
--- a/rsf-open-api/src/main/java/com/vincent/rsf/openApi/common/datasource/HttpAuditDataSourceAspect.java
+++ b/rsf-open-api/src/main/java/com/vincent/rsf/openApi/common/datasource/HttpAuditDataSourceAspect.java
@@ -1,25 +1,26 @@
 package com.vincent.rsf.openApi.common.datasource;
 
+import com.vincent.rsf.httpaudit.props.HttpAuditProperties;
 import org.aspectj.lang.ProceedingJoinPoint;
 import org.aspectj.lang.annotation.Around;
 import org.aspectj.lang.annotation.Aspect;
-import org.springframework.beans.factory.annotation.Value;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.Ordered;
 import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Component;
 
 /**
- * http-audit 鏁版嵁婧愬垏鎹�
+ * http-audit 鏁版嵁婧愬垏鎹紱涓嶅垏 props 鍖咃紝閬垮厤鍒囬潰鍐呰皟 {@link HttpAuditProperties} 鑷�掑綊
  */
 @Aspect
 @Component
 @Order(Ordered.HIGHEST_PRECEDENCE + 10)
 public class HttpAuditDataSourceAspect {
 
-    @Value("${http-audit.datasource:primary}")
-    private String dataSource;
+    @Autowired
+    private HttpAuditProperties httpAuditProperties;
 
-    @Around("execution(* com.vincent.rsf.httpaudit..*(..))")
+    @Around("execution(* com.vincent.rsf.httpaudit..*(..)) && !execution(* com.vincent.rsf.httpaudit.props..*(..))")
     public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
         String selected = resolveDataSource();
         DataSourceContextHolder.push(selected);
@@ -31,6 +32,10 @@
     }
 
     private String resolveDataSource() {
+        if (httpAuditProperties.resolveLogStorageMode() == 2) {
+            return DataSourceNames.PRIMARY;
+        }
+        String dataSource = httpAuditProperties.getDatasource();
         if ("jdxaj-log".equalsIgnoreCase(dataSource)) {
             return DataSourceNames.JDXAJ_LOG;
         }
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/common/datasource/HttpAuditDataSourceAspect.java b/rsf-server/src/main/java/com/vincent/rsf/server/common/datasource/HttpAuditDataSourceAspect.java
index 6f3f9c5..40c7e85 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/common/datasource/HttpAuditDataSourceAspect.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/common/datasource/HttpAuditDataSourceAspect.java
@@ -1,25 +1,26 @@
 package com.vincent.rsf.server.common.datasource;
 
+import com.vincent.rsf.httpaudit.props.HttpAuditProperties;
 import org.aspectj.lang.ProceedingJoinPoint;
 import org.aspectj.lang.annotation.Around;
 import org.aspectj.lang.annotation.Aspect;
-import org.springframework.beans.factory.annotation.Value;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.Ordered;
 import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Component;
 
 /**
- * http-audit 鏁版嵁婧愬垏鎹�
+ * http-audit 鏁版嵁婧愬垏鎹紱涓嶅垏 props 鍖咃紝閬垮厤鍒囬潰鍐呰皟 {@link HttpAuditProperties} 鑷�掑綊
  */
 @Aspect
 @Component
 @Order(Ordered.HIGHEST_PRECEDENCE + 10)
 public class HttpAuditDataSourceAspect {
 
-    @Value("${http-audit.datasource:primary}")
-    private String dataSource;
+    @Autowired
+    private HttpAuditProperties httpAuditProperties;
 
-    @Around("execution(* com.vincent.rsf.httpaudit..*(..))")
+    @Around("execution(* com.vincent.rsf.httpaudit..*(..)) && !execution(* com.vincent.rsf.httpaudit.props..*(..))")
     public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
         String selected = resolveDataSource();
         DataSourceContextHolder.push(selected);
@@ -31,6 +32,10 @@
     }
 
     private String resolveDataSource() {
+        if (httpAuditProperties.resolveLogStorageMode() == 2) {
+            return DataSourceNames.PRIMARY;
+        }
+        String dataSource = httpAuditProperties.getDatasource();
         if ("dj-cloud-wms".equalsIgnoreCase(dataSource)) {
             return DataSourceNames.DJ_CLOUD_WMS;
         }
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/CusBarcodeSyncViewQueryService.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/CusBarcodeSyncViewQueryService.java
index 115b48d..4842a25 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/CusBarcodeSyncViewQueryService.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/CusBarcodeSyncViewQueryService.java
@@ -1,6 +1,5 @@
 package com.vincent.rsf.server.manager.service;
 
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -18,6 +17,7 @@
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.sql.DataSource;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.LinkedHashMap;
@@ -104,30 +104,39 @@
             log.warn("dj-cloud-wms 鏁版嵁婧愭湭閰嶇疆锛岃烦杩� cus_barcode_sync_view");
             return Collections.emptyList();
         }
-        List<CusBarcodeSyncView> rows = cusBarcodeSyncViewMapper.selectList(
-                buildBarcodeOrQuery(codes)
-                        .select(
-                                CusBarcodeSyncView::getBarcode,
-                                CusBarcodeSyncView::getItemName,
-                                CusBarcodeSyncView::getItemSpec,
-                                CusBarcodeSyncView::getUnitNo));
+        List<CusBarcodeSyncView> rows = new ArrayList<>();
+        for (String code : codes) {
+            List<CusBarcodeSyncView> part = cusBarcodeSyncViewMapper.selectList(
+                    Wrappers.<CusBarcodeSyncView>lambdaQuery()
+                            .eq(CusBarcodeSyncView::getBarcode, code)
+                            .select(
+                                    CusBarcodeSyncView::getBarcode,
+                                    CusBarcodeSyncView::getItemName,
+                                    CusBarcodeSyncView::getItemSpec,
+                                    CusBarcodeSyncView::getUnitNo)
+                            .last("LIMIT 1"));
+            if (part != null && !part.isEmpty()) {
+                rows.addAll(part);
+            }
+        }
         return toViewMaps(rows);
     }
 
-    private LambdaQueryWrapper<CusBarcodeSyncView> buildBarcodeOrQuery(List<String> codes) {
-        LambdaQueryWrapper<CusBarcodeSyncView> wrapper = Wrappers.lambdaQuery();
-        wrapper.and(q -> {
-            for (int i = 0; i < codes.size(); i++) {
-                String code = codes.get(i);
-                if (i == 0) {
-                    q.eq(CusBarcodeSyncView::getBarcode, code);
-                } else {
-                    q.or().eq(CusBarcodeSyncView::getBarcode, code);
-                }
-            }
-        });
-        return wrapper;
-    }
+    // 鍘熷崟娆� OR 鎷兼帴锛堥伩鍏� IN/OR 鍗曟潯鏃跺彲鏀瑰洖锛�
+    // private LambdaQueryWrapper<CusBarcodeSyncView> buildBarcodeOrQuery(List<String> codes) {
+    //     LambdaQueryWrapper<CusBarcodeSyncView> wrapper = Wrappers.lambdaQuery();
+    //     wrapper.and(q -> {
+    //         for (int i = 0; i < codes.size(); i++) {
+    //             String code = codes.get(i);
+    //             if (i == 0) {
+    //                 q.eq(CusBarcodeSyncView::getBarcode, code);
+    //             } else {
+    //                 q.or().eq(CusBarcodeSyncView::getBarcode, code);
+    //             }
+    //         }
+    //     });
+    //     return wrapper;
+    // }
 
     private List<Map<String, Object>> toViewMaps(List<CusBarcodeSyncView> rows) {
         if (rows == null || rows.isEmpty()) {
diff --git a/rsf-server/src/main/resources/application-dev.yml b/rsf-server/src/main/resources/application-dev.yml
index 708b81f..71985d7 100644
--- a/rsf-server/src/main/resources/application-dev.yml
+++ b/rsf-server/src/main/resources/application-dev.yml
@@ -138,11 +138,5 @@
       sync-cron: "0/3 * * * * ?"
       recover-cron: "0/5 * * * * ?"
 
-# HTTP 鎺ュ彛瀹¤锛坮sf-http-audit锛屼笉寮曞叆渚濊禆鍒欐棤瀹¤锛沞nabled=false 鍏抽棴 Filter 涓庣鐞嗘帴鍙o級
-# admin-api-enabled锛氭槸鍚︽敞鍐� /httpAuditRule銆�/httpAuditLog銆�/httpAuditSysConfig
-# 绠�鏄撻〉榛樿寮�鍚紱simple-ui-token 闈炵┖鍒欐牎楠岃姹傚ご锛堝叕缃戝缓璁厤缃級
 http-audit:
-  enabled: true
-#  enabled: false
-  # 瀹¤鏁版嵁婧愶細primary / dj-cloud-wms / jdxaj-log
   datasource: jdxaj-log
\ No newline at end of file
diff --git a/rsf-server/src/main/resources/application-prod.yml b/rsf-server/src/main/resources/application-prod.yml
index aeb7a8f..a451e26 100644
--- a/rsf-server/src/main/resources/application-prod.yml
+++ b/rsf-server/src/main/resources/application-prod.yml
@@ -149,10 +149,5 @@
       sync-cron: "0 0/1 * * * ?"
       recover-cron: "0 0/2 * * * ?"
 
-# HTTP 鎺ュ彛瀹¤锛坮sf-http-audit锛屽紩鍏ヤ緷璧栧嵆鐢熸晥锛屽彲 enabled=false 鍏抽棴锛�
-# whitelist-only=true锛氫粎 sys_http_audit_rule 鍛戒腑瑙勫垯鎵嶅啓瀹¤锛涙棤瑙勫垯鏃朵笉钀藉簱銆俧alse锛氭帓闄よ矾寰勫鍏ㄩ噺璁板綍銆�
-# rule-cache-refresh-ms锛氳鍒欒〃缂撳瓨鍒锋柊闂撮殧锛堟绉掞級
 http-audit:
-  enabled: true
-  # 瀹¤鏁版嵁婧愶細primary / dj-cloud-wms / jdxaj-log
   datasource: jdxaj-log
\ No newline at end of file

--
Gitblit v1.9.1