Browse Source

Merge remote-tracking branch 'origin/master'

17358629955 2 years ago
parent
commit
e3839f1d10
34 changed files with 2261 additions and 7 deletions
  1. 13 0
      .gitignore
  2. 0 3
      .idea/.gitignore
  3. 2 1
      README.md
  4. 10 0
      pom.xml
  5. 12 0
      sckw-common/sckw-common-core/pom.xml
  6. 20 1
      sckw-common/sckw-common-elasticsearch/pom.xml
  7. 348 0
      sckw-common/sckw-common-elasticsearch/src/main/java/com/sckw/elasticsearch/service/es/EsUtils.java
  8. 108 0
      sckw-common/sckw-common-elasticsearch/src/main/java/com/sckw/elasticsearch/service/es/autoconfigure/EsAutoConfiguration.java
  9. 11 0
      sckw-common/sckw-common-elasticsearch/src/main/java/com/sckw/elasticsearch/service/es/constants/EsConstant.java
  10. 39 0
      sckw-common/sckw-common-elasticsearch/src/main/java/com/sckw/elasticsearch/service/es/properties/EsProperties.java
  11. 2 0
      sckw-common/sckw-common-elasticsearch/src/main/resources/META-INF/spring.factories
  12. 1 0
      sckw-common/sckw-common-elasticsearch/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
  13. 1 0
      sckw-modules-api/pom.xml
  14. 38 0
      sckw-modules-api/sckw-file-api/pom.xml
  15. 16 0
      sckw-modules-api/sckw-file-api/src/main/java/com/sckw/file/api/dubbo/FileApiDubboService.java
  16. 45 0
      sckw-modules-api/sckw-file-api/src/main/java/com/sckw/file/api/feign/FileApiFeignService.java
  17. 1 0
      sckw-modules/pom.xml
  18. 14 2
      sckw-modules/sckw-example/pom.xml
  19. 70 0
      sckw-modules/sckw-example/src/main/java/com/sckw/example/controller/EsController.java
  20. 131 0
      sckw-modules/sckw-example/src/main/java/com/sckw/example/controller/FileApiController.java
  21. 24 0
      sckw-modules/sckw-example/src/main/java/com/sckw/example/dubbo/FileServiceImpl.java
  22. 13 0
      sckw-modules/sckw-example/src/main/java/com/sckw/example/feign/FileApiFeignServiceImpl.java
  23. 23 0
      sckw-modules/sckw-example/src/main/java/com/sckw/example/model/Employees.java
  24. 45 0
      sckw-modules/sckw-example/src/main/java/com/sckw/example/service/FileService.java
  25. 87 0
      sckw-modules/sckw-file/pom.xml
  26. 33 0
      sckw-modules/sckw-file/src/main/java/com/sckw/file/FileApplication.java
  27. 67 0
      sckw-modules/sckw-file/src/main/java/com/sckw/file/common/enums/AliyunOssFileTypeEnum.java
  28. 76 0
      sckw-modules/sckw-file/src/main/java/com/sckw/file/common/enums/FileEnum.java
  29. 108 0
      sckw-modules/sckw-file/src/main/java/com/sckw/file/controller/FileApiController.java
  30. 129 0
      sckw-modules/sckw-file/src/main/java/com/sckw/file/service/FileService.java
  31. 660 0
      sckw-modules/sckw-file/src/main/java/com/sckw/file/utils/FileUtils.java
  32. 5 0
      sckw-modules/sckw-file/src/main/resouces/banner.txt
  33. 82 0
      sckw-modules/sckw-file/src/main/resouces/bootstrap-dev.yml
  34. 27 0
      sckw-modules/sckw-file/src/main/resouces/bootstrap.yml

+ 13 - 0
.gitignore

@@ -1,5 +1,6 @@
 # ---> Java
 *.class
+target
 
 # Mobile Tools for Java (J2ME)
 .mtj.tmp/
@@ -12,3 +13,15 @@
 # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
 hs_err_pid*
 
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### VS Code ###
+.vscode
+
+### logs目录 ###
+logs
+

+ 0 - 3
.idea/.gitignore

@@ -1,3 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml

+ 2 - 1
README.md

@@ -48,7 +48,7 @@
 | 分布式日志中心     | 采用 ELK 业界成熟解决方案 实时收集所有服务的运行日志 快速发现定位问题                                                                  |
 | 分布式搜索引擎     | 采用 ElasticSearch以 Mybatis-Plus 方式操作 ElasticSearch                                                       |
 | *分布式消息队列    | 采用 SpringCloud-Stream + RabbitMQ                                                                        |
-| 文件存储        | 采用 Minio 分布式文件存储 天生支持多机、多硬盘、多分片、多副本存储支持权限管理 安全可靠 文件可加密存储                                                |
+| *文件存储       | 采用 Minio 分布式文件存储 天生支持多机、多硬盘、多分片、多副本存储支持权限管理 安全可靠 文件可加密存储(采用的aliyun-oss)                                 |
 | *短信         | 使用 spring-cloud-alicloud-sms                                                                            |
 | 短链接         | 购买现成产品                                                                                                  |
 | 接口文档        | 援用现有接口文档系统                                                                                              |
@@ -87,6 +87,7 @@ sckw-service-platform
 │       └── sckw-xxx                            // xxxx服务 [10040]
 ├── sckw-modules-api                    // 接口模块
 │       └── sckw-system-api                     // 系统基础服务接口
+│       └── sckw-file-api                     // 系统文件服务接口
 ├── sckw-ops          				    // 运维中心
 ├── sckw-common          				// 通用模块
 │       └── sckw-common-core                    // 核心模块

+ 10 - 0
pom.xml

@@ -125,6 +125,16 @@
             <artifactId>spring-boot-configuration-processor</artifactId>
             <optional>true</optional>
         </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-autoconfigure</artifactId>
+            <optional>true</optional>
+        </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-test</artifactId>

+ 12 - 0
sckw-common/sckw-common-core/pom.xml

@@ -46,6 +46,18 @@
             </exclusions>
         </dependency>
         <!--log4j2日志-->
+        <!--全局日志排除-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-logging</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>*</groupId>
+                    <artifactId>*</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <!--采用log4j2 日志输出方式-->
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-log4j2</artifactId>

+ 20 - 1
sckw-common/sckw-common-elasticsearch/pom.xml

@@ -18,11 +18,30 @@
         <maven.compiler.target>17</maven.compiler.target>
         <maven.compiler.compilerVersion>17</maven.compiler.compilerVersion>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <elasticsearch.version>7.14.0</elasticsearch.version>
     </properties>
 
 
     <dependencies>
