130

Is it possible to upload a txt/pdf/png file to Amazon S3 in a single action, and get the uploaded file URL as the response?

If so, is AWS Java SDK the right library that I need to add in my java struts2 web application?

Please suggest me a solution for this.

Andrzej Sydor
  • 1,373
  • 4
  • 13
  • 28
Sangram Anand
  • 10,526
  • 23
  • 70
  • 103
  • https://stackoverflow.com/questions/6524041/how-do-you-make-an-s3-object-public-via-the-aws-java-sdk/60052151#60052151 – Rajat Feb 04 '20 at 07:05

10 Answers10

144

No you cannot get the URL in single action but two :)

First of all, you may have to make the file public before uploading because it makes no sense to get the URL that no one can access. You can do so by setting ACL as Michael Astreiko suggested. You can get the resource URL either by calling getResourceUrl or getUrl.

AmazonS3Client s3Client = (AmazonS3Client)AmazonS3ClientBuilder.defaultClient();
s3Client.putObject(new PutObjectRequest("your-bucket", "some-path/some-key.jpg", new File("somePath/someKey.jpg")).withCannedAcl(CannedAccessControlList.PublicRead))
s3Client.getResourceUrl("your-bucket", "some-path/some-key.jpg");

Note1: The different between getResourceUrl and getUrl is that getResourceUrl will return null when exception occurs.

Note2: getUrl method is not defined in the AmazonS3 interface. You have to cast the object to AmazonS3Client if you use the standard builder.

hussachai
  • 4,322
  • 2
  • 16
  • 17
  • 37
    It's worth noting that this only results in a single call to AWS. If you dig into the Java SDK you'll see that `s3Client.getResourceUrl("your-bucket", "some-path/some-key.jpg")` works out the URL without a call to AWS. – sihil Sep 30 '16 at 10:52
  • 3
    This really should be the recommended answer. The other answer fails for cases where the file-name includes spaces. In such scenarios, the file-name displayed on S3, and the URL suffix, are different from one another. The above s3Client.getUrl method handles this scenario correctly – RvPr Feb 23 '18 at 04:58
  • 9
    Note, `getResourceUrl` is not in the latest sdk. – Martin Serrano Mar 21 '18 at 22:01
  • 1
    It's still there. You may have to cast the interface (AmazonS3) to the class (AmazonS3Client). – hussachai Mar 22 '18 at 05:57
  • 8
    for latest sdk `s3Client.getUrl("your-bucket", "some-path/some-key.jpg").toString();` will get the public url. – kristianva Jun 11 '18 at 16:34
  • 15
    For even newer SDK versions, try `s3Client.utilities().getUrl(getUrlRequest);` – mrog Jul 12 '19 at 21:39
  • `s3.getUrl(bucketName, fileName).toExternalForm()` does the trick in most recent version – Mavic More Feb 24 '23 at 16:02
92

You can work it out for yourself given the bucket and the file name you specify in the upload request.

e.g. if your bucket is mybucket and your file is named myfilename:

https://mybucket.s3.amazonaws.com/myfilename

The s3 bit will be different depending on which region your bucket is in. For example, I use the south-east asia region so my urls are like:

https://mybucket.s3-ap-southeast-1.amazonaws.com/myfilename
Jeffrey Kemp
  • 59,135
  • 14
  • 106
  • 158
  • After uploading the file from AWS management console, the following links works for a single file, so which one could be the response.. https://s3.amazonaws.com/cdn.generalsentiment.com/MVR/reports/2010-11_Hollywood_Buzz_Digest.pdf -- http://cdn.generalsentiment.com.s3.amazonaws.com/MVR/reports/2010-11_Hollywood_Buzz_Digest.pdf -- http://cdn.generalsentiment.com/MVR/reports/2010-11_Hollywood_Buzz_Digest.pdf – Sangram Anand Jun 11 '12 at 07:07
  • 1
    Yes, there are variations to the url that should work. Pick the one you want to use and go with it. – Jeffrey Kemp Jun 11 '12 at 07:27
  • Kool.. thanks for the info.. By the way the uploading part am going to do with AWS sdk library right? – Sangram Anand Jun 11 '12 at 07:56
  • Yes, I believe so. But I have no experience with struts. – Jeffrey Kemp Jun 13 '12 at 08:53
  • I am almost done with uploading thing.. but strucked at the permissions. Is there a way in the AWS java sdk for S3 to let us make a file public before uploading. – Sangram Anand Jun 13 '12 at 08:55
  • I suggest you raise a new question, you might get an answer that way. – Jeffrey Kemp Jun 14 '12 at 05:09
  • Note that using dev.mybucket.s3.amazonaws.com/myfilename vs s3.amazonaws.com/dev.mybucket/myfilename can make a difference in terms of certificates if the bucket name uses dots. This happens because amazon's s3 certificate doesn't support multi subdomains. – Federico Aug 23 '13 at 18:56
  • @Federico what happens if we use bucket name with dots. for ex : "dev.mybucket.com", "static.mybucket.com" etc. can you explain a bit more please ? – oko Feb 17 '14 at 09:22
  • @oko this is related to certificate subdomain policies. Take sub.domain.com and subsub.sub.domain.com. If the certificate supports multiple subdomain *.domain.com will work for both. If it doesn't it would only work for sub.domain.com. Last time I checked amazon didn't support multiple subdomain, so using a bucket name with dots can make a difference if you use it in the domain part of the url. – Federico Mar 18 '14 at 13:59
  • @JeffreyKemp With the URL Format mentioned above, I am able to access all the Files inside the Bucket but I am not able to access Individual Files. Can you Please guide me in How to get the UploadPathURL once the upload is completed? – Pradeep Reddy Kypa Sep 07 '17 at 16:58
  • Sorry mate I have no idea what you mean. If you know the filename, the path and the bucket, you can work out the URL. – Jeffrey Kemp Sep 08 '17 at 13:36
  • I'm assuming this doesn't work if {myfilename} includes spaces. Example: "picture from vacation.jpg". That's a valid file name which Amazon will accept and display accordingly, though the url will look like "picture+from+vacation.jpg" – RvPr Feb 23 '18 at 04:40
  • @RvPr of course, it should go without saying that you must encode the filename before rendering any links in a web page. There's more risks than just spaces in a filename if you're accepting end user-specified filenames... – Jeffrey Kemp Feb 23 '18 at 08:32
  • @Jeffrey Kemp, call me stupid, but after reading your answer above, I walked away with the impression that a simple string concatenation would do the job. I hadn't considered that complications may arise, where this approach wouldn't work. "You can work it out for yourself" doesn't do sufficient justice to the additional parsing that needs to be done. I would recommend editing your answer to mention this complication, and referencing the other answer given below. The getUrl method referenced below doesn't even make a network call, so there's little reason not to use it – RvPr Feb 23 '18 at 14:08
