3 Комити 037559fdf5 ... 5781e6ca7e

Аутор SHA1 Порука Датум
  tangsong 5781e6ca7e minio架包 пре 3 месеци
  tangsong 6c2494cc9f Merge branch 'dev' of http://101.36.160.140:21044/crk-java-qinghai/armyfoodSrcQh into dev пре 3 месеци
  tangsong f0b764368a minio上传 пре 3 месеци
30 измењених фајлова са 2403 додато и 6 уклоњено
  1. 18 6
      pom.xml
  2. 93 0
      src/main/java/com/unis/crk/file/controller/CommonCacheOperator.java
  3. 152 0
      src/main/java/com/unis/crk/file/controller/DevFileController.java
  4. 100 0
      src/main/java/com/unis/crk/file/entity/DevConfig.java
  5. 109 0
      src/main/java/com/unis/crk/file/entity/DevFile.java
  6. 38 0
      src/main/java/com/unis/crk/file/enums/DevFileBucketAuthEnum.java
  7. 43 0
      src/main/java/com/unis/crk/file/enums/DevFileEngineTypeEnum.java
  8. 25 0
      src/main/java/com/unis/crk/file/mapper/DevConfigMapper.java
  9. 25 0
      src/main/java/com/unis/crk/file/mapper/DevFileMapper.java
  10. 6 0
      src/main/java/com/unis/crk/file/mapper/mapping/DevConfigMapper.xml
  11. 6 0
      src/main/java/com/unis/crk/file/mapper/mapping/DevFileMapper.xml
  12. 35 0
      src/main/java/com/unis/crk/file/param/DevFileIdParam.java
  13. 36 0
      src/main/java/com/unis/crk/file/param/DevFileListParam.java
  14. 36 0
      src/main/java/com/unis/crk/file/param/DevFilePageParam.java
  15. 37 0
      src/main/java/com/unis/crk/file/provider/DevConfigApiProvider.java
  16. 74 0
      src/main/java/com/unis/crk/file/provider/DevFileApiProvider.java
  17. 38 0
      src/main/java/com/unis/crk/file/service/DevConfigService.java
  18. 98 0
      src/main/java/com/unis/crk/file/service/DevFileService.java
  19. 59 0
      src/main/java/com/unis/crk/file/service/impl/DevConfigServiceImpl.java
  20. 275 0
      src/main/java/com/unis/crk/file/service/impl/DevFileServiceImpl.java
  21. 63 0
      src/main/java/com/unis/crk/file/util/CommonDownloadUtil.java
  22. 50 0
      src/main/java/com/unis/crk/file/util/CommonException.java
  23. 42 0
      src/main/java/com/unis/crk/file/util/CommonExceptionEnum.java
  24. 37 0
      src/main/java/com/unis/crk/file/util/CommonProperties.java
  25. 64 0
      src/main/java/com/unis/crk/file/util/CommonResponseUtil.java
  26. 165 0
      src/main/java/com/unis/crk/file/util/CommonResult.java
  27. 86 0
      src/main/java/com/unis/crk/file/util/CommonServletUtil.java
  28. 30 0
      src/main/java/com/unis/crk/file/util/DevConfigApi.java
  29. 104 0
      src/main/java/com/unis/crk/file/util/DevFileApi.java
  30. 459 0
      src/main/java/com/unis/crk/file/util/DevFileMinIoUtil.java

+ 18 - 6
pom.xml

@@ -257,13 +257,25 @@ org.springframework.boot</groupId>-->
257 257
 			<version>2.3</version>
258 258
 		</dependency>
259 259
 		<dependency>
260
-			<groupId>minio</groupId>
260
+			<groupId>io.minio</groupId>
261 261
 			<artifactId>minio</artifactId>
262
-			<version>0.6.0.11</version>
263
-			<scope>system</scope>
264
-			<systemPath>
265
-				${project.basedir}/src/main/resources/lib/minio-6.0.11.jar
266
-			</systemPath>
262
+			<version>8.5.2</version>
263
+			<exclusions>
264
+				<exclusion>
265
+					<artifactId>okhttp</artifactId>
266
+					<groupId>com.squareup.okhttp3</groupId>
267
+				</exclusion>
268
+			</exclusions>
269
+		</dependency>
270
+		<dependency>
271
+			<groupId>com.squareup.okhttp3</groupId>
272
+			<artifactId>okhttp</artifactId>
273
+			<version>4.10.0</version>
274
+		</dependency>
275
+		<dependency>
276
+			<groupId>org.jetbrains.kotlin</groupId>
277
+			<artifactId>kotlin-stdlib</artifactId>
278
+			<version>1.3.70</version>
267 279
 		</dependency>
268 280
 		<dependency>
269 281
 			<groupId>autoconfigure</groupId>

+ 93 - 0
src/main/java/com/unis/crk/file/controller/CommonCacheOperator.java

@@ -0,0 +1,93 @@
1
+/*
2
+ * Copyright [2022] [https://www.xiaonuo.vip]
3
+ *
4
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
5
+ *
6
+ * 1.请不要删除和修改根目录下的LICENSE文件。
7
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
8
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
9
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
10
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
11
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
12
+ */
13
+package com.unis.crk.file.controller;
14
+
15
+import cn.hutool.core.collection.CollectionUtil;
16
+import cn.hutool.core.map.MapUtil;
17
+import cn.hutool.core.util.StrUtil;
18
+import org.springframework.data.redis.core.RedisTemplate;
19
+import org.springframework.stereotype.Component;
20
+
21
+import javax.annotation.Resource;
22
+import java.util.*;
23
+import java.util.concurrent.TimeUnit;
24
+import java.util.stream.Collectors;
25
+
26
+/**
27
+ * 通用Redis缓存操作器
28
+ *
29
+ * @author xuyuxiang
30
+ * @date 2022/6/21 16:00
31
+ **/
32
+@Component
33
+public class CommonCacheOperator {
34
+
35
+    /** 所有缓存Key的前缀 */
36
+    private static final String CACHE_KEY_PREFIX = "Cache:";
37
+
38
+    @Resource
39
+    private RedisTemplate<String, Object> redisTemplate;
40
+
41
+    public void put(String key, Object value) {
42
+        redisTemplate.boundValueOps(CACHE_KEY_PREFIX + key).set(value);
43
+    }
44
+
45
+    public void put(String key, Object value, long timeoutSeconds) {
46
+        redisTemplate.boundValueOps(CACHE_KEY_PREFIX + key).set(value, timeoutSeconds, TimeUnit.SECONDS);
47
+    }
48
+
49
+    public Object get(String key) {
50
+        return redisTemplate.boundValueOps(CACHE_KEY_PREFIX + key).get();
51
+    }
52
+
53
+    public void remove(String... key) {
54
+        ArrayList<String> keys = CollectionUtil.toList(key);
55
+        List<String> withPrefixKeys = keys.stream().map(i -> CACHE_KEY_PREFIX + i).collect(Collectors.toList());
56
+        redisTemplate.delete(withPrefixKeys);
57
+    }
58
+
59
+    public Collection<String> getAllKeys() {
60
+        Set<String> keys = redisTemplate.keys(CACHE_KEY_PREFIX + "*");
61
+        if (keys != null) {
62
+            // 去掉缓存key的common prefix前缀
63
+            return keys.stream().map(key -> StrUtil.removePrefix(key, CACHE_KEY_PREFIX)).collect(Collectors.toSet());
64
+        } else {
65
+            return CollectionUtil.newHashSet();
66
+        }
67
+    }
68
+
69
+    public Collection<Object> getAllValues() {
70
+        Set<String> keys = redisTemplate.keys(CACHE_KEY_PREFIX + "*");
71
+        if (keys != null) {
72
+            return redisTemplate.opsForValue().multiGet(keys);
73
+        } else {
74
+            return CollectionUtil.newArrayList();
75
+        }
76
+    }
77
+
78
+    public Map<String, Object> getAllKeyValues() {
79
+        Collection<String> allKeys = this.getAllKeys();
80
+        HashMap<String, Object> results = MapUtil.newHashMap();
81
+        for (String key : allKeys) {
82
+            results.put(key, this.get(key));
83
+        }
84
+        return results;
85
+    }
86
+
87
+    public void removeBatch(String pattern) {
88
+        Set<String> keys = redisTemplate.keys(CACHE_KEY_PREFIX + pattern);
89
+        if (keys != null) {
90
+            redisTemplate.delete(keys);
91
+        }
92
+    }
93
+}

+ 152 - 0
src/main/java/com/unis/crk/file/controller/DevFileController.java

@@ -0,0 +1,152 @@
1
+/*
2
+ * Copyright [2022] [https://www.xiaonuo.vip]
3
+ *
4
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
5
+ *
6
+ * 1.请不要删除和修改根目录下的LICENSE文件。
7
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
8
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
9
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
10
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
11
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
12
+ */
13
+package com.unis.crk.file.controller;
14
+
15
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
16
+import com.unis.crk.file.entity.DevFile;
17
+import com.unis.crk.file.enums.DevFileEngineTypeEnum;
18
+import com.unis.crk.file.param.DevFileIdParam;
19
+import com.unis.crk.file.param.DevFileListParam;
20
+import com.unis.crk.file.param.DevFilePageParam;
21
+import com.unis.crk.file.service.DevFileService;
22
+import com.unis.crk.file.util.CommonResult;
23
+import com.unis.crk.file.util.DevConfigApi;
24
+import io.swagger.annotations.Api;
25
+import io.swagger.annotations.ApiOperation;
26
+import org.springframework.http.MediaType;
27
+import org.springframework.validation.annotation.Validated;
28
+import org.springframework.web.bind.annotation.*;
29
+import org.springframework.web.multipart.MultipartFile;
30
+
31
+import javax.annotation.Resource;
32
+import javax.servlet.http.HttpServletResponse;
33
+import javax.validation.Valid;
34
+import javax.validation.constraints.NotEmpty;
35
+import java.io.IOException;
36
+import java.util.List;
37
+
38
+/**
39
+ * 文件控制器
40
+ *
41
+ * @author xuyuxiang
42
+ * @date 2022/2/23 18:26
43
+ **/
44
+@Api(tags = "文件控制器")
45
+@RestController
46
+@Validated
47
+public class DevFileController {
48
+
49
+    /** 默认文件引擎 */
50
+    private static final String SNOWY_SYS_DEFAULT_FILE_ENGINE_KEY = "SNOWY_SYS_DEFAULT_FILE_ENGINE";
51
+
52
+
53
+    @Resource
54
+    private DevFileService devFileService;
55
+
56
+
57
+
58
+
59
+
60
+
61
+
62
+    /**
63
+
64
+
65
+    /**
66
+     * MINIO文件上传,返回文件id
67
+     *
68
+     * @author xuyuxiang
69
+     * @date 2021/10/13 14:01
70
+     **/
71
+    @ApiOperation("上传MINIO文件返回id")
72
+    @PostMapping("/dev/file/uploadMinioReturnId")
73
+    public CommonResult<String> uploadMinioReturnId(@RequestPart("file") MultipartFile file) {
74
+        return CommonResult.data(devFileService.uploadReturnId(DevFileEngineTypeEnum.MINIO.getValue(), file));
75
+    }
76
+
77
+    /**
78
+     * MINIO文件上传,返回文件Url
79
+     *
80
+     * @author xuyuxiang
81
+     * @date 2021/10/13 14:01
82
+     **/
83
+    @ApiOperation("上传MINIO文件返回url")
84
+    @PostMapping("/dev/file/uploadMinioReturnUrl")
85
+    public CommonResult<String> uploadMinioReturnUrl(@RequestPart("file") MultipartFile file) {
86
+        return CommonResult.data(devFileService.uploadReturnUrl(DevFileEngineTypeEnum.MINIO.getValue(), file));
87
+    }
88
+
89
+
90
+
91
+    /**
92
+     * 获取文件分页列表
93
+     *
94
+     * @author xuyuxiang
95
+     * @date 2022/4/24 20:00
96
+     */
97
+    @ApiOperation("获取文件分页列表")
98
+    @GetMapping("/dev/file/page")
99
+    public CommonResult<Page<DevFile>> page(DevFilePageParam devFilePageParam) {
100
+        return CommonResult.data(devFileService.page(devFilePageParam));
101
+    }
102
+
103
+    /**
104
+     * 获取文件列表
105
+     *
106
+     * @author xuyuxiang
107
+     * @date 2022/4/24 20:00
108
+     */
109
+    @ApiOperation("获取文件列表")
110
+    @GetMapping("/dev/file/list")
111
+    public CommonResult<List<DevFile>> list(DevFileListParam devFileListParam) {
112
+        return CommonResult.data(devFileService.list(devFileListParam));
113
+    }
114
+
115
+    /**
116
+     * 下载文件
117
+     *
118
+     * @author xuyuxiang
119
+     * @date 2022/6/21 15:44
120
+     **/
121
+    @ApiOperation("下载文件")
122
+    @GetMapping(value = "/dev/file/download", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
123
+    public void download(@Valid DevFileIdParam devFileIdParam, HttpServletResponse response) throws IOException {
124
+        devFileService.download(devFileIdParam, response);
125
+    }
126
+
127
+    /**
128
+     * 删除文件
129
+     *
130
+     * @author xuyuxiang
131
+     * @date 2022/4/24 20:00
132
+     */
133
+    @ApiOperation("删除文件")
134
+    @PostMapping(value = "/dev/file/delete")
135
+    public CommonResult<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
136
+                                               List<DevFileIdParam> devFileIdParamList) {
137
+        devFileService.delete(devFileIdParamList);
138
+        return CommonResult.ok();
139
+    }
140
+
141
+    /**
142
+     * 获取文件详情
143
+     *
144
+     * @author xuyuxiang
145
+     * @date 2022/6/21 15:44
146
+     **/
147
+    @ApiOperation("获取文件详情")
148
+    @GetMapping("/dev/file/detail")
149
+    public CommonResult<DevFile> detail(@Valid DevFileIdParam devFileIdParam) {
150
+        return CommonResult.data(devFileService.detail(devFileIdParam));
151
+    }
152
+}

