fbpx

Transferindo imagem via Datasnap REST – Parte 1


Uma das grandes questões quando se está começando a entrar no universo REST/JSON é como fazer para efetuar a transferência de imagens entre o Servidor e seus clients. Veja como simplificar isso com o uso da classe TNetEnconding.

A Classe TNetEncoding

Incluída no Delphi XE7, a classe TNetEncoding e todas as suas subclasses trabalham como métodos codificadores (Encode) e decodificadores (Decode), veja abaixo uma tabela de entradas e saídas de métodos comuns a todas as subclasses de TNetEncoding:

Entradas e Saídas dos métodos de TNetEncoding

Descrevendo nosso exemplo

Para nosso exemplo usaremos a propriedade Base64 para converter a imagem no lado servidor e entregá-la no lado cliente em  Base64 para que possamos decodificá-la e exibi-la para o usuário. Esta imagem está salva em um banco de dados no servidor e será disponibilizada para seus clientes através requisições REST (Representational State Transfer). Vamos iniciar a parte prática!

Criando o banco de dados

Para ganharmos um pouco de velocidade na produção do nosso exemplo optei pela utilização do SQLite, que dispensa grandes esforços de instalação. Criei um arquivo chamado exemplo.db3 que será o nosso banco de dados e nele criei uma tabela chamada personagens, como script abaixo:

