SpringBoot集成AWS S3 生成预签名url进行上传文件到S3

依赖


    
        <dependency>
            <groupId>commons-fileuploadgroupId>
            <artifactId>commons-fileuploadartifactId>
            <version>1.4version>
        dependency>

       
        <dependency>
            <groupId>com.amazonawsgroupId>
            <artifactId>aws-java-sdk-s3artifactId>
            <version>1.12.198version>
        dependency>
        

接口层


   private final AwsS3Service awsS3Service;
   
   private static final String bucket = "s3Demo";

    public GpLandPageController(AwsS3Service awsS3Service) {
        this.awsS3Service = awsS3Service;
    }

    @PostMapping("/upload")
    public String uploadImage(@RequestParam("file") @NotNull MultipartFile file) {
        return awsS3Service.uploadFileToS3(bucket, file);
    }

    @PostMapping("/preUpload")
    public PreUploadRes preUpload(@RequestParam("fileName") @NotEmpty String fileName) {
        return awsS3Service.preUploadFile(bucket, fileName);
    }
    

service接口层


    /**
     * 预签名上传文件
     *
     * @param bucket bucket
     * @param fileName 文件名
     * @return {@link PreUploadRes} 上传连接和key在这里插入代码片
     */
    PreUploadRes preUploadFile(String bucket, String fileName);

    /**
     * 将文件上传到s3
     *
     * @param bucket 桶
     * @param file   文件
     * @return {@link AwsS3UploadFileResDto}
     */
    public AwsS3UploadFileResDto uploadFileToS3(String bucket, MultipartFile file);
    

service实现层


    private static final String PREFIX = "demo";


    @Override
    public PreUploadRes preUploadFile(String bucket, String fileName) {
        PreUploadRes res = new PreUploadRes();
        try {
                AmazonS3 amazonS3 = s3client();
                String fastFileName = getFileKey(prefix);
                // token设置1小时后过期
                DateTime expiration = DateUtil.offsetHour(new Date(), 1);
                URL url = amazonS3.generatePresignedUrl(new GeneratePresignedUrlRequest(bucket, fastFileName).withExpiration(expiration).withMethod(HttpMethod.PUT));
                res.setKey(fastFileName).setUrl(url.toString());
                log.info("Generate preUrl Request is success :{}", JSONUtil.toJsonStr(res));
        } catch (Exception e) {
            log.error("Generate preUrl Request is failure :{}", e.getMessage(), e);
            throw new ServiceException(ErrorCode.CONNECT_S3_FAILED);
        }
        return res;
    }

    @Override
    public AwsS3UploadFileResDto uploadFileToS3(String bucket, MultipartFile file) {
        String fastFileName = getFileKey(file.getOriginalFilename());
        try {
            PutObjectRequest request = new PutObjectRequest(bucket, fastFileName, file.getInputStream(), null);
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentType(file.getContentType());
            request.setMetadata(metadata);
            PutObjectResult putObjectResult = s3client().putObject(request);
            GpLandPageConfigDto config = getConfig();
            String url = config.getCdnPrefix() + "/" + fastFileName;
            log.info("upload to s3 bucket:{} file:{} url:{} is success ! ===> putRes:{}", bucket, fastFileName, url, JSONUtil.toJsonStr(putObjectResult));
            AwsS3UploadFileResDto awsS3UploadFileResDto = new AwsS3UploadFileResDto().setS3PutRes(putObjectResult);
            awsS3UploadFileResDto.setFileName(fastFileName);
            awsS3UploadFileResDto.setBucketName(bucket);
            awsS3UploadFileResDto.setFileUrl(url);
            return awsS3UploadFileResDto;
        } catch (Exception e) {
            log.error("upload original file:{}, fastFileName:{} to S3 is Error:{}", file.getName(), fastFileName, e.getMessage());
            throw new ServiceException(ErrorCode.CONNECT_S3_FAILED);
        }
    }
    /**
     * s3client
     *
     * @return {@link AmazonS3}
     */
    public AmazonS3 s3client() {
        try {
            AtomicReference<AmazonS3> res = new AtomicReference<>();
                Regions regions = Regions.fromName(regions);
                res.set(AmazonS3ClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(keyId, secretKey))).withRegion(regions).build());
            if (Objects.isNull(res.get())) {
                log.warn("connect S3 Server is failure , please check your config param!");
                throw new ServiceException(ErrorCode.CONNECT_S3_FAILED);
            }
            return res.get();
        } catch (ServiceException | IllegalArgumentException e) {
            log.warn("Failed to connect to S3 server e:{}", e.getMessage(), e);
            throw new ServiceException(ErrorCode.CONNECT_S3_FAILED);
        }
    }
    
   	private String getFileKey(String fileName) {
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        String dateDir = new SimpleDateFormat("yyyyMMdd").format(new Date());
        return String.format("%s/%s/%s_%s", PREFIX, dateDir, uuid, fileName);
    }

DTO

Aws S3 上传后文件响应dto

/**
 * Aws S3 上传后文件响应dto
 *
 * @author yunnuo
 * @date 2022-04-15
 * @since 1.0
 */
@EqualsAndHashCode(callSuper = true)
@ToString
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class AwsS3UploadFileResDto extends S3FileInfoDto {

    /**
     * s3 put 响应数据
     */
    private PutObjectResult s3PutRes;
    
}

S3 文件 DTO


/**
 *  S3 文件 DTO
 *
 * @author yunnuo
 * @date 2022-04-15
 * @since 1.0
 */
@ToString
@Data
@NoArgsConstructor
@AllArgsConstructor
public class S3FileInfoDto {
    /**
     * 文件名称
     */
    private String fileName;

    /**
     * bucket名称
     */
    private String bucketName;

    /**
     * 文件url
     */
    private String fileUrl;
}

AWS S3 预签名响应


/**
 * AWS S3 预签名响应
 *
 * @author yunnuo
 * @date 2022-04-18
 * @since 1.0
 */
@ToString
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class PreUploadRes {

    private String key;

    private String url;

}

测试

预签名url生成

  1. 使用postman进行请求后获得url
    SpringBoot集成AWS S3 生成预签名url进行上传文件到S3_第1张图片

  2. 通过生成的预签名url进行上传到S3,返回200则说明文件上传成功了!
    SpringBoot集成AWS S3 生成预签名url进行上传文件到S3_第2张图片

  3. 然后通过CDN映射到S3的域名进行访问,或者直接访问S3,可以查看文件。

其他方法(可以参考着用)

在这里插入代码片

/**
 * AwsS3 服务实现
 *
 * @author yunnuo
 * @date 2022-04-14
 * @since 1.0
 */
@Slf4j
@Service
public class AwsS3ServiceImpl implements AwsS3Service {

    private final ConfigCenter configCenter;

    private static final String OPS_PREFIX = "ops";

    public AwsS3ServiceImpl(ConfigCenter configCenter) {
        this.configCenter = configCenter;
    }

    @Override
    public List<AwsS3UploadFileResDto> uploadFilesToS3(String bucket, List<MultipartFile> files) {
        log.info("start upload files to s3 files size:{}", files.size());
        if (CollUtil.isEmpty(files)) {
            log.warn("upload to s3 files is must be nut null!");
            throw new ServiceException(ErrorCode.FILE_IS_EMPTY);
        }
        return files.stream().filter(Objects::nonNull).map(file -> uploadFileToS3(bucket, file)).collect(Collectors.toList());

    }

    @Override
    public PreUploadRes preUploadFile(String prefix) {
        PreUploadRes res = new PreUploadRes();
        try {
            Optional<List<GpLandPageConfigDto>> s3config = configCenter.getDataWithType2(GpLandPageConstant.CONFIG_KEY, GpLandPageConfigDto.class);
            s3config.flatMap(configs -> configs.stream().findFirst()).ifPresent(config -> {
                AmazonS3 amazonS3 = s3client();
                String fastFileName = getFileKey(prefix);
                // 往后1小时
                DateTime expiration = DateUtil.offsetHour(new Date(), 1);
                URL url = amazonS3.generatePresignedUrl(new GeneratePresignedUrlRequest(config.getS3Bucket(), fastFileName).withExpiration(expiration).withMethod(HttpMethod.PUT));
                res.setKey(config.getCdnPrefix() + "/" + fastFileName).setUrl(url.toString());
                log.info("Generate preUrl Request is success :{}", JSONUtil.toJsonStr(res));
            });
        } catch (Exception e) {
            log.error("Generate preUrl Request is failure :{}", e.getMessage(), e);
            throw new ServiceException(ErrorCode.CONNECT_S3_FAILED);
        }
        return res;
    }

    @Override
    public AwsS3UploadFileResDto uploadFileToS3(String bucket, MultipartFile file) {
        String fastFileName = getFileKey(file.getOriginalFilename());
        try {
            PutObjectRequest request = new PutObjectRequest(bucket, fastFileName, file.getInputStream(), null);
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentType(file.getContentType());
            request.setMetadata(metadata);
            PutObjectResult putObjectResult = s3client().putObject(request);
//            String url = getUrlFor7Day(bucket, fastFileName);
            GpLandPageConfigDto config = getConfig();
            String url = config.getCdnPrefix() + "/" + fastFileName;
            log.info("upload to s3 bucket:{} file:{} url:{} is success ! ===> putRes:{}", bucket, fastFileName, url, JSONUtil.toJsonStr(putObjectResult));
            AwsS3UploadFileResDto awsS3UploadFileResDto = new AwsS3UploadFileResDto().setS3PutRes(putObjectResult);
            awsS3UploadFileResDto.setFileName(fastFileName);
            awsS3UploadFileResDto.setBucketName(bucket);
            awsS3UploadFileResDto.setFileUrl(url);
            return awsS3UploadFileResDto;
        } catch (Exception e) {
            log.error("upload original file:{}, fastFileName:{} to S3 is Error:{}", file.getName(), fastFileName, e.getMessage());
            throw new ServiceException(ErrorCode.CONNECT_S3_FAILED);
        }
    }

    private GpLandPageConfigDto getConfig() {
        GpLandPageConfigDto landPageConfigDto = new GpLandPageConfigDto();
        configCenter.getDataWithType2(GpLandPageConstant.CONFIG_KEY, GpLandPageConfigDto.class).flatMap(configs -> configs.stream().findFirst()).ifPresent(config -> BeanUtil.copyProperties(config, landPageConfigDto));
        if (StringUtils.isBlank(landPageConfigDto.getS3Bucket())) {
            throw new ServiceException(ErrorCode.CONFIG_CENTER_CONFIG_EMPTY);
        }
        return landPageConfigDto;
    }


    /**
     * s3client
     *
     * @return {@link AmazonS3}
     */
    public AmazonS3 s3client() {
        try {
            AtomicReference<AmazonS3> res = new AtomicReference<>();
            Optional<List<GpLandPageConfigDto>> s3config = configCenter.getDataWithType2(GpLandPageConstant.CONFIG_KEY, GpLandPageConfigDto.class);
            s3config.flatMap(configs -> configs.stream().findFirst()).ifPresent(config -> {
                Regions regions = Regions.fromName(config.getRegions());
                res.set(AmazonS3ClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(config.getS3AccessKeyId(), config.getS3SecretAccessKey()))).withRegion(regions).build());
            });
            if (Objects.isNull(res.get())) {
                log.warn("connect S3 Server is failure , please check your config param!");
                throw new ServiceException(ErrorCode.CONNECT_S3_FAILED);
            }
            return res.get();
        } catch (ServiceException | IllegalArgumentException e) {
            log.warn("Failed to connect to S3 server e:{}", e.getMessage(), e);
            throw new ServiceException(ErrorCode.CONNECT_S3_FAILED);
        }
    }


    @Override
    public InputStream downloadFile(String bucketName, String fileKey) {
        AmazonS3 s3client = s3client();
        GetObjectRequest request = new GetObjectRequest(bucketName, fileKey);
        S3Object response = s3client.getObject(request);
        return response.getObjectContent();
    }


    @Override
    public void deleteFile(String bucketName, String fileKey) {
        log.info("delete S3 file bucketName:{}, fileKey:{}", bucketName, fileKey);
        AmazonS3 s3client = s3client();
        DeleteObjectRequest request = new DeleteObjectRequest(bucketName, fileKey);
        s3client.deleteObject(request);
    }

    @Override
    public void deleteFiles(String bucketName, List<String> fileKeys) {
        if (StringUtils.isBlank(bucketName) || CollUtil.isEmpty(fileKeys)) {
            log.warn("bucketName or fileKeys");
        }
        AmazonS3 s3client = s3client();
        DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(bucketName).withKeys(StringUtils.join(fileKeys, ","));
        DeleteObjectsResult deleteObjectsResult = s3client.deleteObjects(deleteObjectsRequest);
        log.info("S3 deleteObjectsResult:{}", JSONUtil.toJsonStr(deleteObjectsResult));
    }


    @Override
    public List<Bucket> listFile() {
        AmazonS3 s3client = s3client();
        ListBucketsRequest request = new ListBucketsRequest();
        return s3client.listBuckets(request);
    }


    @Override
    public boolean isExistBucket(String bucketName) {
        AmazonS3 s3client = s3client();
        try {
            HeadBucketRequest request = new HeadBucketRequest(bucketName);
            s3client.headBucket(request);
        } catch (Exception e) {
            return false;
        }
        return true;
    }


    @Override
    public void createBucket(String bucketName) {
        boolean isBucketExists = isExistBucket(bucketName);
        AmazonS3 s3client;
        if (!isBucketExists) {
            s3client = s3client();
            CreateBucketRequest request = new CreateBucketRequest(bucketName);
            s3client.createBucket(request);
        }
    }


    @Override
    public void deleteBucket(String bucketName) {
        AmazonS3 s3client = s3client();
        DeleteBucketRequest request = new DeleteBucketRequest(bucketName);
        s3client.deleteBucket(request);
    }


    @Override
    public boolean isExistFileKey(String bucketName, String fileKey) {
        AmazonS3 s3client = s3client();
        GetObjectRequest request = new GetObjectRequest(bucketName, fileKey);
        S3Object response = s3client.getObject(request);
        return response != null && fileKey.equals(response.getKey());
    }

    @Override
    public String getUrlFor7Day(String bucketName, String fileKey) {
        GeneratePresignedUrlRequest urlRequest = new GeneratePresignedUrlRequest(bucketName, fileKey);
        // 往后7天
        DateTime offset = DateUtil.offsetDay(new Date(), 7);
        urlRequest.setExpiration(offset);
        urlRequest.setMethod(HttpMethod.GET);
        URL url = s3client().generatePresignedUrl(urlRequest);
        return url.toString();
    }


    @Override
    public String getFileKey(String fileName) {
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        String dateDir = new SimpleDateFormat("yyyyMMdd").format(new Date());
        return String.format("%s/%s/%s_%s", OPS_PREFIX, dateDir, uuid, fileName);
    }

    @Override
    public S3FileInfoDto getFileInfoByUrl(String url) {
        String urlPreFix = url.substring(url.indexOf("//") + 2);
        GpLandPageConfigDto config = getConfig();
        String bucket = config.getS3Bucket();
        String fileName = urlPreFix.substring(urlPreFix.indexOf('/') + 1);
        return new S3FileInfoDto(fileName, bucket, url);
    }

}

你可能感兴趣的:(springboot,S3,springBoot)