+ 100 - 0
src/main/java/com/unis/crk/file/entity/DevConfig.java

@@ -0,0 +1,100 @@
1
+/*
2
+ * Copyright [2022] [https://www.xiaonuo.vip]
3
+ *
4
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
5
+ *
6
+ * 1.请不要删除和修改根目录下的LICENSE文件。
7
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
8
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
9
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
10
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
11
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
12
+ */
13
+package com.unis.crk.file.entity;
14
+
15
+import com.baomidou.mybatisplus.annotation.FieldFill;
16
+import com.baomidou.mybatisplus.annotation.TableField;
17
+import com.baomidou.mybatisplus.annotation.TableLogic;
18
+import com.baomidou.mybatisplus.annotation.TableName;
19
+import com.fasterxml.jackson.annotation.JsonIgnore;
20
+import io.swagger.annotations.ApiModelProperty;
21
+import lombok.Getter;
22
+import lombok.Setter;
23
+
24
+import java.util.Date;
25
+
26
+/**
27
+ * 配置实体
28
+ *
29
+ * @author xuyuxiang
30
+ * @date 2022/2/23 18:27
31
+ **/
32
+@Getter
33
+@Setter
34
+@TableName("DEV_CONFIG")
35
+public class DevConfig  {
36
+
37
+    /** id */
38
+    @ApiModelProperty(value = "id", position = 1)
39
+    private String id;
40
+
41
+    /** 配置键 */
42
+    @ApiModelProperty(value = "配置键", position = 2)
43
+    private String configKey;
44
+
45
+    /** 配置值 */
46
+    @ApiModelProperty(value = "配置值", position = 3)
47
+    private String configValue;
48
+
49
+    /** 分类 */
50
+    @ApiModelProperty(value = "分类", position = 4)
51
+    private String category;
52
+
53
+    /** 备注 */
54
+    @ApiModelProperty(value = "备注", position = 5)
55
+    private String remark;
56
+
57
+    /** 排序码 */
58
+    @ApiModelProperty(value = "排序码", position = 6)
59
+    private Integer sortCode;
60
+
61
+    /** 扩展信息 */
62
+    @ApiModelProperty(value = "扩展信息", position = 7)
63
+    private String extJson;
64
+
65
+    /** 删除标志 */
66
+    @JsonIgnore
67
+    @ApiModelProperty(value = "删除标志", position = 999)
68
+    @TableField(fill = FieldFill.INSERT)
69
+    private String deleteFlag;
70
+
71
+    /** 创建时间 */
72
+    @ApiModelProperty(value = "创建时间", position = 1000)
73
+    @TableField(fill = FieldFill.INSERT)
74
+    private Date createTime;
75
+
76
+    /** 创建人 */
77
+    @ApiModelProperty(value = "创建人", position = 1001)
78
+    @TableField(fill = FieldFill.INSERT)
79
+    private String createUser;
80
+
81
+    /** 创建人名称 */
82
+    @ApiModelProperty(value = "创建人名称", position = 1002)
83
+    @TableField(exist = false)
84
+    private String createUserName;
85
+
86
+    /** 更新时间 */
87
+    @ApiModelProperty(value = "更新时间", position = 1003)
88
+    @TableField(fill = FieldFill.UPDATE)
89
+    private Date updateTime;
90
+
91
+    /** 更新人 */
92
+    @ApiModelProperty(value = "更新人", position = 1004)
93
+    @TableField(fill = FieldFill.UPDATE)
94
+    private String updateUser;
95
+
96
+    /** 更新人名称 */
97
+    @ApiModelProperty(value = "更新人名称", position = 1005)
98
+    @TableField(exist = false)
99
+    private String updateUserName;
100
+}

+ 109 - 0
src/main/java/com/unis/crk/file/entity/DevFile.java

@@ -0,0 +1,109 @@
1
+package com.unis.crk.file.entity;
2
+
3
+import com.baomidou.mybatisplus.annotation.FieldFill;
4
+import com.baomidou.mybatisplus.annotation.TableField;
5
+import com.baomidou.mybatisplus.annotation.TableLogic;
6
+import com.baomidou.mybatisplus.annotation.TableName;
7
+import com.fasterxml.jackson.annotation.JsonIgnore;
8
+import io.swagger.annotations.ApiModelProperty;
9
+import lombok.Getter;
10
+import lombok.Setter;
11
+
12
+import java.util.Date;
13
+
14
+/**
15
+ * 文件实体
16
+ *
17
+ * @author xuyuxiang
18
+ * @date 2022/2/23 18:27
19
+ **/
20
+@Getter
21
+@Setter
22
+@TableName("DEV_FILE")
23
+public class DevFile   {
24
+
25
+    /** id */
26
+    @ApiModelProperty(value = "id", position = 1)
27
+    private String id;
28
+
29
+    /** 存储引擎 */
30
+    @ApiModelProperty(value = "存储引擎", position = 2)
31
+    private String engine;
32
+
33
+    /** 存储桶 */
34
+    @ApiModelProperty(value = "存储桶", position = 3)
35
+    private String bucket;
36
+
37
+    /** 文件名称 */
38
+    @ApiModelProperty(value = "文件名称", position = 4)
39
+    private String name;
40
+
41
+    /** 文件后缀 */
42
+    @ApiModelProperty(value = "文件后缀", position = 5)
43
+    private String suffix;
44
+
45
+    /** 文件大小kb */
46
+    @ApiModelProperty(value = "文件大小kb", position = 6)
47
+    private String sizeKb;
48
+
49
+    /** 文件大小(格式化后) */
50
+    @ApiModelProperty(value = "文件大小(格式化后)", position = 7)
51
+    private String sizeInfo;
52
+
53
+    /** 文件的对象名(唯一名称) */
54
+    @ApiModelProperty(value = "文件的对象名(唯一名称)", position = 8)
55
+    private String objName;
56
+
57
+    /** 文件存储路径 */
58
+    @ApiModelProperty(value = "文件存储路径", position = 9)
59
+    private String storagePath;
60
+
61
+    /** 文件下载路径 */
62
+    @ApiModelProperty(value = "文件下载路径", position = 10)
63
+    private String downloadPath;
64
+
65
+    /** 图片缩略图 */
66
+    @ApiModelProperty(value = "图片缩略图", position = 11)
67
+    private String thumbnail;
68
+
69
+    /** 扩展信息 */
70
+    @ApiModelProperty(value = "扩展信息", position = 12)
71
+    private String extJson;
72
+
73
+
74
+    /** 删除标志 */
75
+    @JsonIgnore
76
+    @ApiModelProperty(value = "删除标志", position = 999)
77
+    @TableField(fill = FieldFill.INSERT)
78
+    private String deleteFlag;
79
+
80
+    /** 创建时间 */
81
+    @ApiModelProperty(value = "创建时间", position = 1000)
82
+    @TableField(fill = FieldFill.INSERT)
83
+    private Date createTime;
84
+
85
+    /** 创建人 */
86
+    @ApiModelProperty(value = "创建人", position = 1001)
87
+    @TableField(fill = FieldFill.INSERT)
88
+    private String createUser;
89
+
90
+    /** 创建人名称 */
91
+    @ApiModelProperty(value = "创建人名称", position = 1002)
92
+    @TableField(exist = false)
93
+    private String createUserName;
94
+
95
+    /** 更新时间 */
96
+    @ApiModelProperty(value = "更新时间", position = 1003)
97
+    @TableField(fill = FieldFill.UPDATE)
98
+    private Date updateTime;
99
+
100
+    /** 更新人 */
101
+    @ApiModelProperty(value = "更新人", position = 1004)
102
+    @TableField(fill = FieldFill.UPDATE)
103
+    private String updateUser;
104
+
105
+    /** 更新人名称 */
106
+    @ApiModelProperty(value = "更新人名称", position = 1005)
107
+    @TableField(exist = false)
108
+    private String updateUserName;
109
+}

+ 38 - 0
src/main/java/com/unis/crk/file/enums/DevFileBucketAuthEnum.java

@@ -0,0 +1,38 @@
1
+/*
2
+ * Copyright [2022] [https://www.xiaonuo.vip]
3
+ *
4
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
5
+ *
6
+ * 1.请不要删除和修改根目录下的LICENSE文件。
7
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
8
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
9
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
10
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
11
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
12
+ */
13
+package com.unis.crk.file.enums;
14
+
15
+/**
16
+ * 文件存储桶的权限策略枚举
17
+ *
18
+ * @author xuyuxiang
19
+ * @date 2022/1/5 23:29
20
+ */
21
+public enum DevFileBucketAuthEnum {
22
+
23
+    /**
24
+     * 私有的(仅有 owner 可以读写)
25
+     */
26
+    PRIVATE,
27
+
28
+    /**
29
+     * 公有读,私有写( owner 可以读写, 其他客户可以读)
30
+     */
31
+    PUBLIC_READ,
32
+
33
+    /**
34
+     * 公共读写(即所有人都可以读写,慎用)
35
+     */
36
+    PUBLIC_READ_WRITE
37
+
38
+}

+ 43 - 0
src/main/java/com/unis/crk/file/enums/DevFileEngineTypeEnum.java

