Recentemente estive no QConSP 2013, onde encontrei muitos amigos e conversei bastante. Conversando com o Milfont, ele me falou que achava que ninguém mais faz upload de arquivos para um file system local, pois o S3 é muito conveniente e fácil de usar.
Nos projetos Ruby dele ele usa o Paperclip, que permite o upload pro S3 com simples configurações.
Porém, nos nossos projetos Amazon vemos que a grande maioria das aplicações ainda não faz os uploads para o S3, e isto me motivou a escrever posts mostrando da forma mais simples possível o upload pro S3 em algumas linguagens, frameworks e produtos.
Este post é o primeiro da série e nele vamos mostrar o upload convencional para o file system e o upload equivalente para o S3. Para a versão TL;DR, simplesmente faça o clone do github e experimente localmente.
git clone https://github.com/RivendelTecnologia/UploadS3Java.git
No diretório WebContent há 2 htmls bem simples, ambos com formulários contendo um único elemento, de upload de arquivo.
O arquivo disco.html aponta para o Servlet /UploadDisco, que manipula o stream de entrada da forma convencional (com o commons-fileupload) e salva em disco, conforme a seguir.
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { List<FileItem> items = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request); for (FileItem item : items) { if (item.isFormField()) { // nada a fazer, só temos o upload de arquivo no formulário } else { // Process form file field (input type="file"). InputStream conteudoArquivo = item.getInputStream(); File arquivo = new File(item.getName() + System.currentTimeMillis()); FileOutputStream fos = new FileOutputStream(arquivo); int read = 0; byte[] bytes = new byte[1024]; int contador = 0; while ((read = conteudoArquivo.read(bytes)) != -1) { fos.write(bytes, 0, read); contador++; System.out.println("escrevendo " + contador); } System.out.println("Pronto! Arquivo: " + arquivo.getAbsolutePath()); conteudoArquivo.close(); fos.flush(); fos.close(); response.getWriter().println("Arquivo escrito: " + arquivo.getAbsolutePath()); } } } catch (FileUploadException e) { throw new ServletException("Cannot parse multipart request.", e); } finally{ } }
Para usar a versão com o S3, precisamos baixar o SDK para Java e adicionar às nossas dependências, ou usar o Maven para isso. As funcionalidades do S3 dependem de algumas bibliotecas do Apache Commons.
Além do SDK no classpath, precisamos adicionar um arquivo AwsCredentials.properties, com sua accessKey e secretKey. Ambas podem ser obtidas na opção Security Credentials, na console da Amazon, conforme a seguir.
A última coisa é que precisamos ter um bucket S3 disponível para o upload. Podemos criar um novo bucket pela API também, mas a opção mais fácil e mais comum é usar um bucket pré-existente.
Colocamos abaixo o Servlet recebendo o upload do arquivo e enviando diretamente a stream para o S3, sem manipular arquivos no file system local.
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { AmazonS3 s3 = new AmazonS3Client(new ClasspathPropertiesFileCredentialsProvider()); Region usWest2 = Region.getRegion(Regions.US_WEST_2); s3.setRegion(usWest2); String nomeBucket = "rivendel-upload-s3"; String nomeArquivo = ""; try { List<FileItem> items = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request); for (FileItem item : items) { if (item.isFormField()) { // nada a fazer, só temos o upload de arquivo no formulário } else { // Process form file field (input type="file"). InputStream conteudoArquivo = item.getInputStream(); ObjectMetadata metadata = new ObjectMetadata(); metadata.setContentType(item.getContentType()); metadata.setContentLength(item.getSize()); nomeArquivo = item.getName(); PutObjectRequest por = new PutObjectRequest(nomeBucket, nomeArquivo, conteudoArquivo, metadata); PutObjectResult result = s3.putObject(por.withCannedAcl(CannedAccessControlList.PublicRead)); response.getWriter().println("Arquivo escrito: " + nomeArquivo); } } } catch (FileUploadException e) { throw new ServletException("Cannot parse multipart request.", e); } finally{ } }
Neste upload, enviamos o arquivo para um bucket chamado rivendel-upload-s3, e definimos a sua política de acesso como público para leitura. Assim, qualquer pessoa poderá baixar o arquivo do S3 sem precisar de autenticação.
Com o nome da região e o nome do bucket é possível montar a URL de acesso ao arquivo, que é sempre no formato: https://s3-nome-regiao.amazonaws.com/nome-bucket/nome-arquivo.
Em breve publicaremos os posts equivalentes em várias outras linguagens. Espero que seja útil para muitas pessoas :). Até a próxima!
Gostou do conteúdo? Tem alguma dúvida? Entre em contato com nossos Especialistas Mandic Cloud, ficamos felizes em ajudá-lo.