除Controller层移植

This commit is contained in:
黄子寒 2024-12-13 17:26:51 +08:00
parent c046cb11cc
commit acb58cefce
34 changed files with 2908 additions and 225 deletions

View File

@ -46,3 +46,54 @@
12:19:32.287 [http-nio-9090-exec-2] INFO c.m.utils.MinioUtils - [getUploadObjectUrl,74] - tip message: 单个文件上传、成功
12:35:11.549 [SpringApplicationShutdownHook] INFO c.z.h.HikariDataSource - [close,350] - HikariPool-1 - Shutdown initiated...
12:35:11.575 [SpringApplicationShutdownHook] INFO c.z.h.HikariDataSource - [close,352] - HikariPool-1 - Shutdown completed.
14:59:06.483 [background-preinit] INFO o.h.v.i.util.Version - [<clinit>,21] - HV000001: Hibernate Validator 8.0.0.Final
14:59:06.493 [restartedMain] INFO c.m.MinioUploadFileApplication - [logStarting,51] - Starting MinioUploadFileApplication using Java 20.0.2.1 with PID 11052 (F:\Project\tutorial_repo\minio-admin\target\classes started by Administrator in F:\Project\tutorial_repo\minio-admin)
14:59:06.494 [restartedMain] INFO c.m.MinioUploadFileApplication - [logStartupProfileInfo,630] - No active profile set, falling back to 1 default profile: "default"
14:59:07.460 [restartedMain] INFO o.a.c.h.Http11NioProtocol - [log,173] - Initializing ProtocolHandler ["http-nio-9090"]
14:59:07.460 [restartedMain] INFO o.a.c.c.StandardService - [log,173] - Starting service [Tomcat]
14:59:07.460 [restartedMain] INFO o.a.c.c.StandardEngine - [log,173] - Starting Servlet engine: [Apache Tomcat/10.1.5]
14:59:07.493 [restartedMain] INFO o.a.c.c.C.[.[.[/] - [log,173] - Initializing Spring embedded WebApplicationContext
14:59:08.220 [restartedMain] INFO o.a.c.h.Http11NioProtocol - [log,173] - Starting ProtocolHandler ["http-nio-9090"]
14:59:08.238 [restartedMain] INFO c.m.MinioUploadFileApplication - [logStarted,57] - Started MinioUploadFileApplication in 1.976 seconds (process running for 2.74)
15:06:31.118 [http-nio-9090-exec-1] INFO o.a.c.c.C.[.[.[/] - [log,173] - Initializing Spring DispatcherServlet 'dispatcherServlet'
15:06:31.147 [http-nio-9090-exec-1] INFO c.m.c.FileMinioController - [checkFileUploadedByMd5,74] - REST: 通过查询 <d4352583feb4f6562a5c831aace01ce1> 文件是否存在、是否进行断点续传
15:06:31.147 [http-nio-9090-exec-1] INFO c.m.s.i.UploadServiceImpl - [getByFileMD5,48] - tip message: 通过 <d4352583feb4f6562a5c831aace01ce1> 查询redis是否存在
15:06:31.371 [http-nio-9090-exec-1] INFO c.m.s.i.UploadServiceImpl - [getByFileMD5,59] - tip message: 通过 <d4352583feb4f6562a5c831aace01ce1> 查询mysql是否存在
15:06:31.421 [http-nio-9090-exec-1] INFO c.z.h.HikariDataSource - [getConnection,110] - HikariPool-1 - Starting...
15:06:31.833 [http-nio-9090-exec-1] INFO c.z.h.p.HikariPool - [checkFailFast,565] - HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@54691a3
15:06:31.834 [http-nio-9090-exec-1] INFO c.z.h.HikariDataSource - [getConnection,123] - HikariPool-1 - Start completed.
15:06:31.915 [http-nio-9090-exec-3] INFO c.m.c.FileMinioController - [initMultiPartUpload,90] - REST: 通过 <FileUploadInfo(fileName=微信图片_20230407024048.jpg, fileSize=309622, contentType=application/octet-stream, chunkNum=1, uploadId=null, chunkSize=10485760, fileMd5=d4352583feb4f6562a5c831aace01ce1, fileType=image, chunkUploadedList=[])> 初始化上传任务
15:06:31.917 [http-nio-9090-exec-3] INFO c.m.s.i.UploadServiceImpl - [initMultiPartUpload,85] - tip message: 通过 <FileUploadInfo(fileName=微信图片_20230407024048.jpg, fileSize=309622, contentType=application/octet-stream, chunkNum=1, uploadId=null, chunkSize=10485760, fileMd5=d4352583feb4f6562a5c831aace01ce1, fileType=image, chunkUploadedList=[])> 开始初始化<分片上传>任务
15:06:32.157 [http-nio-9090-exec-3] INFO c.m.s.i.UploadServiceImpl - [initMultiPartUpload,91] - tip message: 当前分片数量 <1> 进行单文件上传
15:06:32.165 [http-nio-9090-exec-3] INFO c.m.c.MybatisPlusConfig - [insertFill,37] - start insert fill ....
15:06:32.307 [http-nio-9090-exec-3] INFO c.m.utils.MinioUtils - [getUploadObjectUrl,64] - tip message: 通过 <d4352583feb4f6562a5c831aace01ce1.jpg-image> 开始单文件上传<minio>
15:06:32.312 [http-nio-9090-exec-3] INFO c.m.utils.MinioUtils - [getUploadObjectUrl,74] - tip message: 单个文件上传、成功
15:18:43.669 [SpringApplicationShutdownHook] INFO c.z.h.HikariDataSource - [close,350] - HikariPool-1 - Shutdown initiated...
15:18:43.671 [SpringApplicationShutdownHook] INFO c.z.h.HikariDataSource - [close,352] - HikariPool-1 - Shutdown completed.
15:18:52.280 [background-preinit] INFO o.h.v.i.util.Version - [<clinit>,21] - HV000001: Hibernate Validator 8.0.0.Final
15:18:52.294 [restartedMain] INFO c.m.MinioUploadFileApplication - [logStarting,51] - Starting MinioUploadFileApplication using Java 20.0.2.1 with PID 111164 (F:\Project\tutorial_repo\minio-admin\target\classes started by Administrator in F:\Project\tutorial_repo\minio-admin)
15:18:52.295 [restartedMain] INFO c.m.MinioUploadFileApplication - [logStartupProfileInfo,630] - No active profile set, falling back to 1 default profile: "default"
15:18:53.049 [restartedMain] INFO o.a.c.h.Http11NioProtocol - [log,173] - Initializing ProtocolHandler ["http-nio-9090"]
15:18:53.050 [restartedMain] INFO o.a.c.c.StandardService - [log,173] - Starting service [Tomcat]
15:18:53.050 [restartedMain] INFO o.a.c.c.StandardEngine - [log,173] - Starting Servlet engine: [Apache Tomcat/10.1.5]
15:18:53.086 [restartedMain] INFO o.a.c.c.C.[.[.[/] - [log,173] - Initializing Spring embedded WebApplicationContext
15:18:53.658 [restartedMain] INFO o.a.c.h.Http11NioProtocol - [log,173] - Starting ProtocolHandler ["http-nio-9090"]
15:18:53.677 [restartedMain] INFO c.m.MinioUploadFileApplication - [logStarted,57] - Started MinioUploadFileApplication in 1.577 seconds (process running for 2.039)
15:20:02.328 [http-nio-9090-exec-1] INFO o.a.c.c.C.[.[.[/] - [log,173] - Initializing Spring DispatcherServlet 'dispatcherServlet'
15:20:02.354 [http-nio-9090-exec-1] INFO c.m.c.FileMinioController - [checkFileUploadedByMd5,74] - REST: 通过查询 <d4352583feb4f6562a5c831aace01ce1> 文件是否存在、是否进行断点续传
15:20:02.355 [http-nio-9090-exec-1] INFO c.m.s.i.UploadServiceImpl - [getByFileMD5,48] - tip message: 通过 <d4352583feb4f6562a5c831aace01ce1> 查询redis是否存在
15:20:02.581 [http-nio-9090-exec-1] INFO c.m.s.i.UploadServiceImpl - [getByFileMD5,59] - tip message: 通过 <d4352583feb4f6562a5c831aace01ce1> 查询mysql是否存在
15:20:02.617 [http-nio-9090-exec-1] INFO c.z.h.HikariDataSource - [getConnection,110] - HikariPool-1 - Starting...
15:20:02.807 [http-nio-9090-exec-1] INFO c.z.h.p.HikariPool - [checkFailFast,565] - HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@5ba8145c
15:20:02.808 [http-nio-9090-exec-1] INFO c.z.h.HikariDataSource - [getConnection,123] - HikariPool-1 - Start completed.
15:20:02.906 [http-nio-9090-exec-2] INFO c.m.c.FileMinioController - [checkFileUploadedByMd5,74] - REST: 通过查询 <20b919730ee383d47e4c008f11652b02> 文件是否存在、是否进行断点续传
15:20:02.906 [http-nio-9090-exec-2] INFO c.m.s.i.UploadServiceImpl - [getByFileMD5,48] - tip message: 通过 <20b919730ee383d47e4c008f11652b02> 查询redis是否存在
15:20:02.908 [http-nio-9090-exec-2] INFO c.m.s.i.UploadServiceImpl - [getByFileMD5,59] - tip message: 通过 <20b919730ee383d47e4c008f11652b02> 查询mysql是否存在
15:20:02.933 [http-nio-9090-exec-3] INFO c.m.c.FileMinioController - [initMultiPartUpload,90] - REST: 通过 <FileUploadInfo(fileName=报名照片.jpg, fileSize=12700, contentType=application/octet-stream, chunkNum=1, uploadId=null, chunkSize=10485760, fileMd5=20b919730ee383d47e4c008f11652b02, fileType=image, chunkUploadedList=[])> 初始化上传任务
15:20:02.935 [http-nio-9090-exec-3] INFO c.m.s.i.UploadServiceImpl - [initMultiPartUpload,85] - tip message: 通过 <FileUploadInfo(fileName=报名照片.jpg, fileSize=12700, contentType=application/octet-stream, chunkNum=1, uploadId=null, chunkSize=10485760, fileMd5=20b919730ee383d47e4c008f11652b02, fileType=image, chunkUploadedList=[])> 开始初始化<分片上传>任务
15:20:03.137 [http-nio-9090-exec-3] INFO c.m.s.i.UploadServiceImpl - [initMultiPartUpload,91] - tip message: 当前分片数量 <1> 进行单文件上传
15:20:03.144 [http-nio-9090-exec-3] INFO c.m.c.MybatisPlusConfig - [insertFill,37] - start insert fill ....
15:20:03.248 [http-nio-9090-exec-3] INFO c.m.s.i.UploadServiceImpl - [initMultiPartUpload,94] - -------文件名20b919730ee383d47e4c008f11652b02.jpg
15:20:03.249 [http-nio-9090-exec-3] INFO c.m.utils.MinioUtils - [getUploadObjectUrl,64] - tip message: 通过 <20b919730ee383d47e4c008f11652b02.jpg-image> 开始单文件上传<minio>
15:20:03.253 [http-nio-9090-exec-3] INFO c.m.utils.MinioUtils - [getUploadObjectUrl,74] - 预签名完成:http://47.103.114.59:9000/image/20b919730ee383d47e4c008f11652b02.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=olive%2F20241213%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20241213T072003Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&X-Amz-Signature=c53c0fc6753a7c55e09b0536ac6141a907018141886e910e68d3b64c513ed1a6
15:20:03.253 [http-nio-9090-exec-3] INFO c.m.utils.MinioUtils - [getUploadObjectUrl,75] - tip message: 单个文件上传、成功

View File

@ -73,6 +73,16 @@
<artifactId>hutool-all</artifactId>
<version>5.7.20</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
<version>1.12.572</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
</dependencies>
<dependencyManagement>

View File

@ -0,0 +1,33 @@
package com.mmg.config;
/*
* Copyright (C) 2023 杭州白书科技有限公司
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import lombok.Data;
import org.springframework.stereotype.Component;
@Data
@Component
public class S3Config {
private String accessKey;
private String secretKey;
private String bucket;
private String endpoint;
private String domain;
private String region;
private String service;
}

View File

@ -0,0 +1,138 @@
package com.mmg.constant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class BackendConstant {
public static final String SUPER_ADMIN_ROLE = "super-role";
public static final List<String> UN_AUTH_URI_WHITELIST =
new ArrayList<>() {
{
add("/backend/v1/system/image-captcha");
add("/backend/v1/auth/login");
add("/backend/v1/captcha/generate");
}
};
public static final List<String> API_LIMIT_WHITELIST =
new ArrayList<>() {
{
add("/backend/v1/upload/minio/pre-sign-url");
}
};
public static final String RESOURCE_TYPE_VIDEO = "VIDEO";
public static final String RESOURCE_TYPE_IMAGE = "IMAGE";
public static final String RESOURCE_TYPE_PDF = "PDF";
public static final String RESOURCE_TYPE_WORD = "WORD";
public static final String RESOURCE_TYPE_PPT = "PPT";
public static final String RESOURCE_TYPE_EXCEL = "EXCEL";
public static final String RESOURCE_TYPE_ZIP = "ZIP";
public static final String RESOURCE_TYPE_RAR = "RAR";
public static final String RESOURCE_TYPE_TXT = "TXT";
public static final String RESOURCE_TYPE_ATTACHMENT =
RESOURCE_TYPE_PDF
+ ","
+ RESOURCE_TYPE_TXT
+ ","
+ RESOURCE_TYPE_ZIP
+ ","
+ RESOURCE_TYPE_RAR
+ ","
+ RESOURCE_TYPE_WORD
+ ","
+ RESOURCE_TYPE_PPT
+ ","
+ RESOURCE_TYPE_EXCEL;
public static final HashMap<String, String> RESOURCE_EXT_2_CONTENT_TYPE =
new HashMap<>() {
{
put("png", "image/png");
put("jpg", "image/jpg");
put("jpeg", "image/jpeg");
put("gif", "image/gif");
put("pdf", "application/pdf");
put("mp4", "video/mp4");
put("doc", "application/msword");
put(
"docx",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document");
put("ppt", "application/vnd.ms-powerpoint");
put(
"pptx",
"application/vnd.openxmlformats-officedocument.presentationml.presentation");
put("xls", "application/vnd.ms-excel");
put(
"xlsx",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
put("txt", "text/plain");
put("zip", "application/zip");
put("rar", "application/x-rar");
}
};
public static final HashMap<String, String> RESOURCE_EXT_2_TYPE =
new HashMap<>() {
{
put("png", RESOURCE_TYPE_IMAGE);
put("jpg", RESOURCE_TYPE_IMAGE);
put("jpeg", RESOURCE_TYPE_IMAGE);
put("gif", RESOURCE_TYPE_IMAGE);
put("pdf", RESOURCE_TYPE_PDF);
put("mp4", RESOURCE_TYPE_VIDEO);
put("doc", RESOURCE_TYPE_WORD);
put("docx", RESOURCE_TYPE_WORD);
put("ppt", RESOURCE_TYPE_PPT);
put("pptx", RESOURCE_TYPE_PPT);
put("xls", RESOURCE_TYPE_EXCEL);
put("xlsx", RESOURCE_TYPE_EXCEL);
put("txt", RESOURCE_TYPE_TXT);
put("zip", RESOURCE_TYPE_ZIP);
put("rar", RESOURCE_TYPE_RAR);
}
};
public static final HashMap<String, String> RESOURCE_TYPE_2_DIR =
new HashMap<>() {
{
put(RESOURCE_TYPE_VIDEO, UPLOAD_VIDEO_DIR);
put(RESOURCE_TYPE_IMAGE, UPLOAD_IMAGE_DIR);
put(RESOURCE_TYPE_PDF, UPLOAD_PDF_DIR);
put(RESOURCE_TYPE_WORD, UPLOAD_WORD_DIR);
put(RESOURCE_TYPE_PPT, UPLOAD_PPT_DIR);
put(RESOURCE_TYPE_EXCEL, UPLOAD_EXCEL_DIR);
put(RESOURCE_TYPE_TXT, UPLOAD_TXT_DIR);
put(RESOURCE_TYPE_ZIP, UPLOAD_ZIP_DIR);
put(RESOURCE_TYPE_RAR, UPLOAD_RAR_DIR);
}
};
public static final String STORAGE_DRIVER_MINIO = "minio";
public static final String[] COURSE_HOUR_TYPE_WHITELIST = {"VIDEO"};
public static final String[] COURSE_HOUR_TYPE_WHITELIST_TEXT = {"视频"};
public static final String UPLOAD_IMAGE_DIR = "images/";
public static final String UPLOAD_VIDEO_DIR = "videos/";
public static final String UPLOAD_PDF_DIR = "pdf/";
public static final String UPLOAD_WORD_DIR = "word/";
public static final String UPLOAD_PPT_DIR = "ppt/";
public static final String UPLOAD_EXCEL_DIR = "excel/";
public static final String UPLOAD_TXT_DIR = "txt/";
public static final String UPLOAD_ZIP_DIR = "zip/";
public static final String UPLOAD_RAR_DIR = "rar/";
public static final String PRIVACY_FIELD_TYPE_EMAIL = "email";
public static final String PRIVACY_FIELD_TYPE_PHONE = "phone";
public static final String PRIVACY_FIELD_TYPE_NAME = "name";
public static final String PRIVACY_FIELD_TYPE_ID_CARD = "IDCard";
public static final String APP_CONFIG_FIELD_TYPE_IMAGE = "image";
public static final String APP_CONFIG_FIELD_TYPE_INPUT = "input";
public static final String APP_CONFIG_FIELD_TYPE_TEXT = "text";
public static final String APP_CONFIG_FIELD_TYPE_SELECT = "select";
public static final String APP_CONFIG_FIELD_TYPE_SWITCH = "switch";
}

View File

@ -0,0 +1,13 @@
package com.mmg.constant;
public class ConfigConstant {
public static final String MINIO_ACCESS_KEY = "minio.access_key";
public static final String MINIO_SECRET_KEY = "minio.secret_key";
public static final String MINIO_BUCKET = "minio.bucket";
public static final String MINIO_ENDPOINT = "minio.endpoint";
public static final String MINIO_DOMAIN = "minio.domain";
}

View File

@ -0,0 +1,15 @@
package com.mmg.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mmg.model.po.AppConfig;
import org.apache.ibatis.annotations.Mapper;
/**
*
* @description 针对表app_config的数据库操作Mapper
* @createDate 2023-03-09 13:55:39
*/
@Mapper
public interface AppConfigMapper extends BaseMapper<AppConfig> {}

View File

@ -0,0 +1,29 @@
/*
* Copyright (C) 2023 杭州白书科技有限公司
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mmg.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mmg.model.po.ResourceCategory;
import org.apache.ibatis.annotations.Mapper;
/**
* @author tengteng
* @description 针对表resource_category的数据库操作Mapper
* @createDate 2023-03-08 16:54:56
*/
@Mapper
public interface ResourceCategoryMapper extends BaseMapper<ResourceCategory> {}

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2023 杭州白书科技有限公司
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mmg.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mmg.model.paginate.ResourcePaginateFilter;
import com.mmg.model.po.Resource;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* @author tengteng
* @description 针对表resources的数据库操作Mapper
* @createDate 2023-03-13 10:25:30
*/
@Mapper
public interface ResourceMapper extends BaseMapper<Resource> {
List<Resource> paginate(ResourcePaginateFilter filter);
Long paginateCount(ResourcePaginateFilter filter);
List<String> paginateType(ResourcePaginateFilter filter);
}

View File

@ -0,0 +1,29 @@
/*
* Copyright (C) 2023 杭州白书科技有限公司
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mmg.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mmg.model.po.ResourceVideo;
import org.apache.ibatis.annotations.Mapper;
/**
* @author tengteng
* @description 针对表resource_videos的数据库操作Mapper
* @createDate 2023-03-08 13:39:06
*/
@Mapper
public interface ResourceVideoMapper extends BaseMapper<ResourceVideo> {}

View File

@ -0,0 +1,27 @@
package com.mmg.model.paginate;
import java.util.List;
public class PaginationResult<T> {
private List<T> data;
private Long total;
public List<T> getData() {
return data;
}
public void setData(List<T> data) {
this.data = data;
}
public Long getTotal() {
return total;
}
public void setTotal(Long total) {
this.total = total;
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2023 杭州白书科技有限公司
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mmg.model.paginate;
import lombok.Data;
import java.util.List;
@Data
public class ResourcePaginateFilter {
private String name;
private String extension;
private String disk;
private String sortField;
private String sortAlgo;
private List<Integer> categoryIds;
private String type;
private Integer adminId;
private Integer pageStart;
private Integer pageSize;
}

View File

@ -0,0 +1,162 @@
package com.mmg.model.po;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* @TableName app_config
*/
@TableName(value = "app_config")
@Data
public class AppConfig implements Serializable {
/** */
@TableId(type = IdType.AUTO)
private Long id;
/** 分组 */
@JsonProperty("group_name")
private String groupName;
/** 名称 */
private String name;
/** 升序 */
private Integer sort;
/** */
@JsonProperty("field_type")
private String fieldType;
/** 键 */
@JsonProperty("key_name")
private String keyName;
/** 值 */
@JsonProperty("key_value")
private String keyValue;
/** 可选值 */
@JsonProperty("option_value")
private String optionValue;
/** 是否私密信息 */
@JsonProperty("is_private")
private Integer isPrivate;
/** 帮助信息 */
private String help;
/** */
@JsonIgnore private Date createdAt;
/** 1显示,0否 */
@JsonIgnore private Integer isHidden;
@JsonGetter("key_value")
public String transformKeyValue() {
return isHidden == 1 ? "******" : keyValue;
}
@TableField(exist = false)
private static final long serialVersionUID = 1L;
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
}
if (that == null) {
return false;
}
if (getClass() != that.getClass()) {
return false;
}
AppConfig other = (AppConfig) that;
return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId()))
&& (this.getGroupName() == null
? other.getGroupName() == null
: this.getGroupName().equals(other.getGroupName()))
&& (this.getName() == null
? other.getName() == null
: this.getName().equals(other.getName()))
&& (this.getSort() == null
? other.getSort() == null
: this.getSort().equals(other.getSort()))
&& (this.getFieldType() == null
? other.getFieldType() == null
: this.getFieldType().equals(other.getFieldType()))
&& (this.getKeyName() == null
? other.getKeyName() == null
: this.getKeyName().equals(other.getKeyName()))
&& (this.getKeyValue() == null
? other.getKeyValue() == null
: this.getKeyValue().equals(other.getKeyValue()))
&& (this.getOptionValue() == null
? other.getOptionValue() == null
: this.getOptionValue().equals(other.getOptionValue()))
&& (this.getIsPrivate() == null
? other.getIsPrivate() == null
: this.getIsPrivate().equals(other.getIsPrivate()))
&& (this.getHelp() == null
? other.getHelp() == null
: this.getHelp().equals(other.getHelp()))
&& (this.getCreatedAt() == null
? other.getCreatedAt() == null
: this.getCreatedAt().equals(other.getCreatedAt()))
&& (this.getIsHidden() == null
? other.getIsHidden() == null
: this.getIsHidden().equals(other.getIsHidden()));
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
result = prime * result + ((getGroupName() == null) ? 0 : getGroupName().hashCode());
result = prime * result + ((getName() == null) ? 0 : getName().hashCode());
result = prime * result + ((getSort() == null) ? 0 : getSort().hashCode());
result = prime * result + ((getFieldType() == null) ? 0 : getFieldType().hashCode());
result = prime * result + ((getKeyName() == null) ? 0 : getKeyName().hashCode());
result = prime * result + ((getKeyValue() == null) ? 0 : getKeyValue().hashCode());
result = prime * result + ((getOptionValue() == null) ? 0 : getOptionValue().hashCode());
result = prime * result + ((getIsPrivate() == null) ? 0 : getIsPrivate().hashCode());
result = prime * result + ((getHelp() == null) ? 0 : getHelp().hashCode());
result = prime * result + ((getCreatedAt() == null) ? 0 : getCreatedAt().hashCode());
result = prime * result + ((getIsHidden() == null) ? 0 : getIsHidden().hashCode());
return result;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getClass().getSimpleName());
sb.append(" [");
sb.append("Hash = ").append(hashCode());
sb.append(", id=").append(id);
sb.append(", groupName=").append(groupName);
sb.append(", name=").append(name);
sb.append(", sort=").append(sort);
sb.append(", fieldType=").append(fieldType);
sb.append(", keyName=").append(keyName);
sb.append(", keyValue=").append(keyValue);
sb.append(", optionValue=").append(optionValue);
sb.append(", isPrivate=").append(isPrivate);
sb.append(", help=").append(help);
sb.append(", createdAt=").append(createdAt);
sb.append(", isHidden=").append(isHidden);
sb.append(", serialVersionUID=").append(serialVersionUID);
sb.append("]");
return sb.toString();
}
}

View File

@ -0,0 +1,161 @@
package com.mmg.model.po;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* @TableName resources
*/
@TableName(value = "resources")
@Data
public class Resource implements Serializable {
/** */
@TableId(type = IdType.AUTO)
private Integer id;
/** */
@JsonProperty("admin_id")
private Integer adminId;
/** 类型 */
private String type;
/** 资源名 */
private String name;
/** 文件类型 */
private String extension;
/** 大小[字节] */
private Long size;
/** 存储磁盘 */
private String disk;
/** 文件id */
@JsonProperty("file_id")
private String fileId;
/** 相对地址 */
private String path;
/** URL地址 */
private String url;
/** */
@JsonProperty("created_at")
private Date createdAt;
/** 所属素材 */
@JsonProperty("parent_id")
private Integer parentId;
/** 隐藏[0:否,1:是] */
@JsonIgnore private Integer isHidden;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
}
if (that == null) {
return false;
}
if (getClass() != that.getClass()) {
return false;
}
Resource other = (Resource) that;
return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId()))
&& (this.getAdminId() == null
? other.getAdminId() == null
: this.getAdminId().equals(other.getAdminId()))
&& (this.getType() == null
? other.getType() == null
: this.getType().equals(other.getType()))
&& (this.getName() == null
? other.getName() == null
: this.getName().equals(other.getName()))
&& (this.getExtension() == null
? other.getExtension() == null
: this.getExtension().equals(other.getExtension()))
&& (this.getSize() == null
? other.getSize() == null
: this.getSize().equals(other.getSize()))
&& (this.getDisk() == null
? other.getDisk() == null
: this.getDisk().equals(other.getDisk()))
&& (this.getFileId() == null
? other.getFileId() == null
: this.getFileId().equals(other.getFileId()))
&& (this.getPath() == null
? other.getPath() == null
: this.getPath().equals(other.getPath()))
&& (this.getUrl() == null
? other.getUrl() == null
: this.getUrl().equals(other.getUrl()))
&& (this.getCreatedAt() == null
? other.getCreatedAt() == null
: this.getCreatedAt().equals(other.getCreatedAt()))
&& (this.getParentId() == null
? other.getParentId() == null
: this.getParentId().equals(other.getParentId()))
&& (this.getIsHidden() == null
? other.getIsHidden() == null
: this.getIsHidden().equals(other.getIsHidden()));
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
result = prime * result + ((getAdminId() == null) ? 0 : getAdminId().hashCode());
result = prime * result + ((getType() == null) ? 0 : getType().hashCode());
result = prime * result + ((getName() == null) ? 0 : getName().hashCode());
result = prime * result + ((getExtension() == null) ? 0 : getExtension().hashCode());
result = prime * result + ((getSize() == null) ? 0 : getSize().hashCode());
result = prime * result + ((getDisk() == null) ? 0 : getDisk().hashCode());
result = prime * result + ((getFileId() == null) ? 0 : getFileId().hashCode());
result = prime * result + ((getPath() == null) ? 0 : getPath().hashCode());
result = prime * result + ((getUrl() == null) ? 0 : getUrl().hashCode());
result = prime * result + ((getCreatedAt() == null) ? 0 : getCreatedAt().hashCode());
result = prime * result + ((getParentId() == null) ? 0 : getParentId().hashCode());
result = prime * result + ((getIsHidden() == null) ? 0 : getIsHidden().hashCode());
return result;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getClass().getSimpleName());
sb.append(" [");
sb.append("Hash = ").append(hashCode());
sb.append(", id=").append(id);
sb.append(", adminId=").append(adminId);
sb.append(", type=").append(type);
sb.append(", name=").append(name);
sb.append(", extension=").append(extension);
sb.append(", size=").append(size);
sb.append(", disk=").append(disk);
sb.append(", fileId=").append(fileId);
sb.append(", path=").append(path);
sb.append(", url=").append(url);
sb.append(", createdAt=").append(createdAt);
sb.append(", parentId=").append(parentId);
sb.append(", isHidden=").append(isHidden);
sb.append(", serialVersionUID=").append(serialVersionUID);
sb.append("]");
return sb.toString();
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright (C) 2023 杭州白书科技有限公司
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mmg.model.po;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
/**
* @TableName resource_category
*/
@TableName(value = "resource_category")
@Data
public class ResourceCategory implements Serializable {
/** */
private Integer cid;
/** */
private Integer rid;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
}
if (that == null) {
return false;
}
if (getClass() != that.getClass()) {
return false;
}
ResourceCategory other = (ResourceCategory) that;
return (this.getCid() == null
? other.getCid() == null
: this.getCid().equals(other.getCid()))
&& (this.getRid() == null
? other.getRid() == null
: this.getRid().equals(other.getRid()));
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((getCid() == null) ? 0 : getCid().hashCode());
result = prime * result + ((getRid() == null) ? 0 : getRid().hashCode());
return result;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getClass().getSimpleName());
sb.append(" [");
sb.append("Hash = ").append(hashCode());
sb.append(", cid=").append(cid);
sb.append(", rid=").append(rid);
sb.append(", serialVersionUID=").append(serialVersionUID);
sb.append("]");
return sb.toString();
}
}