@@ -0,0 +1,43 @@
1
+/*
2
+ * Copyright [2022] [https://www.xiaonuo.vip]
3
+ *
4
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
5
+ *
6
+ * 1.请不要删除和修改根目录下的LICENSE文件。
7
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
8
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
9
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
10
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
11
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
12
+ */
13
+package com.unis.crk.file.enums;
14
+
15
+import lombok.Getter;
16
+
17
+/**
18
+ * 文件存储引擎类型枚举
19
+ *
20
+ * @author xuyuxiang
21
+ * @date 2022/6/16 16:14
22
+ **/
23
+@Getter
24
+public enum DevFileEngineTypeEnum {
25
+
26
+    /** 本地 */
27
+    LOCAL("LOCAL"),
28
+
29
+    /** 阿里云 */
30
+    ALIYUN("ALIYUN"),
31
+
32
+    /** 腾讯云 */
33
+    TENCENT("TENCENT"),
34
+
35
+    /** MINIO */
36
+    MINIO("MINIO");
37
+
38
+    private final String value;
39
+
40
+    DevFileEngineTypeEnum(String value) {
41
+        this.value = value;
42
+    }
43
+}

+ 25 - 0
src/main/java/com/unis/crk/file/mapper/DevConfigMapper.java

@@ -0,0 +1,25 @@
1
+/*
2
+ * Copyright [2022] [https://www.xiaonuo.vip]
3
+ *
4
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
5
+ *
6
+ * 1.请不要删除和修改根目录下的LICENSE文件。
7
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
8
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
9
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
10
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
11
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
12
+ */
13
+package com.unis.crk.file.mapper;
14
+
15
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
16
+import com.unis.crk.file.entity.DevConfig;
17
+
18
+/**
19
+ * 配置Mapper接口
20
+ *
21
+ * @author xuyuxiang
22
+ * @date 2022/4/22 10:43
23
+ **/
24
+public interface DevConfigMapper extends BaseMapper<DevConfig> {
25
+}

+ 25 - 0
src/main/java/com/unis/crk/file/mapper/DevFileMapper.java

@@ -0,0 +1,25 @@
1
+/*
2
+ * Copyright [2022] [https://www.xiaonuo.vip]
3
+ *
4
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
5
+ *
6
+ * 1.请不要删除和修改根目录下的LICENSE文件。
7
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
8
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
9
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
10
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
11
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
12
+ */
13
+package com.unis.crk.file.mapper;
14
+
15
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
16
+import com.unis.crk.file.entity.DevFile;
17
+
18
+/**
19
+ * 文件Mapper接口
20
+ *
21
+ * @author xuyuxiang
22
+ * @date 2022/2/23 18:40
23
+ **/
24
+public interface DevFileMapper extends BaseMapper<DevFile> {
25
+}

+ 6 - 0
src/main/java/com/unis/crk/file/mapper/mapping/DevConfigMapper.xml

@@ -0,0 +1,6 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
3
+<mapper namespace="com.unis.dev.modular.config.mapper.DevConfigMapper">
4
+
5
+
6
+</mapper>

+ 6 - 0
src/main/java/com/unis/crk/file/mapper/mapping/DevFileMapper.xml

@@ -0,0 +1,6 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
3
+<mapper namespace="com.unis.dev.modular.file.mapper.DevFileMapper">
4
+
5
+
6
+</mapper>

+ 35 - 0
src/main/java/com/unis/crk/file/param/DevFileIdParam.java

@@ -0,0 +1,35 @@
1
+/*
2
+ * Copyright [2022] [https://www.xiaonuo.vip]
3
+ *
4
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
5
+ *
6
+ * 1.请不要删除和修改根目录下的LICENSE文件。
7
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
8
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
9
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
10
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
11
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
12
+ */
13
+package com.unis.crk.file.param;
14
+
15
+import io.swagger.annotations.ApiModelProperty;
16
+import lombok.Getter;
17
+import lombok.Setter;
18
+
19
+import javax.validation.constraints.NotBlank;
20
+
21
+/**
22
+ * 文件Id参数
23
+ *
24
+ * @author xuyuxiang
25
+ * @date 2022/7/31 10:24
26
+ */
27
+@Getter
28
+@Setter
29
+public class DevFileIdParam {
30
+
31
+    /** id */
32
+    @ApiModelProperty(value = "id", required = true)
33
+    @NotBlank(message = "id不能为空")
34
+    private String id;
35
+}

+ 36 - 0
src/main/java/com/unis/crk/file/param/DevFileListParam.java

@@ -0,0 +1,36 @@
1
+/*
2
+ * Copyright [2022] [https://www.xiaonuo.vip]
3
+ *
4
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
5
+ *
6
+ * 1.请不要删除和修改根目录下的LICENSE文件。
7
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
8
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
9
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
10
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
11
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
12
+ */
13
+package com.unis.crk.file.param;
14
+
15
+import io.swagger.annotations.ApiModelProperty;
16
+import lombok.Getter;
17
+import lombok.Setter;
18
+
19
+/**
20
+ * 文件列表参数
21
+ *
22
+ * @author xuyuxiang
23
+ * @date 2022/7/31 10:24
24
+ */
25
+@Getter
26
+@Setter
27
+public class DevFileListParam {
28
+
29
+    /** 文件引擎 */
30
+    @ApiModelProperty(value = "文件引擎")
31
+    private String engine;
32
+
33
+    /** 文件名关键词 */
34
+    @ApiModelProperty(value = "文件名关键词")
35
+    private String searchKey;
36
+}

+ 36 - 0
src/main/java/com/unis/crk/file/param/DevFilePageParam.java

@@ -0,0 +1,36 @@
1
+/*
2
+ * Copyright [2022] [https://www.xiaonuo.vip]
3
+ *
4
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
5
+ *
6
+ * 1.请不要删除和修改根目录下的LICENSE文件。
7
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
8
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
9
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
10
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
11
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
12
+ */
13
+package com.unis.crk.file.param;
14
+
15
+import io.swagger.annotations.ApiModelProperty;
16
+import lombok.Getter;
17
+import lombok.Setter;
18
+
19
+/**
20
+ * 文件分页列表参数
21
+ *
22
+ * @author xuyuxiang
23
+ * @date 2022/7/31 10:24
24
+ */
25
+@Getter
26
+@Setter
27
+public class DevFilePageParam {
28
+
29
+    /** 文件引擎 */
30
+    @ApiModelProperty(value = "文件引擎")
31
+    private String engine;
32
+
33
+    /** 文件名关键词 */
34
+    @ApiModelProperty(value = "文件名关键词")
35
+    private String searchKey;
36
+}

+ 37 - 0
src/main/java/com/unis/crk/file/provider/DevConfigApiProvider.java

@@ -0,0 +1,37 @@
1
+/*
2
+ * Copyright [2022] [https://www.xiaonuo.vip]
3
+ *
4
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
5
+ *
6
+ * 1.请不要删除和修改根目录下的LICENSE文件。
7
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
8
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
9
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
10
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
11
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
12
+ */
13
+package com.unis.crk.file.provider;
14
+
15
+import com.unis.crk.file.service.DevConfigService;
16
+import com.unis.crk.file.util.DevConfigApi;
17
+import org.springframework.stereotype.Service;
18
+
19
+import javax.annotation.Resource;
20
+
21
+/**
22
+ * 配置API接口实现类
23
+ *
24
+ * @author xuyuxiang
25
+ * @date 2022/6/17 14:43
26
+ **/
27
+@Service
28
+public class DevConfigApiProvider implements DevConfigApi {
29
+
30
+    @Resource
31
+    private DevConfigService devConfigService;
32
+
33
+    @Override
34
+    public String getValueByKey(String key) {
35
+        return devConfigService.getValueByKey(key);
36
+    }
37
+}

+ 74 - 0
src/main/java/com/unis/crk/file/provider/DevFileApiProvider.java

@@ -0,0 +1,74 @@
1
+/*
2
+ * Copyright [2022] [https://www.xiaonuo.vip]
3
+ *
4
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
5
+ *
6
+ * 1.请不要删除和修改根目录下的LICENSE文件。
7
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
8
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
9
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
10
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
11
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
12
+ */
13
+package com.unis.crk.file.provider;
14
+
15
+import com.unis.crk.file.enums.DevFileEngineTypeEnum;
16
+import com.unis.crk.file.service.DevFileService;
17
+import com.unis.crk.file.util.DevFileApi;
18
+import org.springframework.stereotype.Service;
19
+import org.springframework.web.multipart.MultipartFile;
20
+
21
+import javax.annotation.Resource;
22
+
23
+/**
24
+ * 文件API接口提供者
25
+ *
26
+ * @author xuyuxiang
27
+ * @date 2022/6/22 15:32
28
+ **/
29
+@Service
30
+public class DevFileApiProvider implements DevFileApi {
31
+
32
+    @Resource
33
+    private DevFileService devFileService;
34
+
35
+    @Override
36
+    public String storageFileWithReturnUrlLocal(MultipartFile file) {
37
+        return devFileService.uploadReturnUrl(DevFileEngineTypeEnum.LOCAL.getValue(), file);
38
+    }
39
+
40
+    @Override
41
+    public String storageFileWithReturnIdLocal(MultipartFile file) {
42
+        return devFileService.uploadReturnId(DevFileEngineTypeEnum.LOCAL.getValue(), file);
43
+    }
44
+
45
+    @Override
46
+    public String storageFileWithReturnUrlAliyun(MultipartFile file) {
47
+        return devFileService.uploadReturnUrl(DevFileEngineTypeEnum.ALIYUN.getValue(), file);
48
+    }
49
+
50
+    @Override
51
+    public String storageFileWithReturnIdAliyun(MultipartFile file) {
52
+        return devFileService.uploadReturnId(DevFileEngineTypeEnum.ALIYUN.getValue(), file);
53
+    }
54
+
55
+    @Override
56
+    public String storageFileWithReturnUrlTencent(MultipartFile file) {
57
+        return devFileService.uploadReturnUrl(DevFileEngineTypeEnum.TENCENT.getValue(), file);
58
+    }
59
+
60
+    @Override
61
+    public String storageFileWithReturnIdTencent(MultipartFile file) {
62
+        return devFileService.uploadReturnId(DevFileEngineTypeEnum.TENCENT.getValue(), file);
63
+    }
64
+
65
+    @Override
66
+    public String storageFileWithReturnUrlMinio(MultipartFile file) {
67
+        return devFileService.uploadReturnUrl(DevFileEngineTypeEnum.MINIO.getValue(), file);
68
+    }
69
+
70
+    @Override
71
+    public String storageFileWithReturnIdMinio(MultipartFile file) {
72
+        return devFileService.uploadReturnId(DevFileEngineTypeEnum.MINIO.getValue(), file);
73
+    }
74
+}

+ 38 - 0
src/main/java/com/unis/crk/file/service/DevConfigService.java

@@ -0,0 +1,38 @@
1
+/*
2
+ * Copyright [2022] [https://www.xiaonuo.vip]
3
+ *
4
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
5
+ *
6
+ * 1.请不要删除和修改根目录下的LICENSE文件。
7
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
8
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
9
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
10
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
11
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
12
+ */
13
+package com.unis.crk.file.service;
14
+
15
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
16
+import com.baomidou.mybatisplus.extension.service.IService;
17
+import com.unis.crk.file.entity.DevConfig;
18
+
19
+import java.util.List;
20
+
21
+/**
22
+ * 配置Service接口
23
+ *
24
+ * @author xuyuxiang
25
+ * @date 2022/4/22 10:41
26
+ **/
27
+public interface DevConfigService extends IService<DevConfig> {
28
+
29
+    /**
30
+     * 根据键获取值
31
+     *
32
+     * @author xuyuxiang
33
+     * @date 2022/4/22 14:52
34
+     **/
35
+    String getValueByKey(String key);
36
+
37
+
38
+}

+ 98 - 0
src/main/java/com/unis/crk/file/service/DevFileService.java