-
+        <dependency>
+            <groupId>org.elasticsearch.client</groupId>
+            <artifactId>elasticsearch-rest-high-level-client</artifactId>
+            <version>${elasticsearch.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.elasticsearch.client</groupId>
+            <artifactId>elasticsearch-rest-client</artifactId>
+            <version>${elasticsearch.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.elasticsearch</groupId>
+            <artifactId>elasticsearch</artifactId>
+            <version>${elasticsearch.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+        </dependency>
     </dependencies>
 
 </project>

+ 348 - 0
sckw-common/sckw-common-elasticsearch/src/main/java/com/sckw/elasticsearch/service/es/EsUtils.java

@@ -0,0 +1,348 @@
+package com.sckw.elasticsearch.service.es;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import lombok.extern.slf4j.Slf4j;
+import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
+import org.elasticsearch.action.bulk.BulkRequest;
+import org.elasticsearch.action.bulk.BulkResponse;
+import org.elasticsearch.action.delete.DeleteRequest;
+import org.elasticsearch.action.index.IndexRequest;
+import org.elasticsearch.action.search.ClearScrollRequest;
+import org.elasticsearch.action.search.SearchRequest;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.action.update.UpdateRequest;
+import org.elasticsearch.client.RequestOptions;
+import org.elasticsearch.client.RestHighLevelClient;
+import org.elasticsearch.client.core.CountRequest;
+import org.elasticsearch.client.core.CountResponse;
+import org.elasticsearch.client.indices.CreateIndexRequest;
+import org.elasticsearch.client.indices.GetIndexRequest;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.xcontent.XContentType;
+import org.elasticsearch.index.query.TermQueryBuilder;
+import org.elasticsearch.index.reindex.BulkByScrollResponse;
+import org.elasticsearch.index.reindex.DeleteByQueryRequest;
+import org.elasticsearch.index.reindex.UpdateByQueryRequest;
+import org.elasticsearch.script.Script;
+import org.elasticsearch.search.SearchHits;
+import org.elasticsearch.search.aggregations.Aggregations;
+import org.elasticsearch.search.builder.SearchSourceBuilder;
+import org.springframework.util.CollectionUtils;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @author yuzhongchuan
+ * @description COMMENT='ES相关工具类'
+ * @create 2023 -06 -06 10:01
+ */
+@Slf4j
+public class EsUtils {
+
+    private RestHighLevelClient client;
+
+    private static EsUtils esUtils;
+
+    public EsUtils(RestHighLevelClient client) {
+        esUtils = this;
+        this.client = client;
+    }
+
+    /**
+     * 创建索引
+     *
+     * @param idxName
+     * @param idxSql
+     */
+    public static void createIndex(String idxName, String idxSql) {
+        if (indexExist(idxName)) {
+            log.error(" idxName={} 已经存在,idxSql={}", idxName, idxSql);
+            return;
+        }
+        log.info(" idxName={} 创建索引,idxSql={}", idxName, idxSql);
+        CreateIndexRequest request = new CreateIndexRequest(idxName);
+        buildSetting(request);
+        request.mapping(idxSql, XContentType.JSON);
+        try {
+            esUtils.client.indices().create(request, RequestOptions.DEFAULT);
+        } catch (IOException e) {
+            log.error("ES createIndex异常", e);
+        }
+    }
+
+    /**
+     * 删除索引
+     *
+     * @param idxName 索引名称
+     */
+    public static void deleteIndex(String idxName) {
+        if (!indexExist(idxName)) {
+            log.error(" idxName={} 索引不存在", idxName);
+            return;
+        }
+        try {
+            esUtils.client.indices().delete(new DeleteIndexRequest(idxName), RequestOptions.DEFAULT);
+        } catch (IOException e) {
+            log.error("ES deleteIndex异常", e);
+        }
+    }
+
+    /**
+     * 设置分片
+     *
+     * @param request
+     */
+    public static void buildSetting(CreateIndexRequest request) {
+        request.settings(Settings.builder().put("index.number_of_shards", 3)
+                .put("index.number_of_replicas", 0));
+    }
+
+    /**
+     * 断某个index是否存在
+     *
+     * @param idxName
+     * @return
+     */
+    public static boolean indexExist(String idxName) {
+        GetIndexRequest request = new GetIndexRequest(idxName);
+        try {
+            return esUtils.client.indices().exists(request, RequestOptions.DEFAULT);
+        } catch (IOException e) {
+            log.error("ES indexExist查询异常", e);
+            throw new RuntimeException(e);
+        }
+    }
+
+
+    /**
+     * 布尔查询
+     *
+     * @param searchRequest
+     * @return
+     */
+    public static SearchHits boolSearch(SearchRequest searchRequest) {
+        log.info("ES开始boolSearch查询SearchRequest:{}", searchRequest);
+        try {
+            SearchResponse searchResponse = esUtils.client.search(searchRequest, RequestOptions.DEFAULT);
+            return searchResponse.getHits();
+        } catch (Exception e) {
+            log.error("ES boolSearch查询SearchRequest异常", e);
+            return null;
+        }
+    }
+
+    /**
+     * 分组聚合查询
+     *
+     * @param searchRequest
+     * @return
+     */
+    public static Aggregations groupBySearch(SearchRequest searchRequest) {
+        log.info("ES开始groupBySearch查询SearchRequest:{}", searchRequest);
+        try {
+            SearchResponse searchResponse = esUtils.client.search(searchRequest, RequestOptions.DEFAULT);
+            return searchResponse.getAggregations();
+        } catch (Exception e) {
+            log.error("ES groupBySearch查询SearchRequest异常", e);
+            return null;
+        }
+    }
+
+    /**
+     * 清除滚屏
+     *
+     * @param scrollId
+     */
+    public static void clearScroll(String scrollId) {
+        if (scrollId != null) {
+            ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
+            clearScrollRequest.addScrollId(scrollId);
+            try {
+                esUtils.client.clearScroll(clearScrollRequest, RequestOptions.DEFAULT);
+                log.info("ES清除滚屏成功");
+            } catch (Exception e) {
+                log.error("ES清除滚屏出错:" + e.getMessage());
+            }
+        }
+    }
+
+    /**
+     * 简单聚合查询
+     *
+     * @param countRequest
+     * @return
+     */
+    public static long count(CountRequest countRequest) {
+        try {
+
+            log.info("开始ES查询indexName:{}的count", Arrays.toString(countRequest.indices()));
+            CountResponse count = esUtils.client.count(countRequest, RequestOptions.DEFAULT);
+            log.info("ES查询到:count={}", count.getCount());
+            return count.getCount();
+        } catch (Exception e) {
+            log.error("ES count异常", e);
+            return 0;
+        }
+    }
+
+    /**
+     * 批量新增
+     *
+     * @param indexName
+     * @param list
+     * @return
+     */
+    public static <T> void bulkSave(String indexName, List<T> list) {
+        if (CollectionUtils.isEmpty(list)) {
+            return;
+        }
+        BulkRequest request = new BulkRequest();
+        for (Object t : list) {
+            String content = JSON.toJSONString(t);
+            String id = JSON.parseObject(content).get("id").toString();
+            request.add(new IndexRequest(indexName).id(id).source(content, XContentType.JSON));
+        }
+        try {
+            BulkResponse bulkResponse = esUtils.client.bulk(request, RequestOptions.DEFAULT);
+            log.info("批量新增 操作es成功,{}", bulkResponse.status());
+        } catch (IOException e) {
+            log.error("es批量新增数据异常:", e);
+        }
+    }
+
+
+    /**
+     * 批量修改
+     *
+     * @param indexName
+     * @param list
+     * @param script
+     */
+    public static <T> void bulkUpdate(String indexName, List<T> list, Script script) {
+        if (CollectionUtils.isEmpty(list)) {
+            return;
+        }
+        BulkRequest request = new BulkRequest();
+        for (Object t : list) {
+            String content = JSON.toJSONString(t);
+            String id = JSON.parseObject(content).get("id").toString();
+            UpdateRequest doc = new UpdateRequest(indexName, id);
+            request.add(doc.script(script));
+        }
+        try {
+            BulkResponse bulkResponse = esUtils.client.bulk(request, RequestOptions.DEFAULT);
+            log.info("批量更新 操作es成功,{}", bulkResponse.status());
+        } catch (IOException e) {
+            log.error("es批量更新数据异常:", e);
+        }
+    }
+
+
+    /**
+     * 批量删除
+     *
+     * @param indexName
+     * @param list
+     * @return
+     */
+    public static <T> void bulkDel(String indexName, List<T> list) {
+        if (CollectionUtils.isEmpty(list)) {
+            return;
+        }
+        BulkRequest request = new BulkRequest();
+        for (Object t : list) {
+            String content = JSON.toJSONString(t);
+            String id = JSON.parseObject(content).get("id").toString();
+            request.add(new DeleteRequest(indexName).id(id));
+        }
+        try {
+            BulkResponse bulkResponse = esUtils.client.bulk(request, RequestOptions.DEFAULT);
+            log.info("批量删除 操作es成功,{}", bulkResponse.status());
+        } catch (IOException e) {
+            log.error("es批量删除数据异常:", e);
+        }
+    }
+
+    /**
+     * 根据条件更新
+     *
+     * @param idxName
+     * @param builder
+     * @param script
+     */
+    public static void updateByQuery(String idxName, SearchSourceBuilder builder, Script script) {
+        SearchRequest request = new SearchRequest(idxName);
+        request.source(builder);
+        UpdateByQueryRequest updateByQueryRequest = new UpdateByQueryRequest(idxName);
+        updateByQueryRequest.setQuery(builder.query());
+        updateByQueryRequest.setScript(script);
+        try {
+            esUtils.client.updateByQuery(updateByQueryRequest, RequestOptions.DEFAULT);
+        } catch (IOException e) {
+            log.error("es根据条件更新数据异常:", e);
+        }
+    }
+
+    /**
+     * 条件删除
+     *
+     * @param idxName
+     * @param builder
+     * @return
+     * @throws IOException
+     */
+    public static void deleteByQuery(String idxName, TermQueryBuilder builder) {
+        DeleteByQueryRequest request = new DeleteByQueryRequest(idxName);
+        request.setQuery(builder);
+        try {
+            BulkByScrollResponse response = esUtils.client.deleteByQuery(request, RequestOptions.DEFAULT);
+            log.info("删除操作状态", JSONArray.toJSONString(response.getStatus().getDeleted()));
+        } catch (IOException e) {
+            log.error("es根据条件删除数据异常:", e);
+        }
+    }
+
+    /**
+     * es根据id更新数据
+     *
+     * @param idxName
+     * @param id
+     * @param script
+     */
+    public static void update(String idxName, String id, Script script) {
+        UpdateRequest updateRequest = new UpdateRequest(idxName, id);
+        updateRequest.script(script);
+        try {
+            esUtils.client.update(updateRequest, RequestOptions.DEFAULT);
+        } catch (IOException e) {
+            log.error("es根据id更新数据异常:", e);
+        }
+    }
+
+    /**
+     * 插入单条
+     *
+     * @param idxName
+     * @param t
+     * @param <T>
+     */
+    public static <T> void bulk(String idxName, T t) {
+        if (Objects.isNull(idxName) || t == null) {
+            return;
+        }
+        BulkRequest request = new BulkRequest();
+        String content = JSON.toJSONString(t);
+        String id = JSON.parseObject(content).get("id").toString();
+        request.add(new IndexRequest(idxName).id(id).source(content, XContentType.JSON));
+        try {
+            esUtils.client.bulk(request, RequestOptions.DEFAULT);
+        } catch (IOException e) {
+            log.error("es插入单条新数据异常:", e);
+        }
+    }
+
+}

+ 108 - 0
sckw-common/sckw-common-elasticsearch/src/main/java/com/sckw/elasticsearch/service/es/autoconfigure/EsAutoConfiguration.java

@@ -0,0 +1,108 @@
+package com.sckw.elasticsearch.service.es.autoconfigure;
+
+
+import com.sckw.elasticsearch.service.es.EsUtils;
+import com.sckw.elasticsearch.service.es.constants.EsConstant;
+import com.sckw.elasticsearch.service.es.properties.EsProperties;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.Header;
+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.apache.http.impl.nio.reactor.IOReactorConfig;
+import org.apache.http.message.BasicHeader;
+import org.elasticsearch.client.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @Author yzc
+ * @Description es自动装配
+ * @createTime 2022年03月03日 09:36:00
+ */
+@EnableConfigurationProperties(EsProperties.class)
+@Slf4j
+public class EsAutoConfiguration {
+
+    @Autowired
+    private EsProperties esProperties;
+
+
+    @Bean
+    @ConditionalOnClass(RestHighLevelClient.class)
+    @ConditionalOnMissingBean(EsUtils.class)
+    public EsUtils esUtils(RestHighLevelClient restHighLevelClient) {
+        log.info("---------------EsUtils 正在初始化");
+        return new EsUtils(restHighLevelClient);
+    }
+
+    @Bean
+    @ConditionalOnMissingBean(RestHighLevelClient.class)
+    public RestHighLevelClient restHighLevelClient() {
+        log.info("---------------es配置正在加载,当前配置为:{}", esProperties);
+        if (EsConstant.DEFAULT_HOST.equals(esProperties.getHostList())) {
+            throw new RuntimeException("es配置错误,无法加载");
+        }
+        //解析hostList配置信息
+        String[] split = esProperties.getHostList().split(",");
+        //创建HttpHost数组,其中存放es主机和端口的配置信息
+        HttpHost[] httpHostArray = new HttpHost[split.length];
+        for (int i = 0; i < split.length; i++) {
+            String item = split[i];
+            httpHostArray[i] = new HttpHost(item.split(":")[0], Integer.parseInt(item.split(":")[1]), esProperties.getScheme());
+        }
+        RestClientBuilder clientBuilder = RestClient.builder(httpHostArray);
+        // 1.设置请求头
+        Header[] defaultHeaders = {new BasicHeader("header", "value")};
+        clientBuilder.setDefaultHeaders(defaultHeaders);
+        // 2.设置失败监听器,每次节点失败都可以监听到,可以作额外处理
+        clientBuilder.setFailureListener(new RestClient.FailureListener() {
+            @Override
+            public void onFailure(Node node) {
+                super.onFailure(node);
+                log.error(node.getName() + "==节点失败了");
+            }
+        });
+        /** 3.配置节点选择器,客户端以循环方式将每个请求发送到每一个配置的节点上,
+         *发送请求的节点,用于过滤客户端,将请求发送到这些客户端节点,默认向每个配置节点发送,
+         *这个配置通常是用户在启用嗅探时向专用主节点发送请求(即只有专用的主节点应该被HTTP请求命中)
+         */
+        clientBuilder.setNodeSelector(NodeSelector.SKIP_DEDICATED_MASTERS);
+        /**
+         *4. 配置异步请求的线程数量,Apache Http Async Client默认启动一个调度程序线程,以及由连接管理器使用的许多工作线程
+         *(与本地检测到的处理器数量一样多,取决于Runtime.getRuntime().availableProcessors()返回的数量)。线程数可以修改如下,
+         *这里是修改为10个线程,默认1
+         */
+        clientBuilder.setHttpClientConfigCallback(httpAsyncClientBuilder -> httpAsyncClientBuilder.setDefaultIOReactorConfig(
+                IOReactorConfig.custom().setIoThreadCount(10).build()
+        ));
+        /**
+         *5. 配置连接超时和套接字超时
+         *配置请求超时,将连接超时(默认为1秒)和套接字超时(默认为30秒)增加,
+         *这里配置完应该相应地调整最大重试超时(默认为30秒),即上面的setMaxRetryTimeoutMillis,一般于最大的那个值一致即60000
+         */
+        clientBuilder.setRequestConfigCallback(requestConfigBuilder -> {
+            // 连接5秒超时,套接字连接60s超时
+            return requestConfigBuilder
+                    .setConnectTimeout(esProperties.getConnectTimeout())
+                    .setSocketTimeout(60000);
+        });
+
+        //6.设置ES需要基本身份验证的默认凭据提供程序及设置KeepAliveStrategy为3分钟
+        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
+        credentialsProvider.setCredentials(AuthScope.ANY,
+                new UsernamePasswordCredentials(esProperties.getUsername(), esProperties.getPassword()));
+        clientBuilder.setHttpClientConfigCallback(callback -> callback.setDefaultCredentialsProvider(credentialsProvider)
+                .setKeepAliveStrategy((response, context) -> TimeUnit.MINUTES.toMillis(3)));
+
+        //创建RestHighLevelClient客户端
+        return new RestHighLevelClient(clientBuilder);
+    }
+}

+ 11 - 0
sckw-common/sckw-common-elasticsearch/src/main/java/com/sckw/elasticsearch/service/es/constants/EsConstant.java

@@ -0,0 +1,11 @@
+package com.sckw.elasticsearch.service.es.constants;
+
+/**
+ * @Author yzc
+ * @Description es常量
+ * @createTime 2023 -06 -06 10:01
+ */
+public class EsConstant {
+
+    public static final String DEFAULT_HOST = "default:9200";
+}

+ 39 - 0
sckw-common/sckw-common-elasticsearch/src/main/java/com/sckw/elasticsearch/service/es/properties/EsProperties.java

@@ -0,0 +1,39 @@
+package com.sckw.elasticsearch.service.es.properties;
+
+import com.sckw.elasticsearch.service.es.constants.EsConstant;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * @Author yzc
+ * @Description es配置
+ * @createTime 2023 -06 -06 10:01
+ */
+@Getter
+@Setter
+@ToString
+@ConfigurationProperties(prefix = "elasticsearch")
+public class EsProperties {
+    /**
+     * host地址
+     */
+    private String hostList = EsConstant.DEFAULT_HOST;
+    /**
+     * scheme
+     */
+    private String scheme = "http";
+    /**
+     * 用户名
+     */
+    private String username = "";
+    /**
+     * 密码
+     */
+    private String password = "";
+    /**
+     * 超时时间
+     */
+    private Integer connectTimeout = 10000;
+}

+ 2 - 0
sckw-common/sckw-common-elasticsearch/src/main/resources/META-INF/spring.factories

@@ -0,0 +1,2 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+com.sckw.elasticsearch.service.es.autoconfigure.EsAutoConfiguration

+ 1 - 0
sckw-common/sckw-common-elasticsearch/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

@@ -0,0 +1 @@
+com.sckw.elasticsearch.service.es.autoconfigure.EsAutoConfiguration

+ 1 - 0
sckw-modules-api/pom.xml

@@ -17,6 +17,7 @@
 
     <modules>
         <module>sckw-system-api</module>
+        <module>sckw-file-api</module>
     </modules>
 
     <properties>

+ 38 - 0
sckw-modules-api/sckw-file-api/pom.xml

@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.sckw</groupId>
+        <artifactId>sckw-modules-api</artifactId>
+        <version>1.0.0</version>
+    </parent>
+
+
+    <artifactId>sckw-file-api</artifactId>
+    <version>1.0.0</version>
+    <description>系统基础服务接口</description>
+
+    <properties>
+        <maven.compiler.source>17</maven.compiler.source>
+        <maven.compiler.target>17</maven.compiler.target>
+        <maven.compiler.compilerVersion>17</maven.compiler.compilerVersion>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-openfeign-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.sckw</groupId>
+            <artifactId>sckw-common-core</artifactId>
+            <version>1.0.0</version>
+        </dependency>
+
+    </dependencies>
+
+</project>

+ 16 - 0
sckw-modules-api/sckw-file-api/src/main/java/com/sckw/file/api/dubbo/FileApiDubboService.java

@@ -0,0 +1,16 @@
+package com.sckw.file.api.dubbo;
+
+import com.sckw.core.web.response.HttpResult;
+
+/**
+ * @author lfdc
+ * @version 1.0
+ * @className FileApiDubboService
+ * @description fileDubbo服务
+ * @company sckw
+ * @date 2023-06-06 10:06:27
+ */
+public interface FileApiDubboService {
+
+    HttpResult fileUpload(String contentType, String oFileName, byte[] bytes);
+}

+ 45 - 0
sckw-modules-api/sckw-file-api/src/main/java/com/sckw/file/api/feign/FileApiFeignService.java

@@ -0,0 +1,45 @@
+package com.sckw.file.api.feign;
+
+import com.sckw.core.web.response.HttpResult;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.Map;
+
+/**
+ * @author lfdc
+ * @version 1.0
+ * @className FileApiFeignService
+ * @description 定义oss文件Feign
+ * @company sckw
+ * @date 2023-06-06 10:06:06
+ */
+//name:调⽤的服务名称,和服务提供者yml⽂件中spring.application.name保持⼀致
+//path: 定义当前FeignClient的统一前缀 ,path = "/file",url = "http://127.0.0.1:10050"
+//url: 定义当前FeignClient调用地址
+@FeignClient(name = "sckw-file")
+public interface FileApiFeignService {
+
+    /**
+     * 上传文件至OSS
+     * @param file
+     * @return
+     */
+//   @RequestMapping(value = "/file/fileFeignUpload",method = RequestMethod.POST)
+    @PostMapping("/file/fileFeignUpload")
+    public HttpResult fileFeignUpload(@RequestParam("file") MultipartFile file) ;
+
+    /**
+     * file-demo
+     * @param userName
+     * @return
+     */
+//    @RequestMapping(value = "/fileFeignUpload",method = RequestMethod.POST)
+    @GetMapping(value = "/file/fileFeignDemo")
+    public String fileFeignDemo(@RequestParam("userName") String userName) ;
+
+
+    @RequestMapping(value = "/file/fileFeignDemo1",method = RequestMethod.POST)
+    String fileFeignDemo1( Map<String, String> map);
+}

+ 1 - 0
sckw-modules/pom.xml

@@ -16,6 +16,7 @@
         <module>sckw-system</module>
         <module>sckw-message</module>
         <module>sckw-example</module>
+        <module>sckw-file</module>
     </modules>
 
     <properties>

+ 14 - 2
sckw-modules/sckw-example/pom.xml

@@ -22,6 +22,12 @@
 
     <dependencies>
 
+        <dependency>
+            <groupId>com.sckw</groupId>
+            <artifactId>sckw-file</artifactId>
+            <version>1.0.0</version>
+        </dependency>
+
 
         <dependency>
             <groupId>com.sckw</groupId>
@@ -34,6 +40,13 @@
             <artifactId>sckw-common-datasource</artifactId>
             <version>1.0.0</version>
         </dependency>
+
+        <dependency>
+            <groupId>com.sckw</groupId>
+            <artifactId>sckw-common-elasticsearch</artifactId>
+            <version>1.0.0</version>
+        </dependency>
+
         <dependency>
             <groupId>com.sckw</groupId>
             <artifactId>sckw-common-excel</artifactId>
@@ -51,10 +64,9 @@
             <artifactId>sckw-system-api</artifactId>
             <version>1.0.0</version>
         </dependency>
-
         <dependency>
             <groupId>com.sckw</groupId>
-            <artifactId>sckw-common-stream</artifactId>
+            <artifactId>sckw-file-api</artifactId>
             <version>1.0.0</version>
         </dependency>
 

+ 70 - 0
sckw-modules/sckw-example/src/main/java/com/sckw/example/controller/EsController.java

@@ -0,0 +1,70 @@
+package com.sckw.example.controller;
+
+import com.sckw.elasticsearch.service.es.EsUtils;
+import com.sckw.example.model.Employees;
+import lombok.RequiredArgsConstructor;
+import org.apache.commons.compress.utils.Lists;
+import org.elasticsearch.action.search.SearchRequest;
+import org.elasticsearch.search.SearchHits;
+import org.elasticsearch.search.builder.SearchSourceBuilder;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * @author: yzc
+ * @date: 2023-06-06 14:40
+ * @description:easy-es测试
+ */
+@RestController
+@RequestMapping("/testEs")
+@RequiredArgsConstructor
+public class EsController {
+
+
+    @GetMapping(value = "/createIndex")
+    public void createIndex() {
+        String mappings = "{\n" +
+                "  \"properties\": {\n" +
+                "    \"id\": {\n" +
+                "      \"type\": \"keyword\"\n" +
+                "    },\n" +
+                "    \"name\": {\n" +
+                "      \"type\": \"text\"\n" +
+                "    }\n" + "  }\n" +
+                "}";
+        System.out.println("mapping is as follows: ");
+        System.out.println(mappings);
+
+        EsUtils.createIndex("test", mappings);
+    }
+
+
+    @GetMapping(value = "/deleteIndex")
+    public void deleteIndex() {
+        EsUtils.deleteIndex("test");
+    }
+
+    @GetMapping(value = "/bulkSave")
+    public void bulkSave() {
+        List<Employees> list = Lists.newArrayList();
+        Employees nancy = Employees.builder().id("2").name("Nancy").build();
+        Employees jason = Employees.builder().id("3").name("Jason").build();
+        list.add(nancy);
+        list.add(jason);
+        EsUtils.bulkSave("test", list);
+
+    }
+
+    @GetMapping(value = "/search")
+    public void search() {
+        SearchRequest request = new SearchRequest("test");
+        SearchSourceBuilder builder = new SearchSourceBuilder();
+        request.source(builder);
+        SearchHits hits = EsUtils.boolSearch(request);
+        System.out.println(hits);
+    }
+}

+ 131 - 0
sckw-modules/sckw-example/src/main/java/com/sckw/example/controller/FileApiController.java

@@ -0,0 +1,131 @@
+package com.sckw.example.controller;
+
+import com.sckw.core.web.response.HttpResult;
+import com.sckw.example.service.FileService;
+import com.sckw.file.api.dubbo.FileApiDubboService;
+import com.sckw.file.api.feign.FileApiFeignService;
+import lombok.AllArgsConstructor;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author lfdc
+ * @version 1.0
+ * @className FileApiController
+ * @description alibaba-oss测试用例
+ * z
+ * @company sckw
+ * @date 2023-06-02 16:06:43
+ */
+@RestController
+@RequestMapping("/file")
+@AllArgsConstructor
+public class FileApiController {
+
+    @Autowired
+    private FileApiFeignService fileApiFeignService;
+
+    @DubboReference(version = "2.0.0", group = "design", check = false)
+    private FileApiDubboService fileApiDubboService;
+
+    @Autowired
+    private FileService fileService;
+
+    /**
+     * 上传文件至OSS
+     *
+     * @param file
+     * @return
+     */
+    @RequestMapping(value = "/fileUpload", method = RequestMethod.POST)
+    public HttpResult fileUpload(@RequestParam("file") MultipartFile file) {
+        //获取上传文件
+        String url = fileService.uploadFile(file);
+        return HttpResult.ok(url);
+
+    }
+
+    /**
+     * OSS下载文件/获取文件地址
+     *
+     * @return
+     */
+    @GetMapping("/fileDownload")
+    public HttpResult fileDownload() {
+        String fileName = "测试=JPEG.webp";
+        //获取上传文件
+        String url = fileService.fileDownload(fileName);
+        return HttpResult.ok(url);
+    }
+
+
+    /**
+     * 基于feign调用
+     *
+     * @param file
+     * @return
+     */
+    @RequestMapping (value = "/fileFeignUpload",method = RequestMethod.POST)
+    public HttpResult fileFeignUpload(@RequestParam("file") MultipartFile file) {
+        //example 服务 调用 file服务提供的feign接口
+        HttpResult result = fileApiFeignService.fileFeignUpload(file);
+        return result;
+    }
+
+    /**
+     * 基于feign调用
+     *
+     * @param
+     * @return
+     */
+    @RequestMapping (value = "/fileFeignDemo",method = RequestMethod.GET)
+    //@RequestParam("file") MultipartFile file
+    public String fileFeignDemo() {
+        //example 服务 调用 file服务提供的feign接口
+        return fileApiFeignService.fileFeignDemo("userName");
+    }
+
+    /**
+     * 基于feign调用
+     *
+     * @param
+     * @return
+     */
+    @RequestMapping (value = "/fileFeignDemo1",method = RequestMethod.POST)
+    public String fileFeignDemo1() {
+       Map<String, String> map = new HashMap<>();
+        map.put("123","456");
+        map.put("asd","asd");
+        return fileApiFeignService.fileFeignDemo1(map);
+    }
+
+
+    /**
+     * 基于dubbo调用
+     *
+     * @param file
+     * @return
+     */
+    @GetMapping("fileDubboUpload")
+    public HttpResult fileDubboUpload(@RequestParam("file") MultipartFile file) throws IOException {
+        // 调用 file服务提供的dubbo接口
+        //需要将文件转换成byte否则为空
+        //获取文件类型
+        String contentType = file.getContentType();
+        //获取上传文件的原始文件名
+        String oFileName = file.getOriginalFilename();
+        //把文件转化成byte[]
+        byte[] bytes = file.getBytes();
+
+        HttpResult result = fileApiDubboService.fileUpload(contentType,oFileName,bytes);
+        return result;
+    }
+
+
+}

+ 24 - 0
sckw-modules/sckw-example/src/main/java/com/sckw/example/dubbo/FileServiceImpl.java

@@ -0,0 +1,24 @@
+package com.sckw.example.dubbo;
+
+import com.sckw.core.web.response.HttpResult;
+import com.sckw.file.api.dubbo.FileApiDubboService;
+import org.apache.dubbo.config.annotation.DubboService;
+
+/**
+ * @author lfdc
+ * @version 1.0
+ * @className FileServiceImpl
+ * @description 实现File的dubbo实现类
+ * @company sckw
+ * @date 2023-06-06 10:06:31
+ */
+@DubboService(group = "design", version = "2.0.0")
+public class FileServiceImpl implements FileApiDubboService {
+
+
+    @Override
+    public HttpResult fileUpload(String contentType, String oFileName, byte[] bytes) {
+        System.out.println("文件类型"+contentType+"文件名称"+oFileName+"文件输出流"+bytes);
+        return HttpResult.ok();
+    }
+}

+ 13 - 0
sckw-modules/sckw-example/src/main/java/com/sckw/example/feign/FileApiFeignServiceImpl.java

@@ -0,0 +1,13 @@
+package com.sckw.example.feign;
+
+/**
+ * @author lfdc
+ * @version 1.0
+ * @className FileApiFeignServiceImpl
+ * @description file文件feign实现类
+ * @company sckw
+ * @date 2023-06-06 10:06:52
+ */
+public class FileApiFeignServiceImpl {
+
+}

+ 23 - 0
sckw-modules/sckw-example/src/main/java/com/sckw/example/model/Employees.java

@@ -0,0 +1,23 @@
+package com.sckw.example.model;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * @author: yzc
+ * @date: 2023-06-07 10:26
+ * @description:
+ */
+@Getter
+@Setter
+@ToString
+@Builder
+public class Employees {
+
+    private String id;
+
+    private String name;
+
+}

+ 45 - 0
sckw-modules/sckw-example/src/main/java/com/sckw/example/service/FileService.java

@@ -0,0 +1,45 @@
+package com.sckw.example.service;
+
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+
+/**
+ * @author lfdc
+ * @version 1.0
+ * @className FileService
+ * @description 文件上传下载service
+ * @company sckw
+ * @date 2023-06-02 16:06:46
+ */
+@Slf4j
+@Service
+public class FileService {
+
+
+    /**
+     * 上传文件至OSS
+     *
+     * @param file
+     * @return
+     */
+    public String uploadFile(MultipartFile file) {
+        //
+//        String url = FileUtils.uploadFile(file, FileEnum.DOCUMENT_ADDRESS);
+        //
+        return "url";
+    }
+
+
+    /**
+     * OSS下载文件/获取文件地址
+     *
+     * @return
+     */
+    public String fileDownload(String fileName) {
+//        FileUtils.downloadByObjectName(RequestHolder.getResponse(),fileName);
+        return null;
+    }
+}

+ 87 - 0
sckw-modules/sckw-file/pom.xml

@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>sckw-modules</artifactId>
+        <groupId>com.sckw</groupId>
+        <version>1.0.0</version>
+    </parent>
+
+<!--    <groupId>com.sckw</groupId>-->
+    <artifactId>sckw-file</artifactId>
+    <version>1.0.0</version>
+    <description>文件服务</description>
+
+    <properties>
+        <maven.compiler.source>17</maven.compiler.source>
+        <maven.compiler.target>17</maven.compiler.target>
+        <maven.compiler.compilerVersion>17</maven.compiler.compilerVersion>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+
+    <dependencies>
+
+        <dependency>
+            <groupId>com.sckw</groupId>
+            <artifactId>sckw-common-remote</artifactId>
+            <version>1.0.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.sckw</groupId>
+            <artifactId>sckw-common-datasource</artifactId>
+            <version>1.0.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.sckw</groupId>
+            <artifactId>sckw-common-redis</artifactId>
+            <version>1.0.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.sckw</groupId>
+            <artifactId>sckw-system-api</artifactId>
+            <version>1.0.0</version>
+        </dependency>
+
+        <!--alibaba oss-->
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alicloud-oss</artifactId>
+            <version>2.2.0.RELEASE</version>
+        </dependency>
+<!--        <dependency>-->
+<!--            <groupId>com.aliyun.oss</groupId>-->
+<!--            <artifactId>aliyun-sdk-oss</artifactId>-->
+<!--            <version>3.8.0</version>-->
+<!--            <scope>compile</scope>-->
+<!--        </dependency>-->
+        <!--jdk9+ 以上需要手动添加-->
+        <dependency>
+            <groupId>javax.xml.bind</groupId>
+            <artifactId>jaxb-api</artifactId>
+            <version>2.3.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <!--注册中心客户端-->
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+        </dependency>
+        <!--配置中心客户端-->
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-bootstrap</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

+ 33 - 0
sckw-modules/sckw-file/src/main/java/com/sckw/file/FileApplication.java

@@ -0,0 +1,33 @@
+package com.sckw.file;
+
+
+import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+
+/**
+ * @author lfdc
+ * @version 1.0
+ * @className FileApplication
+ * @description 文件上传下载启动类
+ * @company sckw
+ * @date 2023-06-02 17:06:43
+ */
+@EnableDubbo
+@EnableFeignClients({"com.sckw.*.api.feign"})
+@EnableDiscoveryClient
+@SpringBootApplication
+public class FileApplication {
+
+    public static void main(String[] args) {
+        // 关闭nacos日志
+        System.setProperty("nacos.logging.default.config.enabled", "false");
+        try {
+            SpringApplication.run(FileApplication.class, args);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 67 - 0
sckw-modules/sckw-file/src/main/java/com/sckw/file/common/enums/AliyunOssFileTypeEnum.java

@@ -0,0 +1,67 @@
+package com.sckw.file.common.enums;
+
+/**
+ * @author lfdc
+ * @version 1.0
+ * @className AliyunOssFileTypeEnum
+ * @description 阿里云文件类型
+ * @company sckw
+ * @date 2023-06-05 13:06:54
+ */
+public enum AliyunOssFileTypeEnum {
+    BMP(".bmp","image/bmp"),
+    GIF(".gif","image/gif"),
+    JPEG(".jpeg","image/jpeg"),
+    JPG(".jpg","image/jpeg"),
+    PNG(".png","image/jpeg"),
+    HTML(".html","text/html"),
+    XML(".xml","text/xml"),
+    TXT(".txt","application/octet-stream"),
+    SQL(".sql","application/octet-stream"),
+    VSD(".vsd","application/vnd.visio"),
+    PDF(".pdf","application/pdf"),
+    PPT(".ppt","application/vnd.ms-powerpoint"),
+    PPTX(".pptx","application/vnd.ms-powerpoint"),
+    DOC(".doc","application/msword"),
+    DOCX(".docx","application/msword"),
+    XLS(".xls","application/vnd.ms-excel"),
+    XLSX(".xlsx","application/vnd.ms-excel"),
+    CSV(".csv","application/vnd.ms-excel");
+
+
+    String code;
+
+
+    String text;
+
+
+    AliyunOssFileTypeEnum() {
+    }
+
+
+    AliyunOssFileTypeEnum(String code, String text) {
+        this.code = code;
+        this.text = text;
+    }
+
+
+    public String getCode() {
+        return code;
+    }
+
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+
+    public String getText() {
+        return text;
+    }
+
+
+    public void setText(String text) {
+        this.text = text;
+    }
+
+}

+ 76 - 0
sckw-modules/sckw-file/src/main/java/com/sckw/file/common/enums/FileEnum.java

@@ -0,0 +1,76 @@
+package com.sckw.file.common.enums;
+/**
+ * @author lfdc
+ * @version 1.0
+ * @className FileEnum
+ * @description 文件上传保存地址
+ * @company sckw
+ * @date 2023-06-02 16:06:43
+ */
+public enum FileEnum {
+
+
+    /**
+     * 本地存储地址
+     */
+    Local_Address("1","/image", "本地上传保存地址"),
+    /**
+     * 用户存储地址
+     */
+    User_Address("2","/user", "用户存储地址"),
+    /**
+     * 企业存储地址
+     */
+    Enterprise_Address("3","/enterprise", "企业存储地址"),
+    /**
+     * 合同存储地址
+     */
+    CONTRACT_ADDRESS("4","/contract", "合同存储地址"),
+    /**
+     * 文件存储地址
+     */
+    DOCUMENT_ADDRESS("5","/excel", "文件存储地址"),;
+//    /**
+//     * 腾讯云的 OSS
+//     */
+//    TENCENT(4, RegionTencent.values()),
+//    /**
+//     * 百度云的OSS
+//     */
+//    BAIDU(5, RegionBaiDu.values()),
+
+    private final String fileType;
+    private final String fileAddress;
+    private final String fileDescription;
+
+    public String getFileType() {
+        return fileType;
+    }
+
+    public String getFileAddress() {
+        return fileAddress;
+    }
+
+    public String getFileDescription() {
+        return fileDescription;
+    }
+
+    FileEnum(String fileType, String fileAddress, String fileDescription) {
+        this.fileType = fileType;
+        this.fileAddress = fileAddress;
+        this.fileDescription = fileDescription;
+    }
+
+
+
+
+    public static String getValue(String fileType) {
+        for (FileEnum ele : FileEnum.values()) {
+            if (ele.getFileType().equals(fileType)) {
+                return ele.getFileAddress();
+            }
+        }
+        return null;
+    }
+
+}

+ 108 - 0
sckw-modules/sckw-file/src/main/java/com/sckw/file/controller/FileApiController.java

@@ -0,0 +1,108 @@
+package com.sckw.file.controller;
+
+import com.sckw.core.web.response.HttpResult;
+import com.sckw.file.service.FileService;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.Map;
+
+/**
+ * @author lfdc
+ * @version 1.0
+ * @className FileApiController
+ * @description alibaba-oss测试用例
+ *
+ * @company sckw
+ * @date 2023-06-02 16:06:43
+ */
+@Slf4j
+@RestController
+@RequestMapping("/file")
+@AllArgsConstructor
+public class FileApiController {
+
+    @Autowired
+    private FileService fileService;
+
+    /**
+     * 上传文件至OSS
+     *
+     * @param file
+     * @return
+     */
+    @RequestMapping(value = "/fileUpload", method = RequestMethod.POST)
+    public HttpResult fileUpload(@RequestParam("file") MultipartFile file) {
+        //获取上传文件
+//        String url = fileService.uploadFile(file);
+        return fileService.uploadFile(file);
+
+    }
+
+    /**
+     * feign接收上传文件至OSS
+     *
+     * @param file
+     * @return
+     */
+    @RequestMapping(value = "/fileFeignUpload", method = RequestMethod.POST)
+    public HttpResult fileFeignUpload(@RequestParam("file") MultipartFile file) {
+        //获取上传文件
+//        String url = fileService.uploadFile(file);
+        return fileService.uploadFile(file);
+
+    }
+
+    /**
+     * 上传文件至OSS
+     *
+     * @param file
+     * @return
+     */
+    @RequestMapping(value = "/fileUploadList", method = RequestMethod.POST)
+    public HttpResult uploadFileList(@RequestParam("file") MultipartFile[] file) {
+        //获取上传文件
+//        String url = fileService.uploadFile(file);
+        return fileService.uploadFileList(file);
+
+    }
+
+    /**
+     * OSS下载文件/获取文件地址
+     * @return
+     */
+    @GetMapping("/fileDownload")
+    public HttpResult fileDownload() {
+//        String fileName = "https://kaiwu-saas.oss-cn-chengdu.aliyuncs.com/kll/uploads/20230605/146288830649995264测试=JPEG.webp";
+//        String fileName = "https://kaiwu-saas.oss-cn-chengdu.aliyuncs.com/kll/uploads/20230605/146325493677821952598454132.jpg";
+        String fileName = "https://kaiwu-saas.oss-cn-chengdu.aliyuncs.com/kll/uploads/20230605/14633197602917990420230605demo.txt";
+        //获取上传文件
+        fileService.fileDownload(fileName);
+        return HttpResult.ok();
+    }
+
+    /**
+     * file-feign-demo
+     * @param userName
+     * @return
+     */
+    @GetMapping(value = "/fileFeignDemo")
+    public HttpResult fileFeignDemo(@RequestParam("userName") String userName) {
+        return HttpResult.ok(userName);
+    }
+
+
+    /**
+     * file-feign-demo1
+     * @param map
+     * @return
+     */
+    @RequestMapping(value = "fileFeignDemo1",method = RequestMethod.POST)
+    public HttpResult fileFeignDemo1(@RequestBody Map<String, String> map) {
+        return HttpResult.ok(map);
+    }
+
+}

+ 129 - 0
sckw-modules/sckw-file/src/main/java/com/sckw/file/service/FileService.java

@@ -0,0 +1,129 @@
+package com.sckw.file.service;
+
+
+import com.sckw.core.utils.StringUtils;
+import com.sckw.core.web.constant.HttpStatus;
+import com.sckw.core.web.response.HttpResult;
+import com.sckw.file.common.enums.FileEnum;
+import com.sckw.file.utils.FileUtils;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+import org.springframework.util.ObjectUtils;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.*;
+
+
+/**
+ * @author lfdc
+ * @version 1.0
+ * @className FileService
+ * @description 文件上传下载service
+ * @company sckw
+ * @date 2023-06-02 16:06:46
+ */
+@Service
+public class FileService {
+    /**
+     * 上传文件至OSS
+     *
+     * @param file
+     * @return
+     */
+    public HttpResult uploadFile(@RequestParam("file") MultipartFile file) {
+        HttpResult result = new HttpResult();
+        List<Map<String,Object>> resultList=new ArrayList<>();
+        result.setCode(HttpStatus.SUCCESS_CODE);
+        boolean isEmpty = file.isEmpty();
+        if (isEmpty) {
+            result.setCode(HttpStatus.GLOBAL_EXCEPTION_CODE);
+            result.setMsg("上传请选择文件");
+        }
+        //文件大小
+        String fileSize = FileUtils.getFileSize(file);
+        //文件名称
+        String originalFilename = file.getOriginalFilename();
+        String url = FileUtils.uploadFile(file, FileEnum.DOCUMENT_ADDRESS);
+        //上传至oss文件地址
+        if (StringUtils.isNotBlank(url)){
+            String oosUrl = url;
+            result.setCode(HttpStatus.SUCCESS_CODE);
+            result.setMsg("上传成功");
+
+            Map<String, Object> map = new HashMap<>();
+            map.put("fileKey",url);
+            map.put("fileName",originalFilename);
+            resultList.add(map);
+            result.setData(resultList);
+        }else {
+            result.setCode(HttpStatus.GLOBAL_EXCEPTION_CODE);
+            result.setMsg("上传请选择文件");
+        }
+        return result;
+    }
+
+
+    /**
+     * 批量上传文件至OSS
+     *
+     * @param file
+     * @return
+     */
+    @Async
+    public HttpResult uploadFileList( MultipartFile[] file) {
+        HttpResult result = new HttpResult();
+        List<Map<String, Object>> resultList = new ArrayList<>();
+        if (!ObjectUtils.isEmpty(file) && file.length > 0) {
+            List<MultipartFile> multipartFiles = Arrays.asList(file);
+            for (MultipartFile multipartFile : multipartFiles) {
+                Map<String, Object> map = new HashMap<>();
+                //文件大小
+                String fileSize = FileUtils.getFileSize(multipartFile);
+                //文件名称
+                String originalFilename = multipartFile.getOriginalFilename();
+                map.put("code", HttpStatus.SUCCESS_CODE);
+                map.put("fileName", originalFilename);
+                map.put("message", HttpStatus.SUCCESS_MESSAGE);
+                String url = null;
+                //上传文件是否成功
+                try {
+                    url = FileUtils.uploadFile(multipartFile, FileEnum.DOCUMENT_ADDRESS);
+                } catch (Exception e) {
+                    map.put("code", HttpStatus.GLOBAL_EXCEPTION_CODE);
+                    map.put("fileName", originalFilename);
+                    map.put("message", e);
+                }
+                if (StringUtils.isBlank(url)) {
+                    map.put("code", HttpStatus.GLOBAL_EXCEPTION_CODE);
+                    map.put("fileName", originalFilename);
+                    map.put("message", HttpStatus.SUCCESS_MESSAGE);
+                }
+                //上传至oss文件地址
+                String oosUrl = url;
+                resultList.add(map);
+            }
+        } else {
+            result.setCode(HttpStatus.GLOBAL_EXCEPTION_CODE);
+            result.setMsg("上传选择文件为空");
+        }
+        result.setData(resultList);
+        return result;
+    }
+
+
+    /**
+     * OSS下载文件/获取文件地址
+     *
+     * @return
+     */
+    public void fileDownload(String fileName) {
+        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
+//        FileUtils.downloadByUrl(response,fileName);
+        FileUtils.downOSSFile(fileName,response);
+//        FileUtils.downloadByFileName(fileName);
+    }
+}

+ 660 - 0
sckw-modules/sckw-file/src/main/java/com/sckw/file/utils/FileUtils.java

@@ -0,0 +1,660 @@
+package com.sckw.file.utils;
+
+import cn.hutool.core.date.DateTime;
+import com.aliyun.oss.ClientException;
+import com.aliyun.oss.OSS;
+import com.aliyun.oss.OSSClientBuilder;
+import com.aliyun.oss.OSSException;
+import com.aliyun.oss.model.*;
+import com.sckw.core.utils.IdWorker;
+import com.sckw.core.utils.StringUtils;
+import com.sckw.file.common.enums.AliyunOssFileTypeEnum;
+import com.sckw.file.common.enums.FileEnum;
+import jakarta.annotation.PostConstruct;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.*;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.text.DecimalFormat;
+import java.util.Date;
+
+/**
+ * @author lfdc
+ * @version 1.0
+ * @className FileUtils
+ * @description Oss文件工具类
+ * @company sckw
+ * @date 2023-06-05 09:06:57
+ */
+@Slf4j
+@Component
+@Configuration
+public class FileUtils {
+
+    private static String BASE_DIR = "kll/uploads/";
+
+    //oss客户端连接
+    private static OSS ossclient = null;
+
+
+    private static String DEFAULT_ENDPOINT = "oss-cn-chengdu.aliyuncs.com";
+    private static String DEFAULT_ACCESS_KEY_ID = "LTAI5tPEbubCGq5Rdwygbz4Q";
+    private static String DEFAULT_ACCESS_KEY_SECRET = "7mQLWMaBJeZPRV1SRGogctYGXwppjQ";
+    private static String DEFAULT_BUCKET_NAME = "kaiwu-saas";
+
+    private static String endpoint;
+    private static String accessKeyId;
+    private static String accessKeySecret;
+    private static String bucketName;
+
+
+    @Value("${aliyun.oss.endpoint}")
+    private String oss_endpoint;
+
+    @Value("${aliyun.oss.accessKeyId}")
+    private String oss_accessKeyId;
+
+    @Value("${aliyun.oss.secret}")
+    private String oss_accessKeySecret;
+
+    @Value("${aliyun.oss.bucket}")
+    public String oss_bucketName;
+
+    @PostConstruct
+    public void setEndpoint() {
+        endpoint = this.oss_endpoint;
+    }
+
+    @PostConstruct
+    public void setAccessKeyId() {
+        accessKeyId = this.oss_accessKeyId;
+    }
+
+    @PostConstruct
+    public void setAccessKeySecret() {
+        accessKeySecret = this.oss_accessKeySecret;
+    }
+
+    @PostConstruct
+    public void setBucketName() {
+        bucketName = this.oss_bucketName;
+    }
+
+
+    /**
+     * 上传文件
+     * <p>
+     * kll/uploads/年月日/md5(file).xxx
+     *
+     * @param file
+     * @param fileEnum
+     * @return
+     */
+    public static String uploadFile(MultipartFile file, FileEnum fileEnum) {
+        try {
+            //创建OSSClient实例
+            defalutOSS();
+            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+
+            //容器不存在,就创建
+            if (!ossClient.doesBucketExist(bucketName)) {
+                ossClient.createBucket(bucketName);
+                CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
+                createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead);
+                ossClient.createBucket(createBucketRequest);
+            }
+            //上传文件流
+            InputStream inputStream = file.getInputStream();
+            String fileName = file.getOriginalFilename();
+            //生成随机唯一值,使用uuid,添加到文件名称里面
+            long uuid = new IdWorker(1).nextId();
+            fileName = String.valueOf(uuid) + fileName;
+            //按照当前日期,创建文件夹,上传到创建文件夹里面
+            //2021/02/02/01.jpgossClient = {OSSClient@13049}
+            String timeUrl = new DateTime().toString("yyyyMMdd");
+            fileName = timeUrl + "/" + fileName;
+            String filePath = BASE_DIR + fileName;
+            //调用方法实现上传
+            ossClient.putObject(bucketName, filePath, inputStream);
+            //上传后的文件地址
+//            String url1 = getUrl(ossClient, bucketName, filePath);
+//            System.out.println(url1);
+            //关闭OSSClient。
+            ossClient.shutdown();
+            //上传之后文件路径
+            //https://yygh-atguigu.oss-cn-beijing.aliyuncs.com/01.jpg
+            String url = "https://" + bucketName + "." + endpoint + "/" + filePath;
+            //返回 上传文件地址
+            return url;
+        } catch (IOException e) {
+            e.printStackTrace();
+            log.error("oss-upload-file-error:{}", e.getMessage(), e);
+            return null;
+        }
+    }
+
+    private static void defalutOSS() {
+        if (StringUtils.isBlank(endpoint)) {
+            endpoint = DEFAULT_ENDPOINT;
+        }
+        if (StringUtils.isBlank(accessKeyId)) {
+            accessKeyId = DEFAULT_ACCESS_KEY_ID;
+        }
+        if (StringUtils.isBlank(accessKeySecret)) {
+            accessKeySecret = DEFAULT_ACCESS_KEY_SECRET;
+        }
+        if (StringUtils.isBlank(bucketName)) {
+            bucketName = DEFAULT_BUCKET_NAME;
+        }
+    }
+
+
+    /**
+     * 获取文件上传大小
+     *
+     * @param file
+     * @return
+     */
+    public static String getFileSize(MultipartFile file) {
+        long size = file.getSize();
+        DecimalFormat df = new DecimalFormat("#.00");
+        String fileSizeString;
+        if (size < 1024) {
+            fileSizeString = df.format((double) size) + "B";
+        } else if (size < 1048576) {
+            fileSizeString = df.format((double) size / 1024) + "KB";
+        } else if (size < 1073741824) {
+            fileSizeString = df.format((double) size / 1048576) + "MB";
+        } else {
+            fileSizeString = df.format((double) size / 1073741824) + "GB";
+        }
+        return fileSizeString;
+    }
+
+    /**
+     * 获得阿里云OSS客户端对象
+     *
+     * @param ossEndpoint
+     * @param accessId
+     * @param accessKey
+     * @return
+     */
+    public static OSS getOssClient(String ossEndpoint, String accessId, String accessKey) {
+        if (ossclient == null) {
+            ossclient = new OSSClientBuilder().build(ossEndpoint, accessId, accessKey);
+        }
+        return ossclient;
+    }
+
+    /**
+     * 通过文件名判断并获取OSS服务文件上传时文件的contentType
+     *
+     * @param fileName 文件名
+     * @return 文件的contentType
+     */
+    public static String getContentType(String fileName) {
+        // 文件的后缀名
+        String fileExtension = fileName.substring(fileName.lastIndexOf("."));
+        log.info("getContentType->fileName={},fileExtension={}", fileName, fileExtension);
+        for (AliyunOssFileTypeEnum e : AliyunOssFileTypeEnum.values()) {
+            if (e.getCode().equalsIgnoreCase(fileExtension)) {
+                return e.getText();
+            }
+        }
+        // 默认返回类型
+        return AliyunOssFileTypeEnum.TXT.getText();
+    }
+
+    public static void downOSSFile(String fileName, HttpServletResponse response) {
+        BufferedInputStream input = null;
+        OutputStream outputStream = null;
+        defalutOSS();
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+//        OSSObject ossObject = ossClient.getObject(bucketName, folder + fileName);
+        OSSObject ossObject = ossClient.getObject(bucketName, fileName);
+        try {
+            response.reset();
+            response.setCharacterEncoding("utf-8");
+            response.setContentType("application/x-msdownload");
+            response.addHeader("Content-Disposition",
+                    "attachment;filename=" + new String(fileName.getBytes("gb2312"), "ISO8859-1"));
+
+            input = new BufferedInputStream(ossObject.getObjectContent());
+            byte[] buffBytes = new byte[1024];
+            outputStream = response.getOutputStream();
+            int read = 0;
+            while ((read = input.read(buffBytes)) != -1) {
+                outputStream.write(buffBytes, 0, read);
+            }
+            outputStream.flush();
+            // 数据读取完成后,获取的流必须关闭,否则会造成连接泄漏,导致请求无连接可用,程序无法正常工作。
+            ossObject.close();
+        } catch (IOException ex) {
+            ex.printStackTrace();
+        } finally {
+            try {
+                if (outputStream != null) {
+                    outputStream.close();
+                }
+                if (input != null) {
+                    input.close();
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        ossClient.shutdown();
+    }
+
+
+    /**
+     * 通过文件名字下载
+     *
+     * @param response response
+     * @param fileName 文件名字,带后缀,例子:postman.txt 文件全路径 https://kaiwu-saas.oss-cn-chengdu.aliyuncs.com/kll/uploads/20230605/146325493677821952598454132.txt
+     */
+    public static void downloadByFileName(HttpServletResponse response, String fileName) {
+        defalutOSS();
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+        OSSObject ossObject = ossClient.getObject(bucketName, fileName);
+        String contentType = ossObject.getObjectMetadata().getContentType();
+        String contentType1 = getContentType(fileName);
+        System.out.println("contentType:" + contentType);
+        System.out.println("contentType1:" + contentType1);
+        //设置响应内容类型,当设置了ContentType为“image/jpg”时,浏览器可以直接显示图片;
+        response.setContentType(contentType);
+        BufferedInputStream in = new BufferedInputStream(ossObject.getObjectContent());
+        try {
+            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
+            //通知浏览器以附件形式下载
+            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8"));
+            byte[] car = new byte[1024];
+            int len = 0;
+            while ((len = in.read(car)) != -1) {
+                out.write(car, 0, len);
+            }
+            out.flush();
+            out.close();
+            in.close();
+            ossClient.shutdown();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 创建存储空间
+     *
+     * @param ossClient  OSS连接
+     * @param bucketName 存储空间
+     * @return
+     */
+    public static String createBucketName(OSS ossClient, String bucketName) {
+        // 存储空间
+        final String bucketNames = bucketName;
+        if (!ossClient.doesBucketExist(bucketName)) {
+            // 创建存储空间
+            Bucket bucket = ossClient.createBucket(bucketName);
+            log.info("创建存储空间成功");
+            return bucket.getName();
+        }
+        return bucketNames;
+    }
+
+
+    /**
+     * 删除存储空间bucketName
+     *
+     * @param ossClient  oss对象
+     * @param bucketName 存储空间
+     */
+    public static void deleteBucket(OSS ossClient, String bucketName) {
+        ossClient.deleteBucket(bucketName);
+        log.info("删除" + bucketName + "Bucket成功");
+    }
+
+
+    /**
+     * 创建模拟文件夹:多级目录
+     *
+     * @param ossClient  oss连接
+     * @param bucketName 存储空间
+     * @param folder     模拟文件夹名如"upload/2023/01/11/"
+     * @return 文件夹名
+     */
+    public static String createFolder(OSS ossClient, String bucketName, String folder) {
+        // 文件夹名
+        final String keySuffixWithSlash = folder;
+        // 判断文件夹是否存在,不存在则创建
+        if (!ossClient.doesObjectExist(bucketName, keySuffixWithSlash)) {
+            // 创建文件夹
+            ossClient.putObject(bucketName, keySuffixWithSlash, new ByteArrayInputStream(new byte[0]));
+            log.info("创建文件夹成功");
+            // 得到文件夹名
+            OSSObject object = ossClient.getObject(bucketName, keySuffixWithSlash);
+            String fileDir = object.getKey();
+            return fileDir;
+        }
+        return keySuffixWithSlash;
+    }
+
+
+    /**
+     * 根据key删除OSS服务器上的文件
+     *
+     * @param ossClient  oss连接
+     * @param bucketName 存储空间
+     * @param key        Bucket下的文件的路径名+文件名 如:"upload/2023/01/11/cake.jpg"
+     */
+    public static void deleteObject(OSS ossClient, String bucketName, String key) {
+        ossClient.deleteObject(bucketName, key);
+        log.info("删除" + bucketName + "下的文件" + key + "成功");
+    }
+
+
+    /**
+     * 上传文件
+     *
+     * @param ossClient  oss连接
+     * @param bucketName 存储空间
+     * @param ossPath    上传文件相对路径+文件名如"upload/2023/01/11/cake.jpg"
+     * @param is         以输入流的形式上传文件
+     * @param fileName   上传文件后新文件名
+     * @return String 返回的唯一MD5数字签名
+     */
+    public static String uploadFileOss(OSS ossClient, String bucketName, String ossPath, InputStream is, String fileName) {
+        try {
+            // 文件大小
+            long fileSize = is.available();
+            // 创建上传Object的Metadata
+            ObjectMetadata metadata = new ObjectMetadata();
+            // 上传的文件的长度
+            metadata.setContentLength(is.available());
+            // 指定该Object被下载时的网页的缓存行为
+            metadata.setCacheControl("no-cache");
+            // 指定该Object下设置Header
+            metadata.setHeader("Pragma", "no-cache");
+            // 指定该Object被下载时的内容编码格式
+            metadata.setContentEncoding("utf-8");
+            // 文件的MIME,定义文件的类型及网页编码,决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成,
+            // 如果没有扩展名则填默认值application/octet-stream
+            metadata.setContentType(getContentType(fileName));
+            // 指定该Object被下载时的名称(指示MINME用户代理如何显示附加的文件,打开或下载,及文件名称)
+            metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte");
+            //上传文件到OSS时需要指定包含文件后缀在内的完整路径如ossPath="upload/2023/01/11/cake.jpg"
+            PutObjectResult putResult = ossClient.putObject(bucketName, ossPath, is, metadata);
+            // 解析结果
+            String resultStr = putResult.getETag();
+            log.info("唯一MD5数字签名:" + resultStr);
+            //上传文件后相对路径如"upload/2023/01/11/cake.jpg"
+            String path = ossPath;
+            return path;
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
+            return null;
+        }
+    }
+
+
+    /**
+     * 下载文件到本地
+     *
+     * @param ossClient     oss连接
+     * @param bucketName    存储空间
+     * @param key           Bucket下的文件的路径名+文件名 如:"upload/2023/01/11/cake.jpg"
+     * @param localFilePath 下载本地文件绝对路径如"C:\Users\Administrator\Desktop\oss-download\xxx.pdf"
+     */
+    public static void downloadFileOss(OSS ossClient, String bucketName, String key, String localFilePath) {
+        try {
+            //创建本地文件
+            File file = new File(localFilePath);
+            GetObjectRequest objectRequest = new GetObjectRequest(bucketName, key);
+            //下载OSS文件到本地文件,若指定的本地文件存在则覆盖,否则新建
+            ossClient.getObject(objectRequest, file);
+            log.info("下载文件到本地成功");
+        } catch (OSSException e) {
+            e.printStackTrace();
+        } catch (ClientException e) {
+            e.printStackTrace();
+        }
+    }
+
+
+    /**
+     * 获取上传文件对象
+     * 备注:最重要的是获取上传文件的输出流InputStream
+     *
+     * @param ossClient  oss连接
+     * @param bucketName 存储空间
+     * @param key        Bucket下的文件的路径名+文件名 如:"upload/2023/01/11/cake.jpg"
+     * @return
+     */
+    public static OSSObject getObject(OSS ossClient, String bucketName, String key) {
+        OSSObject object = null;
+        try {
+            object = ossClient.getObject(bucketName, key);
+            //文件大小
+            long fileSize = object.getObjectMetadata().getContentLength();
+            //文件相对路径
+            String ossPath = object.getKey();
+            //文件输入流
+            InputStream is = object.getObjectContent();
+            log.info("success to getObject,fileSize:" + fileSize + "\nossPath:" + ossPath + "\ninputStream:" + is);
+        } catch (OSSException e) {
+            e.printStackTrace();
+        } catch (ClientException e) {
+            e.printStackTrace();
+        }
+        return object;
+    }
+
+
+    /**
+     * 获取上传文件url
+     *
+     * @param ossClient  oss连接
+     * @param bucketName bucketName
+     * @param key        文件全路径
+     * @return
+     */
+    public static String getUrl(OSS ossClient, String bucketName, String key) {
+        //设置URl过期时间为99年:3600L*1000*24*365*99
+        Date expiration = new Date(new Date().getTime() + 3600l * 1000 * 24 * 365 * 99);
+        GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, key);
+        generatePresignedUrlRequest.setExpiration(expiration);
+        URL url = ossClient.generatePresignedUrl(generatePresignedUrlRequest);
+        String returnUrl = url.toString();
+        return returnUrl;
+    }
+
+
+    public static void downloadByFileName(String objectName) {
+        // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。关于其他Region对应的Endpoint信息,请参见访问域名和数据中心。
+//        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
+        // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
+//        String accessKeyId = "yourAccessKeyId";
+//        String accessKeySecret = "yourAccessKeySecret";
+        // 填写Bucket名称,例如examplebucket。
+//        String bucketName = "examplebucket";
+        // 填写Object完整路径,例如exampledir/exampleobject.txt。Object完整路径中不能包含Bucket名称。
+//        String objectName = "exampledir/exampleobject.txt";
+
+        // 创建OSSClient实例。
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+        try {
+            // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
+            OSSObject ossObject = ossClient.getObject(bucketName, objectName);
+            // 读取文件内容。
+            System.out.println("Object content:");
+            BufferedReader reader = new BufferedReader(new InputStreamReader(ossObject.getObjectContent()));
+            while (true) {
+                String line = reader.readLine();
+                if (line == null) break;
+
+                System.out.println("\n" + line);
+            }
+            // 数据读取完成后,获取的流必须关闭,否则会造成连接泄漏,导致请求无连接可用,程序无法正常工作。
+            reader.close();
+            // ossObject对象使用完毕后必须关闭,否则会造成连接泄漏,导致请求无连接可用,程序无法正常工作。
+            ossObject.close();
+
+        } catch (OSSException oe) {
+            System.out.println("Caught an OSSException, which means your request made it to OSS, "
+                    + "but was rejected with an error response for some reason.");
+            System.out.println("Error Message:" + oe.getErrorMessage());
+            System.out.println("Error Code:" + oe.getErrorCode());
+            System.out.println("Request ID:" + oe.getRequestId());
+            System.out.println("Host ID:" + oe.getHostId());
+        } catch (Throwable ce) {
+            System.out.println("Caught an ClientException, which means the client encountered "
+                    + "a serious internal problem while trying to communicate with OSS, "
+                    + "such as not being able to access the network.");
+            System.out.println("Error Message:" + ce.getMessage());
+        } finally {
+            if (ossClient != null) {
+                ossClient.shutdown();
+            }
+        }
+    }
+
+
+    /**
+     * 通过oss的完整key下载
+     *
+     * @param response   response
+     * @param objectName oss完整的key,例子:fj_wechat_web/public/postman.txt
+     */
+    public static void downloadByObjectName(HttpServletResponse response, String objectName) {
+//        String endpointStr = "http://" + endpoint + ".aliyuncs.com";
+        String endpointStr = "http://" + endpoint;
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+        OSSObject ossObject = ossClient.getObject(bucketName, objectName);
+
+        BufferedInputStream in = new BufferedInputStream(ossObject.getObjectContent());
+
+        try {
+            BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
+            //通知浏览器以附件形式下载
+            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("postman.txt", "utf-8"));
+
+            byte[] car = new byte[1024];
+            int len;
+            while ((len = in.read(car)) != -1) {
+                out.write(car, 0, len);
+            }
+            out.flush();
+            out.close();
+            in.close();
+            ossClient.shutdown();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 通过oss的完整key下载
+     *
+     * @param response response
+     * @param url      全路径的url地址
+     */
+    public static void downloadByUrl(HttpServletResponse response, String url) {
+        downloadByFileName(response, url);
+    }
+
+    /**
+     * 判断文件是否存在
+     *
+     * @param fileName 文件名:postman.txt
+     * @return true文件存在,false文件不存在
+     */
+    public boolean isExitByFileName(String fileName) {
+//        String endpointStr = "http://" + endpoint + ".aliyuncs.com";
+        String endpointStr = "http://" + endpoint;
+        OSS ossClient = new OSSClientBuilder().build(endpointStr, accessKeyId, accessKeySecret);
+        return ossClient.doesObjectExist(bucketName, BASE_DIR + fileName);
+    }
+
+    /**
+     * 判断文件是否存在
+     *
+     * @param url 能直接访问的完整url
+     * @return true文件存在,false文件不存在
+     */
+    public boolean isExitByUrl(String url) {
+        return isExitByFileName(getFileNameByUrl(url));
+    }
+
+    /**
+     * 通过url获取文件名
+     *
+     * @param url 能够直接访问的url
+     * @return 文件名:postman.txt
+     */
+    public static String getFileNameByUrl(String url) {
+        String[] split = url.split("/");
+        return split[split.length - 1];
+    }
+
+
+    // 测试
+    public static void main(String[] args) throws FileNotFoundException {
+        //阿里云OSS账号自行到阿里云官网申请
+        String ossEndpoint = "XXX";
+        String accessId = "XXX";
+        String accessKey = "XXX";
+        String bucketName = "test";
+        // 初始化OSSClient
+//        OSS ossClient = AliyunOSSClientUtil.getOssClient(ossEndpoint, accessId, accessKey);
+        OSS ossClient = FileUtils.getOssClient(ossEndpoint, accessId, accessKey);
+
+
+        //测试创建多级目录
+        /*String tmpDir = "upload/2023/01/11/";
+        String folder = createFolder(ossClient, bucketName, tmpDir);
+        System.out.println("folder:"+folder);*/
+
+
+        //测试删除文件
+        /*String key="upload/2023/01/11/xxx.pdf";
+        deleteObject(ossClient,bucketName,key);*/
+
+
+        //测试上传文件
+        /*String pathAndname = "C:\\Users\\Administrator\\Desktop\\测试文件上传\\xxx.pdf";
+        File file = new File(pathAndname);
+        //原始文件名:带后缀
+        String oldfilename = file.getName();
+        //新文件名:带后缀
+        String newfilename = "9065df0f3ab72419b36d2dec088e11d6.pdf";//可以自行生成随机唯一文件名
+        String newpath = "C:\\Users\\Administrator\\Desktop\\upload\\2023\\01\\11\\";
+        String ossPath = newpath + newfilename;
+        InputStream is = new FileInputStream(file);
+        String absolutePath = uploadFileOss(ossClient, bucketName, ossPath, is, newfilename);
+        System.out.println("absolutePath:"+absolutePath);*/
+
+
+        //测试获取文件url
+        /*String key="upload/2023/01/11/9065df0f3ab72419b36d2dec088e11d6.pdf";
+        String url = getUrl(ossClient, bucketName, key);
+        System.out.println("url:"+url);*/
+
+
+        //测试获取上传对象
+        /*String key = "upload/2023/01/11/9065df0f3ab72419b36d2dec088e11d6.pdf";
+        getObject(ossClient, bucketName, key);*/
+
+
+        //测试下载文件到本地
+        /*String key = "upload/2023/01/11/9065df0f3ab72419b36d2dec088e11d6.pdf";
+        String localFilePath = "C:\\Users\\Administrator\\Desktop\\oss-download\\xxx.pdf";
+        downloadFileOss(ossClient, bucketName, key, localFilePath);*/
+    }
+
+}

+ 5 - 0
sckw-modules/sckw-file/src/main/resouces/banner.txt

@@ -0,0 +1,5 @@
+====================================================================================================================
+
+                    欢迎使用 [sckw-file] 开物供应链服务平台-文件服务 - Powered By https://www.xxxx.com
+
+====================================================================================================================

+ 82 - 0
sckw-modules/sckw-file/src/main/resouces/bootstrap-dev.yml

@@ -0,0 +1,82 @@
+spring:
+  cloud:
+    nacos:
+      discovery:
+        # 服务注册地址
+        server-addr: 127.0.0.1:8848
+        # 命名空间
+        namespace: sckw-service-platform-dev
+        # 共享配置
+        group: sckw-service-platform
+      config:
+        # 配置中心地址
+        server-addr: 127.0.0.1:8848
+        # 配置文件格式
+        file-extension: yaml
+        # 命名空间
+        namespace: sckw-service-platform-dev
+        # 共享配置
+        group: sckw-service-platform
+    function:
+      definition: sckwSms;sckwMessage
+    stream:
+      bindings:
+        sckwSms-in-0:
+          destination: sckw-sms
+          content-type: application/json
+          default-binder: defaultRabbit
+          group: sckw
+        sckwSms-out-0:
+          destination: sckw-sms
+          content-type: application/json
+          default-binder: defaultRabbit
+          group: sckw
+        sckwMessage-in-0:
+          destination: sckw-message
+          content-type: application/json
+          default-binder: defaultRabbit
+          group: sckw
+        sckwMessage-out-0:
+          destination: sckw-message
+          content-type: application/json
+          default-binder: defaultRabbit
+          group: sckw
+      binders:
+        defaultRabbit:
+          type: rabbit
+          environment:
+            spring:
+              rabbitmq:
+                virtual-host: /
+                host: 39.104.134.114
+                port: 5672
+                username: wph
+                password: Yy123...
+#限制上传文件大小
+  servlet:
+    multipart:
+      max-file-size: 100MB
+      max-request-size: 100MB
+
+
+# dubbo
+dubbo:
+  application:
+    # 此处没有延用spring.application.name是因为当前项目本身也会注册到nacos中,如果dubbo也延用相同的名称,在nacos服务里会看到注册的producer-server服务数为2
+    name: file-dubbo-server
+  protocol:
+    name: dubbo
+    port: -1
+  registry:
+    # 配置dubbo的注册中心为nacos
+    address: nacos://${spring.cloud.nacos.discovery.server-addr}
+    group: ${spring.cloud.nacos.config.group}
+    protocol: nacos
+    #use-as-config-center: false
+    #use-as-metadata-center: false
+aliyun:
+  oss:
+    endpoint: oss-cn-chengdu.aliyuncs.com
+    accessKeyId: LTAI5tPEbubCGq5Rdwygbz4Q
+    secret: 7mQLWMaBJeZPRV1SRGogctYGXwppjQ
+    bucket: kaiwu-saas

+ 27 - 0
sckw-modules/sckw-file/src/main/resouces/bootstrap.yml

@@ -0,0 +1,27 @@
+server:
+  port: 10050
+
+spring:
+  application:
+    name: sckw-file
+  profiles:
+    active: ${DEPLOY_MODE:dev}
+  main:
+    allow-bean-definition-overriding: true
+# Spring
+dubbo:
+  application:
+    name: file-dubbo-server
+    # 该配置在producer-server中是没有的,但是在consumer这里要配置一下
+    # 如果不配置这个QOS的端口,它会延用dubbo自动生成的端口,在启动的时候,QOS注册就会提示该端口已经被使用的错误
+    # 虽然启动时有打印端口已经被使用的错误,但是依旧可以正常启动服务,并且dubbo也可以正常调用,但是为了解决启动报错还是加上这个端口
+    # 这个也是apache官方给出的解决方案,这个端口不能给-1,它不会自动找到一个可用的端口,给-1会报错,端口1-65535自己选择一个
+    qos-port: 3334
+  protocol:
+    name: dubbo
+    # port为-1表示自动找一个可用的端口
+    port: -1
+  registry:
+    address: nacos://${spring.cloud.nacos.discovery.server-addr}
+    group: ${spring.cloud.nacos.config.group}
+    protocol: nacos