View File

@ -0,0 +1,98 @@
/*
* Copyright (C) 2023 杭州白书科技有限公司
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mmg.model.po;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* @TableName resource_videos
*/
@TableName(value = "resource_videos")
@Data
public class ResourceVideo implements Serializable {
/** */
private Integer rid;
/** 封面 */
private String poster;
/** 视频时长[s] */
private Integer duration;
/** 创建时间 */
@JsonIgnore private Date createdAt;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
}
if (that == null) {
return false;
}
if (getClass() != that.getClass()) {
return false;
}
ResourceVideo other = (ResourceVideo) that;
return (this.getRid() == null
? other.getRid() == null
: this.getRid().equals(other.getRid()))
&& (this.getPoster() == null
? other.getPoster() == null
: this.getPoster().equals(other.getPoster()))
&& (this.getDuration() == null
? other.getDuration() == null
: this.getDuration().equals(other.getDuration()))
&& (this.getCreatedAt() == null
? other.getCreatedAt() == null
: this.getCreatedAt().equals(other.getCreatedAt()));
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((getRid() == null) ? 0 : getRid().hashCode());
result = prime * result + ((getPoster() == null) ? 0 : getPoster().hashCode());
result = prime * result + ((getDuration() == null) ? 0 : getDuration().hashCode());
result = prime * result + ((getCreatedAt() == null) ? 0 : getCreatedAt().hashCode());
return result;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getClass().getSimpleName());
sb.append(" [");
sb.append("Hash = ").append(hashCode());
sb.append(", rid=").append(rid);
sb.append(", poster=").append(poster);
sb.append(", duration=").append(duration);
sb.append(", createdAt=").append(createdAt);
sb.append(", serialVersionUID=").append(serialVersionUID);
sb.append("]");
return sb.toString();
}
}