@@ -0,0 +1,98 @@
1
+/*
2
+ * Copyright [2022] [https://www.xiaonuo.vip]
3
+ *
4
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
5
+ *
6
+ * 1.请不要删除和修改根目录下的LICENSE文件。
7
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
8
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
9
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
10
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
11
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
12
+ */
13
+package com.unis.crk.file.service;
14
+
15
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
16
+import com.baomidou.mybatisplus.extension.service.IService;
17
+import com.unis.crk.file.entity.DevFile;
18
+import com.unis.crk.file.param.DevFileIdParam;
19
+import com.unis.crk.file.param.DevFileListParam;
20
+import com.unis.crk.file.param.DevFilePageParam;
21
+import org.springframework.web.multipart.MultipartFile;
22
+
23
+import javax.servlet.http.HttpServletResponse;
24
+import java.io.IOException;
25
+import java.util.List;
26
+
27
+/**
28
+ * 文件Service接口
29
+ *
30
+ * @author xuyuxiang
31
+ * @date 2022/2/23 18:27
32
+ **/
33
+public interface DevFileService extends IService<DevFile> {
34
+
35
+    /**
36
+     * MultipartFile文件上传,返回文件id
37
+     *
38
+     * @author xuyuxiang
39
+     * @date 2022/4/22 15:53
40
+     **/
41
+    String uploadReturnId(String engine, MultipartFile file);
42
+
43
+    /**
44
+     * MultipartFile文件上传,返回文件Url
45
+     *
46
+     * @author xuyuxiang
47
+     * @date 2022/4/22 15:53
48
+     **/
49
+    String uploadReturnUrl(String engine, MultipartFile file);
50
+
51
+    /**
52
+     * 文件分页列表接口
53
+     *
54
+     * @author xuyuxiang
55
+     * @date 2022/6/21 15:44
56
+     **/
57
+    Page<DevFile> page(DevFilePageParam devFilePageParam);
58
+
59
+    /**
60
+     * 文件列表接口
61
+     *
62
+     * @author xuyuxiang
63
+     * @date 2022/6/21 15:44
64
+     **/
65
+    List<DevFile> list(DevFileListParam devFileListParam);
66
+
67
+    /**
68
+     * 下载文件
69
+     *
70
+     * @author xuyuxiang
71
+     * @date 2022/6/21 15:44
72
+     **/
73
+    void download(DevFileIdParam devFileIdParam, HttpServletResponse response) throws IOException;
74
+
75
+    /**
76
+     * 删除文件
77
+     *
78
+     * @author xuyuxiang
79
+     * @date 2022/8/4 10:36
80
+     **/
81
+    void delete(List<DevFileIdParam> devFileIdParamList);
82
+
83
+    /**
84
+     * 获取文件详情
85
+     *
86
+     * @author xuyuxiang
87
+     * @date 2022/4/24 21:18
88
+     */
89
+    DevFile detail(DevFileIdParam devFileIdParam);
90
+
91
+    /**
92
+     * 获取文件详情
93
+     *
94
+     * @author xuyuxiang
95
+     * @date 2022/4/24 21:18
96
+     */
97
+    DevFile queryEntity(String id);
98
+}

+ 59 - 0
src/main/java/com/unis/crk/file/service/impl/DevConfigServiceImpl.java

@@ -0,0 +1,59 @@
1
+/*
2
+ * Copyright [2022] [https://www.xiaonuo.vip]
3
+ *
4
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
5
+ *
6
+ * 1.请不要删除和修改根目录下的LICENSE文件。
7
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
8
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
9
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
10
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
11
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
12
+ */
13
+package com.unis.crk.file.service.impl;
14
+
15
+import cn.hutool.core.convert.Convert;
16
+import cn.hutool.core.util.ObjectUtil;
17
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
18
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
19
+import com.unis.crk.file.controller.CommonCacheOperator;
20
+import com.unis.crk.file.entity.DevConfig;
21
+import com.unis.crk.file.mapper.DevConfigMapper;
22
+import com.unis.crk.file.service.DevConfigService;
23
+import org.springframework.stereotype.Service;
24
+
25
+import javax.annotation.Resource;
26
+
27
+/**
28
+ * 配置Service接口实现类
29
+ *
30
+ * @author xuyuxiang
31
+ * @date 2022/4/22 10:41
32
+ **/
33
+@Service
34
+public class DevConfigServiceImpl extends ServiceImpl<DevConfigMapper, DevConfig> implements DevConfigService {
35
+
36
+    private static final String CONFIG_CACHE_KEY = "dev-config:";
37
+
38
+
39
+    @Resource
40
+    private CommonCacheOperator commonCacheOperator;
41
+
42
+    @Override
43
+    public String getValueByKey(String key) {
44
+        // 从缓存中取
45
+//        Object cacheValue = commonCacheOperator.get(CONFIG_CACHE_KEY + key);
46
+//        if(ObjectUtil.isNotEmpty(cacheValue)) {
47
+//            return Convert.toStr(cacheValue);
48
+//        }
49
+        DevConfig devConfig = this.getOne(new LambdaQueryWrapper<DevConfig>().eq(DevConfig::getConfigKey, key));
50
+        if(ObjectUtil.isNotEmpty(devConfig)) {
51
+            // 更新到缓存
52
+            commonCacheOperator.put(CONFIG_CACHE_KEY + key, devConfig.getConfigValue());
53
+            return devConfig.getConfigValue();
54
+        }
55
+        return null;
56
+    }
57
+
58
+
59
+}

+ 275 - 0
src/main/java/com/unis/crk/file/service/impl/DevFileServiceImpl.java

@@ -0,0 +1,275 @@
1
+/*
2
+ * Copyright [2022] [https://www.xiaonuo.vip]
3
+ *
4
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
5
+ *
6
+ * 1.请不要删除和修改根目录下的LICENSE文件。
7
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
8
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
9
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
10
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
11
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
12
+ */
13
+package com.unis.crk.file.service.impl;
14
+
15
+import cn.hutool.core.collection.CollStreamUtil;
16
+import cn.hutool.core.convert.Convert;
17
+import cn.hutool.core.date.DateUtil;
18
+import cn.hutool.core.img.ImgUtil;
19
+import cn.hutool.core.io.FileUtil;
20
+import cn.hutool.core.io.IoUtil;
21
+import cn.hutool.core.util.NumberUtil;
22
+import cn.hutool.core.util.ObjectUtil;
23
+import cn.hutool.core.util.StrUtil;
24
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
25
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
26
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
27
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
28
+import com.unis.crk.file.entity.DevFile;
29
+import com.unis.crk.file.enums.DevFileEngineTypeEnum;
30
+import com.unis.crk.file.mapper.DevFileMapper;
31
+import com.unis.crk.file.param.DevFileIdParam;
32
+import com.unis.crk.file.param.DevFileListParam;
33
+import com.unis.crk.file.param.DevFilePageParam;
34
+import com.unis.crk.file.service.DevFileService;
35
+import com.unis.crk.file.util.CommonDownloadUtil;
36
+import com.unis.crk.file.util.CommonProperties;
37
+import com.unis.crk.file.util.CommonResponseUtil;
38
+import com.unis.crk.file.util.DevFileMinIoUtil;
39
+import org.springframework.stereotype.Service;
40
+import org.springframework.web.multipart.MultipartFile;
41
+
42
+import javax.annotation.Resource;
43
+import javax.servlet.http.HttpServletResponse;
44
+import java.io.File;
45
+import java.io.IOException;
46
+import java.math.BigDecimal;
47
+import java.util.List;
48
+
49
+/**
50
+ * 文件Service接口实现类
51
+ *
52
+ * @author xuyuxiang
53
+ * @date 2022/2/23 18:43
54
+ **/
55
+@Service
56
+public class DevFileServiceImpl extends ServiceImpl<DevFileMapper, DevFile> implements DevFileService {
57
+
58
+    @Resource
59
+    private CommonProperties commonProperties;
60
+
61
+    @Override
62
+    public String uploadReturnId(String engine, MultipartFile file) {
63
+        return this.storageFile(engine, file, true);
64
+    }
65
+
66
+    @Override
67
+    public String uploadReturnUrl(String engine, MultipartFile file) {
68
+        return this.storageFile(engine, file, false);
69
+    }
70
+
71
+    @Override
72
+    public Page<DevFile> page(DevFilePageParam devFilePageParam) {
73
+        QueryWrapper<DevFile> queryWrapper = new QueryWrapper<>();
74
+        if(ObjectUtil.isNotEmpty(devFilePageParam.getEngine())) {
75
+            queryWrapper.lambda().eq(DevFile::getEngine, devFilePageParam.getEngine());
76
+        }
77
+        if(ObjectUtil.isNotEmpty(devFilePageParam.getSearchKey())) {
78
+            queryWrapper.lambda().like(DevFile::getName, devFilePageParam.getSearchKey());
79
+        }
80
+        return null;
81
+    }
82
+
83
+    @Override
84
+    public List<DevFile> list(DevFileListParam devFileListParam) {
85
+        QueryWrapper<DevFile> queryWrapper = new QueryWrapper<>();
86
+        if(ObjectUtil.isNotEmpty(devFileListParam.getEngine())) {
87
+            queryWrapper.lambda().eq(DevFile::getEngine, devFileListParam.getEngine());
88
+        }
89
+        if(ObjectUtil.isNotEmpty(devFileListParam.getSearchKey())) {
90
+            queryWrapper.lambda().like(DevFile::getName, devFileListParam.getSearchKey());
91
+        }
92
+        return this.list(queryWrapper);
93
+    }
94
+
95
+    @Override
96
+    public void download(DevFileIdParam devFileIdParam, HttpServletResponse response) throws IOException {
97
+        DevFile devFile;
98
+        try {
99
+            devFile = this.queryEntity(devFileIdParam.getId());
100
+        } catch (Exception e) {
101
+            CommonResponseUtil.renderError(response, e.getMessage());
102
+            return;
103
+        }
104
+        if(!devFile.getEngine().equals(DevFileEngineTypeEnum.LOCAL.getValue())) {
105
+            CommonResponseUtil.renderError(response, "非本地文件不支持此方式下载,id值为:" + devFile.getId());
106
+            return;
107
+        }
108
+        File file = FileUtil.file(devFile.getStoragePath());
109
+        if(!FileUtil.exist(file)) {
110
+            CommonResponseUtil.renderError(response, "找不到存储的文件,id值为:" + devFile.getId());
111
+            return;
112
+        }
113
+        CommonDownloadUtil.download(devFile.getName(), IoUtil.readBytes(FileUtil.getInputStream(file)), response);
114
+    }
115
+
116
+    @Override
117
+    public void delete(List<DevFileIdParam> devFileIdParamList) {
118
+        this.removeByIds(CollStreamUtil.toList(devFileIdParamList, DevFileIdParam::getId));
119
+    }
120
+
121
+    /**
122
+     * 存储文件
123
+     *
124
+     * @author xuyuxiang
125
+     * @date 2022/6/16 16:24
126
+     **/
127
+    private String storageFile(String engine, MultipartFile file, boolean returnFileId) {
128
+
129
+        // 如果引擎为空,默认使用本地
130
+        if(ObjectUtil.isEmpty(engine)) {
131
+            engine = DevFileEngineTypeEnum.LOCAL.getValue();
132
+        }
133
+
134
+        // 生成id
135
+        String fileId = IdWorker.getIdStr();
136
+
137
+        // 存储桶名称
138
+        String bucketName="";
139
+
140
+        // 定义存储的url,本地文件返回文件实际路径,其他引擎返回网络地址
141
+        String storageUrl ="";
142
+
143
+        // 根据引擎类型执行不同方法
144
+        if(engine.equals(DevFileEngineTypeEnum.LOCAL.getValue())) {
145
+
146
+            // 使用固定名称defaultBucketName
147
+        } else if(engine.equals(DevFileEngineTypeEnum.ALIYUN.getValue())) {
148
+
149
+            // 使用阿里云默认配置的bucketName
150
+        } else if(engine.equals(DevFileEngineTypeEnum.TENCENT.getValue())) {
151
+
152
+            // 使用腾讯云默认配置的bucketName
153
+        } else if(engine.equals(DevFileEngineTypeEnum.MINIO.getValue())) {
154
+
155
+            // 使用MINIO默认配置的bucketName
156
+            bucketName = DevFileMinIoUtil.getDefaultBucketName();
157
+            storageUrl = DevFileMinIoUtil.storageFileWithReturnUrl(bucketName, genFileKey(fileId, file), file);
158
+        } else {
159
+            throw new RuntimeException("不支持的文件引擎:"+ engine);
160
+        }
161
+
162
+        // 将文件信息保存到数据库
163
+        DevFile devFile = new DevFile();
164
+
165
+        // 设置文件id
166
+        devFile.setId(fileId);
167
+
168
+        // 设置存储引擎类型
169
+        devFile.setEngine(engine);
170
+        devFile.setBucket(bucketName);
171
+        devFile.setName(file.getOriginalFilename());
172
+        String suffix = ObjectUtil.isNotEmpty(file.getOriginalFilename())?StrUtil.subAfter(file.getOriginalFilename(),
173
+                StrUtil.DOT, true):null;
174
+        devFile.setSuffix(suffix);
175
+        devFile.setSizeKb(Convert.toStr(NumberUtil.div(new BigDecimal(file.getSize()), BigDecimal.valueOf(1024))
176
+                .setScale(0, BigDecimal.ROUND_HALF_UP)));
177
+        devFile.setSizeInfo(FileUtil.readableFileSize(file.getSize()));
178
+        devFile.setObjName(ObjectUtil.isNotEmpty(devFile.getSuffix())?fileId + StrUtil.DOT + devFile.getSuffix():null);
179
+        // 如果是图片,则压缩生成缩略图
180
+        if(ObjectUtil.isNotEmpty(suffix)) {
181
+            if(isPic(suffix)) {
182
+                try {
183
+                    devFile.setThumbnail(ImgUtil.toBase64DataUri(ImgUtil.scale(ImgUtil.toImage(file.getBytes()),
184
+                            100, 100, null), suffix));
185
+                } catch (Exception ignored) {
186
+                }
187
+            }
188
+        }
189
+        // 存储路径
190
+        devFile.setStoragePath(storageUrl);
191
+
192
+        // 定义下载地址
193
+        String downloadUrl;
194
+
195
+        // 下载路径,注意:本地文件下载地址设置为下载接口地址 + 文件id
196
+        if(engine.equals(DevFileEngineTypeEnum.LOCAL.getValue())) {
197
+            String apiUrl = commonProperties.getBackendUrl();
198
+            if(ObjectUtil.isEmpty(apiUrl)) {
199
+                throw new RuntimeException("后端域名地址未正确配置:snowy.config.common.backend-url为空");
200
+            }
201
+            downloadUrl= apiUrl + "/dev/file/download?id=" + fileId;
202
+            devFile.setDownloadPath(downloadUrl);
203
+        } else {
204
+            // 阿里云、腾讯云、MINIO可以直接使用存储地址(公网)作为下载地址
205
+            downloadUrl= storageUrl;
206
+            devFile.setDownloadPath(devFile.getStoragePath());
207
+        }
208
+
209
+        this.save(devFile);
210
+
211
+        // 如果是返回id则返回文件id
212
+        if(returnFileId) {
213
+            return fileId;
214
+        } else {
215
+            // 否则返回下载地址
216
+            return downloadUrl;
217
+        }
218
+    }
219
+
220
+    /**
221
+     * 生成文件的key,格式如 2021/10/11/1377109572375810050.docx
222
+     *
223
+     * @author xuyuxiang
224
+     * @date 2022/4/22 15:58
225
+     **/
226
+    public String genFileKey(String fileId, MultipartFile file) {
227
+
228
+        // 获取文件原始名称
229
+        String originalFileName = file.getOriginalFilename();
230
+
231
+        // 获取文件后缀
232
+        String fileSuffix = FileUtil.getSuffix(originalFileName);
233
+
234
+        // 生成文件的对象名称,格式如:1377109572375810050.docx
235
+        String fileObjectName = fileId + StrUtil.DOT + fileSuffix;
236
+
237
+        // 获取日期文件夹,格式如,2021/10/11/
238
+        String dateFolderPath = DateUtil.thisYear() + StrUtil.SLASH +
239
+                (DateUtil.thisMonth() + 1) + StrUtil.SLASH +
240
+                DateUtil.thisDayOfMonth() + StrUtil.SLASH;
241
+
242
+        // 返回
243
+        return dateFolderPath + fileObjectName;
244
+    }
245
+
246
+    @Override
247
+    public DevFile detail(DevFileIdParam devFileIdParam) {
248
+        return this.queryEntity(devFileIdParam.getId());
249
+    }
250
+
251
+    @Override
252
+    public DevFile queryEntity(String id) {
253
+        DevFile devFile = this.getById(id);
254
+        if(ObjectUtil.isEmpty(devFile)) {
255
+            throw new RuntimeException("文件不存在,id值为:"+id);
256
+        }
257
+        return devFile;
258
+    }
259
+
260
+    /**
261
+     * 根据文件后缀判断是否图片
262
+     *
263
+     * @author xuyuxiang
264
+     * @date 2020/7/6 15:31
265
+     */
266
+    private static boolean isPic(String fileSuffix) {
267
+        fileSuffix = fileSuffix.toLowerCase();
268
+        return ImgUtil.IMAGE_TYPE_GIF.equals(fileSuffix)
269
+                || ImgUtil.IMAGE_TYPE_JPG.equals(fileSuffix)
270
+                || ImgUtil.IMAGE_TYPE_JPEG.equals(fileSuffix)
271
+                || ImgUtil.IMAGE_TYPE_BMP.equals(fileSuffix)
272
+                || ImgUtil.IMAGE_TYPE_PNG.equals(fileSuffix)
273
+                || ImgUtil.IMAGE_TYPE_PSD.equals(fileSuffix);
274
+    }
275
+}