[cc lang = “SQL”]CREATE TABLE [personagens](CREATE TABLE [personagens](
[ID] INTEGER PRIMARY KEY ASC  ON CONFLICT ROLLBACK  AUTOINCREMENT NOT NULL  ON CONFLICT ROLLBACK  UNIQUE ON CONFLICT ROLLBACK,
[NOME] VARCHAR2(30) NOT NULL  ON CONFLICT ROLLBACK,
[DATA_NASC] DATE NOT NULL  ON CONFLICT ROLLBACK,
[FOTO] BLOB,
[SEXO] varchar(1) NOT NULL DEFAULT M);

[/cc]

Em seguida inseri alguns dados, obviamente carreguei algumas fotos nos registros. 

Nota: Particularmente gosto de utilizar o SQLite Expert Personal Edition. 
Não conhece? Veja no link:sqliteexpert.com

Ao final do processo minha tabela ficou como na imagem abaixo:

Exemplo - Tabela Personagens

Agora que já temos nossos dados vamos criar o nosso servidor.

Criando o Datasnap REST Server

Abra o Delphi vamos criar um Servidor Datasnap REST, para isso acesse a opção File -> New -> Other ->Delphi Projects -> DataSnap Server -> DataSnap REST Application.

Datasnap REST Server

Isso abrirá o Wizard, e nele vamos selecionar a opção Windows em seguida clique em Next, Stand-alone GUI Application em seguida clique em Next, VCL Application e clique em Next novamente, Selecione a porta em que o servidor vai funcionar (Sugiro manter o padrão: 8080 sem HTTPS) e clique em Next, em seguida configure as características como a imagem abaixo:

Características do Servidor DataSnap

Em seguida pressione Next mais uma vez, e na classe ancestral do Server Method selecione a opção TDSServerModule e clique em Next novamente, agora selecione o local onde armazenar seu Projeto e já temos um servidor pronto para executar.

Conectando com o Banco de dados

Agora precisamos adicionar os componentes responsáveis por fazer com que nosso servidor se comunique com o banco de dados que criamos. Como opção escolhi utilizar o FireDAC, então vamos adicionar no ServerMethod de nossa aplicação os seguintes componentes e alterar suas propriedades:

  • FDConnection (Name: FDConnBD)
  • FDPhysSQLiteDriverLink (Name: FDPhysSQLiteDriverLink1)
  • FDQuery (Name: fdqPersonagens; Connection: FDConnBD)

Feito isso vamos configurar o FDConnection apontando para o arquivo de banco de dados criado anteriormente (exemplo.db3)

Configurando a conexão FireDAC SQLite

Efetue o teste de conexão para se certificar que tudo ficou de acordo!

Criando nosso método para transferência

Como disse nossa ideia é implementar a transferência da imagens através de chamadas REST, então vamos criar um método para mapeamento à chamada GET, já abordei os mapeamentos REST para métodos no Datasnap nas postagens REST COM DATASNAP DETALHES NA APLICAÇÃO PRÁTICA e REST COM DATASNAP DETALHES NA APLICAÇÃO PRÁTICA PARTE 2, logo não abordarei o tema. 

Declare as seguintes units na cláusula uses da seção implementation:

[cc lang = “Delphi”]uses System.StrUtils, System.NetEncoding; [/cc]

Feito isso nosso método personagens (mapeamento para Get) fica declarado:

[cc lang = “Delphi”]public
{ Public declarations }

function Personagens (minID, maxID : integer) : TJSONArray;
end;

[/cc] 

E implementado conforme sequência abaixo:

[cc lang = “Delphi”]function TServerMethods1.Personagens(minID, maxID: integer): TJSONArray;
var
lJO : TJSONObject;
i: integer;
StreamIn: TStream;
StreamOut : TStringStream;
begin
fdqPersonagens.Close;
fdqPersonagens.Params.Clear;
fdqPersonagens.SQL.Clear;
if ((minID <= 0) or (minID.ToString.IsEmpty)) and ((maxID <= 0) or (maxID.ToString.IsEmpty)) then
begin
fdqPersonagens.SQL.Text := ‘select * from personagens’;
end
else if ((minID <= 0) or (minID.ToString.IsEmpty)) and (maxID > 0) then
begin
fdqPersonagens.SQL.Text := ‘select * from personagens where id <= :pIDMax’;
fdqPersonagens.Params.Add(‘pIDMax’, ftInteger, ptInput);
fdqPersonagens.Params[0].AsInteger := maxID;
end
else if (minID > 0) and ((maxID <= 0) or (maxID.ToString.IsEmpty)) then
begin
fdqPersonagens.SQL.Text := ‘select * from personagens where id >= :pIDMin’;
fdqPersonagens.Params.Add(‘pIDMin’, ftInteger, ptInput);
fdqPersonagens.Params[0].AsInteger := minID;
end
else if (minID > 0) and (maxID > 0) then
begin
fdqPersonagens.SQL.Text := ‘select * from personagens where id between :pIDMin and :pIDMAX’;
fdqPersonagens.Params.Add(‘pIDMin’, ftInteger, ptInput);
fdqPersonagens.Params[0].AsInteger := minID;
fdqPersonagens.Params.Add(‘pIDMax’, ftInteger, ptInput);
fdqPersonagens.Params[1].AsInteger := maxID;
end;

fdqPersonagens.Open();
if fdqPersonagens.Active then
begin
if fdqPersonagens.RecordCount > 0 then
begin
Result := TJSONArray.Create;
try
fdqPersonagens.First;
while not(fdqPersonagens.Eof) do
begin
lJO := TJSONObject.Create;
for i := 0 to fdqPersonagens.FieldCount -1 do
begin
if fdqPersonagens.Fields[I].IsNull then
//Tratando valores nulos para não “quebrar” a aplicação
lJO.AddPair(fdqPersonagens.Fields[I].DisplayName, EmptyStr)
else
begin
if fdqPersonagens.Fields[i].IsBlob then
begin
StreamIn := fdqPersonagens.CreateBlobStream(fdqPersonagens.Fields[i], bmRead);
StreamOut := TStringStream.Create;
TNetEncoding.Base64.Encode(StreamIn, StreamOut);
StreamOut.Position := 0;
lJO.AddPair(fdqPersonagens.Fields[i].DisplayName, StreamOut.DataString);
end
else
begin
lJO.AddPair(fdqPersonagens.Fields[i].DisplayName, fdqPersonagens.Fields[i].Value);
end;
end;
end;
Result.AddElement(lJO);
fdqPersonagens.Next;
end;
finally
//
end;
end;
end;
end;[/cc]

Na primeira parte do código configuramos a instrução SQL do FDQuery, em seguida criamos um JSONArray recebendo os dados retornados na consulta. Aqui chamo atenção para a parte em que efetuamos uma checagem que campos do tipo Blob, neste caso vamos efetuar o Encode de seu conteúdo para Base64:

[cc lang = “delphi”]if fdqPersonagens.Fields[i].IsBlob then
begin
StreamIn := fdqPersonagens.CreateBlobStream(fdqPersonagens.Fields[i], bmRead);
StreamOut := TStringStream.Create;
TNetEncoding.Base64.Encode(StreamIn, StreamOut);
StreamOut.Position := 0;
lJO.AddPair(fdqPersonagens.Fields[i].DisplayName, StreamOut.DataString);
end
else
begin
lJO.AddPair(fdqPersonagens.Fields[i].DisplayName, fdqPersonagens.Fields[i].Value);
end;[/cc]

É aí que a mágica acontece… 

Vídeo

 

Na segunda parte vamos implementar a aplicação cliente consumindo esse recurso no nosso servidor.

Até lá!

 

Nota: A segunda parte foi publicada no dia 28 de setembro, você pode lê-la clicando aqui: TRANSFERINDO IMAGEM VIA DATASNAP REST – PARTE 2.

,

Comente