View File

@ -1,45 +0,0 @@
package com.mmg.model.vo;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
@Data
@Accessors(chain = true)
public class FileUploadInfo {
@NotBlank(message = "文件名不能为空")
private String fileName;
@NotNull(message = "文件大小不能为空")
private Long fileSize;
@NotBlank(message = "Content-Type不能为空")
private String contentType;
@NotNull(message = "分片数量不能为空")
private Integer chunkNum;
@NotBlank(message = "uploadId 不能为空")
private String uploadId;
private Long chunkSize;
// 桶名称
//private String bucketName;
//md5
private String fileMd5;
//文件类型
private String fileType;
//已上传的分片索引+1
private List<Integer> chunkUploadedList;
}

View File

@ -0,0 +1,21 @@
package com.mmg.model.vo;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
@Data
public class UploadFileInfo {
private String originalName;
private String extension;
private long size;
private String saveName;
private String resourceType;
private String savePath;
private String url;
}

View File

@ -0,0 +1,26 @@
package com.mmg.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.mmg.config.S3Config;
import com.mmg.model.po.AppConfig;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public interface AppConfigService extends IService<AppConfig> {
Map<String, Long> allKeys();
List<AppConfig> allShow();
void saveFromMap(HashMap<String, String> data);
Map<String, String> keyValues();
S3Config getS3Config();
}