+ 63 - 0
src/main/java/com/unis/crk/file/util/CommonDownloadUtil.java

@@ -0,0 +1,63 @@
1
+/*
2
+ * Copyright [2022] [https://www.xiaonuo.vip]
3
+ *
4
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
5
+ *
6
+ * 1.请不要删除和修改根目录下的LICENSE文件。
7
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
8
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
9
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
10
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
11
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
12
+ */
13
+package com.unis.crk.file.util;
14
+
15
+import cn.hutool.core.io.FileUtil;
16
+import cn.hutool.core.io.IoUtil;
17
+import cn.hutool.core.util.URLUtil;
18
+import lombok.extern.slf4j.Slf4j;
19
+
20
+import javax.servlet.http.HttpServletResponse;
21
+import java.io.File;
22
+import java.io.IOException;
23
+
24
+/**
25
+ * 文件下载工具类,使用本类前,对参数校验的异常使用CommonResponseUtil.renderError()方法进行渲染
26
+ *
27
+ * @author xuyuxiang
28
+ * @date 2020/8/5 21:45
29
+ */
30
+@Slf4j
31
+public class CommonDownloadUtil {
32
+
33
+    /**
34
+     * 下载文件
35
+     *
36
+     * @param file     要下载的文件
37
+     * @param response 响应
38
+     * @author xuyuxiang
39
+     * @date 2020/8/5 21:46
40
+     */
41
+    public static void download(File file, HttpServletResponse response) {
42
+        download(file.getName(), FileUtil.readBytes(file), response);
43
+    }
44
+
45
+    /**
46
+     * 下载文件
47
+     *
48
+     * @author xuyuxiang
49
+     * @date 2022/7/31 10:57
50
+     */
51
+    public static void download(String fileName, byte[] fileBytes, HttpServletResponse response) {
52
+        try {
53
+            response.setHeader("Content-Disposition", "attachment;filename=" + URLUtil.encode(fileName));
54
+            response.addHeader("Content-Length", "" + fileBytes.length);
55
+            response.setHeader("Access-Control-Allow-Origin", "*");
56
+            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
57
+            response.setContentType("application/octet-stream;charset=UTF-8");
58
+            IoUtil.write(response.getOutputStream(), true, fileBytes);
59
+        } catch (IOException e) {
60
+            log.error(">>> 文件下载异常:", e);
61
+        }
62
+    }
63
+}

+ 50 - 0
src/main/java/com/unis/crk/file/util/CommonException.java

@@ -0,0 +1,50 @@
1
+/*
2
+ * Copyright [2022] [https://www.xiaonuo.vip]
3
+ *
4
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
5
+ *
6
+ * 1.请不要删除和修改根目录下的LICENSE文件。
7
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
8
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
9
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
10
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
11
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
12
+ */
13
+package com.unis.crk.file.util;
14
+
15
+import cn.hutool.core.util.StrUtil;
16
+import lombok.Getter;
17
+import lombok.Setter;
18
+
19
+/**
20
+ * 通用异常
21
+ *
22
+ * @author xuyuxiang
23
+ * @date 2020/4/8 15:54
24
+ */
25
+@Getter
26
+@Setter
27
+public class CommonException extends RuntimeException {
28
+
29
+    private Integer code;
30
+
31
+    private String msg;
32
+
33
+    public CommonException() {
34
+        super("服务器异常");
35
+        this.code = 500;
36
+        this.msg = "服务器异常";
37
+    }
38
+
39
+    public CommonException(String msg, Object... arguments) {
40
+        super(StrUtil.format(msg, arguments));
41
+        this.code = 500;
42
+        this.msg = StrUtil.format(msg, arguments);
43
+    }
44
+
45
+    public CommonException(Integer code, String msg, Object... arguments) {
46
+        super(StrUtil.format(msg, arguments));
47
+        this.code = code;
48
+        this.msg = StrUtil.format(msg, arguments);
49
+    }
50
+}

+ 42 - 0
src/main/java/com/unis/crk/file/util/CommonExceptionEnum.java

@@ -0,0 +1,42 @@
1
+/*
2
+ * Copyright [2022] [https://www.xiaonuo.vip]
3
+ *
4
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
5
+ *
6
+ * 1.请不要删除和修改根目录下的LICENSE文件。
7
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
8
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
9
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
10
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
11
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
12
+ */
13
+package com.unis.crk.file.util;
14
+
15
+import lombok.Getter;
16
+
17
+/**
18
+ * 异常码枚举
19
+ *
20
+ * @author xuyuxiang
21
+ * @date 2022/8/15 16:09
22
+ **/
23
+@Getter
24
+public enum CommonExceptionEnum {
25
+
26
+    OK200(200, "请求成功"),
27
+    ERROR401(401, "未登录"),
28
+    ERROR403(403, "无权限"),
29
+    ERROR404(404, "路径不存在"),
30
+    ERROR405(405, "请求方法不正确"),
31
+    ERROR415(415, "参数传递异常"),
32
+    ERROR500(500, "业务异常");
33
+
34
+    private final Integer code;
35
+
36
+    private final String message;
37
+
38
+    CommonExceptionEnum(Integer code, String message) {
39
+        this.code = code;
40
+        this.message = message;
41
+    }
42
+}

+ 37 - 0
src/main/java/com/unis/crk/file/util/CommonProperties.java

@@ -0,0 +1,37 @@
1
+/*
2
+ * Copyright [2022] [https://www.xiaonuo.vip]
3
+ *
4
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
5
+ *
6
+ * 1.请不要删除和修改根目录下的LICENSE文件。
7
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
8
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
9
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
10
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
11
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
12
+ */
13
+package com.unis.crk.file.util;
14
+
15
+import lombok.Getter;
16
+import lombok.Setter;
17
+import org.springframework.boot.context.properties.ConfigurationProperties;
18
+import org.springframework.stereotype.Component;
19
+
20
+/**
21
+ * 通用基础配置
22
+ *
23
+ * @author xuyuxiang
24
+ * @date 2022/1/2 17:03
25
+ */
26
+@Getter
27
+@Setter
28
+@Component
29
+@ConfigurationProperties(prefix = "snowy.config.common")
30
+public class CommonProperties {
31
+
32
+    /** 前端地址 */
33
+    private String frontUrl;
34
+
35
+    /** 后端地址 */
36
+    private String backendUrl;
37
+}

