首页 > 解决方案 > 如何使用 Java 为 S3 对象创建自定义文件名

问题描述

我正在使用 Spring Boot、Snowflake 和 AWS S3。

我有查询两个表并获得结果的 SQL 查询。结果我必须像 CSV 文件一样写入 S3 并获取下载 URL 作为回报。

我通过创建临时表并在将数据复制到 S3 后将其删除来做到这一点。

这是我的代码:

@Override
    public void getUserTest(String userId) {

        String q = "CREATE TEMPORARY TABLE \"TEST\".\"PUBLIC\".\"USER_TABLE_TEMP\" AS SELECT \"ID\", \"FIRST_NAME\", \"LAST_NAME\" from \"TEST\".\"PUBLIC\".\"USER_TABLE\"\n" +
                "          where \"ID\" = ?\n" +
                "          union all\n" +
                "          select \"ID\",\"ACCOUNT_NAME\", \"ACCOUNT_NUMBER\" from \"TEST\".\"PUBLIC\".\"ACCOUNT_DATA\"\n" +
                "          where \"ID\" = ?";
        jdbcTemplate.query(q, s -> {}, userId, userId);
    }

写入 S3 的方法。

   @Override
    public URL writeToS3() {

        String q = "copy into s3://snowflake171 from \"TEST\".\"PUBLIC\".\"USER_TABLE_TEMP\" storage_integration = s3_int file_format = CSV_TEST;\n";
        jdbcTemplate.query(q, s -> {});

        URL url = generateURL();

        String dropTable = "drop table if exists \"TEST\".\"PUBLIC\".\"USER_TABLE_TEMP\"";
        jdbcTemplate.query(dropTable, s -> {});
        return url;
    }

生成 URL 的方法:

public URL generateURL() {

    try {
        BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKey, secretKey);
        final AmazonS3 s3Client = AmazonS3ClientBuilder.standard().withCredentials(new
                AWSStaticCredentialsProvider(awsCreds)).withRegion(clientRegion).build();

        // Set the presigned URL to expire after 2h.
        java.util.Date expiration = new java.util.Date();
        long expTimeMillis = Instant.now().toEpochMilli();
        expTimeMillis += 1000 * 60 * 120;
        expiration.setTime(expTimeMillis);

        // Generate the presigned URL.
        System.out.println("Generating pre-signed URL.");
        GeneratePresignedUrlRequest generatePresignedUrlRequest =
                new GeneratePresignedUrlRequest(bucket, objectKey)
                        .withMethod(HttpMethod.GET)
                        .withExpiration(expiration);
        URL url = s3Client.generatePresignedUrl(generatePresignedUrlRequest);
        System.out.println("Pre-Signed URL: " + url.toString());
        return url;

    } catch (AmazonServiceException e) {
        // The call was transmitted successfully, but Amazon S3 couldn't process
        // it, so it returned an error response.
        e.printStackTrace();
    } catch (SdkClientException e) {
        // Amazon S3 couldn't be contacted for a response, or the client
        // couldn't parse the response from Amazon S3.
        e.printStackTrace();
    }
    return null;
}

数据由userId我发送查询。一切正常,但我生成的每个时间文件都具有相同的名称。如果我不删除 S3 中的现有文件,我将无法上传新文件。

我应该能够为不同的用户 ID 上传不同的文件。

我怎样才能做到这一点?

如何从 S3 中创建的文件中给出不同的名称?

我在文档https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html中看到了这一点,但我不知道在代码中应用的最佳方式。

有没有办法可以将 userId 添加为文件名的前缀?

标签: javaamazon-web-servicesspring-bootamazon-s3snowflake-cloud-data-platform

解决方案


您可以在 COPY 查询中使用 userId 添加自定义对象键:

   @Override
    public URL writeToS3(userId) {

        String q = "copy into s3://snowflake171/" + userId + " from \"TEST\".\"PUBLIC\".\"USER_TABLE_TEMP\" storage_integration = s3_int file_format = CSV_TEST;\n";
        jdbcTemplate.query(q, s -> {});

推荐阅读