Armazenando imagens protocolo SFTP com java - Springboot
Tags: java, springboot, sftp, docker
Published: 2022-07-02 02:22:16

Ferramentas necessárias:
* [Java SDK](https://www.oracle.com/java/technologies/downloads/)
* [Docker](https://docs.docker.com/desktop/windows/install/#:~:text=%20Install%20Docker%20Desktop%20on%20Windows%20%F0%9F%94%97%20,to%20authorize%20the%20installer%20and%20proceed...%20More%20)
* [Postman](https://www.postman.com/downloads/)
* [Filezila Client](https://filezilla-project.org/download.php?type=client)
* Ide de sua preferencia
* Criar uma aplicação Springboot pelo [Spring Initializr](https://start.spring.io/)

Neste post vamos abordar o armazenamento de imagens utilizando o protocolo `SFTP`, vamos subir um servidor SFTP utilizando a chave SSH **Importante mecanismo de autenticação que asseguram a proteção de dados e informações** dentro de um container docker e enviar imagens para este servidor através de uma api rest java.
Crie uma aplicação Springboot, como nosso objetivo e apenas demonstrar o envio de imagens via SFTP não vamos nos preocupar com padrões arquiteturais.
Crie uma pasta na raiz do projeto com o nome de sua escolha e dentro desta pasta um arquivo `dockerfile` e cole dentro dele os seguintes comandos.
`dockerfile`
```
FROM ubuntu:latest

RUN mkdir -p /var/run/sshd

RUN apt update && \
    apt install -y openjdk-8-jdk && \
    apt install -y openssh-server

RUN useradd -rm -d /home/remote_user -s /bin/bash remote_user && \
    echo remote_user:password1234 | chpasswd

RUN mkdir /home/remote_user/.ssh && \
    chmod 700 /home/remote_user/.ssh

COPY id_rsa.pub /home/remote_user/.ssh/authorized_keys

RUN chown remote_user:remote_user -R /home/remote_user/.ssh && \
    chmod 600 /home/remote_user/.ssh/authorized_keys

CMD [ "/usr/sbin/sshd" , "-D"]
```
E um arquivo com o nome docker-compose.yml com a seguinte configuração no mesmo
`docker-compose.yml`
```
version: '3.7'
services:
  app:
    container_name: sftp
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - '58898:22'
```
Feito isso, via cmd, entre na pasta onde esta localizado os arquivos dockerfile e docker-compose.yml e rode o seguinte comando para criar uma chave de segurança `SSH`
`ssh-keygen -t rsa -m PEM -f id_rsa` apos rodar o comando sera pedido para você escrever uma frase e depois confirmar esta frase para gerar o ssh.
![ssh](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ulow5ytlgmqjqsnw0mcl.png)
Ainda dentro desta pasta via cmd rode o comando `docker compose up -d` e será criado nosso servidor dentro de um container docker.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yu4hei51t6rosuh7k8eh.png)
Já podemos acessar nosso servidor através do `Filezila CLient`
*Obs: Password tem que ser o mesmo especificado no dockerfile, neste caso password1234
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z91fdcol2md6jap6649b.png)

Vamos utilizar a lib `JSch` para armazenar a imagem recebida no servidor `SFTP`, para isto adicione a seguinte dependência em seu projeto.
```
<!-- https://mavenlibs.com/maven/dependency/org.lucee/jsch -->
<dependency>
    <groupId>org.lucee</groupId>
    <artifactId>jsch</artifactId>
    <version>0.1.55</version>
</dependency>
```
Crie uma classe de configuração do JSch para acessar nosso servidor junto com os métodos necessarios.
`SftpConfig`
```
package com.example.sftp;

import com.jcraft.jsch.*;

import java.io.InputStream;


public class SftpConfig {

    /* criar canal para acessar servidor sftp */
    public static ChannelSftp setupJsch() throws JSchException {

        Session jschSession = null;

        Channel sftp = null;

        JSch jsch = new JSch();
        JSch.setConfig("StrictHostKeyChecking", "no");
        //jsch.setKnownHosts("/home/remote_user/.ssh/known_hosts");
        jschSession = jsch.getSession("remote_user", "localhost", 58898);

        // authenticate using private key
        // jsch.addIdentity(<destino da chave ssh>);

        // authenticate using password
        jschSession.setPassword("password1234");

        // 10 seconds session timeout
        jschSession.connect(100000);

        sftp = jschSession.openChannel("sftp");

        return  (ChannelSftp) sftp;

    }

    /* armazenar imagem servidor SFTP */
    public static void salvarImagemSftp(InputStream storedImage, String originalFilename) throws SftpException, JSchException {

        Session jschSession = null;

        Channel sftp = null;
        // transfer file from local to remote server
        ChannelSftp channelSftp = setupJsch();
        channelSftp.connect(50000);

        channelSftp.put(storedImage,channelSftp.getHome() + "/" + originalFilename );
        
        channelSftp.exit();

        System.out.println("Done");

    }

    /* buscar imagem servidor sftp e transferir para pasta local */
    public static void buscarImagemSftp(String originalFilename) throws SftpException, JSchException {

        Session jschSession = null;

        Channel sftp = null;
        // transfer file from local to remote server
        ChannelSftp channelSftp = setupJsch();
        channelSftp.connect(50000);

        channelSftp.get(channelSftp.getHome() + "/" + originalFilename, "C:\\Users\\Dell\\Desktop\\testeImagem" );

        channelSftp.exit();

        System.out.println("Done");

    }

    /* deletar imagem servidor sftp */
    public static void deletarImagemSftp(String nomeImagem) throws SftpException, JSchException {

        Session jschSession = null;

        Channel sftp = null;
        // transfer file from local to remote server
        ChannelSftp channelSftp = setupJsch();
        channelSftp.connect(50000);

        channelSftp.rm(channelSftp.getHome() + "/" + nomeImagem);

        channelSftp.exit();

        System.out.println("Done");

    }
}
```
Agora vamos criar uma classe `controller` para testarmos o envio de imagens para nosso servidor `SFTP` e uma classe `model` para mapear a imagem que vamos receber pelo input via controller.
`Imagem`
````
import org.springframework.web.multipart.MultipartFile;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Imagem {

    private MultipartFile file;
}
```
`ImagemController`
```
package com.example.sftp;

import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.io.InputStream;

@RestController
public class ImagemController {

    @PostMapping("/imagem")
    public void armazenarImagemApenasSftp(Imagem imagem) throws IOException {
        InputStream image = imagem.getFile().getInputStream();

        try{
            SftpConfig.salvarImagemSftp(image, imagem.getFile().getOriginalFilename() );
        }catch (Exception e){
            System.out.println(e.getMessage());
            throw new IOException("Erro ao salvar imagem no cdn");
        }
    }

    @GetMapping("/imagem")
    public void buscarImagemSftp() throws IOException {

        try{
            SftpConfig.buscarImagemSftp("tcc.png");
        }catch (Exception e){
            System.out.println(e.getMessage());
            throw new IOException("Erro ao salvar imagem no cdn");
        }
    }

    @DeleteMapping("/imagem")
    public void deletarImagemSftp() throws IOException {

        try{
            SftpConfig.deletarImagemSftp("tcc.png");
        }catch (Exception e){
            System.out.println(e.getMessage());
            throw new IOException("Erro ao salvar imagem no cdn");
        }
    }
}
```

Vamos testar nossa aplicação via postman.

**requisicao para salvar imagem**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fn561t1ghl208t8ud61t.png)

**imagem salva em nosso servidor**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vpyej4732rthm2qqoz9q.png)

**requisicao para buscar imagem servidor SFTP e tranferir pasta local**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ku0cmt2ouqe6d5uwezh0.png)
 

**imagem salva na pasta passada como path**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/akeaxhfmdgxbdv8afnma.png)

**requisicao para deletar imagem servidor SFTP**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pu3gdxicmwyr8t0igmcr.png)

**imagem deletada do servidor SFTP**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jnc1ofj88ixxyhegacn2.png)
 
E isso ai devs mas um conhecimento passado, deixarei no meu [github](https://github.com/2020nani/sftp-springboot) para quem quiser acessar o projeto
Deixo aqui também meu [linkedin](https://www.linkedin.com/in/nanialmeida/) para quem quiser me adicionar, grato a todos que leram este artigo e bora aprender galera.