View File

@ -0,0 +1,29 @@
/*
* Copyright (C) 2023 杭州白书科技有限公司
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mmg.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.mmg.model.po.ResourceCategory;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public interface ResourceCategoryService extends IService<ResourceCategory> {
void rebuild(Integer resourceId, List<Integer> categoryIds);
List<Integer> getRidsByCategoryId(Integer id);
}

View File

@ -0,0 +1,50 @@
package com.mmg.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.mmg.model.paginate.PaginationResult;
import com.mmg.model.paginate.ResourcePaginateFilter;
import com.mmg.model.po.Resource;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public interface ResourceService extends IService<Resource> {
PaginationResult<Resource> paginate(int page, int size, ResourcePaginateFilter filter);
List<String> paginateType(ResourcePaginateFilter filter);
Resource create(
Integer adminId,
String categoryIds,
String type,
String filename,
String ext,
Long size,
String disk,
String fileId,
String path,
String url);
Resource findOrFail(Integer id) throws Exception;
void changeParentId(Integer id, Integer parentId);
void storeResourceVideo(Integer rid, Integer duration, String poster);
List<Resource> chunks(List<Integer> ids);
List<Resource> chunks(List<Integer> ids, List<String> fields);
Integer total(String type);
Integer duration(Integer id);
void updateNameAndCategoryId(Integer id, String name, Integer categoryId);
List<Integer> categoryIds(Integer resourceId);
Integer total(List<String> types);
}

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2023 杭州白书科技有限公司
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mmg.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.mmg.model.po.ResourceVideo;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author tengteng
* @description 针对表resource_videos的数据库操作Service
* @createDate 2023-03-02 15:13:03
*/
@Service
public interface ResourceVideoService extends IService<ResourceVideo> {
void create(Integer resourceId, Integer duration, String poster);
void removeByRid(Integer resourceId);
List<ResourceVideo> chunksByRids(List<Integer> resourceIds);
}

View File

@ -1,50 +1,23 @@
package com.mmg.service;
import com.mmg.model.vo.FileUploadInfo;
import com.mmg.utils.R;
import com.mmg.model.po.Resource;
import com.mmg.model.vo.UploadFileInfo;
import org.springframework.web.multipart.MultipartFile;
import java.util.Map;
public interface UploadService {
/**
* 分片上传初始化
*
* @param fileUploadInfo
* @return Map<String, Object>
*/
Map<String, Object> initMultiPartUpload(FileUploadInfo fileUploadInfo);
/**
* 完成分片上传
*
* @param fileUploadInfo
* @return String
*/
String mergeMultipartUpload(FileUploadInfo fileUploadInfo);
UploadFileInfo upload(MultipartFile file, String dir) throws Exception;
/**
* 通过 md5 获取已上传的数据
* @param md5 String
* @return Mono<Map<String, Object>>
*/
R getByFileMD5(String md5);
Resource storeMinio(Integer adminId, MultipartFile file, String categoryIds)
throws Exception;
UploadFileInfo uploadTmp(MultipartFile file, String dir) throws Exception;
/**
* 获取文件地址
* @param bucketName
* @param fileName
*
*/
String getFliePath(String bucketName, String fileName);
Resource storeMinioTmp(Integer adminId, MultipartFile file, String categoryIds)
throws Exception;
/**
* 单文件上传
* @param file
* @param bucketName
* @return
*/
String upload(MultipartFile file, String bucketName);
Resource storeBase64Image(Integer adminId, String content, String categoryIds)
throws Exception;
}

View File