+ 64 - 0
src/main/java/com/unis/crk/file/util/CommonResponseUtil.java

@@ -0,0 +1,64 @@
1
+/*
2
+ * Copyright [2022] [https://www.xiaonuo.vip]
3
+ *
4
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
5
+ *
6
+ * 1.请不要删除和修改根目录下的LICENSE文件。
7
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
8
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
9
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
10
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
11
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
12
+ */
13
+package com.unis.crk.file.util;
14
+
15
+import cn.hutool.core.util.CharsetUtil;
16
+import cn.hutool.core.util.ObjectUtil;
17
+import cn.hutool.http.ContentType;
18
+import cn.hutool.json.JSONUtil;
19
+
20
+import javax.servlet.http.HttpServletResponse;
21
+import java.io.IOException;
22
+
23
+/**
24
+ * 通用响应工具类
25
+ *
26
+ * @author xuyuxiang
27
+ * @date 2022/8/4 9:40
28
+ **/
29
+public class CommonResponseUtil {
30
+
31
+    /**
32
+     * 以流的方式响应错误信息,默认错误消息
33
+     *
34
+     * @author xuyuxiang
35
+     * @date 2022/8/4 9:41
36
+     **/
37
+    public static void renderError(HttpServletResponse response) throws IOException {
38
+        renderError(response, null);
39
+    }
40
+
41
+    /**
42
+     * 以流的方式响应错误信息,指定错误消息
43
+     *
44
+     * @author xuyuxiang
45
+     * @date 2022/8/4 9:41
46
+     **/
47
+    public static void renderError(HttpServletResponse response, String msg) throws IOException {
48
+        response.setCharacterEncoding(CharsetUtil.UTF_8);
49
+        response.setContentType(ContentType.JSON.toString());
50
+        response.getWriter().write(JSONUtil.toJsonStr(ObjectUtil.isNotEmpty(msg)?CommonResult.error(msg):CommonResult.error()));
51
+    }
52
+
53
+    /**
54
+     * 以流的方式响应错误信息,指定错误码和错误消息
55
+     *
56
+     * @author xuyuxiang
57
+     * @date 2022/8/4 9:41
58
+     **/
59
+    public static void renderError(HttpServletResponse response, Integer code, String msg) throws IOException {
60
+        response.setCharacterEncoding(CharsetUtil.UTF_8);
61
+        response.setContentType(ContentType.JSON.toString());
62
+        response.getWriter().write(JSONUtil.toJsonStr(CommonResult.get(code, msg, null)));
63
+    }
64
+}

+ 165 - 0
src/main/java/com/unis/crk/file/util/CommonResult.java

@@ -0,0 +1,165 @@
1
+/*
2
+ * Copyright [2022] [https://www.xiaonuo.vip]
3
+ *
4
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
5
+ *
6
+ * 1.请不要删除和修改根目录下的LICENSE文件。
7
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
8
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
9
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
10
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
11
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
12
+ */
13
+package com.unis.crk.file.util;
14
+
15
+import io.swagger.annotations.ApiModelProperty;
16
+import springfox.documentation.builders.ResponseMessageBuilder;
17
+import springfox.documentation.service.ResponseMessage;
18
+
19
+import java.io.Serializable;
20
+import java.util.Arrays;
21
+import java.util.List;
22
+import java.util.stream.Collectors;
23
+
24
+/**
25
+ * 对Ajax请求返回Json格式数据的简易封装
26
+ *
27
+ * @author xuyuxiang
28
+ * @date 2022/8/15 16:08
29
+ **/
30
+public class CommonResult<T> implements Serializable {
31
+    private static final long serialVersionUID = 1L;
32
+    public static final int CODE_SUCCESS = 200;
33
+    public static final int CODE_ERROR = 500;
34
+
35
+    @ApiModelProperty(value = "状态码")
36
+    private int code;
37
+
38
+    @ApiModelProperty(value = "提示语")
39
+    private String msg;
40
+
41
+    @ApiModelProperty(value = "返回数据")
42
+    private T data;
43
+
44
+    public CommonResult() {
45
+    }
46
+
47
+    public CommonResult(int code, String msg, T data) {
48
+        this.setCode(code);
49
+        this.setMsg(msg);
50
+        this.setData(data);
51
+    }
52
+
53
+    /**
54
+     * 获取code
55
+     * @return code
56
+     */
57
+    public Integer getCode() {
58
+        return this.code;
59
+    }
60
+
61
+    /**
62
+     * 获取msg
63
+     * @return msg
64
+     */
65
+    public String getMsg() {
66
+        return this.msg;
67
+    }
68
+    /**
69
+     * 获取data
70
+     * @return data
71
+     */
72
+    public T getData() {
73
+        return this.data;
74
+    }
75
+
76
+    /**
77
+     * 给code赋值,连缀风格
78
+     * @param code code
79
+     * @return 对象自身
80
+     */
81
+    public CommonResult<T> setCode(int code) {
82
+        this.code = code;
83
+        return this;
84
+    }
85
+
86
+    /**
87
+     * 给msg赋值,连缀风格
88
+     * @param msg msg
89
+     * @return 对象自身
90
+     */
91
+    public CommonResult<T> setMsg(String msg) {
92
+        this.msg = msg;
93
+        return this;
94
+    }
95
+
96
+    /**
97
+     * 给data赋值,连缀风格
98
+     * @param data data
99
+     * @return 对象自身
100
+     */
101
+    public CommonResult<T> setData(T data) {
102
+        this.data = data;
103
+        return this;
104
+    }
105
+
106
+
107
+    // ============================  构建  ==================================
108
+
109
+    // 构建成功
110
+    public static <T> CommonResult<T> ok() {
111
+        return new CommonResult<>(CODE_SUCCESS, "操作成功", null);
112
+    }
113
+    public static <T> CommonResult<T> ok(String msg) {
114
+        return new CommonResult<>(CODE_SUCCESS, msg, null);
115
+    }
116
+    public static <T> CommonResult<T> code(int code) {
117
+        return new CommonResult<>(code, null, null);
118
+    }
119
+    public static <T> CommonResult<T> data(T data) {
120
+        return new CommonResult<>(CODE_SUCCESS, "操作成功", data);
121
+    }
122
+
123
+    // 构建失败
124
+    public static <T> CommonResult<T> error() {
125
+        return new CommonResult<>(CODE_ERROR, "服务器异常", null);
126
+    }
127
+
128
+    public static <T> CommonResult<T> error(Integer code, String msg) {
129
+        return new CommonResult<>(code, msg, null);
130
+    }
131
+
132
+
133
+    public static <T> CommonResult<T> error(String msg) {
134
+        return new CommonResult<>(CODE_ERROR, msg, null);
135
+    }
136
+
137
+    // 构建指定状态码
138
+    public static <T> CommonResult<T> get(int code, String msg, T data) {
139
+        return new CommonResult<>(code, msg, data);
140
+    }
141
+
142
+    /*
143
+     * toString()
144
+     */
145
+    @Override
146
+    public String toString() {
147
+        return "{"
148
+                + "\"code\": " + this.getCode()
149
+                + ", \"msg\": \"" + this.getMsg() + "\""
150
+                + ", \"data\": \"" + this.getData() + "\""
151
+                + "}";
152
+    }
153
+
154
+    /**
155
+     * 响应状态码集合
156
+     *
157
+     * @author xuyuxiang
158
+     * @date 2022/7/25 13:36
159
+     **/
160
+    public static List<ResponseMessage> responseList() {
161
+        return Arrays.stream(CommonExceptionEnum.values()).map(commonExceptionEnum -> new ResponseMessageBuilder()
162
+                .code(commonExceptionEnum.getCode()).message(commonExceptionEnum.getMessage()).build())
163
+                .collect(Collectors.toList());
164
+    }
165
+}

+ 86 - 0
src/main/java/com/unis/crk/file/util/CommonServletUtil.java

@@ -0,0 +1,86 @@
1
+package com.unis.crk.file.util;
2
+
3
+import cn.hutool.core.util.ObjectUtil;
4
+import lombok.extern.slf4j.Slf4j;
5
+import org.springframework.web.context.request.RequestContextHolder;
6
+import org.springframework.web.context.request.ServletRequestAttributes;
7
+
8
+import javax.servlet.http.Cookie;
9
+import javax.servlet.http.HttpServletRequest;
10
+import javax.servlet.http.HttpServletResponse;
11
+
12
+/**
13
+ * HttpServlet工具类,获取当前request和response
14
+ *
15
+ * @author xuyuxiang
16
+ * @date 2020/3/30 15:09
17
+ */
18
+@Slf4j
19
+public class CommonServletUtil {
20
+
21
+    /**
22
+     * 从请求中中获取参数
23
+     *
24
+     * @author xuyuxiang
25
+     * @date 2021/10/14 10:44
26
+     **/
27
+    public static String getParamFromRequest(String paramName) {
28
+        HttpServletRequest request = getRequest();
29
+
30
+        // 1. 尝试从请求体里面读取
31
+        String paramValue = request.getParameter(paramName);
32
+
33
+        // 2. 尝试从header里读取
34
+        if (ObjectUtil.isEmpty(paramValue)) {
35
+            paramValue = request.getHeader(paramName);
36
+        }
37
+        // 3. 尝试从cookie里读取
38
+        if (ObjectUtil.isEmpty(paramValue)) {
39
+            Cookie[] cookies = request.getCookies();
40
+            if(ObjectUtil.isNotEmpty(cookies)) {
41
+                for (Cookie cookie : cookies) {
42
+                    String cookieName = cookie.getName();
43
+                    if (cookieName.equals(paramName)) {
44
+                        return cookie.getValue();
45
+                    }
46
+                }
47
+            }
48
+        }
49
+        // 4. 返回
50
+        return paramValue;
51
+    }
52
+
53
+    public static HttpServletRequest getRequest() {
54
+        ServletRequestAttributes servletRequestAttributes;
55
+        try {
56
+            servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
57
+        } catch (Exception e) {
58
+            log.error(">>> 非Web上下文无法获取Request:", e);
59
+            throw new CommonException("非Web上下文无法获取Request");
60
+        }
61
+        if (servletRequestAttributes == null) {
62
+            throw new CommonException("非Web上下文无法获取Request");
63
+        } else {
64
+            return servletRequestAttributes.getRequest();
65
+        }
66
+    }
67
+
68
+    public static HttpServletResponse getResponse() {
69
+        ServletRequestAttributes servletRequestAttributes;
70
+        try {
71
+            servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
72
+        } catch (Exception e) {
73
+            log.error(">>> 非Web上下文无法获取Response:", e);
74
+            throw new CommonException("非Web上下文无法获取Response");
75
+        }
76
+        if (servletRequestAttributes == null) {
77
+            throw new CommonException("非Web上下文无法获取Response");
78
+        } else {
79
+            return servletRequestAttributes.getResponse();
80
+        }
81
+    }
82
+
83
+    public static boolean isWeb() {
84
+        return RequestContextHolder.getRequestAttributes() != null;
85
+    }
86
+}

+ 30 - 0
src/main/java/com/unis/crk/file/util/DevConfigApi.java