16

For AWS SDK 2+

String key = "filePath";
String bucketName = "bucketName";
PutObjectResponse response = s3Client
            .putObject(PutObjectRequest.builder().bucket(bucketName ).key(key).build(), RequestBody.fromFile(file));
 GetUrlRequest request = GetUrlRequest.builder().bucket(bucketName ).key(key).build();
 String url = s3Client.utilities().getUrl(request).toExternalForm();
Bala
  • 1,295
  • 1
  • 12
  • 23
12

@hussachai and @Jeffrey Kemp answers are pretty good. But they have something in common is the url returned is of virtual-host-style, not in path style. For more info regarding to the s3 url style, can refer to AWS S3 URL Styles. In case of some people want to have path style s3 url generated. Here's the step. Basically everything will be the same as @hussachai and @Jeffrey Kemp answers, only with one line setting change as below:

AmazonS3Client s3Client = (AmazonS3Client) AmazonS3ClientBuilder.standard()
                    .withRegion("us-west-2")
                    .withCredentials(DefaultAWSCredentialsProviderChain.getInstance())
                    .withPathStyleAccessEnabled(true)
                    .build();

// Upload a file as a new object with ContentType and title specified.
PutObjectRequest request = new PutObjectRequest(bucketName, stringObjKeyName, fileToUpload);
s3Client.putObject(request);
URL s3Url = s3Client.getUrl(bucketName, stringObjKeyName);
logger.info("S3 url is " + s3Url.toExternalForm());

This will generate url like: https://s3.us-west-2.amazonaws.com/mybucket/myfilename

james
  • 191
  • 3
  • 9
8

Similarly if you want link through s3Client you can use below.

System.out.println("filelink: " + s3Client.getUrl("your_bucket_name", "your_file_key"));
anothernode
  • 5,100
  • 13
  • 43
  • 62
Omkar Ayachit
  • 89
  • 1
  • 1
2

a bit old but still for anyone stumbling upon this in the future:

you can do it with one line assuming you already wrote the CredentialProvider and the AmazonS3Client.

it will look like this:

 String ImageURL = String.valueOf(s3.getUrl(
                                  ConstantsAWS3.BUCKET_NAME, //The S3 Bucket To Upload To
                                  file.getName())); //The key for the uploaded object

and if you didn't wrote the CredentialProvider and the AmazonS3Client then just add them before getting the URL like this:

  CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
        getApplicationContext(),
        "POOL_ID", // Identity pool ID
        Regions.US_EAST_1 // Region
);
rollcage
  • 101
  • 1
  • 10
1

Below method uploads file in a particular folder in a bucket and return the generated url of the file uploaded.

private String uploadFileToS3Bucket(final String bucketName, final File file) {
    final String uniqueFileName = uploadFolder + "/" + file.getName();
    LOGGER.info("Uploading file with name= " + uniqueFileName);
    final PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, uniqueFileName, file);
    amazonS3.putObject(putObjectRequest);
    return ((AmazonS3Client) amazonS3).getResourceUrl(bucketName, uniqueFileName);
}
Ankitech
  • 9
  • 1
  • 3
1

If you're using AWS-SDK, the data object returned contains the Object URL in data.Location

const AWS = require('aws-sdk')
const s3 = new AWS.S3(config)

s3.upload(params).promise()
    .then((data)=>{
        console.log(data.Location)
    })
    .catch(err=>console.log(err))
0
System.out.println("Link : " + s3Object.getObjectContent().getHttpRequest().getURI());

With this code you can retrieve the link of already uploaded file to S3 bucket.

hooknc
  • 4,854
  • 5
  • 31
  • 60
Omkar Ayachit
  • 89
  • 1
  • 1
-47

To make the file public before uploading you can use the #withCannedAcl method of PutObjectRequest:

myAmazonS3Client.putObject(new PutObjectRequest('some-grails-bucket',  'somePath/someKey.jpg', new    File('/Users/ben/Desktop/photo.jpg')).withCannedAcl(CannedAccessControlList.PublicRead))

String url = myAmazonS3Client.getUrl('some-grails-bucket',  'somePath/someKey.jpg').toString();
Parag Kadam
  • 3,620
  • 5
  • 25
  • 51