Dando continuidade a transferência de imagem via Datasnap REST, nesta postagem vamos construir um App cliente multiplataforma para receber o arquivo trafegado. Confira!
Vale lembrar que na postagem TRANSFERINDO IMAGEM VIA DATASNAP REST – PARTE 1 criamos o nosso servidor DataSnap REST contendo o método personagens que nos lista o conteúdo da tabela Personagens retornando um JSONArray.
Como mencionei na postagem anterior a transferência de imagens foi tema de uma conversa minha com George De Luca, no final do ano passado. Embora tenha abordado com De Luca o tema teoricamente, somente em agosto desse ano consegui disponibilizar tempo para implementar este exemplo, que por sinal foi fruto da viabilidade de um leitor aqui do blog, Marcos Paulo Berger… fica aqui o agradecimento pela escolha. Agradecimento também ao companheiro na troca de ideias o sempre presente Cesar Romero, MVP da Embarcadero, valeu mister!
Criando o App Client
Como consumiremos um servidor REST, vamos criar um App Client multiplataforma. Via Delphi vamos em File -> New -> Other -> Delphi Projects -> Multi Device Project -> Blank Application.
Basicamente precisamos de 1 Edit para informar o ID do personagem a solicitarmos em nossa requisição, 1 Image para exibir o resultado e 1 Button para executar nossa requisição. Isso nos bataria para definir a interface de usuário. Entretanto adicionei mais 1 Edit para informarmos o endereço IP de nossa aplicação servidora e um 1 Label para exibir o resultado do nome do personagem.
Ao final do processo teremos uma tela parecida com esta abaixo:
Note que já consta na nossa tela os componentes responsáveis pela comunicação com o Servidor, vamos falar deles agora.
Comunicação via biblioteca REST Client
A Biblioteca REST Client possui componentes para prover de maneira rápida e prática a comunicação com serviços REST. Para maiores informações acesse Biblioteca REST Client na Embarcadero DocWiki. Não vou explicar cada um deles, vamos direto efetuar a configuração de cada um dos elementos:
object RESTClient1: TRESTClient Accept = 'application/json, text/plain; q=0.9, text/html;q=0.8,' AcceptCharset = 'UTF-8, *;q=0.8' BaseURL = 'http://localhost:8080/datasnap/rest/TServerMethods1/personagens/1/1' end object RESTRequest1: TRESTRequest Client = RESTClient1 Response = RESTResponse1 end object RESTResponse1: TRESTResponse ContentType = 'application/json' RootElement = 'result[0]' end
Com essas poucas linhas configuramos a Biblioteca REST Client e comunicação de nossa Aplicação Client, com o servidor.
Codificando a chamada para a transferência
Entramos agora na codificação para que nossa App Client efetue a chamada ao servidor e consequentemente execute a transferência da imagem. Antes vamos preparar o processo adicionando as seguintes Units na cláusula uses da seção Implementation :
implementation {$R *.fmx} uses System.JSON.Readers, System.JSON, System.JSON.Types, System.NetEncoding;
Vamos codificar o evento onClick do Button1 como abaixo, note que já comentei todo o código:
procedure TFormClient.Button1Click(Sender: TObject); var // Traz o Stream do Servidor Recebido : TStringStream; // Armazena a decodificação Foto : TMemoryStream; // Recebe a response da chamada SR : TStringReader; // Processa a response como JSON JR : TJsonTextReader; begin if EditHost.Text = EmptyStr then EditHost.Text := 'localhost'; // Como o foco é a transferência não fiz a criação de parâmetros no request // Definimos a url base da requisição // adicionamos 3 parâmetros no format: Host, MinID e MaxID RESTClient1.BaseURL := Format('http://%s:8080/datasnap/rest/TServerMethods1/personagens/%u/%u', [EditHost.Text, StrToInt(edit1.text), StrToInt(edit1.text)]); // Executamos a requisição RESTRequest1.Execute; // Armazenamos o conteúdo da resposta da requisição SR := TStringReader.Create(RESTResponse1.Content); try // Criamos o JSON a partir do armazenamento acima JR := TJsonTextReader.Create(SR); try while JR.Read do begin // Verifica se é Propriedade if jr.TokenType = TJSonToken.PropertyName then begin // Se é a propriedade FOTO if UpperCase(jr.value.toString) = 'FOTO' then begin jr.Read; Recebido := TStringStream.Create(jr.Value.ToString); Recebido.Position := 0; //Cria o stream que vai receber o conteúdo depois de trafegado Foto := TMemoryStream.Create; // Decodifica a transferência do Stream de Recebido para Foto TNetEncoding.Base64.Decode(Recebido, Foto); // Posiciona o Stream Foto no início Foto.Position := 0; // Carrega o Stream Foto para a imagem Image1.MultiResBitmap.LoadItemFromStream(Foto, 1); //Libera os Streams da memória Recebido.Free; Foto.Free; end // Se o for a propriedade nome else if UpperCase(jr.Value.ToString) = 'NOME' then begin jr.Read; // Atribui seu valor ao label na tela Label1.Text := jr.Value.ToString; end; end; end; finally jr.Free; end; finally sr.Free; end; end;
Com todos esses comentários o código aparenta ser maior que realmente é, entretanto fiz questão de comentar linha a linha o processo.
O pulo do gato
Você deve ter percebido que a linha 42, na qual efetuamos a decodificação do nosso Stream:
TNetEncodind.Base64.Decode(Recebido, Foto);
Através dela transformamos o Base64 Recebido passando para o Stream Foto que em seguida é carregado na tela pelo componente Image1.
Executando
Com isso nosso exemplo já está pronto para ser executado, confira no vídeo abaixo:
Você pode notar que com a utilização das variações de TNetEncoding temos nossa vida simplificada ao extremo.
Como diria o grande mestre Ricardo Barbieri: “Simples assim”!