@@ -0,0 +1,30 @@
1
+/*
2
+ * Copyright [2022] [https://www.xiaonuo.vip]
3
+ *
4
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
5
+ *
6
+ * 1.请不要删除和修改根目录下的LICENSE文件。
7
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
8
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
9
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
10
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
11
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
12
+ */
13
+package com.unis.crk.file.util;
14
+
15
+/**
16
+ * 配置APi接口
17
+ *
18
+ * @author xuyuxiang
19
+ * @date 2022/6/17 10:37
20
+ **/
21
+public interface DevConfigApi {
22
+
23
+    /**
24
+     * 根据键获取值
25
+     *
26
+     * @author xuyuxiang
27
+     * @date 2022/6/17 11:11
28
+     **/
29
+    String getValueByKey(String key);
30
+}

+ 104 - 0
src/main/java/com/unis/crk/file/util/DevFileApi.java

@@ -0,0 +1,104 @@
1
+/*
2
+ * Copyright [2022] [https://www.xiaonuo.vip]
3
+ *
4
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
5
+ *
6
+ * 1.请不要删除和修改根目录下的LICENSE文件。
7
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
8
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
9
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
10
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
11
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
12
+ */
13
+package com.unis.crk.file.util;
14
+
15
+import org.springframework.web.multipart.MultipartFile;
16
+
17
+/**
18
+ * 文件API接口,可参考com.unis.dev.core.util.file包下的工具类扩展更多需要的方法
19
+ *
20
+ * @author xuyuxiang
21
+ * @date 2022/6/22 15:21
22
+ **/
23
+public interface DevFileApi {
24
+
25
+    /* =========本地文件========= */
26
+
27
+    /**
28
+     * 上传文件返回Url
29
+     *
30
+     * @param file 文件
31
+     * @author xuyuxiang
32
+     * @date 2022/6/22 17:44
33
+     **/
34
+    String storageFileWithReturnUrlLocal(MultipartFile file);
35
+
36
+    /**
37
+     * 上传文件返回Id
38
+     *
39
+     * @param file 文件
40
+     * @author xuyuxiang
41
+     * @date 2022/6/22 17:44
42
+     **/
43
+    String storageFileWithReturnIdLocal(MultipartFile file);
44
+
45
+    /* =========阿里云文件========= */
46
+
47
+    /**
48
+     * 上传文件返回Url
49
+     *
50
+     * @param file 文件
51
+     * @author xuyuxiang
52
+     * @date 2022/6/22 17:44
53
+     **/
54
+    String storageFileWithReturnUrlAliyun(MultipartFile file);
55
+
56
+    /**
57
+     * 上传文件返回Id
58
+     *
59
+     * @param file 文件
60
+     * @author xuyuxiang
61
+     * @date 2022/6/22 17:44
62
+     **/
63
+    String storageFileWithReturnIdAliyun(MultipartFile file);
64
+
65
+    /* =========腾讯云件========= */
66
+
67
+    /**
68
+     * 上传文件返回Url
69
+     *
70
+     * @param file 文件
71
+     * @author xuyuxiang
72
+     * @date 2022/6/22 17:44
73
+     **/
74
+    String storageFileWithReturnUrlTencent(MultipartFile file);
75
+
76
+    /**
77
+     * 上传文件返回Id
78
+     *
79
+     * @param file 文件
80
+     * @author xuyuxiang
81
+     * @date 2022/6/22 17:44
82
+     **/
83
+    String storageFileWithReturnIdTencent(MultipartFile file);
84
+
85
+    /* =========MINIO件========= */
86
+
87
+    /**
88
+     * 上传文件返回Url
89
+     *
90
+     * @param file 文件
91
+     * @author xuyuxiang
92
+     * @date 2022/6/22 17:44
93
+     **/
94
+    String storageFileWithReturnUrlMinio(MultipartFile file);
95
+
96
+    /**
97
+     * 上传文件返回Id
98
+     *
99
+     * @param file 文件
100
+     * @author xuyuxiang
101
+     * @date 2022/6/22 17:44
102
+     **/
103
+    String storageFileWithReturnIdMinio(MultipartFile file);
104
+}

+ 459 - 0
src/main/java/com/unis/crk/file/util/DevFileMinIoUtil.java

