Já faz algum tempo em que eu tenho utilizado o Google App Engine para desenvolver meus projetos pessoais em Java, que atualmente o maior é o e-Karros. Apesar dos vários benefícios da plataforma, existem alguns pontos que trazem dificuldades ao desenvolvimento. A dificuldade mais recente que encontrei foi o armazenamento de arquivos no Datastore do App Engine. No meu caso específico foi o armazenamento de imagens. Após um bom tempo de pesquisa na net encontrei a solução abaixo.
Para podermos armazenar arquivos precisamos utilizar o tipo de dado Blob, através da API Blobstore. Bom, em primeiro lugar temos que criar nossa classe que irá armazenar o arquivo, que neste caso pode ser uma imagem:
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import com.google.appengine.api.datastore.Blob;
@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Imagem {
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Long id;
@Persistent
private Blob imagem;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public void setImagem(Blob imagem) {
this.imagem = imagem;
}
public Blob getImagem() {
return imagem;
}
public void adiciona() throws Exception {
new ImagemDAO().adiciona(this);
}
public ImagemCarro buscaImagem(Long id) {
return new ImagemDAO().buscaImagem(id);
}
}Vamos supor que nossa classe ImagemDAO já esteja implementada.
Após isso temos nossa classe Servlet que irá receber o arquivo que foi feito upload, tratá-lo e chamar o método de gravação. Para se "caputrar" o arquivo e converter para o formato da classe Blob (array de bytes), precisando da biblioteca Commons IOUtils, da Apache.
import org.apache.commons.io.IOUtils;
public class ArmazenaImagem extends HttpServlet {
public void doPost(HttpServletRequest req, HttpServletResponse resp) {
try {
InputStream imgStream = req.getInputStream();
Blob imageBlob = new Blob(IOUtils.toByteArray(imgStream));
Imagem img = new Imagem();
img.setImagem(imageBlob);
img.adiciona();
resp.setStatus(HttpServletResponse.SC_OK);
resp.setContentType("text/plain");
resp.getWriter().println( "{success: true}" );
} catch (Exception e {
e.printStackTrace();
resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
resp.setContentType("text/plain");
resp.getWriter().println( "{success: false}" );
}
}
}
Como podemos ver, é bem simples gravar um arquivo no Datastore.
Aqui uma pausa para explicar a linha resp.getWriter().println( "{success: true}" ); e seu equivalente no bloco catch. É um requerimento da plugin JavaScript Ajax Upload, o melhor que encontrei para esse trabalho ;-). A utilização de um plugin para upload foi a única forma que eu encontrei para enviar o arquivo ao servidor utilizando AJAX, porém ainda estou a procura de uma outra forma.
A recuperação da imagem é igualmente simples. Abaixo segue o servlet:
public class BuscaIMagemServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp) {
try {
resp.setContentType("image/jpeg");
resp.setHeader("Content-Disposition","inline");
Long id = Long.parseLong( req.getParameter( "id" ) );
Imagem imagem = new Imagem().buscaImagem(ido);
Blob blobImagem = imagem.getImagem();
byte[] btImg = blobImagem.getBytes();
resp.getOutputStream().write(btImg);
} catch (Exception e) {
e.printStackTrace();
}
}
}
É somente isso. Ao recuperarmos a imagem do Datastore precisamos transformá-la em um array de bytes.
Nesse caso usei o campo id para recuperar uma imagem específica. Para exibir a imagem na página precisamos inserir a tag img em nossa página:
Onde '/buscaImagem?id=1' é o nosso servlet que recupera a imagem, e id=1 é o parâmetro para buscarmos uma imagem específica (o número 1 q coloquei é só um exemplo).![]()
Espero que este breve tutorial sirva para que outras pessoas não fiquem batendo tanta cabeça quanto eu ;-).
Comentários
Meu problema atual era somente a recuperação do arquivo na Nuvem.
Estava convertendo errado o tipo Blob.
Muito obrigado, ótimo post ;)
você pode me ajudar?
Estou com um problema...
Estou tentando listar vários arquivos que realizei upload no app engine...
Só que quando chamo o list no jsp... e tento lista-los
aparece o seguinte erro:
No meta data for modelo.Arquivo. Perhaps you need to run the enhancer on this class?
Consegui resolver, este erro estava aparecendo porque não utilizei um modelo na classe arquivo. @PersistenceCapable.
Mais obrigado pela atenção, abraço.