diff --git a/pom.xml b/pom.xml index e78337b..52e743f 100644 --- a/pom.xml +++ b/pom.xml @@ -37,6 +37,11 @@ 1.18.30 + + io.minio + minio + ${minio.version} + com.jayway.jsonpath json-path diff --git a/src/main/java/com/project/base/domain/dto/BaseDTO.java b/src/main/java/com/project/base/domain/dto/BaseDTO.java index 8b9023d..044db63 100644 --- a/src/main/java/com/project/base/domain/dto/BaseDTO.java +++ b/src/main/java/com/project/base/domain/dto/BaseDTO.java @@ -2,6 +2,7 @@ package com.project.base.domain.dto; import cn.hutool.core.bean.BeanUtil; +import com.project.base.domain.enums.StatusEnum; import lombok.Data; import java.util.Date; @@ -20,7 +21,7 @@ public class BaseDTO { private Date updateTime; - private Boolean deleted; + private Boolean deleted = StatusEnum.Normal.getValue(); public T toEntity(Supplier supplier) { diff --git a/src/main/java/com/project/information/application/ProductLineApplicationService.java b/src/main/java/com/project/information/application/ProductLineApplicationService.java new file mode 100644 index 0000000..3632dc3 --- /dev/null +++ b/src/main/java/com/project/information/application/ProductLineApplicationService.java @@ -0,0 +1,17 @@ +package com.project.information.application; + +import com.project.base.domain.result.Result; +import com.project.information.domain.dto.ProductLineDTO; +import com.project.information.domain.param.ProductLineParam; + +import java.util.List; + +public interface ProductLineApplicationService { + Result save(ProductLineDTO dto) throws Exception; + + Result> treeList(ProductLineParam param) throws Exception; + + Result rename(ProductLineDTO dto) throws Exception; + + Result delete(Long id) throws Exception; +} diff --git a/src/main/java/com/project/information/application/impl/ProductLineApplicationServiceImpl.java b/src/main/java/com/project/information/application/impl/ProductLineApplicationServiceImpl.java new file mode 100644 index 0000000..c64f1a9 --- /dev/null +++ b/src/main/java/com/project/information/application/impl/ProductLineApplicationServiceImpl.java @@ -0,0 +1,44 @@ +package com.project.information.application.impl; + +import com.project.base.domain.result.Result; +import com.project.information.application.ProductLineApplicationService; +import com.project.information.domain.dto.ProductLineDTO; +import com.project.information.domain.param.ProductLineParam; +import com.project.information.domain.service.GetTreeListProductLineDomainService; +import com.project.information.domain.service.SaveProductLineDomainService; +import com.project.information.domain.service.UpdateProductLineDomainService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class ProductLineApplicationServiceImpl implements ProductLineApplicationService { + @Autowired + private SaveProductLineDomainService saveProductLineDomainService; + + @Autowired + private GetTreeListProductLineDomainService treeListProductLineDomainService; + + @Autowired + private UpdateProductLineDomainService updateProductLineDomainService; + @Override + public Result save(ProductLineDTO dto) throws Exception { + return saveProductLineDomainService.save(dto); + } + + @Override + public Result> treeList(ProductLineParam param) throws Exception { + return treeListProductLineDomainService.treeList(param); + } + + @Override + public Result rename(ProductLineDTO dto) throws Exception { + return updateProductLineDomainService.rename(dto); + } + + @Override + public Result delete(Long id) throws Exception { + return updateProductLineDomainService.delete(id); + } +} diff --git a/src/main/java/com/project/information/config/CustomMinioClient.java b/src/main/java/com/project/information/config/CustomMinioClient.java new file mode 100644 index 0000000..34478eb --- /dev/null +++ b/src/main/java/com/project/information/config/CustomMinioClient.java @@ -0,0 +1,35 @@ +package com.project.information.config; +import com.google.common.collect.Multimap; +import io.minio.CreateMultipartUploadResponse; +import io.minio.MinioClient; +import io.minio.ObjectWriteResponse; +import io.minio.ListPartsResponse; +import io.minio.errors.*; +import io.minio.messages.Part; + +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + + +public class CustomMinioClient extends MinioClient { + + public CustomMinioClient(MinioClient client) { + super(client); + } + + public String initMultiPartUpload(String bucket, String region, String object, Multimap headers, Multimap extraQueryParams) throws IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, ServerException, InternalException, XmlParserException, InvalidResponseException, ErrorResponseException, ServerException, InsufficientDataException, ErrorResponseException, XmlParserException, InvalidResponseException { + CreateMultipartUploadResponse response = this.createMultipartUpload(bucket, region, object, headers, extraQueryParams); + + return response.result().uploadId(); + } + + public ObjectWriteResponse mergeMultipartUpload(String bucketName, String region, String objectName, String uploadId, Part[] parts, Multimap extraHeaders, Multimap extraQueryParams) throws IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, ServerException, InternalException, XmlParserException, InvalidResponseException, ErrorResponseException { + + return this.completeMultipartUpload(bucketName, region, objectName, uploadId, parts, extraHeaders, extraQueryParams); + } + + public ListPartsResponse listMultipart(String bucketName, String region, String objectName, Integer maxParts, Integer partNumberMarker, String uploadId, Multimap extraHeaders, Multimap extraQueryParams) throws NoSuchAlgorithmException, InsufficientDataException, IOException, InvalidKeyException, ServerException, XmlParserException, ErrorResponseException, InternalException, InvalidResponseException { + return this.listParts(bucketName, region, objectName, maxParts, partNumberMarker, uploadId, extraHeaders, extraQueryParams); + } +} \ No newline at end of file diff --git a/src/main/java/com/project/information/config/MinioProperties.java b/src/main/java/com/project/information/config/MinioProperties.java new file mode 100644 index 0000000..d31e2dd --- /dev/null +++ b/src/main/java/com/project/information/config/MinioProperties.java @@ -0,0 +1,24 @@ +package com.project.information.config; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * @Description: minio配置类 + */ +@Component +@ConfigurationProperties(prefix = "minio") +@Getter +@Setter +public class MinioProperties { + + private String endpoint; + + private String accessKey; + + private String secretKey; + + private String bucket; +} \ No newline at end of file diff --git a/src/main/java/com/project/information/controller/InformationController.java b/src/main/java/com/project/information/controller/InformationController.java new file mode 100644 index 0000000..72b9066 --- /dev/null +++ b/src/main/java/com/project/information/controller/InformationController.java @@ -0,0 +1,13 @@ +package com.project.information.controller; + + +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@Slf4j +@RequestMapping("/information") +public class InformationController { + +} diff --git a/src/main/java/com/project/information/controller/ProductLineController.java b/src/main/java/com/project/information/controller/ProductLineController.java new file mode 100644 index 0000000..11f1426 --- /dev/null +++ b/src/main/java/com/project/information/controller/ProductLineController.java @@ -0,0 +1,45 @@ +package com.project.information.controller; + + +import com.project.base.domain.result.Result; +import com.project.information.application.ProductLineApplicationService; +import com.project.information.domain.dto.ProductLineDTO; +import com.project.information.domain.param.ProductLineParam; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + + +@RestController +@Slf4j +@RequestMapping("/productLine") +public class ProductLineController { + + @Autowired + private ProductLineApplicationService productLineApplicationService; + + @PostMapping("/save") + public Result save(ProductLineDTO dto) throws Exception { + return productLineApplicationService.save(dto); + } + + @GetMapping("/treeList") + public Result> treeList(ProductLineParam param) throws Exception { + return productLineApplicationService.treeList(param); + } + + @PostMapping("/rename") + public Result rename(ProductLineDTO dto) throws Exception { + return productLineApplicationService.rename(dto); + } + + @PostMapping("/delete") + public Result delete(Long id) throws Exception { + return productLineApplicationService.delete(id); + } +} diff --git a/src/main/java/com/project/information/domain/dto/FileDTO.java b/src/main/java/com/project/information/domain/dto/FileDTO.java new file mode 100644 index 0000000..7069d6d --- /dev/null +++ b/src/main/java/com/project/information/domain/dto/FileDTO.java @@ -0,0 +1,31 @@ +package com.project.information.domain.dto; + +import lombok.Data; + +@Data +public class FileDTO { + /** + * 文件ID + */ + private Long id; + /** + * 文件名 + */ + private String fileName; + /** + * 分片数量 + */ + private Integer partCount = 1; + /** + * minIO文件完整路径 + */ + private String objectName; + /** + * 单次传输Id + */ + private String uploadId; + /** + * 子产品线id + */ + private String subLineId; +} \ No newline at end of file diff --git a/src/main/java/com/project/information/domain/dto/InformationDTO.java b/src/main/java/com/project/information/domain/dto/InformationDTO.java index 9290fa8..ed98ea0 100644 --- a/src/main/java/com/project/information/domain/dto/InformationDTO.java +++ b/src/main/java/com/project/information/domain/dto/InformationDTO.java @@ -10,5 +10,8 @@ public class InformationDTO extends BaseDTO { private String name; private String filePath; private Integer parseStatus; + private Integer partCount; + private String uploadId; + } diff --git a/src/main/java/com/project/information/domain/dto/InitMultipartDTO.java b/src/main/java/com/project/information/domain/dto/InitMultipartDTO.java new file mode 100644 index 0000000..f9fb8cc --- /dev/null +++ b/src/main/java/com/project/information/domain/dto/InitMultipartDTO.java @@ -0,0 +1,16 @@ +package com.project.information.domain.dto; + +import lombok.Data; + +import java.util.List; + +@Data +public class InitMultipartDTO { + private String uploadId; + + private List uploadUrls; + + private String objectName; + + +} \ No newline at end of file diff --git a/src/main/java/com/project/information/domain/dto/ProductLineDTO.java b/src/main/java/com/project/information/domain/dto/ProductLineDTO.java index a9acfd1..7de7023 100644 --- a/src/main/java/com/project/information/domain/dto/ProductLineDTO.java +++ b/src/main/java/com/project/information/domain/dto/ProductLineDTO.java @@ -1,14 +1,20 @@ package com.project.information.domain.dto; +import com.project.base.domain.dto.BaseDTO; import lombok.Data; +import java.util.ArrayList; +import java.util.List; + @Data -public class ProductLineDTO { +public class ProductLineDTO extends BaseDTO { private String name; - private Integer sort; + private Integer sort = 0; private Boolean leaf; private String business; private Long parentId; private String parentName; + private List childrenList = new ArrayList<>(); + } diff --git a/src/main/java/com/project/information/domain/dto/StreamInfoDTO.java b/src/main/java/com/project/information/domain/dto/StreamInfoDTO.java new file mode 100644 index 0000000..8432e9c --- /dev/null +++ b/src/main/java/com/project/information/domain/dto/StreamInfoDTO.java @@ -0,0 +1,21 @@ +package com.project.information.domain.dto; + +import java.io.InputStream; + +public class StreamInfoDTO { + private long size; + private InputStream stream; + + public StreamInfoDTO(long size, InputStream stream) { + this.size = size; + this.stream = stream; + } + + public long getSize() { + return size; + } + + public InputStream getStream() { + return stream; + } +} \ No newline at end of file diff --git a/src/main/java/com/project/information/domain/entity/InformationEntity.java b/src/main/java/com/project/information/domain/entity/InformationEntity.java index bd8209a..2b348c5 100644 --- a/src/main/java/com/project/information/domain/entity/InformationEntity.java +++ b/src/main/java/com/project/information/domain/entity/InformationEntity.java @@ -29,6 +29,9 @@ public class InformationEntity extends BaseEntity { @Column(name = "name" , columnDefinition="varchar(550) comment '文件名称'") private String name; + @Column(name = "file_suffix" , columnDefinition="varchar(50) comment '文件后缀'") + @TableField("file_suffix") + private String fileSuffix; @Column(name = "file_path" , columnDefinition="varchar(550) comment '文件存储路径'") @TableField("file_path") diff --git a/src/main/java/com/project/information/domain/param/ProductLineParam.java b/src/main/java/com/project/information/domain/param/ProductLineParam.java index 1623fd2..1af30ac 100644 --- a/src/main/java/com/project/information/domain/param/ProductLineParam.java +++ b/src/main/java/com/project/information/domain/param/ProductLineParam.java @@ -5,4 +5,6 @@ import lombok.Data; @Data public class ProductLineParam extends BaseParam { + private String business; + } diff --git a/src/main/java/com/project/information/domain/service/GetTreeListProductLineDomainService.java b/src/main/java/com/project/information/domain/service/GetTreeListProductLineDomainService.java new file mode 100644 index 0000000..6dfbc2e --- /dev/null +++ b/src/main/java/com/project/information/domain/service/GetTreeListProductLineDomainService.java @@ -0,0 +1,11 @@ +package com.project.information.domain.service; + +import com.project.base.domain.result.Result; +import com.project.information.domain.dto.ProductLineDTO; +import com.project.information.domain.param.ProductLineParam; + +import java.util.List; + +public interface GetTreeListProductLineDomainService { + Result> treeList(ProductLineParam param) throws Exception; +} diff --git a/src/main/java/com/project/information/domain/service/InformationBaseService.java b/src/main/java/com/project/information/domain/service/InformationBaseService.java new file mode 100644 index 0000000..1c87f8a --- /dev/null +++ b/src/main/java/com/project/information/domain/service/InformationBaseService.java @@ -0,0 +1,7 @@ +package com.project.information.domain.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.project.information.domain.entity.InformationEntity; + +public interface InformationBaseService extends IService { +} diff --git a/src/main/java/com/project/information/domain/service/ProductLineBaseService.java b/src/main/java/com/project/information/domain/service/ProductLineBaseService.java new file mode 100644 index 0000000..b0d62ec --- /dev/null +++ b/src/main/java/com/project/information/domain/service/ProductLineBaseService.java @@ -0,0 +1,7 @@ +package com.project.information.domain.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.project.information.domain.entity.ProductLineEntity; + +public interface ProductLineBaseService extends IService { +} diff --git a/src/main/java/com/project/information/domain/service/SaveProductLineDomainService.java b/src/main/java/com/project/information/domain/service/SaveProductLineDomainService.java new file mode 100644 index 0000000..3cef714 --- /dev/null +++ b/src/main/java/com/project/information/domain/service/SaveProductLineDomainService.java @@ -0,0 +1,9 @@ +package com.project.information.domain.service; + +import com.project.base.domain.result.Result; +import com.project.information.domain.dto.ProductLineDTO; + +public interface SaveProductLineDomainService { + + Result save(ProductLineDTO dto) throws Exception; +} diff --git a/src/main/java/com/project/information/domain/service/UpdateProductLineDomainService.java b/src/main/java/com/project/information/domain/service/UpdateProductLineDomainService.java new file mode 100644 index 0000000..de6eb7a --- /dev/null +++ b/src/main/java/com/project/information/domain/service/UpdateProductLineDomainService.java @@ -0,0 +1,10 @@ +package com.project.information.domain.service; + +import com.project.base.domain.result.Result; +import com.project.information.domain.dto.ProductLineDTO; + +public interface UpdateProductLineDomainService { + Result rename(ProductLineDTO dto) throws Exception; + + Result delete(Long id) throws Exception; +} diff --git a/src/main/java/com/project/information/domain/service/UploadInformationDomainService.java b/src/main/java/com/project/information/domain/service/UploadInformationDomainService.java new file mode 100644 index 0000000..4754cb7 --- /dev/null +++ b/src/main/java/com/project/information/domain/service/UploadInformationDomainService.java @@ -0,0 +1,11 @@ +package com.project.information.domain.service; + +import com.project.base.domain.result.Result; +import com.project.information.domain.dto.FileDTO; +import com.project.information.domain.dto.InformationDTO; +import com.project.information.domain.dto.InitMultipartDTO; + +public interface UploadInformationDomainService { + + Result initMultiPartUpload(InformationDTO dto) throws Exception; +} diff --git a/src/main/java/com/project/information/domain/service/UploadService.java b/src/main/java/com/project/information/domain/service/UploadService.java new file mode 100644 index 0000000..d00e743 --- /dev/null +++ b/src/main/java/com/project/information/domain/service/UploadService.java @@ -0,0 +1,28 @@ +package com.project.information.domain.service; + +import com.project.information.domain.dto.StreamInfoDTO; + +import java.util.Map; + +public interface UploadService { + + /** + * 分片上传初始化 + * + * @param path 路径 + * @param filename 文件名 + * @param partCount 分片数量 + * @param contentType / + * @return / + */ + Map initMultiPartUpload(String path, String filename, Integer partCount, String contentType); + + /** + * 完成分片上传 + * + * @param objectName 文件名 + * @param uploadId 标识 + * @return / + */ + StreamInfoDTO mergeMultipartUpload(String objectName, String uploadId); +} \ No newline at end of file diff --git a/src/main/java/com/project/information/domain/service/impl/GetTreeListProductLineDomainServiceImpl.java b/src/main/java/com/project/information/domain/service/impl/GetTreeListProductLineDomainServiceImpl.java new file mode 100644 index 0000000..b68d68e --- /dev/null +++ b/src/main/java/com/project/information/domain/service/impl/GetTreeListProductLineDomainServiceImpl.java @@ -0,0 +1,37 @@ +package com.project.information.domain.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.project.base.domain.exception.BusinessErrorException; +import com.project.base.domain.result.Result; +import com.project.base.domain.utils.TreeUtils; +import com.project.information.domain.dto.ProductLineDTO; +import com.project.information.domain.entity.ProductLineEntity; +import com.project.information.domain.param.ProductLineParam; +import com.project.information.domain.service.GetTreeListProductLineDomainService; +import com.project.information.domain.service.ProductLineBaseService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class GetTreeListProductLineDomainServiceImpl implements GetTreeListProductLineDomainService { + @Autowired + private ProductLineBaseService productLineBaseService; + @Override + public Result> treeList(ProductLineParam param) throws Exception { + if (StrUtil.isBlank(param.getBusiness())) { + throw new BusinessErrorException("所属 BG 不能为空"); + } + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(ProductLineEntity::getBusiness , param.getBusiness()); + List res = productLineBaseService.list(queryWrapper) + .stream().map(entity -> entity.toDTO(ProductLineDTO::new)) + .collect(Collectors.toList()); + return Result.success(TreeUtils.buildLongTree(res , ProductLineDTO::getId , ProductLineDTO::getParentId , + ProductLineDTO::setChildrenList)); + + } +} diff --git a/src/main/java/com/project/information/domain/service/impl/InformationBaseServiceImpl.java b/src/main/java/com/project/information/domain/service/impl/InformationBaseServiceImpl.java new file mode 100644 index 0000000..0edadb5 --- /dev/null +++ b/src/main/java/com/project/information/domain/service/impl/InformationBaseServiceImpl.java @@ -0,0 +1,11 @@ +package com.project.information.domain.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.project.information.domain.entity.InformationEntity; +import com.project.information.domain.service.InformationBaseService; +import com.project.information.mapper.InformationMapper; +import org.springframework.stereotype.Service; + +@Service +public class InformationBaseServiceImpl extends ServiceImpl implements InformationBaseService { +} diff --git a/src/main/java/com/project/information/domain/service/impl/ProductLineBaseServiceImpl.java b/src/main/java/com/project/information/domain/service/impl/ProductLineBaseServiceImpl.java new file mode 100644 index 0000000..c3650e0 --- /dev/null +++ b/src/main/java/com/project/information/domain/service/impl/ProductLineBaseServiceImpl.java @@ -0,0 +1,12 @@ +package com.project.information.domain.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.project.information.domain.entity.ProductLineEntity; +import com.project.information.domain.service.ProductLineBaseService; +import com.project.information.mapper.ProductLineMapper; +import org.springframework.stereotype.Service; + + +@Service +public class ProductLineBaseServiceImpl extends ServiceImpl implements ProductLineBaseService { +} diff --git a/src/main/java/com/project/information/domain/service/impl/SaveProductLineDomainServiceImpl.java b/src/main/java/com/project/information/domain/service/impl/SaveProductLineDomainServiceImpl.java new file mode 100644 index 0000000..47c208f --- /dev/null +++ b/src/main/java/com/project/information/domain/service/impl/SaveProductLineDomainServiceImpl.java @@ -0,0 +1,63 @@ +package com.project.information.domain.service.impl; + +import cn.hutool.core.util.BooleanUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.project.base.domain.exception.BusinessErrorException; +import com.project.base.domain.result.Result; +import com.project.information.domain.dto.ProductLineDTO; +import com.project.information.domain.entity.ProductLineEntity; +import com.project.information.domain.service.ProductLineBaseService; +import com.project.information.domain.service.SaveProductLineDomainService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Objects; + +@Service +public class SaveProductLineDomainServiceImpl implements SaveProductLineDomainService { + @Autowired + private ProductLineBaseService productLineBaseService; + @Override + public Result save(ProductLineDTO dto) throws Exception { + // 校验 + if (StrUtil.isBlank(dto.getBusiness())) { + throw new BusinessErrorException("所属 BG 不能为空"); + } + if (Objects.isNull(dto.getLeaf())) { + throw new BusinessErrorException("产品线/子产品线类别不能为空"); + } + if (BooleanUtil.isTrue(dto.getLeaf()) && Objects.isNull(dto.getParentId())) { + throw new BusinessErrorException("子产品线所属产品线id不能为空"); + } + if (BooleanUtil.isTrue(dto.getLeaf()) && Objects.isNull(dto.getParentName())) { + throw new BusinessErrorException("子产品线所属产品线名称不能为空"); + } + + if (BooleanUtil.isTrue(dto.getLeaf())) { + ProductLineEntity parentProductLine = productLineBaseService.getById(dto.getParentId()); + if (Objects.isNull(parentProductLine)) { + throw new BusinessErrorException("不存在的子产品线所属产品线id"); + } + + } + // 校验名称是否重复 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(ProductLineEntity::getBusiness , dto.getBusiness()); + queryWrapper.eq(ProductLineEntity::getLeaf , dto.getLeaf()); + queryWrapper.eq(ProductLineEntity::getName , dto.getName()); + ProductLineEntity existOne = productLineBaseService.getOne(queryWrapper); + if (Objects.nonNull(existOne)) { + if (BooleanUtil.isFalse(dto.getLeaf())) { + throw new BusinessErrorException("同一 BG 下产品线名称不能重复"); + } else { + throw new BusinessErrorException("同一产品线下子产品线名称不能重复"); + } + } + // 保存 + ProductLineEntity entity = dto.toEntity(ProductLineEntity::new); + productLineBaseService.save(entity); + + return Result.success(entity.toDTO(ProductLineDTO::new)); + } +} diff --git a/src/main/java/com/project/information/domain/service/impl/UpdateProductLineDomainServiceImpl.java b/src/main/java/com/project/information/domain/service/impl/UpdateProductLineDomainServiceImpl.java new file mode 100644 index 0000000..ff4248e --- /dev/null +++ b/src/main/java/com/project/information/domain/service/impl/UpdateProductLineDomainServiceImpl.java @@ -0,0 +1,53 @@ +package com.project.information.domain.service.impl; + +import cn.hutool.core.util.BooleanUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.project.base.domain.exception.BusinessErrorException; +import com.project.base.domain.result.Result; +import com.project.information.domain.dto.ProductLineDTO; +import com.project.information.domain.entity.ProductLineEntity; +import com.project.information.domain.service.ProductLineBaseService; +import com.project.information.domain.service.UpdateProductLineDomainService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Objects; + +@Service +public class UpdateProductLineDomainServiceImpl implements UpdateProductLineDomainService { + @Autowired + private ProductLineBaseService productLineBaseService; + + @Override + public Result rename(ProductLineDTO dto) throws Exception { + if (Objects.isNull(dto.getId())) { + throw new BusinessErrorException("重命名id不能为空"); + } + if (StrUtil.isBlank(dto.getName())) { + throw new BusinessErrorException("名称不能为空"); + } + ProductLineEntity entity = productLineBaseService.getById(dto.getId()); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(ProductLineEntity::getBusiness , entity.getBusiness()); + queryWrapper.eq(ProductLineEntity::getLeaf , entity.getLeaf()); + queryWrapper.eq(ProductLineEntity::getName , dto.getName()); + ProductLineEntity existOne = productLineBaseService.getOne(queryWrapper); + if (Objects.nonNull(existOne)) { + if (BooleanUtil.isFalse(entity.getLeaf())) { + throw new BusinessErrorException("同一 BG 下产品线名称不能重复"); + } else { + throw new BusinessErrorException("同一产品线下子产品线名称不能重复"); + } + } + entity.setName(dto.getName()); + productLineBaseService.updateById(entity); + return Result.success(entity.toDTO(ProductLineDTO::new)); + } + + @Override + public Result delete(Long id) throws Exception { + productLineBaseService.removeById(id); + return Result.success("删除成功"); + } +} diff --git a/src/main/java/com/project/information/domain/service/impl/UploadInformationDomainServiceImpl.java b/src/main/java/com/project/information/domain/service/impl/UploadInformationDomainServiceImpl.java new file mode 100644 index 0000000..f99172c --- /dev/null +++ b/src/main/java/com/project/information/domain/service/impl/UploadInformationDomainServiceImpl.java @@ -0,0 +1,56 @@ +package com.project.information.domain.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.bean.copier.CopyOptions; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.project.base.domain.exception.MissingParameterException; +import com.project.base.domain.result.Result; +import com.project.base.domain.result.ResultCodeEnum; +import com.project.information.domain.dto.FileDTO; +import com.project.information.domain.dto.InformationDTO; +import com.project.information.domain.dto.InitMultipartDTO; +import com.project.information.domain.entity.InformationEntity; +import com.project.information.domain.service.InformationBaseService; +import com.project.information.domain.service.UploadInformationDomainService; +import com.project.information.domain.service.UploadService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Map; +import java.util.Objects; + + +@Service +public class UploadInformationDomainServiceImpl implements UploadInformationDomainService { + + @Autowired + private UploadService uploadService; + + @Autowired + private InformationBaseService informationBaseService; + + + + @Override + public Result initMultiPartUpload(InformationDTO dto) throws Exception { + if (StrUtil.isBlank(dto.getName()) || Objects.isNull(dto.getPartCount()) || Objects.isNull(dto.getSubLineId())) { + throw new MissingParameterException(ResultCodeEnum.MISSING_PARAMETER.getMessage()); + } + String path = dto.getSubLineId().toString(); + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(InformationEntity::getSubLineId , dto.getSubLineId()); + queryWrapper.eq(InformationEntity::getName , dto.getName()); + InformationEntity existOne = informationBaseService.getOne(queryWrapper); + if (Objects.nonNull(existOne)) { + + } + + Map stringObjectMap = uploadService.initMultiPartUpload(path, dto.getName() , dto.getPartCount() , "application/octet-stream"); + InitMultipartDTO initMultipartDTO = BeanUtil.mapToBean(stringObjectMap, InitMultipartDTO.class, true, CopyOptions.create()); + initMultipartDTO.setObjectName(path + "/" + dto.getName()); + return Result.success(initMultipartDTO); + } +} diff --git a/src/main/java/com/project/information/domain/service/impl/UploadServiceImpl.java b/src/main/java/com/project/information/domain/service/impl/UploadServiceImpl.java new file mode 100644 index 0000000..85e641b --- /dev/null +++ b/src/main/java/com/project/information/domain/service/impl/UploadServiceImpl.java @@ -0,0 +1,43 @@ +package com.project.information.domain.service.impl; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.project.information.domain.dto.StreamInfoDTO; +import com.project.information.domain.service.UploadService; +import com.project.information.utils.MinIoUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Map; + +@Service +@RequiredArgsConstructor +public class UploadServiceImpl implements UploadService { + + private final MinIoUtils minIoUtils; + + @Override + public Map initMultiPartUpload(String path, String filename, Integer partCount, String contentType) { + path = path.replaceAll("/+", "/"); + if (path.indexOf("/") == 0) { + path = path.substring(1); + } + String filePath = path + "/" + filename; + + Map result; + // 单文件,直接上传 + if (partCount == 1) { + String uploadObjectUrl = minIoUtils.getUploadObjectUrl(filePath); + result = ImmutableMap.of("uploadUrls", ImmutableList.of(uploadObjectUrl)); + } else {//多文件,分片上传 + result = minIoUtils.initMultiPartUpload(filePath, partCount, contentType); + } + + return result; + } + + @Override + public StreamInfoDTO mergeMultipartUpload(String objectName, String uploadId) { + return minIoUtils.mergeMultipartUpload(objectName, uploadId); + } +} \ No newline at end of file diff --git a/src/main/java/com/project/information/utils/MinIoUtils.java b/src/main/java/com/project/information/utils/MinIoUtils.java new file mode 100644 index 0000000..fa37d12 --- /dev/null +++ b/src/main/java/com/project/information/utils/MinIoUtils.java @@ -0,0 +1,127 @@ +package com.project.information.utils; + +import cn.hutool.core.util.StrUtil; +import com.google.common.collect.HashMultimap; +import com.project.information.config.CustomMinioClient; +import com.project.information.config.MinioProperties; +import com.project.information.domain.dto.StreamInfoDTO; +import io.minio.GetObjectArgs; +import io.minio.GetPresignedObjectUrlArgs; +import io.minio.ListPartsResponse; +import io.minio.MinioClient; +import io.minio.http.Method; +import io.minio.messages.Part; +import jakarta.annotation.PostConstruct; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +@Slf4j +@Configuration +@EnableConfigurationProperties({MinioProperties.class}) +public class MinIoUtils { + private final MinioProperties minioProperties; + private CustomMinioClient customMinioClient; + + public MinIoUtils(MinioProperties minioProperties) { + this.minioProperties = minioProperties; + } + + @PostConstruct + public void init() { + MinioClient minioClient = MinioClient.builder() + .endpoint(minioProperties.getEndpoint()) + .credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey()) + .build(); + customMinioClient = new CustomMinioClient(minioClient); + } + + public String getUploadObjectUrl(String objectName) { + try { + String url = customMinioClient.getPresignedObjectUrl( + GetPresignedObjectUrlArgs.builder() + .method(Method.PUT) + .bucket(minioProperties.getBucket()) + .object(objectName) + .expiry(1, TimeUnit.HOURS) + //.extraHeaders(headers) + .build() + ); + + + return url; + + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + public Map initMultiPartUpload(String objectName, int partCount, String contentType) { + Map result = new HashMap<>(); + try { + if (StrUtil.isBlank(contentType)) { + contentType = "application/octet-stream"; + } + HashMultimap headers = HashMultimap.create(); + headers.put("Content-Type", contentType); + String uploadId = customMinioClient.initMultiPartUpload(minioProperties.getBucket(), null, objectName, headers, null); + + result.put("uploadId", uploadId); + List partList = new ArrayList<>(); + + Map reqParams = new HashMap<>(); + //reqParams.put("response-content-type", "application/json"); + reqParams.put("uploadId", uploadId); + for (int i = 1; i <= partCount; i++) { + reqParams.put("partNumber", String.valueOf(i)); + String uploadUrl = customMinioClient.getPresignedObjectUrl( + GetPresignedObjectUrlArgs.builder() + .method(Method.PUT) + .bucket(minioProperties.getBucket()) + .object(objectName) + .expiry(1, TimeUnit.HOURS) + .extraQueryParams(reqParams) + .build()); + partList.add(uploadUrl); + } + result.put("uploadUrls", partList); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + + return result; + } + + public StreamInfoDTO mergeMultipartUpload(String objectName, String uploadId) { + try { + //单文件,不需要合并 + if (StrUtil.isNotBlank(uploadId)) { + //TODO目前仅做了最大1000分片 + Part[] parts = new Part[1000]; + ListPartsResponse partResult = customMinioClient.listMultipart(minioProperties.getBucket(), null, objectName, 1000, 0, uploadId, null, null); + int partNumber = 1; + for (Part part : partResult.result().partList()) { + parts[partNumber - 1] = new Part(partNumber, part.etag()); + partNumber++; + } + customMinioClient.mergeMultipartUpload(minioProperties.getBucket(), null, objectName, uploadId, parts, null, null); + } + return StreamUtils.getInputStreamSizeAndCopy(customMinioClient.getObject(GetObjectArgs.builder() + .bucket(minioProperties.getBucket()) + .object(objectName).build())); + + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/src/main/java/com/project/information/utils/StreamUtils.java b/src/main/java/com/project/information/utils/StreamUtils.java new file mode 100644 index 0000000..7771630 --- /dev/null +++ b/src/main/java/com/project/information/utils/StreamUtils.java @@ -0,0 +1,46 @@ +package com.project.information.utils; + +import com.project.information.domain.dto.StreamInfoDTO; + +import java.io.InputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + + + +public class StreamUtils { + + /** + * 获取 InputStream 的大小,并返回一个可重复读取的新 InputStream。 + * 这个方法会消耗原始的输入流。 + * + * @param originalStream 原始的、一次性的输入流。 + * @return 包含大小和新的、可重复读取的流的 StreamInfo 对象。 + * @throws IOException 如果读取时发生错误。 + */ + public static StreamInfoDTO getInputStreamSizeAndCopy(InputStream originalStream) throws IOException { + if (originalStream == null) { + return new StreamInfoDTO(0, new ByteArrayInputStream(new byte[0])); + } + + // 使用 ByteArrayOutputStream 作为内存中的缓冲区 + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buffer = new byte[4096]; + int bytesRead; + + // 将原始流的所有内容读取并写入到 ByteArrayOutputStream 中 + while ((bytesRead = originalStream.read(buffer)) != -1) { + baos.write(buffer, 0, bytesRead); + } + + // 现在 baos 中包含了流的全部内容 + byte[] allBytes = baos.toByteArray(); + long size = allBytes.length; + + // 创建一个新的 ByteArrayInputStream,它可以被重复读取 + InputStream newStream = new ByteArrayInputStream(allBytes); + + return new StreamInfoDTO(size, newStream); + } +} \ No newline at end of file