@@ -0,0 +1,459 @@
1
+package com.unis.crk.file.util;
2
+
3
+import cn.hutool.core.io.FileUtil;
4
+import cn.hutool.core.io.IORuntimeException;
5
+import cn.hutool.core.io.IoUtil;
6
+import cn.hutool.core.util.ObjectUtil;
7
+import cn.hutool.core.util.StrUtil;
8
+import cn.hutool.extra.spring.SpringUtil;
9
+import cn.hutool.json.JSONArray;
10
+import cn.hutool.json.JSONObject;
11
+import cn.hutool.json.JSONUtil;
12
+import com.unis.crk.file.enums.DevFileBucketAuthEnum;
13
+import io.minio.*;
14
+import io.minio.http.Method;
15
+import lombok.extern.slf4j.Slf4j;
16
+import org.springframework.web.multipart.MultipartFile;
17
+
18
+import javax.activation.MimetypesFileTypeMap;
19
+import java.io.*;
20
+
21
+/**
22
+ * MINIO文件工具类
23
+ * 参考文档:http://docs.minio.org.cn/docs/master/java-client-quickstart-guide
24
+ *
25
+ * @author xuyuxiang
26
+ * @date 2022/1/2 18:13
27
+ */
28
+@Slf4j
29
+public class DevFileMinIoUtil {
30
+
31
+    private static MinioClient client;
32
+
33
+    private static String defaultBucketName;
34
+
35
+    private static final String SNOWY_FILE_MINIO_ACCESS_KEY_KEY = "CRK_FILE_MINIO_ACCESS_KEY";
36
+    private static final String SNOWY_FILE_MINIO_SECRET_KEY_KEY = "CRK_FILE_MINIO_SECRET_KEY";
37
+    private static final String SNOWY_FILE_MINIO_END_POINT_KEY = "CRK_FILE_MINIO_END_POINT";
38
+    /**
39
+     * 文件访问前缀
40
+     *
41
+     * @author: ybw
42
+     * @date: 2024/5/31
43
+     **/
44
+    private static final String SNOWY_FILE_MINIO_ACCESS_PREFIX = "CRK_FILE_MINIO_ACCESS_PREFIX";
45
+    private static final String SNOWY_FILE_MINIO_DEFAULT_BUCKET_NAME = "CRK_FILE_MINIO_DEFAULT_BUCKET_NAME";
46
+
47
+
48
+    /**
49
+     * 初始化操作的客户端
50
+     *
51
+     * @author xuyuxiang
52
+     * @date 2022/1/5 23:24
53
+     */
54
+    private static void initClient() {
55
+
56
+        DevConfigApi devConfigApi = SpringUtil.getBean(DevConfigApi.class);
57
+
58
+        /* accessKey */
59
+        String accessKey = devConfigApi.getValueByKey(SNOWY_FILE_MINIO_ACCESS_KEY_KEY);
60
+
61
+        if(ObjectUtil.isEmpty(accessKey)) {
62
+            throw new RuntimeException("MINIO文件操作客户端未正确配置:accessKey为空");
63
+        }
64
+
65
+        /* secretKey */
66
+        String secretKey = devConfigApi.getValueByKey(SNOWY_FILE_MINIO_SECRET_KEY_KEY);
67
+
68
+        if(ObjectUtil.isEmpty(secretKey)) {
69
+            throw new RuntimeException("MINIO文件操作客户端未正确配置:secretKey为空");
70
+        }
71
+
72
+        /* endpoint */
73
+        String endpoint = devConfigApi.getValueByKey(SNOWY_FILE_MINIO_END_POINT_KEY);
74
+
75
+        if(ObjectUtil.isEmpty(endpoint)) {
76
+            throw new RuntimeException("MINIO文件操作客户端未正确配置:endpoint为空");
77
+        }
78
+
79
+        /* 默认BucketName */
80
+        defaultBucketName = devConfigApi.getValueByKey(SNOWY_FILE_MINIO_DEFAULT_BUCKET_NAME);
81
+
82
+        if(ObjectUtil.isEmpty(defaultBucketName)) {
83
+            throw new RuntimeException("MINIO文件操作客户端未正确配置:defaultBucketName为空");
84
+        }
85
+
86
+        client = MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();
87
+    }
88
+
89
+    /**
90
+     * 获取默认存储桶名称
91
+     *
92
+     * @author xuyuxiang
93
+     * @date 2022/6/22 18:05
94
+     **/
95
+    public static String getDefaultBucketName() {
96
+        initClient();
97
+        return defaultBucketName;
98
+    }
99
+
100
+    /**
101
+     * 销毁操作的客户端
102
+     *
103
+     * @author xuyuxiang
104
+     * @date 2022/1/5 23:24
105
+     */
106
+    public static void destroyClient() {
107
+        // 无需
108
+    }
109
+
110
+    /**
111
+     * 获取操作的客户端
112
+     *
113
+     * @author xuyuxiang
114
+     * @date 2022/1/5 23:24
115
+     */
116
+    public static MinioClient getClient() {
117
+        return client;
118
+    }
119
+
120
+    /**
121
+     * 查询存储桶是否存在
122
+     * 例如:传入参数examplebucket-1250000000,返回true代表存在此桶
123
+     *
124
+     * @param bucketName 桶名称
125
+     * @author xuyuxiang
126
+     * @date 2022/1/5 23:24
127
+     */
128
+    public static boolean doesBucketExist(String bucketName) {
129
+        try {
130
+            initClient();
131
+            BucketExistsArgs bucketExistsArgs = BucketExistsArgs.builder().bucket(bucketName).build();
132
+            client.bucketExists(bucketExistsArgs);
133
+        } catch (Exception e) {
134
+            throw new RuntimeException(e.getMessage());
135
+        }
136
+        return false;
137
+    }
138
+
139
+    /**
140
+     * 设置预定义策略
141
+     * 预定义策略如公有读、公有读写、私有读
142
+     *
143
+     * @param bucketName 桶名称
144
+     * @param devFileBucketAuthEnum 存储桶权限
145
+     * @author xuyuxiang
146
+     * @date 2022/1/5 23:24
147
+     */
148
+    public static void setBucketAcl(String bucketName, DevFileBucketAuthEnum devFileBucketAuthEnum) {
149
+        setFileAcl(bucketName, "*", devFileBucketAuthEnum);
150
+    }
151
+
152
+    /**
153
+     * 判断是否存在文件
154
+     *
155
+     * @param bucketName 桶名称
156
+     * @param key        唯一标示id,例如a.txt, doc/a.txt
157
+     * @author xuyuxiang
158
+     * @date 2022/1/5 23:24
159
+     */
160
+    public static boolean isExistingFile(String bucketName, String key) {
161
+        try {
162
+            initClient();
163
+            GetObjectArgs getObjectArgs = GetObjectArgs.builder().bucket(bucketName).object(key).build();
164
+            InputStream object = client.getObject(getObjectArgs);
165
+            return !ObjectUtil.isEmpty(object);
166
+        } catch (Exception e) {
167
+            return false;
168
+        }
169
+    }
170
+
171
+    /**
172
+     * 存储文件,不返回地址
173
+     *
174
+     * @param bucketName 桶名称
175
+     * @param key        唯一标示id,例如a.txt, doc/a.txt
176
+     * @param file      文件
177
+     * @author xuyuxiang
178
+     * @date 2022/1/5 23:45
179
+     */
180
+    public static void storageFile(String bucketName, String key, File file) {
181
+        BufferedInputStream inputStream;
182
+        try {
183
+            inputStream = FileUtil.getInputStream(file);
184
+        } catch (IORuntimeException e) {
185
+            throw new RuntimeException("获取文件流异常,名称是:"+file.getName());
186
+        }
187
+        storageFile(bucketName, key, inputStream);
188
+    }
189
+
190
+    /**
191
+     * 存储文件,不返回地址
192
+     *
193
+     * @param bucketName 桶名称
194
+     * @param key        唯一标示id,例如a.txt, doc/a.txt
195
+     * @param multipartFile      文件
196
+     * @author xuyuxiang
197
+     * @date 2022/1/5 23:45
198
+     */
199
+    public static void storageFile(String bucketName, String key, MultipartFile multipartFile) {
200
+        InputStream inputStream;
201
+        try {
202
+            inputStream = multipartFile.getInputStream();
203
+        } catch (IOException e) {
204
+            throw new RuntimeException("获取文件流异常,名称是:"+ multipartFile.getName());
205
+        }
206
+        storageFile(bucketName, key, inputStream);
207
+    }
208
+
209
+    /**
210
+     * 存储文件,不返回地址
211
+     *
212
+     * @param bucketName 桶名称
213
+     * @param key        唯一标示id,例如a.txt, doc/a.txt
214
+     * @param bytes      文件字节数组
215
+     * @author xuyuxiang
216
+     * @date 2022/1/5 23:24
217
+     */
218
+    public static void storageFile(String bucketName, String key, byte[] bytes) {
219
+        ByteArrayInputStream byteArrayInputStream = null;
220
+        try {
221
+            initClient();
222
+            byteArrayInputStream = new ByteArrayInputStream(bytes);
223
+            PutObjectArgs putObjectArgs = PutObjectArgs.builder().bucket(bucketName).object(key)
224
+                    .contentType(getFileContentType(key)).stream(byteArrayInputStream, bytes.length, -1).build();
225
+            client.putObject(putObjectArgs);
226
+        } catch (Exception e) {
227
+            throw new RuntimeException(e.getMessage());
228
+        } finally {
229
+            IoUtil.close(byteArrayInputStream);
230
+        }
231
+    }
232
+
233
+    /**
234
+     * 存储文件,不返回地址
235
+     *
236
+     * @param bucketName  桶名称
237
+     * @param key         唯一标示id,例如a.txt, doc/a.txt
238
+     * @param inputStream 文件流
239
+     * @author xuyuxiang
240
+     * @date 2022/1/5 23:24
241
+     */
242
+    public static void storageFile(String bucketName, String key, InputStream inputStream) {
243
+        try {
244
+            initClient();
245
+            PutObjectArgs putObjectArgs = PutObjectArgs.builder().bucket(bucketName).object(key)
246
+                    .contentType(getFileContentType(key)).stream(inputStream, inputStream.available(), -1).build();
247
+            client.putObject(putObjectArgs);
248
+        } catch (Exception e) {
249
+            throw new RuntimeException(e.getMessage());
250
+        } finally {
251
+            IoUtil.close(inputStream);
252
+        }
253
+    }
254
+
255
+    /**
256
+     * 存储文件,返回外网地址
257
+     *
258
+     * @param bucketName 桶名称
259
+     * @param key        唯一标示id,例如a.txt, doc/a.txt
260
+     * @param file      文件
261
+     * @author xuyuxiang
262
+     * @date 2022/1/5 23:45
263
+     */
264
+    public static String storageFileWithReturnUrl(String bucketName, String key, File file) {
265
+        storageFile(bucketName, key, file);
266
+        setFileAcl(bucketName, key, DevFileBucketAuthEnum.PUBLIC_READ);
267
+        return getFileAuthUrl(bucketName, key);
268
+    }
269
+
270
+    /**
271
+     * 存储文件,返回外网地址
272
+     *
273
+     * @param bucketName 桶名称
274
+     * @param key        唯一标示id,例如a.txt, doc/a.txt
275
+     * @param multipartFile      文件
276
+     * @author xuyuxiang
277
+     * @date 2022/1/5 23:45
278
+     */
279
+    public static String storageFileWithReturnUrl(String bucketName, String key, MultipartFile multipartFile) {
280
+        storageFile(bucketName, key, multipartFile);
281
+        setFileAcl(bucketName, key, DevFileBucketAuthEnum.PUBLIC_READ);
282
+        return getFileAuthUrl(bucketName, key);
283
+    }
284
+
285
+    /**
286
+     * 存储文件,返回外网地址
287
+     *
288
+     * @param bucketName 桶名称
289
+     * @param key        唯一标示id,例如a.txt, doc/a.txt
290
+     * @param bytes      文件字节数组
291
+     * @author xuyuxiang
292
+     * @date 2022/1/5 23:24
293
+     */
294
+    public static String storageFileWithReturnUrl(String bucketName, String key, byte[] bytes) {
295
+        storageFile(bucketName, key, bytes);
296
+        setFileAcl(bucketName, key, DevFileBucketAuthEnum.PUBLIC_READ);
297
+        return getFileAuthUrl(bucketName, key);
298
+    }
299
+
300
+    /**
301
+     * 存储文件,返回外网地址
302
+     *
303
+     * @param bucketName  桶名称
304
+     * @param key         唯一标示id,例如a.txt, doc/a.txt
305
+     * @param inputStream 文件流
306
+     * @author xuyuxiang
307
+     * @date 2022/1/5 23:24
308
+     */
309
+    public static String storageFileWithReturnUrl(String bucketName, String key, InputStream inputStream) {
310
+        storageFile(bucketName, key, inputStream);
311
+        setFileAcl(bucketName, key, DevFileBucketAuthEnum.PUBLIC_READ);
312
+        return getFileAuthUrl(bucketName, key);
313
+    }
314
+
315
+    /**
316
+     * 获取某个bucket下的文件字节
317
+     *
318
+     * @param bucketName 桶名称
319
+     * @param key        唯一标示id,例如a.txt, doc/a.txt
320
+     * @author xuyuxiang
321
+     * @date 2022/1/5 23:24
322
+     */
323
+    public static byte[] getFileBytes(String bucketName, String key) {
324
+        try {
325
+            initClient();
326
+            GetObjectArgs getObjectArgs = GetObjectArgs.builder().bucket(bucketName).object(key).build();
327
+            InputStream inputStream = client.getObject(getObjectArgs);
328
+            return IoUtil.readBytes(inputStream);
329
+        } catch (Exception e) {
330
+            throw new RuntimeException(e.getMessage());
331
+        }
332
+    }
333
+
334
+    /**
335
+     * 设置文件访问权限管理
336
+     *
337
+     * @param bucketName     桶名称
338
+     * @param key             唯一标示id,例如a.txt, doc/a.txt
339
+     * @param devFileBucketAuthEnum 文件权限
340
+     * @author xuyuxiang
341
+     * @date 2022/1/5 23:24
342
+     */
343
+    public static void setFileAcl(String bucketName, String key, DevFileBucketAuthEnum devFileBucketAuthEnum) {
344
+        try {
345
+            JSONObject configObject = JSONUtil.createObj().set("Version", "2012-10-17");
346
+            JSONArray statementArray = JSONUtil.createArray();
347
+            JSONArray actionArray = JSONUtil.createArray();
348
+            if(devFileBucketAuthEnum.equals(DevFileBucketAuthEnum.PUBLIC_READ)) {
349
+                actionArray.put("s3:GetObject");
350
+            }
351
+            if(devFileBucketAuthEnum.equals(DevFileBucketAuthEnum.PUBLIC_READ_WRITE)) {
352
+                actionArray.put("s3:GetObject");
353
+                actionArray.put("s3:PutObject");
354
+            }
355
+            JSONObject statementObject = JSONUtil.createObj();
356
+            statementObject.set("Effect", "Allow").set("Principal", JSONUtil.createObj().set("AWS", JSONUtil.createArray().put("*")))
357
+                    .set("Action", actionArray).set("Resource", JSONUtil.createArray().put("arn:aws:s3:::" + bucketName + "/*"));
358
+            statementArray.put(statementObject);
359
+            configObject.set("Statement", statementArray);
360
+            String config = JSONUtil.toJsonStr(configObject);
361
+            SetBucketPolicyArgs setBucketPolicyArgs = SetBucketPolicyArgs.builder().bucket(bucketName).config(config).build();
362
+            client.setBucketPolicy(setBucketPolicyArgs);
363
+        } catch (Exception e) {
364
+            throw new RuntimeException(e.getMessage());
365
+        }
366
+    }
367
+
368
+    /**
369
+     * 拷贝文件
370
+     *
371
+     * @param originBucketName 源文件桶
372
+     * @param originFileKey    源文件名称
373
+     * @param newBucketName    新文件桶
374
+     * @param newFileKey       新文件名称
375
+     * @author xuyuxiang
376
+     * @date 2022/1/5 23:24
377
+     */
378
+    public static void copyFile(String originBucketName, String originFileKey, String newBucketName, String newFileKey) {
379
+        try {
380
+            initClient();
381
+            CopySource copySource = CopySource.builder().bucket(originBucketName).object(originFileKey).build();
382
+            CopyObjectArgs copyObjectArgs = CopyObjectArgs.builder().source(copySource).bucket(newBucketName).object(newFileKey).build();
383
+            client.copyObject(copyObjectArgs);
384
+        } catch (Exception e) {
385
+            throw new RuntimeException(e.getMessage());
386
+        }
387
+    }
388
+
389
+    /**
390
+     * 获取文件的下载地址(带鉴权和有效时间的),生成外网地址
391
+     *
392
+     * @param bucketName 文件桶
393
+     * @param key        唯一标示id,例如a.txt, doc/a.txt
394
+     * @param timeoutMillis 时效
395
+     * @author xuyuxiang
396
+     * @date 2022/1/5 23:24
397
+     */
398
+    public static String getFileAuthUrl(String bucketName, String key, Long timeoutMillis) {
399
+        try {
400
+            initClient();
401
+            GetPresignedObjectUrlArgs getPresignedObjectUrlArgs = GetPresignedObjectUrlArgs.builder().bucket(bucketName)
402
+                    .object(key).method(Method.GET).expiry(timeoutMillis.intValue()).build();
403
+            return client.getPresignedObjectUrl(getPresignedObjectUrlArgs);
404
+        } catch (Exception e) {
405
+            throw new RuntimeException(e.getMessage());
406
+        }
407
+    }
408
+
409
+    /**
410
+     * 获取文件的下载地址(永久的,文件必须为公有读),生成外网地址
411
+     *
412
+     * @param bucketName 文件桶
413
+     * @param key        唯一标示id,例如a.txt, doc/a.txt
414
+     * @author xuyuxiang
415
+     * @date 2022/1/5 23:24
416
+     */
417
+    public static String getFileAuthUrl(String bucketName, String key) {
418
+        try {
419
+            initClient();
420
+            DevConfigApi devConfigApi = SpringUtil.getBean(DevConfigApi.class);
421
+            return devConfigApi.getValueByKey(SNOWY_FILE_MINIO_ACCESS_PREFIX) + StrUtil.SLASH + bucketName + StrUtil.SLASH + key;
422
+        } catch (Exception e) {
423
+            throw new RuntimeException(e.getMessage());
424
+        }
425
+    }
426
+
427
+    /**
428
+     * 删除文件
429
+     *
430
+     * @param bucketName 文件桶
431
+     * @param key        唯一标示id,例如a.txt, doc/a.txt
432
+     * @author xuyuxiang
433
+     * @date 2022/1/5 23:24
434
+     */
435
+    public static void deleteFile(String bucketName, String key) {
436
+        try {
437
+            RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder().bucket(bucketName).object(key).build();
438
+            client.removeObject(removeObjectArgs);
439
+        } catch (Exception e) {
440
+            throw new RuntimeException(e.getMessage());
441
+        }
442
+    }
443
+
444
+    /**
445
+     * 根据文件名获取ContentType
446
+     *
447
+     * @author xuyuxiang
448
+     * @date 2022/1/6 11:27
449
+     **/
450
+    private static String getFileContentType(String key) {
451
+        // 根据文件名获取contentType
452
+        String contentType = "application/octet-stream";
453
+        if (key.contains(".")) {
454
+            contentType = MimetypesFileTypeMap.getDefaultFileTypeMap().getContentType(key);
455
+        }
456
+        return contentType;
457
+    }
458
+
459
+}