@ -0,0 +1,130 @@
package com.mmg.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mmg.config.S3Config;
import com.mmg.constant.ConfigConstant;
import com.mmg.mapper.AppConfigMapper;
import com.mmg.model.po.AppConfig;
import com.mmg.service.AppConfigService;
import com.mmg.utils.StringUtil;
import lombok.extern.log4j.Log4j2;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
@Log4j2
@Transactional
public class AppConfigServiceImpl extends ServiceImpl<AppConfigMapper, AppConfig>
implements AppConfigService {
private Environment environment;
@Override
public Map<String, Long> allKeys() {
return list().stream().collect(Collectors.toMap(AppConfig::getKeyName, AppConfig::getId));
}
@Override
public List<AppConfig> allShow() {
return list(query().getWrapper().eq("is_hidden", 0));
}
@Override
public void saveFromMap(HashMap<String, String> data) {
Map<String, AppConfig> configs =
list(query().getWrapper().in("key_name", data.keySet())).stream()
.collect(Collectors.toMap(AppConfig::getKeyName, e -> e));
List<AppConfig> list = new ArrayList<>();
data.forEach(
(keyNameValue, keyValueValue) -> {
if (keyValueValue == null) {
return;
}
if ("******".equals(keyNameValue)) { // 私密信息默认place
return;
}
AppConfig configItem = configs.get(keyNameValue);
if (configItem == null) { // 不存在的配置
return;
}
if (keyValueValue.equals(configItem.getKeyValue())) { // 没有变化
return;
}
list.add(
new AppConfig() {
{
setId(configItem.getId());
setKeyValue(keyValueValue);
}
});
});
if (!list.isEmpty()) {
updateBatchById(list);
}
}
@Override
public Map<String, String> keyValues() {
return list(query().getWrapper().eq("is_hidden", 0)).stream()
.collect(Collectors.toMap(AppConfig::getKeyName, AppConfig::getKeyValue));
}
@Override
public S3Config getS3Config() {
// 全部的系统配置
Map<String, String> config = keyValues();
S3Config s3Config = new S3Config();
s3Config.setAccessKey(config.get(ConfigConstant.MINIO_ACCESS_KEY));
s3Config.setSecretKey(config.get(ConfigConstant.MINIO_SECRET_KEY));
s3Config.setBucket(config.get(ConfigConstant.MINIO_BUCKET));
s3Config.setEndpoint(config.get(ConfigConstant.MINIO_ENDPOINT));
s3Config.setDomain(config.get(ConfigConstant.MINIO_DOMAIN));
s3Config.setRegion(null);
s3Config.setService("minio");
if (StringUtil.isEmpty(s3Config.getAccessKey())) {
s3Config.setAccessKey(environment.getProperty("MINIO_USERNAME"));
}
if (StringUtil.isEmpty(s3Config.getSecretKey())) {
s3Config.setSecretKey(environment.getProperty("MINIO_PASSWORD"));
}
if (StringUtil.isEmpty(s3Config.getBucket())) {
s3Config.setBucket(environment.getProperty("MINIO_BUCKET"));
}
if (StringUtil.isEmpty(s3Config.getEndpoint())) {
s3Config.setEndpoint(environment.getProperty("MINIO_ENDPOINT"));
}
if (StringUtil.isEmpty(s3Config.getDomain())) {
s3Config.setDomain(environment.getProperty("MINIO_DOMAIN"));
}
if (s3Config.getService().equals("minio") && StringUtil.isNotEmpty(s3Config.getDomain())) {
String _domain = s3Config.getDomain();
// 移除 / 后缀
if (StringUtil.endsWith(_domain, "/")) {
_domain = _domain.substring(0, _domain.length() - 1);
}
// 判断是否携带了bucket
if (!StringUtil.endsWith(_domain, s3Config.getBucket())) {
_domain += "/" + s3Config.getBucket();
}
s3Config.setDomain(_domain);
}
return s3Config;
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright (C) 2023 杭州白书科技有限公司
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mmg.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mmg.mapper.ResourceCategoryMapper;
import com.mmg.model.po.ResourceCategory;
import com.mmg.service.ResourceCategoryService;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
public class ResourceCategoryServiceImpl
extends ServiceImpl<ResourceCategoryMapper, ResourceCategory>
implements ResourceCategoryService {
@Override
public void rebuild(Integer resourceId, List<Integer> categoryIds) {
remove(query().getWrapper().eq("rid", resourceId));
List<ResourceCategory> data = new ArrayList<>();
categoryIds.forEach(
categoryId -> {
data.add(
new ResourceCategory() {
{
setCid(categoryId);
setRid(resourceId);
}
});
});
saveBatch(data);
}
@Override
public List<Integer> getRidsByCategoryId(Integer id) {
return list(query().getWrapper().in("cid", id)).stream()
.map(ResourceCategory::getRid)
.toList();
}
}

View File

@ -0,0 +1,197 @@
/*
* Copyright (C) 2023 杭州白书科技有限公司
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mmg.service.impl;
import com.amazonaws.services.kms.model.NotFoundException;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mmg.mapper.ResourceMapper;
import com.mmg.model.paginate.PaginationResult;
import com.mmg.model.paginate.ResourcePaginateFilter;
import com.mmg.model.po.Resource;
import com.mmg.model.po.ResourceCategory;
import com.mmg.model.po.ResourceVideo;
import com.mmg.service.ResourceCategoryService;
import com.mmg.service.ResourceService;
import com.mmg.service.ResourceVideoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* @author tengteng
* {@code @description} 针对表resources的数据库操作Service实现
* {@code @createDate} 2023-02-23 10:50:26
*/
@Service
public class ResourceServiceImpl extends ServiceImpl<ResourceMapper, Resource>
implements ResourceService {
@Autowired private ResourceVideoService resourceVideoService;
@Autowired private ResourceCategoryService relationService;
@Override
public PaginationResult<Resource> paginate(int page, int size, ResourcePaginateFilter filter) {
PaginationResult<Resource> pageResult = new PaginationResult<>();
filter.setPageStart((page - 1) * size);
filter.setPageSize(size);
pageResult.setData(getBaseMapper().paginate(filter));
pageResult.setTotal(getBaseMapper().paginateCount(filter));
return pageResult;
}
@Override
public List<String> paginateType(ResourcePaginateFilter filter) {
return getBaseMapper().paginateType(filter);
}
@Override
@Transactional
public Resource create(
Integer adminId,
String categoryIds,
String type,
String filename,
String ext,
Long size,
String disk,
String fileId,
String path,
String url) {
Resource resource = new Resource();
resource.setAdminId(adminId);
resource.setType(type);
resource.setName(filename);
resource.setExtension(ext);
resource.setSize(size);
resource.setDisk(disk);
resource.setFileId(fileId);
resource.setPath(path);
resource.setUrl(url);
resource.setCreatedAt(new Date());
save(resource);
if (categoryIds != null && categoryIds.trim().length() > 0) {
String[] idArray = categoryIds.split(",");
List<ResourceCategory> relations = new ArrayList<>();
for (String s : idArray) {
int tmpId = Integer.parseInt(s);
if (tmpId == 0) {
continue;
}
relations.add(
new ResourceCategory() {
{
setCid(tmpId);
setRid(resource.getId());
}
});
}
relationService.saveBatch(relations);
}
return resource;
}
@Override
public Resource findOrFail(Integer id) throws NotFoundException {
Resource resource = getById(id);
if (resource == null) {
throw new NotFoundException("资源不存在");
}
return resource;
}
@Override
public void changeParentId(Integer id, Integer parentId) {
Resource resource = new Resource();
resource.setId(id);
resource.setParentId(parentId);
resource.setIsHidden(1);
updateById(resource);
}
@Override
public void storeResourceVideo(Integer rid, Integer duration, String poster) {
resourceVideoService.create(rid, duration, poster);
}
@Override
public List<Resource> chunks(List<Integer> ids) {
return list(query().getWrapper().in("id", ids));
}
@Override
public List<Resource> chunks(List<Integer> ids, List<String> fields) {
return list(query().getWrapper().in("id", ids).select(fields));
}
@Override
public Integer total(String type) {
return Math.toIntExact(count(query().getWrapper().eq("type", type).eq("is_hidden", 0)));
}
@Override
public Integer duration(Integer id) {
ResourceVideo resourceVideo =
resourceVideoService.getOne(
resourceVideoService.query().getWrapper().eq("rid", id));
if (resourceVideo == null) {
return null;
}
return resourceVideo.getDuration();
}
@Override
@Transactional
public void updateNameAndCategoryId(Integer id, String name, Integer categoryId) {
Resource resource = new Resource();
resource.setId(id);
resource.setName(name);
updateById(resource);
relationService.rebuild(
id,
new ArrayList<>() {
{
add(categoryId);
}
});
}
@Override
public List<Integer> categoryIds(Integer resourceId) {
return relationService
.list(relationService.query().getWrapper().eq("rid", resourceId))
.stream()
.map(ResourceCategory::getCid)
.toList();
}
@Override
public Integer total(List<String> types) {
return Math.toIntExact(count(query().getWrapper().in("type", types).eq("is_hidden", 0)));
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2023 杭州白书科技有限公司
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mmg.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import xyz.playedu.resource.domain.ResourceVideo;
import xyz.playedu.resource.mapper.ResourceVideoMapper;
import xyz.playedu.resource.service.ResourceVideoService;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* @author tengteng
* @description 针对表resource_videos的数据库操作Service实现
* @createDate 2023-03-02 15:13:03
*/
@Service
public class ResourceVideoServiceImpl extends ServiceImpl<ResourceVideoMapper, ResourceVideo>
implements ResourceVideoService {
@Override
public void create(Integer resourceId, Integer duration, String poster) {
ResourceVideo video = new ResourceVideo();
video.setRid(resourceId);
video.setDuration(duration);
video.setPoster(poster);
video.setCreatedAt(new Date());
save(video);
}
@Override
public void removeByRid(Integer resourceId) {
remove(query().getWrapper().eq("rid", resourceId));
}
@Override
public List<ResourceVideo> chunksByRids(List<Integer> resourceIds) {
if (resourceIds == null || resourceIds.size() == 0) {
return new ArrayList<>();
}
return list(query().getWrapper().in("rid", resourceIds));
}
}

View File

@ -1,155 +1,203 @@
package com.mmg.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.mmg.mapper.FilesMapper;
import com.mmg.model.po.Files;
import com.mmg.model.vo.FileUploadInfo;
import com.mmg.config.S3Config;
import com.mmg.constant.BackendConstant;
import com.mmg.model.po.Resource;
import com.mmg.model.vo.UploadFileInfo;
import com.mmg.service.AppConfigService;
import com.mmg.service.ResourceService;
import com.mmg.service.UploadService;
import com.mmg.utils.MinioUtils;
import com.mmg.utils.R;
import com.mmg.utils.RedisUtil;
import com.mmg.utils.RespEnum;
import jakarta.annotation.Resource;
import com.mmg.utils.Base64Util;
import com.mmg.utils.HelperUtil;
import com.mmg.utils.S3Util;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import java.util.Map;
import java.util.Date;
@Slf4j
@Service
@Slf4j
public class UploadServiceImpl implements UploadService {
@Resource
private FilesMapper filesMapper;
@Autowired private ResourceService resourceService;
@Resource
private MinioUtils minioUtils;
@Autowired private AppConfigService appConfigService;
@Resource
private RedisUtil redisUtil;
@Value("${minio.breakpoint-time}")
private Integer breakpointTime;
/**
* 通过 md5 获取已上传的数据断点续传
*
* @param md5 String
* @return Mono<Map < String, Object>>
*/
@Override
public R getByFileMD5(String md5) {
log.info("tip message: 通过 <{}> 查询redis是否存在", md5);
// 从redis获取文件名称和id
FileUploadInfo fileUploadInfo = (FileUploadInfo) redisUtil.get(md5);
if (fileUploadInfo != null) {
// 正在上传查询上传后的分片数据
List<Integer> chunkList = minioUtils.getChunkByFileMD5(fileUploadInfo.getFileName(), fileUploadInfo.getUploadId(), fileUploadInfo.getFileType());
fileUploadInfo.setChunkUploadedList(chunkList);
return R.ok(RespEnum.UPLOADING).setData(fileUploadInfo);
@SneakyThrows
public UploadFileInfo upload(MultipartFile file, String dir) {
if (file == null || file.isEmpty() || file.getOriginalFilename() == null) {
throw new Exception("请上传文件");
}
log.info("tip message: 通过 <{}> 查询mysql是否存在", md5);
// 查询数据库是否上传成功
Files one = filesMapper.selectOne(new LambdaQueryWrapper<Files>().eq(Files::getFileMd5, md5));
if (one != null) {
FileUploadInfo mysqlsFileUploadInfo = new FileUploadInfo();
BeanUtils.copyProperties(one, mysqlsFileUploadInfo);
return R.ok(RespEnum.UPLOADSUCCESSFUL).setData(mysqlsFileUploadInfo);
// 上传上来的文件名名
String filename = file.getOriginalFilename();
UploadFileInfo fileInfo = new UploadFileInfo();
// 文件大小
fileInfo.setSize(file.getSize());
// 解析扩展名
fileInfo.setExtension(HelperUtil.fileExt(filename));
// 解析扩展名称对应的系统资源类型
fileInfo.setResourceType(BackendConstant.RESOURCE_EXT_2_TYPE.get(fileInfo.getExtension()));
// 检测是否为系统不支持的资源类型
if (fileInfo.getResourceType() == null) {
throw new Exception("当前资源扩展不支持上传");
}
return R.ok(RespEnum.NOT_UPLOADED);
}
/**
* 文件分片上传
*
* @param fileUploadInfo
* @return Mono<Map < String, Object>>
*/
@Override
public Map<String, Object> initMultiPartUpload(FileUploadInfo fileUploadInfo) {
FileUploadInfo redisFileUploadInfo = (FileUploadInfo) redisUtil.get(fileUploadInfo.getFileMd5());
if (redisFileUploadInfo != null) {
fileUploadInfo = redisFileUploadInfo;
// 上传原文件的文件名
fileInfo.setOriginalName(filename.replaceAll("(?i)." + fileInfo.getExtension(), ""));
// 自定义新的存储文件名
fileInfo.setSaveName(HelperUtil.randomString(32) + "." + fileInfo.getExtension());
// 生成保存的相对路径
if (dir == null || dir.isEmpty()) {
dir = BackendConstant.RESOURCE_TYPE_2_DIR.get(fileInfo.getResourceType());
}
log.info("tip message: 通过 <{}> 开始初始化<分片上传>任务", fileUploadInfo);
// 获取桶
String bucketName = minioUtils.getBucketName(fileUploadInfo.getFileType());
fileInfo.setSavePath(dir + fileInfo.getSaveName());
// 保存文件并生成访问url
S3Util s3Util = new S3Util(appConfigService.getS3Config());
String url =
s3Util.saveFile(
file,
fileInfo.getSavePath(),
BackendConstant.RESOURCE_EXT_2_CONTENT_TYPE.get(fileInfo.getExtension()));
fileInfo.setUrl(url);
// 单文件上传
if (fileUploadInfo.getChunkNum() == 1) {
log.info("tip message: 当前分片数量 <{}> 进行单文件上传", fileUploadInfo.getChunkNum());
Files files = saveFileToDB(fileUploadInfo);
String fileName = files.getUrl().substring(files.getUrl().lastIndexOf("/") + 1);
return minioUtils.getUploadObjectUrl(fileName, bucketName);
}
// 分片上传
else {
log.info("tip message: 当前分片数量 <{}> 进行分片上传", fileUploadInfo.getChunkNum());
Map<String, Object> map = minioUtils.initMultiPartUpload(fileUploadInfo, fileUploadInfo.getFileName(), fileUploadInfo.getChunkNum(), fileUploadInfo.getContentType(), bucketName);
String uploadId = (String) map.get("uploadId");
fileUploadInfo.setUploadId(uploadId);
redisUtil.set(fileUploadInfo.getFileMd5(), fileUploadInfo, breakpointTime * 60 * 60 * 24);
return map;
}
}
/**
* 文件合并
*
* @param
* @return String
*/
@Override
public String mergeMultipartUpload(FileUploadInfo fileUploadInfo) {
log.info("tip message: 通过 <{}> 开始合并<分片上传>任务", fileUploadInfo);
FileUploadInfo redisFileUploadInfo = (FileUploadInfo) redisUtil.get(fileUploadInfo.getFileMd5());
if (redisFileUploadInfo != null) {
fileUploadInfo.setFileName(redisFileUploadInfo.getFileName());
}
boolean result = minioUtils.mergeMultipartUpload(fileUploadInfo.getFileName(), fileUploadInfo.getUploadId(), fileUploadInfo.getFileType());
//合并成功
if (result) {
//存入数据库
Files files = saveFileToDB(fileUploadInfo);
redisUtil.del(fileUploadInfo.getFileMd5());
return files.getUrl();
}
return null;
return fileInfo;
}
@Override
public String getFliePath(String bucketName, String fileName) {
return minioUtils.getFliePath(bucketName, fileName);
@SneakyThrows
public Resource storeMinio(Integer adminId, MultipartFile file, String categoryIds) {
UploadFileInfo info = upload(file, null);
return resourceService.create(
adminId,
categoryIds,
info.getResourceType(),
info.getOriginalName(),
info.getExtension(),
file.getSize(),
BackendConstant.STORAGE_DRIVER_MINIO,
"",
info.getSavePath(),
info.getUrl());
}
@Override
public String upload(MultipartFile file, String bucketName) {
minioUtils.upload(file, bucketName);
return getFliePath(bucketName, file.getName());
@SneakyThrows
public Resource storeBase64Image(Integer adminId, String content, String categoryIds) {
// data:image/jpeg;base64,
String[] base64Rows = content.split(",");
// 解析出content-type
String contentType =
base64Rows[0].replaceAll("data:", "").replaceAll(";base64", "").toLowerCase();
// 解析出文件格式
String ext = contentType.replaceAll("image/", "");
// 通过文件格式解析资源类型
String type = BackendConstant.RESOURCE_EXT_2_TYPE.get(ext);
// 资源类型必须存在
if (type == null) {
throw new Exception("资源类型不支持");
}
byte[] binary = Base64Util.decode(base64Rows[1]);
String filename = HelperUtil.randomString(32) + "." + ext;
String savePath = BackendConstant.RESOURCE_TYPE_2_DIR.get(type) + filename;
// 保存文件
S3Util s3Util = new S3Util(appConfigService.getS3Config());
String url =
s3Util.saveBytes(
binary, savePath, BackendConstant.RESOURCE_EXT_2_CONTENT_TYPE.get(ext));
// 上传记录
return resourceService.create(
adminId,
categoryIds,
type,
filename,
ext,
(long) binary.length,
BackendConstant.STORAGE_DRIVER_MINIO,
"",
savePath,
url);
}
private Files saveFileToDB(FileUploadInfo fileUploadInfo) {
String suffix = fileUploadInfo.getFileName().substring(fileUploadInfo.getFileName().lastIndexOf("."));
String url = this.getFliePath(fileUploadInfo.getFileType().toLowerCase(), fileUploadInfo.getFileMd5() + suffix);
//存入数据库
Files files = new Files();
BeanUtils.copyProperties(fileUploadInfo, files);
files.setBucketName(fileUploadInfo.getFileType());
files.setUrl(url);
filesMapper.insert(files);
return files;
@Override
@SneakyThrows
public UploadFileInfo uploadTmp(MultipartFile file, String dir) {
if (file == null || file.isEmpty() || file.getOriginalFilename() == null) {
throw new Exception("请上传文件");
}
// 上传上来的文件名名
String filename = file.getOriginalFilename();
UploadFileInfo fileInfo = new UploadFileInfo();
// 文件大小
fileInfo.setSize(file.getSize());
// 解析扩展名
fileInfo.setExtension(HelperUtil.fileExt(filename));
// 解析扩展名称对应的系统资源类型
fileInfo.setResourceType(BackendConstant.RESOURCE_EXT_2_TYPE.get(fileInfo.getExtension()));
// 检测是否为系统不支持的资源类型
if (fileInfo.getResourceType() == null) {
throw new Exception("当前资源扩展不支持上传");
}
// 上传原文件的文件名
fileInfo.setOriginalName(filename.replaceAll("(?i)." + fileInfo.getExtension(), ""));
// 自定义新的存储文件名
fileInfo.setSaveName(filename);
// 生成保存的相对路径
if (dir == null || dir.isEmpty()) {
dir = BackendConstant.RESOURCE_TYPE_2_DIR.get(fileInfo.getResourceType());
}
fileInfo.setSavePath(dir + fileInfo.getSaveName());
// 保存文件并生成访问url
S3Config s3Config=appConfigService.getS3Config();
s3Config.setBucket("tmp");
String originDomain = s3Config.getDomain();
String[] parts = originDomain.split("/");
if (parts.length > 3) {
parts[3] = "tmp"; // 替换第三个斜杠后的部分为 "tmp"
}
String newDomain = String.join("/", parts);
s3Config.setDomain(newDomain);
S3Util s3Util = new S3Util(s3Config);
String url =
s3Util.saveFile(
file,
fileInfo.getSavePath(),
BackendConstant.RESOURCE_EXT_2_CONTENT_TYPE.get(fileInfo.getExtension()));
fileInfo.setUrl(url);
return fileInfo;
}
@Override
@SneakyThrows
public Resource storeMinioTmp(Integer adminId, MultipartFile file, String categoryIds) {
UploadFileInfo info = uploadTmp(file, null);
return resourceService.create(
adminId,
categoryIds,
info.getResourceType(),
info.getOriginalName(),
info.getExtension(),
file.getSize(),
BackendConstant.STORAGE_DRIVER_MINIO,
"",
info.getSavePath(),
info.getUrl());
}
}

View File

@ -0,0 +1,277 @@
/*
* Copyright (C) 2023 杭州白书科技有限公司
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mmg.utils;
/** Base64工具类 */
public final class Base64Util {
private static final int BASE_LENGTH = 128;
private static final int LOOK_UP_LENGTH = 64;
private static final int TWENTY_FOUR_BIT_GROUP = 24;
private static final int EIGHT_BIT = 8;
private static final int SIXTEEN_BIT = 16;
private static final int FOUR_BYTE = 4;
private static final int SIGN = -128;
private static final char PAD = '=';
private static final byte[] base64Alphabet = new byte[BASE_LENGTH];
private static final char[] lookUpBase64Alphabet = new char[LOOK_UP_LENGTH];
static {
for (int i = 0; i < BASE_LENGTH; ++i) {
base64Alphabet[i] = -1;
}
for (int i = 'Z'; i >= 'A'; i--) {
base64Alphabet[i] = (byte) (i - 'A');
}
for (int i = 'z'; i >= 'a'; i--) {
base64Alphabet[i] = (byte) (i - 'a' + 26);
}
for (int i = '9'; i >= '0'; i--) {
base64Alphabet[i] = (byte) (i - '0' + 52);
}
base64Alphabet['+'] = 62;
base64Alphabet['/'] = 63;
for (int i = 0; i <= 25; i++) {
lookUpBase64Alphabet[i] = (char) ('A' + i);
}
for (int i = 26, j = 0; i <= 51; i++, j++) {
lookUpBase64Alphabet[i] = (char) ('a' + j);
}
for (int i = 52, j = 0; i <= 61; i++, j++) {
lookUpBase64Alphabet[i] = (char) ('0' + j);
}
lookUpBase64Alphabet[62] = '+';
lookUpBase64Alphabet[63] = '/';
}
/**
* 转码
*
* @param binaryData 未转码数据
* @return 转码后数据串
*/
public static String encode(byte[] binaryData) {
if (binaryData == null) {
return null;
}
int lengthDataBits = binaryData.length * EIGHT_BIT;
if (lengthDataBits == 0) {
return "";
}
int fewerThan24bits = lengthDataBits % TWENTY_FOUR_BIT_GROUP;
int numberTriplets = lengthDataBits / TWENTY_FOUR_BIT_GROUP;
int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets;
char[] encodedData;
encodedData = new char[numberQuartet * 4];
byte k, l, b1, b2, b3;
int encodedIndex = 0;
int dataIndex = 0;
for (int i = 0; i < numberTriplets; i++) {
b1 = binaryData[dataIndex++];
b2 = binaryData[dataIndex++];
b3 = binaryData[dataIndex++];
k = (byte) (b1 & 0x03);
l = (byte) (b2 & 0x0f);
byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);
encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];
encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
}
if (fewerThan24bits == EIGHT_BIT) {
b1 = binaryData[dataIndex];
k = (byte) (b1 & 0x03);
byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];
encodedData[encodedIndex++] = PAD;
encodedData[encodedIndex++] = PAD;
} else if (fewerThan24bits == SIXTEEN_BIT) {
b1 = binaryData[dataIndex];
b2 = binaryData[dataIndex + 1];
l = (byte) (b2 & 0x0f);
k = (byte) (b1 & 0x03);
byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];
encodedData[encodedIndex++] = PAD;
}
return new String(encodedData);
}
/**
* 解码
*
* @param encoded 已转码数据
* @return 解码后数据
*/
public static byte[] decode(String encoded) {
if (encoded == null) {
return null;
}
char[] base64Data = encoded.toCharArray();
int len = removeWhiteSpace(base64Data);
if (len % FOUR_BYTE != 0) {
return null;
}
int numberQuadruple = (len / FOUR_BYTE);
if (numberQuadruple == 0) {
return new byte[0];
}
byte[] decodedData;
byte b1, b2, b3, b4;
char d1, d2, d3, d4;
int i = 0;
int encodedIndex = 0;
int dataIndex = 0;
decodedData = new byte[(numberQuadruple) * 3];
for (; i < numberQuadruple - 1; i++) {
if (!isData((d1 = base64Data[dataIndex++]))
|| !isData((d2 = base64Data[dataIndex++]))
|| !isData((d3 = base64Data[dataIndex++]))
|| !isData((d4 = base64Data[dataIndex++]))) {
return null;
}
b1 = base64Alphabet[d1];
b2 = base64Alphabet[d2];
b3 = base64Alphabet[d3];
b4 = base64Alphabet[d4];
decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
}
if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) {
return null;
}
b1 = base64Alphabet[d1];
b2 = base64Alphabet[d2];
d3 = base64Data[dataIndex++];
d4 = base64Data[dataIndex++];
if (!isData((d3)) || !isData((d4))) {
if (isPad(d3) && isPad(d4)) {
if ((b2 & 0xf) != 0) {
return null;
}
byte[] tmp = new byte[i * 3 + 1];
System.arraycopy(decodedData, 0, tmp, 0, i * 3);
tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
return tmp;
} else if (!isPad(d3) && isPad(d4)) {
b3 = base64Alphabet[d3];
if ((b3 & 0x3) != 0) {
return null;
}
byte[] tmp = new byte[i * 3 + 2];
System.arraycopy(decodedData, 0, tmp, 0, i * 3);
tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
return tmp;
} else {
return null;
}
} else {
b3 = base64Alphabet[d3];
b4 = base64Alphabet[d4];
decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
decodedData[encodedIndex++] = (byte) (b4 | b3 << 6);
}
return decodedData;
}
/**
* 是否空白
*
* @param octEct
* @return boolean
*/
private static boolean isWhiteSpace(char octEct) {
return (octEct == 0x20 || octEct == 0xd || octEct == 0xa || octEct == 0x9);
}
/**
* 是否填充
*
* @param octEct
* @return boolean
*/
private static boolean isPad(char octEct) {
return (octEct == PAD);
}
/**
* 是否数据
*
* @param octEct
* @return Boolean
*/
private static Boolean isData(char octEct) {
return (octEct < BASE_LENGTH && base64Alphabet[octEct] != -1);
}
/**
* 移除空白
*
* @param data 数据
* @return int
*/
private static int removeWhiteSpace(char[] data) {
if (data == null) {
return 0;
}
int newSize = 0;
int len = data.length;
for (int i = 0; i < len; i++) {
if (!isWhiteSpace(data[i])) {
data[newSize++] = data[i];
}
}
return newSize;
}
}

View File

@ -0,0 +1,190 @@
/*
* Copyright (C) 2023 杭州白书科技有限公司
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mmg.utils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.util.DigestUtils;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.*;
public class HelperUtil {
public static List<Integer> zeroIntegerList() {
return new ArrayList<>() {
{
add(0);
}
};
}
public static String MD5(String text) {
return DigestUtils.md5DigestAsHex(text.getBytes(StandardCharsets.UTF_8));
}
/**
* 制作UUID
*
* @return String
* @author fzr
*/
public static String uuid() {
return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
}
/**
* 返回随机字符串
*
* @param length 要生成的长度
* @return String
* @author fzr
*/
public static String randomString(int length) {
Random random = new Random();
StringBuilder stringBuffer = new StringBuilder();
String str = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
int strLength = str.length();
for (int i = 0; i < length; i++) {
int index = random.nextInt(strLength);
stringBuffer.append(str.charAt(index));
}
return stringBuffer.toString();
}
/**
* 返回随机数字字符串
*
* @param length 要生成的长度
* @return String
* @author fzr
*/
public static String randomInt(int length) {
Random random = new Random();
StringBuilder stringBuffer = new StringBuilder();
String str = "0123456789";
for (int i = 0; i < length; i++) {
int index = random.nextInt(10);
stringBuffer.append(str.charAt(index));
}
return stringBuffer.toString();
}
/**
* 转换存储单位: KB MB GB TB
*
* @return String
* @author fzr
*/
public static String storageUnit(Long size) {
if (size == null) {
return "0B";
}
if (size < 1024) {
return size + "B";
} else {
size = size / 1024;
}
if (size < 1024) {
return size + "KB";
} else {
size = size / 1024;
}
if (size < 1024) {
size = size * 100;
return (size / 100) + "." + (size % 100) + "MB";
} else {
size = size * 100 / 1024;
return (size / 100) + "." + (size % 100) + "GB";
}
}
/**
* 下载文件
*
* @param urlString (文件网址)
* @param savePath (保存路径,: /www/uploads)
* @param filename (保存名称,: aa.png)
* @throws IOException 异常
* @author fzr
*/
public static void download(String urlString, String savePath, String filename)
throws IOException {
URL url = new URL(urlString);
URLConnection con = url.openConnection();
con.setConnectTimeout(20 * 1000);
File sf = new File(savePath);
if (!sf.exists()) {
if (sf.mkdirs()) {
throw new IOException("创建目录失败");
}
}
try (InputStream in = con.getInputStream();
OutputStream out = new FileOutputStream(sf.getPath() + "\\" + filename)) {
byte[] buff = new byte[1024];
int n;
while ((n = in.read(buff)) >= 0) {
out.write(buff, 0, n);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 对象类型Map合并
*
* @param map 对象
* @return Object
* @author fzr
*/
public static Map<String, Object> mergeMapByObj(
Map<String, Object> map, Map<String, Object> map1) {
HashMap<String, Object> map2 = new HashMap<>();
map2.putAll(map);
map2.putAll(map1);
return map2;
}
/**
* 字符串类型Map合并
*
* @param map 对象
* @return Object
* @author fzr
*/
public static Map<String, String> mergeMapByStr(
Map<String, String> map, Map<String, String> map1) {
HashMap<String, String> map2 = new HashMap<>();
map2.putAll(map);
map2.putAll(map1);
return map2;
}
public static String toJsonStr(Object obj) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
}
public static String fileExt(String filename) {
String[] array = filename.split("\\.");
return array[array.length - 1].toLowerCase();
}
}

View File

@ -71,6 +71,7 @@ public class MinioUtils {
.object(objectName)
.expiry(expiry, TimeUnit.DAYS)
.build());
log.info("预签名完成:"+url);
log.info("tip message: 单个文件上传、成功");
partList.add(url);
resMap.put("uploadId", "SingleFileUpload");

View File

@ -0,0 +1,161 @@
package com.mmg.utils;
import com.amazonaws.HttpMethod;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;
import com.mmg.config.S3Config;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Slf4j
@Component
public class S3Util {
@Autowired
private S3Config defaultConfig;
public S3Config getS3Config() {
return defaultConfig;
}
public S3Util(S3Config s3Config) {
defaultConfig = s3Config;
}
public S3Util setConfig(S3Config config) {
defaultConfig = config;
return this;
}
public boolean configIsEmpty() {
return defaultConfig == null
|| StringUtil.isEmpty(defaultConfig.getDomain())
|| StringUtil.isEmpty(defaultConfig.getEndpoint())
|| StringUtil.isEmpty(defaultConfig.getAccessKey())
|| StringUtil.isEmpty(defaultConfig.getSecretKey());
}
@SneakyThrows
private AmazonS3 getClient() {
if (defaultConfig == null) {
throw new Exception("存储服务未配置");
}
AWSCredentials credentials =
new BasicAWSCredentials(defaultConfig.getAccessKey(), defaultConfig.getSecretKey());
AwsClientBuilder.EndpointConfiguration endpointConfiguration =
new AwsClientBuilder.EndpointConfiguration(
defaultConfig.getEndpoint(), defaultConfig.getRegion());
AmazonS3ClientBuilder builder = AmazonS3ClientBuilder.standard();
// 开启路径访问
builder.setPathStyleAccessEnabled(true);
return builder.withCredentials(new AWSStaticCredentialsProvider(credentials))
.withEndpointConfiguration(endpointConfiguration)
.build();
}
@SneakyThrows
public String saveFile(MultipartFile file, String savePath, String contentType) {
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentType(contentType);
objectMetadata.setContentLength(file.getInputStream().available());
getClient()
.putObject(
defaultConfig.getBucket(), savePath, file.getInputStream(), objectMetadata);
return generateEndpointPreSignUrl(savePath);
}
@SneakyThrows
public String saveBytes(byte[] file, String savePath, String contentType) {
InputStream inputStream = new ByteArrayInputStream(file);
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentType(contentType);
objectMetadata.setContentLength(inputStream.available());
getClient().putObject(defaultConfig.getBucket(), savePath, inputStream, objectMetadata);
return generateEndpointPreSignUrl(savePath);
}
public String uploadId(String path) {
InitiateMultipartUploadRequest request =
new InitiateMultipartUploadRequest(defaultConfig.getBucket(), path);
InitiateMultipartUploadResult result = getClient().initiateMultipartUpload(request);
return result.getUploadId();
}
public String generatePartUploadPreSignUrl(
String filename, String partNumber, String uploadId) {
GeneratePresignedUrlRequest request =
new GeneratePresignedUrlRequest(
defaultConfig.getBucket(), filename, HttpMethod.PUT);
request.setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000)); // 一个小时有效期
request.addRequestParameter("partNumber", partNumber); // 分块索引
request.addRequestParameter("uploadId", uploadId); // uploadId
return getClient().generatePresignedUrl(request).toString();
}
@SneakyThrows
public String merge(String filename, String uploadId) {
AmazonS3 client = getClient();
ListPartsRequest listPartsRequest =
new ListPartsRequest(defaultConfig.getBucket(), filename, uploadId);
PartListing parts = client.listParts(listPartsRequest);
if (parts.getParts().isEmpty()) {
throw new Exception("没有已上传的分片文件");
}
List<PartETag> eTags = new ArrayList<>();
parts.getParts()
.forEach(
item -> eTags.add(new PartETag(item.getPartNumber(), item.getETag())));
CompleteMultipartUploadRequest request = new CompleteMultipartUploadRequest();
request.setBucketName(defaultConfig.getBucket());
request.setKey(filename);
request.setUploadId(uploadId);
request.setPartETags(eTags);
client.completeMultipartUpload(request);
return generateEndpointPreSignUrl(filename);
}
public void removeByPath(String path) {
DeleteObjectRequest request = new DeleteObjectRequest(defaultConfig.getBucket(), path);
getClient().deleteObject(request);
}
public boolean exists(String path) {
return getClient().doesObjectExist(defaultConfig.getBucket(), path);
}
@SneakyThrows
public String getContent(String path) {
S3Object s3Object = getClient().getObject(defaultConfig.getBucket(), path);
return new String(s3Object.getObjectContent().readAllBytes(), StandardCharsets.UTF_8);
}
public String generateEndpointPreSignUrl(String path) {
if (defaultConfig.getService().equals("minio")) {
return defaultConfig.getDomain() + "/" + path;
}
return "";
}
}

View File

@ -0,0 +1,547 @@
/*
* Copyright (C) 2023 杭州白书科技有限公司
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mmg.utils;
import cn.hutool.json.JSONUtil;
import org.springframework.util.AntPathMatcher;
import java.util.*;
/** 字符串工具类 */
public class StringUtil extends org.apache.commons.lang3.StringUtils {
/** 空字符串 */
private static final String NULL_STR = "";
/** 下划线 */
private static final char SEPARATOR = '_';
/**
* 获取参数不为空值
*
* @param value defaultValue 要判断的value
* @return value 返回值
*/
public static <T> T nvl(T value, T defaultValue) {
return value != null ? value : defaultValue;
}
/**
* 判断一个Collection是否为空,包含List, Set, Queue
*
* @param coll 要判断的Collection
* @return true=为空, false=非空
*/
public static boolean isEmpty(Collection<?> coll) {
return isNull(coll) || coll.isEmpty();
}
/**
* 判断一个Collection是否非空,包含List, Set, Queue
*
* @param coll 要判断的Collection
* @return true=非空, false=
*/
public static boolean isNotEmpty(Collection<?> coll) {
return !isEmpty(coll);
}
/**
* 判断一个对象数组是否为空
*
* @param objects 要判断的对象数组
* @return true=为空, false=非空
*/
public static boolean isEmpty(Object[] objects) {
return isNull(objects) || (objects.length == 0);
}
/**
* 判断一个对象数组是否非空
*
* @param objects 要判断的对象数组
* @return true=非空, false=
*/
public static boolean isNotEmpty(Object[] objects) {
return !isEmpty(objects);
}
/**
* 判断一个Map是否为空
*
* @param map 要判断的Map
* @return true=为空, false=非空
*/
public static boolean isEmpty(Map<?, ?> map) {
return isNull(map) || map.isEmpty();
}
/**
* 判断一个Map是否为空
*
* @param map 要判断的Map
* @return true=非空, false=
*/
public static boolean isNotEmpty(Map<?, ?> map) {
return !isEmpty(map);
}
/**
* 判断一个字符串是否为空串
*
* @param str String
* @return true=为空, false=非空
*/
public static boolean isEmpty(String str) {
return isNull(str) || NULL_STR.equals(str.trim());
}
/**
* 判断一个字符串是否为非空串
*
* @param str String
* @return true=非空串, false=空串
*/
public static boolean isNotEmpty(String str) {
return !isEmpty(str);
}
/**
* 判断一个对象是否为空
*
* @param object Object
* @return true=为空, false=非空
*/
public static boolean isNull(Object object) {
return object == null;
}
/**
* 判断一个对象是否非空
*
* @param object Object
* @return true=非空, false=
*/
public static boolean isNotNull(Object object) {
return !isNull(object);
}
/**
* 判断一个对象是否是数组类型Java基本型别的数组
*
* @param object 对象
* @return true=是数组, false=不是数组
*/
public static boolean isArray(Object object) {
return isNotNull(object) && object.getClass().isArray();
}
/** 去空格 */
public static String trim(String str) {
return (str == null ? "" : str.trim());
}
/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @return 结果
*/
public static String substring(final String str, int start) {
if (str == null) {
return NULL_STR;
}
if (start < 0) {
start = str.length() + start;
}
if (start < 0) {
start = 0;
}
if (start > str.length()) {
return NULL_STR;
}
return str.substring(start);
}
/**
* 截取字符串
*
* @param str 字符串
* @param start 开始
* @param end 结束
* @return 结果
*/
public static String substring(final String str, int start, int end) {
if (str == null) {
return NULL_STR;
}
if (end < 0) {
end = str.length() + end;
}
if (start < 0) {
start = str.length() + start;
}
if (end > str.length()) {
end = str.length();
}
if (start > end) {
return NULL_STR;
}
if (start < 0) {
start = 0;
}
if (end < 0) {
end = 0;
}
return str.substring(start, end);
}
/**
* 字符串转set
*
* @param str 字符串
* @param sep 分隔符
* @return set集合
*/
public static Set<String> str2Set(String str, String sep) {
return new HashSet<String>(str2List(str, sep, true, false));
}
/**
* 字符串转list
*
* @param str 字符串
* @param sep 分隔符
* @param filterBlank 过滤纯空白
* @param trim 去掉首尾空白
* @return list集合
*/
public static List<String> str2List(String str, String sep, boolean filterBlank, boolean trim) {
List<String> list = new ArrayList<String>();
if (StringUtil.isEmpty(str)) {
return list;
}
// 过滤空白字符串
if (filterBlank && StringUtil.isBlank(str)) {
return list;
}
String[] split = str.split(sep);
for (String string : split) {
if (filterBlank && StringUtil.isBlank(string)) {
continue;
}
if (trim) {
string = string.trim();
}
list.add(string);
}
return list;
}
/**
* 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写
*
* @param cs 指定字符串
* @param searchCharSequences 需要检查的字符串数组
* @return 是否包含任意一个字符串
*/
public static boolean containsAnyIgnoreCase(
CharSequence cs, CharSequence... searchCharSequences) {
if (isEmpty(cs) || isEmpty(searchCharSequences)) {
return false;
}
for (CharSequence testStr : searchCharSequences) {
if (containsIgnoreCase(cs, testStr)) {
return true;
}
}
return false;
}
/** 驼峰转下划线命名 */
public static String toUnderScoreCase(String str) {
if (str == null) {
return null;
}
StringBuilder sb = new StringBuilder();
// 前置字符是否大写
boolean preCharIsUpperCase = true;
// 当前字符是否大写
boolean cureCharIsUpperCase = true;
// 下一字符是否大写
boolean nextCharIsUpperCase = true;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (i > 0) {
preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
} else {
preCharIsUpperCase = false;
}
cureCharIsUpperCase = Character.isUpperCase(c);
if (i < (str.length() - 1)) {
nextCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
}
if (preCharIsUpperCase && cureCharIsUpperCase && !nextCharIsUpperCase) {
sb.append(SEPARATOR);
} else if ((i != 0 && !preCharIsUpperCase) && cureCharIsUpperCase) {
sb.append(SEPARATOR);
}
sb.append(Character.toLowerCase(c));
}
return sb.toString();
}
/**
* 是否包含字符串
*
* @param str 验证字符串
* @param strArr 字符串组
* @return 包含返回true
*/
public static boolean inStringIgnoreCase(String str, String... strArr) {
if (str != null && strArr != null) {
for (String s : strArr) {
if (str.equalsIgnoreCase(trim(s))) {
return true;
}
}
}
return false;
}
/**
* 将下划线大写方式命名的字符串转换为驼峰式 如果转换前的下划线大写方式命名的字符串为空, 则返回空字符串 例如HELLO_WORLD->HelloWorld
*
* @param name 转换前的下划线大写方式命名的字符串
* @return 转换后的驼峰式命名的字符串
*/
public static String convertToCamelCase(String name) {
StringBuilder result = new StringBuilder();
// 快速检查
if (name == null || name.isEmpty()) {
// 没必要转换
return "";
} else if (!name.contains("_")) {
// 不含下划线仅将首字母大写
return name.substring(0, 1).toUpperCase() + name.substring(1);
}
// 用下划线将原始字符串分割
String[] camels = name.split("_");
for (String camel : camels) {
// 跳过原始字符串中开头结尾的下换线或双重下划线
if (camel.isEmpty()) {
continue;
}
// 首字母大写
result.append(camel.substring(0, 1).toUpperCase());
result.append(camel.substring(1).toLowerCase());
}
return result.toString();
}
/**
* 驼峰式命名法 例如user_name->userName
*
* @param s 字符串
* @return 驼峰字符串
*/
public static String toCamelCase(String s) {
if (s == null) {
return null;
}
s = s.toLowerCase();
StringBuilder sb = new StringBuilder(s.length());
boolean upperCase = false;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == SEPARATOR) {
upperCase = true;
} else if (upperCase) {
sb.append(Character.toUpperCase(c));
upperCase = false;
} else {
sb.append(c);
}
}
return sb.toString();
}
/**
* 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
*
* @param str 指定字符串
* @param strArr 需要检查的字符串数组
* @return 是否匹配
*/
public static boolean matches(String str, List<String> strArr) {
if (isEmpty(str) || isEmpty(strArr)) {
return false;
}
for (String pattern : strArr) {
if (isMatch(pattern, str)) {
return true;
}
}
return false;
}
/**
* 判断url是否与规则配置: ? 表示单个字符; * 表示一层路径内的任意字符串不可跨层级; ** 表示任意层路径;
*
* @param pattern 匹配规则
* @param url 需要匹配的url
* @return boolean
*/
public static boolean isMatch(String pattern, String url) {
AntPathMatcher matcher = new AntPathMatcher();
return matcher.match(pattern, url);
}
/**
* 数字左边补齐0,使之达到指定长度 注意如果数字转换为字符串后,长度大于size,则只保留 最后size个字符
*
* @param num 数字对象
* @param size 字符串指定长度
* @return 返回数字的字符串格式该字符串为指定长度
*/
public static String padL(final Number num, final int size) {
return padL(num.toString(), size, '0');
}
/**
* 字符串左补齐 如果原始字符串s长度大于size,则只保留最后size个字符
*
* @param s 原始字符串
* @param size 字符串指定长度
* @param c 用于补齐的字符
* @return 返回指定长度的字符串由原字符串左补齐或截取得到
*/
public static String padL(final String s, final int size, final char c) {
final StringBuilder sb = new StringBuilder(size);
if (s != null) {
final int len = s.length();
if (s.length() <= size) {
for (int i = size - len; i > 0; i--) {
sb.append(c);
}
sb.append(s);
} else {
return s.substring(len - size, len);
}
} else {
for (int i = size; i > 0; i--) {
sb.append(c);
}
}
return sb.toString();
}
/**
* 格式化文本, {} 表示占位符<br>
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
* 如果想输出 {} 使用 \\转义 { 即可如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
* <br>
* 通常使用format("this is {} for {}", "a", "b") -> this is a for b<br>
* 转义{} format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
* 转义\ format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
*
* @param strPattern 文本模板被替换的部分用 {} 表示
* @param argArray 参数值
* @return 格式化后的文本
*/
public static String format(String strPattern, Object... argArray) {
String EMPTY_JSON = "{}";
char C_BACKSLASH = '\\';
char C_DELIM_START = '{';
if (isEmpty(argArray) || isEmpty(strPattern)) {
return strPattern;
}
final int strPatternLength = strPattern.length();
StringBuilder sbuf = new StringBuilder(strPatternLength + 50);
int handledPosition = 0;
int delimIndex;
for (int argIndex = 0; argIndex < argArray.length; argIndex++) {
delimIndex = strPattern.indexOf(EMPTY_JSON, handledPosition);
if (delimIndex == -1) {
if (handledPosition == 0) {
return strPattern;
} else {
sbuf.append(strPattern, handledPosition, strPatternLength);
return sbuf.toString();
}
} else {
if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == C_BACKSLASH) {
if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == C_BACKSLASH) {
sbuf.append(strPattern, handledPosition, delimIndex - 1);
sbuf.append(argArray[argIndex]);
handledPosition = delimIndex + 2;
} else {
// 占位符被转义
argIndex--;
sbuf.append(strPattern, handledPosition, delimIndex - 1);
sbuf.append(C_DELIM_START);
handledPosition = delimIndex + 1;
}
} else {
// 正常占位符
sbuf.append(strPattern, handledPosition, delimIndex);
sbuf.append(argArray[argIndex]);
handledPosition = delimIndex + 2;
}
}
}
sbuf.append(strPattern, handledPosition, strPattern.length());
return sbuf.toString();
}
public static String arrayToString(Object[] array) {
StringBuilder result = new StringBuilder();
if (array != null && array.length > 0) {
for (Object o : array) {
if (StringUtil.isNotNull(o)) {
try {
Object jsonObj = JSONUtil.toJsonStr(o);
result.append(jsonObj.toString());
} catch (Exception e) {
}
}
}
}
return result.toString();
}
}

