31 changed files with 800 additions and 3 deletions
@ -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<ProductLineDTO> save(ProductLineDTO dto) throws Exception; |
|||
|
|||
Result<List<ProductLineDTO>> treeList(ProductLineParam param) throws Exception; |
|||
|
|||
Result<ProductLineDTO> rename(ProductLineDTO dto) throws Exception; |
|||
|
|||
Result<String> delete(Long id) throws Exception; |
|||
} |
|||
@ -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<ProductLineDTO> save(ProductLineDTO dto) throws Exception { |
|||
return saveProductLineDomainService.save(dto); |
|||
} |
|||
|
|||
@Override |
|||
public Result<List<ProductLineDTO>> treeList(ProductLineParam param) throws Exception { |
|||
return treeListProductLineDomainService.treeList(param); |
|||
} |
|||
|
|||
@Override |
|||
public Result<ProductLineDTO> rename(ProductLineDTO dto) throws Exception { |
|||
return updateProductLineDomainService.rename(dto); |
|||
} |
|||
|
|||
@Override |
|||
public Result<String> delete(Long id) throws Exception { |
|||
return updateProductLineDomainService.delete(id); |
|||
} |
|||
} |
|||
@ -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<String, String> headers, Multimap<String, String> 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<String, String> extraHeaders, Multimap<String, String> 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<String, String> extraHeaders, Multimap<String, String> extraQueryParams) throws NoSuchAlgorithmException, InsufficientDataException, IOException, InvalidKeyException, ServerException, XmlParserException, ErrorResponseException, InternalException, InvalidResponseException { |
|||
return this.listParts(bucketName, region, objectName, maxParts, partNumberMarker, uploadId, extraHeaders, extraQueryParams); |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
@ -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 { |
|||
|
|||
} |
|||
@ -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<ProductLineDTO> save(ProductLineDTO dto) throws Exception { |
|||
return productLineApplicationService.save(dto); |
|||
} |
|||
|
|||
@GetMapping("/treeList") |
|||
public Result<List<ProductLineDTO>> treeList(ProductLineParam param) throws Exception { |
|||
return productLineApplicationService.treeList(param); |
|||
} |
|||
|
|||
@PostMapping("/rename") |
|||
public Result<ProductLineDTO> rename(ProductLineDTO dto) throws Exception { |
|||
return productLineApplicationService.rename(dto); |
|||
} |
|||
|
|||
@PostMapping("/delete") |
|||
public Result<String> delete(Long id) throws Exception { |
|||
return productLineApplicationService.delete(id); |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
@ -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<String> uploadUrls; |
|||
|
|||
private String objectName; |
|||
|
|||
|
|||
} |
|||
@ -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<ProductLineDTO> childrenList = new ArrayList<>(); |
|||
|
|||
} |
|||
|
|||
@ -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; |
|||
} |
|||
} |
|||
@ -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<List<ProductLineDTO>> treeList(ProductLineParam param) throws Exception; |
|||
} |
|||
@ -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<InformationEntity> { |
|||
} |
|||
@ -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<ProductLineEntity> { |
|||
} |
|||
@ -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<ProductLineDTO> save(ProductLineDTO dto) throws Exception; |
|||
} |
|||
@ -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<ProductLineDTO> rename(ProductLineDTO dto) throws Exception; |
|||
|
|||
Result<String> delete(Long id) throws Exception; |
|||
} |
|||
@ -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<InitMultipartDTO> initMultiPartUpload(InformationDTO dto) throws Exception; |
|||
} |
|||
@ -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<String, Object> initMultiPartUpload(String path, String filename, Integer partCount, String contentType); |
|||
|
|||
/** |
|||
* 完成分片上传 |
|||
* |
|||
* @param objectName 文件名 |
|||
* @param uploadId 标识 |
|||
* @return / |
|||
*/ |
|||
StreamInfoDTO mergeMultipartUpload(String objectName, String uploadId); |
|||
} |
|||
@ -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<List<ProductLineDTO>> treeList(ProductLineParam param) throws Exception { |
|||
if (StrUtil.isBlank(param.getBusiness())) { |
|||
throw new BusinessErrorException("所属 BG 不能为空"); |
|||
} |
|||
LambdaQueryWrapper<ProductLineEntity> queryWrapper = new LambdaQueryWrapper<>(); |
|||
queryWrapper.eq(ProductLineEntity::getBusiness , param.getBusiness()); |
|||
List<ProductLineDTO> 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)); |
|||
|
|||
} |
|||
} |
|||
@ -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<InformationMapper, InformationEntity> implements InformationBaseService { |
|||
} |
|||
@ -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<ProductLineMapper, ProductLineEntity> implements ProductLineBaseService { |
|||
} |
|||
@ -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<ProductLineDTO> 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<ProductLineEntity> 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)); |
|||
} |
|||
} |
|||
@ -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<ProductLineDTO> 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<ProductLineEntity> 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<String> delete(Long id) throws Exception { |
|||
productLineBaseService.removeById(id); |
|||
return Result.success("删除成功"); |
|||
} |
|||
} |
|||
@ -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<InitMultipartDTO> 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<InformationEntity> 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<String, Object> 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); |
|||
} |
|||
} |
|||
@ -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<String, Object> 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<String, Object> 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); |
|||
} |
|||
} |
|||
@ -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<String, Object> initMultiPartUpload(String objectName, int partCount, String contentType) { |
|||
Map<String, Object> result = new HashMap<>(); |
|||
try { |
|||
if (StrUtil.isBlank(contentType)) { |
|||
contentType = "application/octet-stream"; |
|||
} |
|||
HashMultimap<String, String> headers = HashMultimap.create(); |
|||
headers.put("Content-Type", contentType); |
|||
String uploadId = customMinioClient.initMultiPartUpload(minioProperties.getBucket(), null, objectName, headers, null); |
|||
|
|||
result.put("uploadId", uploadId); |
|||
List<String> partList = new ArrayList<>(); |
|||
|
|||
Map<String, String> 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; |
|||
} |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue