亚马逊aws错误与s3桶不存在(Spring Boot )

dvtswwa3  于 2023-03-08  发布在  Spring
关注(0)|答案(2)|浏览(803)

我在spring Boot 中开发了一个产品注册API,在post方法中,我通过multipart/form-data发送了一个图像上传,沿着一个带有产品dto的json。

@RestController
@CrossOrigin(origins = "*", maxAge = 3600)
@RequestMapping("/product")
public class ProductController {
    final ProductService productService;
    final CategoryService categoryService;
    final ProductMapper productMapper;
    final S3Client s3Client;

    private final String BUCKET_NAME = "awstockproducts" + System.currentTimeMillis();

    public ProductController(ProductService productService, ProductMapper productMapper, CategoryService categoryService, S3Client s3Client) {
        this.productService = productService;
        this.productMapper = productMapper;
        this.categoryService = categoryService;
        this.s3Client = s3Client;
    }
    @PostMapping(value = "/", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public ResponseEntity<Object> saveProduct (@RequestParam("productDto") String jsonString, @RequestParam("file")MultipartFile file) {
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            ProductDto productDto = objectMapper.readValue(jsonString, ProductDto.class);

            if (productService.existsByProduct(productDto.getProduct())) {
                return ResponseEntity.status(HttpStatus.CONFLICT).body("Product already exists!");
            }
            ProductModel productModel = productMapper.toProductModel(productDto);
            CategoryModel categoryModel = categoryService.findById(productDto.getProductCategory().getCategory_id())
                    .orElseThrow(() -> new RuntimeException("Category not found"));
            productModel.setProductCategory(categoryModel);

            String fileName = "/products/images/" + UUID.randomUUID().toString() + "-" + file.getOriginalFilename();

            s3Client.putObject(PutObjectRequest
                            .builder()
                            .bucket(BUCKET_NAME)
                            .key(fileName)
                            .build(),
                        software.amazon.awssdk.core.sync.RequestBody.fromString("Testing java sdk"));
            return ResponseEntity.status(HttpStatus.CREATED).body(productService.save(productModel));
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.CONFLICT).body(e);
        }
    }

问题是我在向 Postman 提出请求时遇到了问题

"localizedMessage": "The specified bucket does not exist (Service: S3, Status Code: 404, Request ID: ZZ27F9CNNTG2RTPR, Extended Request ID:

尽管有这样的消息,但检查amazonaws时我可以看到我的bucket确实存在,并且与我在应用程序中配置的bucket具有相同的名称。

package com.api.business_manager_api.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;

@Configuration
public class AmazonConfig {
    private final String AWS_REGION = "us-east-1";
    private final String BUCKET_NAME = "productstockimages";

    @Value("${aws.accessKeyId}")
    private String accessKeyId;

    @Value("${aws.secretAccessKey}")
    private String secretAccessKey;

    @Bean
    public S3Client s3Client() {
        AwsBasicCredentials awsCreds = AwsBasicCredentials.create(accessKeyId, secretAccessKey);
        return S3Client.builder()
                .region(Region.of(AWS_REGION))
                .credentialsProvider(StaticCredentialsProvider.create(awsCreds))
                .build();
    }
}

在secretKey和AccessKey中,我使用amazonaws控制台中的授权IAM用户的密钥配置了inproperties。

htrmnn0y

htrmnn0y1#

要将您的数据(照片、视频、文档等)上传到Amazon S3,您必须首先在其中一个AWS区域创建一个S3存储桶,存储桶是存储在Amazon S3中的对象的容器。
您需要确保正在使用的存储桶已存在
使用此条件确保在将文件上载到S3之前存储桶已经存在:

if (s3Client.doesBucketExist(bucketName)) {
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentType(contentType);
            metadata.setContentLength(stream.available());

            s3Client.putObject(new PutObjectRequest(bucketName, key, stream, metadata));
        } else {
            log.warn("AWS S3 '{}' Bucket does not exist", bucketName);
             s3client.createBucket(bucketName);
        }

如果s3client.createBucket(bucketName);抛出一个异常,这意味着不允许您创建存储桶,请使用此文档创建一个https://docs.aws.amazon.com/AmazonS3/latest/userguide/create-bucket-overview.html
如果您根本没有访问权限,您需要与AWS管理员联系,为您创建一个。
也不要像这样每次都创建一个存储桶

private final String BUCKET_NAME = "awstockproducts" + System.currentTimeMillis();

只需为不同类型应用程序使用一个

private final String BUCKET_NAME = "awstockproducts-app1-dev"

这样就不用在每次运行应用程序时都创建一个存储桶

icnyk63a

icnyk63a2#

以上答案引用了AWS SDK for Java V1-建议不再使用。请参阅此处的SDK页面以了解版本信息:
https://github.com/awsdocs/aws-doc-sdk-examples
现在,请参考使用最新SDK版本的AWS Code Library,而不是查看包含V1代码的AWS S3服务指南,对于Java,最新SDK版本是AWS SDK for Java V2。

有关AWS SDK for Java V2示例,请参见:
Code examples for Amazon S3 using AWS SDKs
我在许多Spring Boot项目中使用过V2,使用S3操作没有问题。所以要在Spring Boot中使用S3 Java功能,请升级到V2-这是最佳实践。

    • 关于可能问题的最新情况**

我正在仔细查看您的代码。我在您的控制器中发现了此问题:

    • 私有最终字符串BUCKET_NAME ="awstockproducts"+系统当前时间米利斯();**
    • 您正在使用时间戳更改bucket名称**,然后调用**putObject()**并使用时间戳引用该bucket名称,除非您使用该名称动态创建了一个bucket(我看不出这种逻辑),否则该bucket不存在,并且您会得到一个异常。

所以你有两个选择:

  • 保持存储桶名称为静态,以便您知道它的存在。
  • 或者如果您必须为一个存储桶保留时间戳,那么在调用putObject之前使用V2API和waiter创建一个存储桶().然后您可以引用带有时间戳的bucket名称。要了解如何使用V2创建一个带有waiter的新bucket,请看这里的创建存储桶的例子。2注意服务员的用户。3这个方法将为每个请求创建一个新的存储桶。我个人会使用静态存储桶名称。

https://docs.aws.amazon.com/code-library/latest/ug/java_2_s3_code_examples.html

相关问题