View File

@ -22,12 +22,12 @@ mybatis-plus:
minio:
endpoint: http://47.103.114.59:9000
accesskey: OliveSmart
secretkey: OliveSmartTmzl
accesskey: olive
secretkey: olivesmart
bucket: playedu
expiry: 1 #分片对象过期时间 单位(天)
breakpoint-time: 1 #断点续传有效时间在redis存储任务的时间 单位(天)
#断点续传有效时间在redis存储任务的时间 单位(天)
logging:
level:

View File

@ -441,16 +441,6 @@
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
},
"node_modules/@popperjs/core": {
"name": "@sxzz/popperjs-es",
"version": "2.11.7",
"resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz",
"integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.18.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz",
@ -948,6 +938,12 @@
"vue": "^3.2.0"
}
},
"node_modules/element-plus/node_modules/@popperjs/core": {
"name": "@sxzz/popperjs-es",
"version": "2.11.7",
"resolved": "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz",
"integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ=="
},
"node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
@ -1507,11 +1503,6 @@
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
},
"@popperjs/core": {
"version": "npm:@sxzz/popperjs-es@2.11.7",
"resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz",
"integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ=="
},
"@rollup/rollup-android-arm-eabi": {
"version": "4.18.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz",
@ -1850,6 +1841,13 @@
"lodash-unified": "^1.0.2",
"memoize-one": "^6.0.0",
"normalize-wheel-es": "^1.2.0"
},
"dependencies": {
"@popperjs/core": {
"version": "npm:@sxzz/popperjs-es@2.11.7",
"resolved": "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz",
"integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ=="
}
}
},
"entities": {