<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Paulo Collares</title>
    <description>The latest articles on DEV Community by Paulo Collares (@pcollares).</description>
    <link>https://dev.to/pcollares</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F244426%2F15cbddd6-a85d-4653-b87d-130420b3fdaa.jpg</url>
      <title>DEV Community: Paulo Collares</title>
      <link>https://dev.to/pcollares</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pcollares"/>
    <language>en</language>
    <item>
      <title>Como configurar o React Router no Apache2</title>
      <dc:creator>Paulo Collares</dc:creator>
      <pubDate>Mon, 10 Feb 2020 12:59:44 +0000</pubDate>
      <link>https://dev.to/pcollares/como-configurar-o-react-router-no-apache2-398a</link>
      <guid>https://dev.to/pcollares/como-configurar-o-react-router-no-apache2-398a</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dKTtfEgH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.paulocollares.com.br/wp-content/uploads/2020/02/configurar-o-react-router-no-apache2-1024x576.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dKTtfEgH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.paulocollares.com.br/wp-content/uploads/2020/02/configurar-o-react-router-no-apache2-1024x576.png" alt="Como configurar o React Router no Apache2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como configurar o Apache2 para funcionar adequadamente com as rotas do React Router. Com essas configurações será possível recarregar a pagina ou acessar uma rota diretamente pela URL no navegador.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Adicione a linha ‘homepage’ no package.json:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"homepage": "/meu-site",
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Adicione o atributo ‘basename’ na tag BrowserRouter:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;BrowserRouter basename="/meu-site"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Habilite o modulo ‘rewrite’ no apache:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo a2enmod rewrite
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Edite o arquivo ‘/etc/apache2/sites-available/000-default.conf’ e adicione a regra de reescrita dentro da tag VirtualHost:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Directory "/var/www/html/meu-site"&amp;gt;
    RewriteEngine on
    RewriteCond %{REQUEST_FILENAME} -f [OR]
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^ - [L]
    RewriteRule ^ index.html [L]
&amp;lt;/Directory&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Reinicie o serviço do Apache:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo service apache2 restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Crie um diretório com o nome ‘meu-site’ em ‘/var/www/html’ e copie o código compilado para ele.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;[]’s&lt;/p&gt;

</description>
      <category>react</category>
      <category>apache2</category>
      <category>ptbr</category>
    </item>
    <item>
      <title>Servidor HTTP simples em Java</title>
      <dc:creator>Paulo Collares</dc:creator>
      <pubDate>Tue, 28 Jan 2020 23:30:28 +0000</pubDate>
      <link>https://dev.to/pcollares/servidor-http-simples-em-java-3da5</link>
      <guid>https://dev.to/pcollares/servidor-http-simples-em-java-3da5</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6_aIhUnt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.paulocollares.com.br/wp-content/uploads/2020/01/Internet1.svg_-1024x824.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6_aIhUnt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.paulocollares.com.br/wp-content/uploads/2020/01/Internet1.svg_-1024x824.png" alt="Servidor HTTP simples em Java"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Neste post iremos montar um servidor HTTP simples em Java. Útil para obter informações simples de uma aplicação rodando um background por exemplo.&lt;/p&gt;

&lt;p&gt;O projeto completo pode ser baixado no Github: &lt;a href="https://github.com/pcollares/exemplos-blog/tree/master/SimpleHTTPServer"&gt;https://github.com/pcollares/exemplos-blog/tree/master/SimpleHTTPServer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O primeiro passo é criar uma instância do servidor http nativo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HttpServer servidor = HttpServer.create(new InetSocketAddress(8080), 0);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Nesse exemplo ele irá executar na porta 8080.&lt;/p&gt;

&lt;p&gt;Agora adiciono um novo contexto e uma classe, que criaremos abaixo que será quem irá resolver as requisições.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;servidor.createContext("/", new Root());
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Bastando iniciar o servidor agora&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;servidor.start();
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Nesse exemplo, a classe Root que irá responder as requisições feitas para o contexto ‘/’ e deve implementar a interface HttpHandler para que o método handle prepare o retorno que será enviado no corpo da resposta http.&lt;/p&gt;

&lt;p&gt;Para isso, crio um StringBuilder para facilitar a concatenação das Strings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;StringBuilder out = new StringBuilder();

out.append("&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;");
out.append("&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;");
out.append("&lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Ola mundo").append("&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;");
out.append("&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;");
out.append("&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;");
out.append("Olá mundo");
out.append("&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;");
out.append("&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;");
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;E escrevo essa saída como um array de bytes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;he.sendResponseHeaders(200, out.toString().length());

try (OutputStream os = he.getResponseBody()) {
    os.write(out.toString().getBytes("ISO-8859-1"));
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;O resultado pode ser visto acessando &lt;a href="http://localhost:8080/"&gt;http://localhost:8080/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No código completo no Github, adicionei mais uma página de exemplo (/stats) que demonstra como pode ser útil para obter informações do Hardware e do sistema operacional, como memória, uso do disco, processador, threads, etc…&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qwViWvuJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.paulocollares.com.br/wp-content/uploads/2020/01/servidor-http-simples-em-java-memoria-processador-sistema-operacional.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qwViWvuJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.paulocollares.com.br/wp-content/uploads/2020/01/servidor-http-simples-em-java-memoria-processador-sistema-operacional.png" alt=""&gt;&lt;/a&gt;Exemplo de resposta do servidor http simples em Java&lt;/p&gt;

&lt;p&gt;[]’s&lt;/p&gt;

</description>
      <category>java</category>
      <category>ptbr</category>
    </item>
    <item>
      <title>API REST com Spring + Testes com MockMVC + Documentação com Swagger</title>
      <dc:creator>Paulo Collares</dc:creator>
      <pubDate>Thu, 08 Aug 2019 22:45:20 +0000</pubDate>
      <link>https://dev.to/pcollares/api-rest-com-spring-testes-com-mockmvc-documentacao-com-swagger-4pk0</link>
      <guid>https://dev.to/pcollares/api-rest-com-spring-testes-com-mockmvc-documentacao-com-swagger-4pk0</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Este post tem como objetivo desenvolver uma API REST 100% funcional com Spring e banco de dados PostgreSQL, o Spring data JPA para facilitar as consultas, o padrão DTO para inclusão e atualização dos dados, listar grandes quantidades de dados paginas, com ordenação e busca, implementar testes de integração para validar nossos endpoints com o MockMVC e gerar a documentação de forma automática com o Swagger.&lt;/p&gt;

&lt;p&gt;O código completo pode ser obtido no Github:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/pcollares/api-rest-spring"&gt;Clone no Github&lt;br&gt;&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Dependências
&lt;/h2&gt;

&lt;p&gt;As dependências na nossa aplicação são:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spring Boot&lt;/li&gt;
&lt;li&gt;Hibernate&lt;/li&gt;
&lt;li&gt;Spring data JPA&lt;/li&gt;
&lt;li&gt;MockMVC&lt;/li&gt;
&lt;li&gt;Swagger&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Todas serão tratadas pelo Maven, segundo o pom.xml abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;dependencies&amp;gt; 
        &amp;lt;dependency&amp;gt; 
            &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt; 
            &amp;lt;artifactId&amp;gt;spring-boot-starter-web&amp;lt;/artifactId&amp;gt; 
        &amp;lt;/dependency&amp;gt;
        &amp;lt;dependency&amp;gt; 
            &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt; 
            &amp;lt;artifactId&amp;gt;spring-boot-starter-test&amp;lt;/artifactId&amp;gt;
            &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
        &amp;lt;/dependency&amp;gt; 
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;io.springfox&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;springfox-swagger2&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;2.6.1&amp;lt;/version&amp;gt;
        &amp;lt;/dependency&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;io.springfox&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;springfox-swagger-ui&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;2.6.1&amp;lt;/version&amp;gt;
        &amp;lt;/dependency&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;junit&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;junit&amp;lt;/artifactId&amp;gt;
            &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
        &amp;lt;/dependency&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.hamcrest&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;hamcrest-core&amp;lt;/artifactId&amp;gt;
            &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
        &amp;lt;/dependency&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-boot-starter-data-jpa&amp;lt;/artifactId&amp;gt;
        &amp;lt;/dependency&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-boot-devtools&amp;lt;/artifactId&amp;gt;
            &amp;lt;scope&amp;gt;runtime&amp;lt;/scope&amp;gt;
        &amp;lt;/dependency&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.postgresql&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;postgresql&amp;lt;/artifactId&amp;gt;
        &amp;lt;/dependency&amp;gt;
    &amp;lt;/dependencies&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Spring boot
&lt;/h2&gt;

&lt;p&gt;O Spring boot dispensa a necessidade de um servidor de aplicação (explicito) para executar nossa aplicação, facilitando a execução durante o desenvolvimento e até em produção.&lt;/p&gt;

&lt;p&gt;Para isso basta criarmos uma classe com o método main do Java:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Hibernate e Spring data JPA
&lt;/h2&gt;

&lt;p&gt;Vamos utilizar o Hibernate em conjunto do Spring data JPA para automatizar o mapeamento de nossas classes de domínio.&lt;/p&gt;

&lt;p&gt;Primeiramente, vamos criar uma classe Produto.java e usar as anotações necessárias para realizar o mapeamento.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;As anotações de @ApiModelProperty serão usadas para a documentação com o Swagger, que veremos mais a frente.

@Entity
@Table(name = "produto")
public class Produto {

    @Id
    @SequenceGenerator(name = "produto_seq", sequenceName = "produto_seq", allocationSize = 1)
    @GeneratedValue(generator = "produto_seq", strategy = GenerationType.AUTO)
    private int id;

    private String nome;

    private double valor;

    @ApiModelProperty(notes = "Identificador do produto")
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @ApiModelProperty(notes = "Nome do produto")
    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    @ApiModelProperty(notes = "Valor do produto")
    public double getValor() {
        return valor;
    }

    public void setValor(double valor) {
        this.valor = valor;
    }

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Depois criaremos um ‘Repository’, estrutura do Spring data JPA que facilita ainda mais as consultas ao banco de dados, além de ser útil mais a frente durante os testes, onde será possível criar uns repositórios falsos para que não seja necessário acessar o banco de dados durante essa etapa.&lt;/p&gt;

&lt;p&gt;No repositório de produto abaixo, criamos dois métodos, um &lt;em&gt;findAll()&lt;/em&gt; passando um objeto de paginação, somente pelo nome do método, será inferido uma busca por todos os elementos, e um método de busca com uma consulta personalizada.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;O 'Repository' são interfaces, que o Spring irá tratar como injeção de dependências quando forem invocadas mais a frente.

@Repository
public interface ProdutoRepository extends PagingAndSortingRepository&amp;lt;Produto, Integer&amp;gt; {

    public Page&amp;lt;Produto&amp;gt; findAll(Pageable pageable);

    @Query("SELECT p FROM Produto p "
            + "WHERE lower(nome) like %:busca% ")
    public Page&amp;lt;Produto&amp;gt; busca(@Param("busca") String busca, Pageable pageable);

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Edite o arquivo application.properties com os dados da sua conexão, configurações da api, como o caminho padrão e o modo de inicialização. Devemos criar também o banco de dados e um esquema no PostgreSQL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#debug
debug=true

#api
server.servlet.context-path=/api

#conexão
javax.persistence.create-database-schemas=true
spring.datasource.url=jdbc:postgresql://127.0.0.1:5432/teste
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.jpa.properties.hibernate.default_schema=api

#define como o hibernate irá se comportar quanto a criação do esquema
#create: Apaga e recria todo o esquema
#update: Atualiza o mapeamento
spring.jpa.hibernate.ddl-auto=update

#define se irá executar o 'data.sql'
#always: Sempre irá executar o data.sql
#never: Nunca irá executar o data.sql
spring.datasource.initialization-mode=never

#codificação do data.sql
spring.datasource.sqlScriptEncoding=UTF-8
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Controlador REST
&lt;/h2&gt;

&lt;p&gt;Para disponibilizar nossa API publicamente, vamos criar uma classe ProdutoController.java para colocar todos os endpoints referentes a essa classe. E com as anotações necessárias do Spring.&lt;/p&gt;

&lt;p&gt;A anotação &lt;em&gt;@RequestMapping(“/produtos”)&lt;/em&gt; irá definir o caminho padrão desse endpoint, nesse caso /produtos.&lt;/p&gt;

&lt;p&gt;Para permitir a invocação de nossos endpoint de outras fontes, como uma aplicação REACT ou Angular, precisamos habilitar o CORS (Cross-Origin Resource Sharing), com a anotação &lt;em&gt;@CrossOrigin.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;As anotações @Api e @ApiOperation servirão para documenta pelo swagger, que veremos mais a frente.

@RestController
@RequestMapping("/produtos")
@CrossOrigin
@Api(tags = "Produtos", description = "API de produtos")
public class ProdutoController {

    private final Logger LOGGER = LoggerFactory.getLogger(this.getClass());

    @Autowired
    ProdutoRepository produtoRepository;

...

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Acima, temos a estrutura básica de um controlador rest, com as anotações necessárias, preparo uma instância do Logger e uma do Repositório de produtos, que será construído por injeção de dependências pelo próprio Spring.&lt;/p&gt;

&lt;h3&gt;
  
  
  GET
&lt;/h3&gt;

&lt;p&gt;O primeiro endpoint que vamos criar, será o responsável pela resposta da consulta por todos os produtos, pela anotação @GetMapping() informo que responderá a uma requisição do tipo GET. Defino os parâmetros que essa URL pode receber, todos opcionais, para que possa paginar, ordenar e fazer uma busca.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@ApiOperation(value = "Lista os produtos")
    @GetMapping()
    public Page&amp;lt;Produto&amp;gt; listar(
            @RequestParam(
                    value = "page",
                    required = false,
                    defaultValue = "0") int page,
            @RequestParam(
                    value = "size",
                    required = false,
                    defaultValue = "10") int size,
            @RequestParam(
                    value = "sort",
                    required = false) String sort,
            @RequestParam(
                    value = "q",
                    required = false) String q
    ) {
        Pageable pageable = new PageableFactory(page, size, sort).getPageable();

        Page&amp;lt;Produto&amp;gt; resultPage;

        if (q == null) {
            resultPage = produtoRepository.findAll(pageable);
        } else {
            resultPage = produtoRepository.busca(q.toLowerCase(), pageable);
        }

        return resultPage;
    }

Preciso criar um objeto Pageable para passar para o repositório, para isso criei uma fábrica para facilitar essa criação, a PageableFactory.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Abaixo uma consulta de exemplo para a URL /api/produtos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "content": [
    {
      "id": 2,
      "nome": "Processador Intel Core i7-9700K",
      "valor": 2454
    },
    {
      "id": 3,
      "nome": "Headset Gamer HyperX Cloud Stinger - HX-HSCS-BK/NA ",
      "valor": 189.37
    },
    {
      "id": 4,
      "nome": "Teclado Mecânico Gamer HyperX Mars, RGB, Switch Outemu Bluem, US - HX-KB3BL3-US/R4 ",
      "valor": 284.11
    },
    {
      "id": 5,
      "nome": "Mouse Logitech M90 Preto 1000DPI ",
      "valor": 26.9
    },
    {
      "id": 6,
      "nome": "Gabinete C3Tech Gamer ATX sem Fonte Preto MT-G50BK",
      "valor": 119.6
    },
    {
      "id": 7,
      "nome": "Headphone Edifier Bluetooth W800BT Preto",
      "valor": 250
    },
    {
      "id": 8,
      "nome": "Kindle Novo Paperwhite, 8GB, Wi-Fi, Preto - AO0705 ",
      "valor": 418.99
    },
    {
      "id": 9,
      "nome": "SSD Kingston A400, 240GB, SATA, Leitura 500MB/s, Gravação 350MB/s - SA400S37/240G ",
      "valor": 166
    },
    {
      "id": 10,
      "nome": "HD Seagate BarraCuda, 1TB, 3.5´, SATA - ST1000DM010",
      "valor": 290
    },
    {
      "id": 11,
      "nome": "Cadeira Gamer DT3sports GT, Black - 10293-5",
      "valor": 552.41
    }
  ],
  "pageable": {
    "sort": {
      "unsorted": true,
      "sorted": false,
      "empty": true
    },
    "pageSize": 10,
    "pageNumber": 0,
    "offset": 0,
    "unpaged": false,
    "paged": true
  },
  "last": false,
  "totalPages": 2,
  "totalElements": 19,
  "numberOfElements": 10,
  "sort": {
    "unsorted": true,
    "sorted": false,
    "empty": true
  },
  "first": true,
  "size": 10,
  "number": 0,
  "empty": false
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Alguns exemplos de outras consultas possíveis:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://127.0.0.1:8080/api/produtos?page=2"&gt;http://127.0.0.1:8080/api/produtos?page=2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://127.0.0.1:8080/api/produtos?page=1&amp;amp;size=30"&gt;http://127.0.0.1:8080/api/produtos?page=1&amp;amp;size=30&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://127.0.0.1:8080/api/produtos?q=teclado"&gt;http://127.0.0.1:8080/api/produtos?q=teclado&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://127.0.0.1:8080/api/produtos?sort=valor,asc"&gt;http://127.0.0.1:8080/api/produtos?sort=valor,asc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://127.0.0.1:8080/api/produtos?sort=valor,desc"&gt;http://127.0.0.1:8080/api/produtos?sort=valor,desc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://127.0.0.1:8080/api/produtos?page=0&amp;amp;size=3&amp;amp;ort=valor,desc&amp;amp;q=intel"&gt;http://127.0.0.1:8080/api/produtos?page=0&amp;amp;size=3&amp;amp;ort=valor,desc&amp;amp;q=intel&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Outro endpoint útil é a listagem de um item pelo seu id, que será feito assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@ApiOperation(value = "Busca um produto pelo id")
    @GetMapping(value = "/{id}")
    public ResponseEntity&amp;lt;Produto&amp;gt; listar(@PathVariable Integer id) {
        Optional&amp;lt;Produto&amp;gt; rastreador = produtoRepository.findById(id);

        if (!rastreador.isPresent()) {
            return ApiError.notFound("Produto não encontrado");
        }

        return new ResponseEntity&amp;lt;&amp;gt;(rastreador.get(), HttpStatus.OK);
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  POST e PUT
&lt;/h3&gt;

&lt;p&gt;Para inserir ou atualizar um novo produto, vamos primeiramente criar uma classe ProdutoDTO.java.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;O padrão DTO (Data transfer object) é uma classe que representa a entidade com apenas os atributos necessários para serem expostos publicamente, no nosso exemplo apenas preciso, na criação ou atualização, informar no nome e valor do produto, e nunca o seu id, por isso a sua classe de DTO não possui esse atributo

public class ProdutoDTO {

    private String nome;
    private Double valor;

    @ApiModelProperty(notes = "Nome do produto")
    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public Double getValor() {
        return valor;
    }

    @ApiModelProperty(notes = "Valor do produto")
    public void setValor(Double valor) {
        this.valor = valor;
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Sendo assim, o método que representa essa criação ficará assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@ApiOperation(value = "Cria um novo Produto")
    @PostMapping()
    public ResponseEntity&amp;lt;Produto&amp;gt; criar(@RequestBody ProdutoDTO dto, UriComponentsBuilder ucBuilder) {
        try {
            //Crio um objeto da entidade preenchendo com os valores do DTO e validando
            Produto produto = new Produto();

            if (dto.getNome() == null || dto.getNome().length() &amp;lt; 2) {
                return ApiError.badRequest("Informe o nome do produto");
            }
            produto.setNome(dto.getNome());

            if (dto.getValor() == null || dto.getValor() &amp;lt;= 0) {
                return ApiError.badRequest("Valor do produto inválido");
            }
            produto.setValor(dto.getValor());

            Produto novo = produtoRepository.save(produto);

            //Se ocorreu algum erro, retorno esse erro para a API
            if (novo == null) {
                return ApiError.badRequest("Ocorreu algum erro na criação do produto");
            }

            //Se foi criado com sucesso, retorno o objeto criado
            return new ResponseEntity&amp;lt;&amp;gt;(novo, HttpStatus.CREATED);
        } catch (Exception e) {
            LOGGER.error("Erro ao criar um produto", e);
            return ApiError.internalServerError("Ocorreu algum erro na criação do produto");
        }
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Repare que informo que o ProdutoDTO é o recurso esperado, logo, quando fizer essa requisição, devo passar um json com esses atributos, por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
"nome": "Teclado Microsoft",
"valor": 124
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Ainda nesse método, faço as validações necessárias, retornando um erro quando não forem atendidos os requisitos, e por final chamo o repositório pedindo para persistir o novo produto.&lt;/p&gt;

&lt;p&gt;No final retorno o produto criado. Esse processo pode ser visto abaixo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uQNt47vD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.paulocollares.com.br/wp-content/uploads/2019/08/post-1024x439.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uQNt47vD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.paulocollares.com.br/wp-content/uploads/2019/08/post-1024x439.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A atualização de um produto segue a mesma lógica, informando na URL o id do mesmo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@ApiOperation(value = "Atualiza um Rastreador Equipamento")
    @PutMapping(value = "/{id}")
    public ResponseEntity&amp;lt;Produto&amp;gt; atualizar(@PathVariable("id") int id, @RequestBody ProdutoDTO dto) {
        try {
            Optional&amp;lt;Produto&amp;gt; produtoAtual = produtoRepository.findById(id);

            if (!produtoAtual.isPresent()) {
                return ApiError.notFound("Produto não encontrado");
            }

            if (dto.getNome() != null) {
                if (dto.getNome().length() &amp;lt; 2) {
                    return ApiError.badRequest("Nome do produto inválido");
                }
                produtoAtual.get().setNome(dto.getNome());
            }

            if (dto.getValor() != null) {
                if (dto.getValor() &amp;lt;= 0) {
                    return ApiError.badRequest("Valor do produto inválido");
                }
                produtoAtual.get().setValor(dto.getValor());
            }

            //Atualizo o objeto utilizando o repositório
            Produto atualizado = produtoRepository.save(produtoAtual.get());

            //Se ocorreu algum erro, retorno esse erro para a API
            if (atualizado == null) {
                return ApiError.internalServerError("Erro na atualização do produto");
            }

            //Se foi criado com sucesso, retorno o objeto atualizado
            return new ResponseEntity&amp;lt;&amp;gt;(atualizado, HttpStatus.CREATED);
        } catch (Exception e) {
            LOGGER.error("Erro ao atualizar um produto", e);
            return ApiError.internalServerError("Erro na atualização do produto");
        }
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  DELETE
&lt;/h2&gt;

&lt;p&gt;A remoção também é bem simples, recebo o id, verifico se existe, e retorno um erro se não existir e removo pelo repositório.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@ApiOperation(value = "Remove um produto")
    @DeleteMapping(value = "/{id}")
    public ResponseEntity&amp;lt;Produto&amp;gt; deletar(@PathVariable Integer id) {
        Optional&amp;lt;Produto&amp;gt; produto = produtoRepository.findById(id);

        if (!produto.isPresent()) {
            return ApiError.notFound("Produto não encontrado");
        } else {
            produtoRepository.deleteById(id);
        }

        return new ResponseEntity&amp;lt;&amp;gt;(HttpStatus.OK);
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Documentação com Swagger
&lt;/h2&gt;

&lt;p&gt;O Swagger irá gerar uma documentação da nossa API de forma automática, olhando as anotações que fizemos nos controladores e nas classes de entidade e DTO.&lt;/p&gt;

&lt;p&gt;Para isso vamos criar uma classe SwaggerConfig com as anotações necessárias e informando o pacote onde se encontram os nossos controladores.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Configuration
@EnableSwagger2
public class SwaggerConfig extends WebMvcConfigurationSupport {

    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(apis())
                .paths(PathSelectors.any())
                .build();
    }

    private Predicate&amp;lt;RequestHandler&amp;gt; apis() {
        return RequestHandlerSelectors.basePackage("br.com.paulocollares.api.controladores.rest");
    }

    private ApiInfo apiInfo() {

        return new ApiInfoBuilder()
                .title("SPRING REST API")
                .description("Documentação das APIs REST")
                .contact(new Contact("pcollares", "www.paulocollares.com.br", null))
                .build();
    }

    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");

        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Acessando a URL /api/swagger-ui.html, podemos ver a documentação gerada, como no exemplo abaixo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7QyB7QUq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.paulocollares.com.br/wp-content/uploads/2019/08/Screenshot_2019-08-08-Swagger-UI-1024x593.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7QyB7QUq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.paulocollares.com.br/wp-content/uploads/2019/08/Screenshot_2019-08-08-Swagger-UI-1024x593.png" alt=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;No projeto há uma classe, MainController, que redireciona a requisição da raiz para essa página, ou seja, se acessar http://127.0.0.1:8080/api/ é redirecionado para http://127.0.0.1:8080/api/swagger-ui.html.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Testes
&lt;/h2&gt;

&lt;p&gt;Para testar todos esses endpoins vamos usar o MockMVC para automatizar esse processo. Ele será responsável por invocar e testar o retorno das requisições.&lt;/p&gt;

&lt;p&gt;A estrutura inicial da classe ProdutoTest inicia o MockMVC.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {
    ProdutoController.class
})
public class ProdutoTest {

    //URL base para acesso desse controlador
    private final String BASE_URL = "/produtos";

    //Instância do ObjectMapper para trabalhar com JSON
    private ObjectMapper objectMapper;

    //Controlador REST tratado por meio de injeção de dependências
    @Autowired
    private ProdutoController restController;

    //Instância do MockMVC
    private MockMvc mockMvc;

    //Instância do mock repository
    @MockBean
    private ProdutoRepository mockRepository;

    @Before
    public void setUp() {
        objectMapper = new ObjectMapper();
        mockMvc = MockMvcBuilders
                .standaloneSetup(restController)
                .build();
    }

...

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Vamos fazer um teste ao endpoint de consulta de um produto, para que não seja necessário acessar p banco de dados, e ter dados salvos no mesmo para realizar os testes, utilizamos do mockito para responder uma requisição ao repositório com um dado falso, e verificamos o retorno do endpoint em si.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Test
    public void buscar_id_200() throws Exception {

        Produto produto = new Produto();
        produto.setId(1);
        produto.setNome("Teste");
        produto.setValor(10.0);

        when(mockRepository.findById(1)).thenReturn(Optional.of(produto));

        mockMvc.perform(get(BASE_URL + "/1"))
                .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.id", is(1)))
                .andExpect(jsonPath("$.nome", is("Teste")))
                .andExpect(jsonPath("$.valor", is(10.0)));

        verify(mockRepository, times(1)).findById(1);
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Essa mesma lógica será usada nos outros endpoins.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Test
    public void buscar_id_404() throws Exception {
        mockMvc.perform(get(BASE_URL + "/2")).andExpect(status().isNotFound());
    }

    @Test
    public void criar_200() throws Exception {

        ProdutoDTO dto = new ProdutoDTO();
        dto.setNome("Teste");
        dto.setValor(11.0);

        Produto produto = new Produto();
        produto.setId(1);
        produto.setNome(dto.getNome());
        produto.setValor(dto.getValor());

        when(mockRepository.save(any(Produto.class))).thenReturn(produto);

        mockMvc.perform(post(BASE_URL)
                .content(objectMapper.writeValueAsString(dto))
                .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON))
                .andExpect(status().isCreated())
                .andExpect(jsonPath("$.id", is(1)))
                .andExpect(jsonPath("$.nome", is("Teste")))
                .andExpect(jsonPath("$.valor", is(11.0)));

        verify(mockRepository, times(1)).save(any(Produto.class));

    }

    @Test
    public void atualizar_200() throws Exception {

        ProdutoDTO dto = new ProdutoDTO();
        dto.setNome("Teste");
        dto.setValor(11.0);

        Produto produto = new Produto();
        produto.setId(1);
        produto.setNome(dto.getNome());
        produto.setValor(dto.getValor());

        when(mockRepository.findById(1)).thenReturn(Optional.of(produto));
        when(mockRepository.save(any(Produto.class))).thenReturn(produto);

        mockMvc.perform(put(BASE_URL + "/1")
                .content(objectMapper.writeValueAsString(dto))
                .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON))
                .andExpect(status().isCreated())
                .andExpect(jsonPath("$.id", is(1)));
    }

    @Test
    public void deletar_200() throws Exception {

        Produto produto = new Produto();
        produto.setId(1);

        when(mockRepository.findById(1)).thenReturn(Optional.of(produto));

        mockMvc.perform(delete(BASE_URL + "/1"))
                .andExpect(status().isOk());

        verify(mockRepository, times(1)).deleteById(1);
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Mostrei nesse post um simples exemplo de uma API REST com Spring, o código completo pode ser encontrado no Github: &lt;a href="https://github.com/pcollares/api-rest-spring"&gt;https://github.com/pcollares/api-rest-spring&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Referências
&lt;/h2&gt;

&lt;p&gt;Lista de links com referências para todos os assuntos abordados nesse post.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conceitos
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://restfulapi.net/resource-naming/"&gt;https://restfulapi.net/resource-naming/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.caelum.com.br/rest-principios-e-boas-praticas/"&gt;https://blog.caelum.com.br/rest-principios-e-boas-praticas/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Spring
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://spring.io/guides/gs/rest-service/"&gt;https://spring.io/guides/gs/rest-service/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.algaworks.com/como-criar-web-services-restful-com-spring-boot/"&gt;https://blog.algaworks.com/como-criar-web-services-restful-com-spring-boot/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mkyong.com/tutorials/spring-boot-tutorials/"&gt;https://www.mkyong.com/tutorials/spring-boot-tutorials/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.algaworks.com/injecao-de-dependencias-com-spring/"&gt;https://blog.algaworks.com/injecao-de-dependencias-com-spring/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Spring data JPA
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.mkyong.com/spring-boot/spring-boot-spring-data-jpa-postgresql/"&gt;https://www.mkyong.com/spring-boot/spring-boot-spring-data-jpa-postgresql/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mkyong.com/spring-boot/spring-boot-spring-data-jpa/"&gt;https://www.mkyong.com/spring-boot/spring-boot-spring-data-jpa/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://domineospring.wordpress.com/2015/05/11/facilite-seus-daos-com-o-spring-data-jpa/"&gt;https://domineospring.wordpress.com/2015/05/11/facilite-seus-daos-com-o-spring-data-jpa/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  MockMVC
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://marcelotozzi.com/teste/java/2014/09/10/usar-o-mockmvc-nos-testes-do-spring-e-mais-maneiro.html"&gt;http://marcelotozzi.com/teste/java/2014/09/10/usar-o-mockmvc-nos-testes-do-spring-e-mais-maneiro.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.baeldung.com/integration-testing-in-spring"&gt;https://www.baeldung.com/integration-testing-in-spring&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://howtodoinjava.com/spring-boot2/spring-boot-mockmvc-example/"&gt;https://howtodoinjava.com/spring-boot2/spring-boot-mockmvc-example/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.marcnuri.com/mockmvc-spring-mvc-framework/"&gt;http://blog.marcnuri.com/mockmvc-spring-mvc-framework/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Swagger
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.marcelferry.com.br/tutoriais/documentando-suas-api-com-swagger-usando-springfox/"&gt;http://www.marcelferry.com.br/tutoriais/documentando-suas-api-com-swagger-usando-springfox/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dzone.com/articles/swagger-generation-with-spring-boot"&gt;https://dzone.com/articles/swagger-generation-with-spring-boot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.baeldung.com/swagger-2-documentation-for-spring-rest-api"&gt;https://www.baeldung.com/swagger-2-documentation-for-spring-rest-api&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  DTO
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.baeldung.com/entity-to-and-from-dto-for-a-java-spring-application"&gt;https://www.baeldung.com/entity-to-and-from-dto-for-a-java-spring-application&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@msealvial/blindando-sua-api-spring-boot-com-o-padr%C3%A3o-dto-44f97020d1a0"&gt;https://medium.com/@msealvial/blindando-sua-api-spring-boot-com-o-padr%C3%A3o-dto-44f97020d1a0&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Paginação e ordenação
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dzone.com/articles/pagination-and-sorting-with-spring-data-jpa"&gt;https://dzone.com/articles/pagination-and-sorting-with-spring-data-jpa&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;[]’s&lt;/p&gt;

</description>
      <category>java</category>
      <category>ptbr</category>
      <category>restapi</category>
      <category>spring</category>
    </item>
    <item>
      <title>Como ler um arquivo JSON no Java</title>
      <dc:creator>Paulo Collares</dc:creator>
      <pubDate>Tue, 18 Jun 2019 19:23:10 +0000</pubDate>
      <link>https://dev.to/pcollares/como-ler-um-arquivo-json-no-java-2am7</link>
      <guid>https://dev.to/pcollares/como-ler-um-arquivo-json-no-java-2am7</guid>
      <description>&lt;p&gt;Forma muito simples de se ler um arquivo JSON no Java e transformar em um objeto, muito útil para criar arquivos de configuração para seu sistema.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependências
&lt;/h2&gt;

&lt;p&gt;A única dependência será o &lt;em&gt;Gson&lt;/em&gt;, para a conversão do JSON para objetos Java.&lt;/p&gt;

&lt;h2&gt;
  
  
  Código
&lt;/h2&gt;

&lt;p&gt;Vamos criar um arquivo chamado &lt;em&gt;config.json&lt;/em&gt; na raiz do nosso projeto, ele irá conter o JSON que será lido.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "nome": "paulo",
    "idade": 31,
    "lista": ["Item 1", "Item 2", "Item 3"],
    "cidade":{
        "nome":"Rio de janeiro",
        "estado": "RJ"
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Vamos criar um arquivo &lt;em&gt;Cidade.java&lt;/em&gt; para encapsular esse objeto. Servirá para demonstrar a capacidade de trabalharmos com objetos dentro do arquivo JSON.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Cidade {

    private String nome;
    private String estado;

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public String getEstado() {
        return estado;
    }

    public void setEstado(String estado) {
        this.estado = estado;
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;E vamos criar também um arquivo &lt;em&gt;Config.java&lt;/em&gt;, para receber o conteúdo principal do arquivo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Config {

    private String nome;
    private int idade;
    private List&amp;lt;String&amp;gt; lista;
    private Cidade cidade;

    public Config() {
        cidade = new Cidade();
        lista = new ArrayList&amp;lt;&amp;gt;();
    }

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public int getIdade() {
        return idade;
    }

    public void setIdade(int idade) {
        this.idade = idade;
    }

    public List&amp;lt;String&amp;gt; getLista() {
        return lista;
    }

    public void setLista(List&amp;lt;String&amp;gt; lista) {
        this.lista = lista;
    }

    public Cidade getCidade() {
        return cidade;
    }

    public void setCidade(Cidade cidade) {
        this.cidade = cidade;
    }

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Por fim, em nossa classe &lt;em&gt;main&lt;/em&gt;, vamos realizar a leitura do arquivo e guardar em uma String o seu conteúdo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;String json
                = String.join(" ",
                        Files.readAllLines(
                                Paths.get("./config.json"),
                                StandardCharsets.UTF_8)
                );
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Logo em seguida, desserializamos o conteúdo em um novo objeto &lt;em&gt;Config&lt;/em&gt;, usando o método &lt;em&gt;fromJson&lt;/em&gt; do &lt;em&gt;Gson&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Config config = new Gson().fromJson(json, Config.class);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;A classe completa ficará assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Main {

    public static void main(String[] args) throws IOException {

        String json
                = String.join(" ",
                        Files.readAllLines(
                                Paths.get("./config.json"),
                                StandardCharsets.UTF_8)
                );

        Config config = new Gson().fromJson(json, Config.class);

        System.out.println(config.getNome());
        System.out.println(config.getIdade());
        System.out.println(config.getLista());
        System.out.println("");
        System.out.println(config.getCidade().getNome());
        System.out.println(config.getCidade().getEstado());

    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Saída da execução dessa aplicação:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;paulo
31
[Item 1, Item 2, Item 3]

Rio de janeiro
RJ
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;[]’s&lt;/p&gt;

</description>
      <category>java</category>
      <category>ptbr</category>
      <category>json</category>
    </item>
    <item>
      <title>Como fazer uma requisição GET de uma API REST em Java e transformar o JSON em um objeto</title>
      <dc:creator>Paulo Collares</dc:creator>
      <pubDate>Wed, 05 Jun 2019 14:02:51 +0000</pubDate>
      <link>https://dev.to/pcollares/como-fazer-uma-requisicao-get-de-uma-api-rest-em-java-e-transformar-o-json-em-um-objeto-55ag</link>
      <guid>https://dev.to/pcollares/como-fazer-uma-requisicao-get-de-uma-api-rest-em-java-e-transformar-o-json-em-um-objeto-55ag</guid>
      <description>&lt;p&gt;Como realizar uma simples leitura de uma API REST que disponibiliza um JSON como resposta de uma requisição GET.&lt;/p&gt;

&lt;p&gt;Nossa única dependência será a biblioteca GSON do Google, para desserializar o JSON em um objeto Java.&lt;/p&gt;

&lt;p&gt;Para nosso exemplo irei obter os dados de aeronaves disponibilizados por um serviço gratuito, o &lt;a href="https://opensky-network.org"&gt;OpenSky&lt;/a&gt;, a documentação de sua API pode ser encontrada aqui: &lt;a href="https://opensky-network.org/apidoc/rest.html"&gt;https://opensky-network.org/apidoc/rest.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Primeiramente vamos criar uma classe com os mesmos campos e tepos da resposta JSON da API que será consultada:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dados.java&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Dados {

        private String time;
        private String[][] states;

        public String getTime() {
            return time;
        }

        public void setTime(String time) {
            this.time = time;
        }

        public String[][] getStates() {
            return states;
        }

        public void setStates(String[][] states) {
            this.states = states;
        }

    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Agora, nossa classe principal, onde é feita uma requisição HTTP da url definida e seu conteúdo é lido pelo BufferedReader.&lt;/p&gt;

&lt;p&gt;Depois simplesmente passo o conteúdo JSON para a biblioteca GSON, onde irá desserializar no objeto ‘Dados’.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Main.java&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class APIRest {

    public static void main(String[] args) {
        try {
            String url = "https://opensky-network.org/api/states/all?lamin=45.8389&amp;amp;lomin=5.9962&amp;amp;lamax=47.8229&amp;amp;lomax=10.5226";

            HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();

            conn.setRequestMethod("GET");
            conn.setRequestProperty("Accept", "application/json");

            if (conn.getResponseCode() != 200) {
                System.out.println("Erro " + conn.getResponseCode() + " ao obter dados da URL " + url);
            }

            BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));

            String output = "";
            String line;
            while ((line = br.readLine()) != null) {
                output += line;
            }

            conn.disconnect();

            Gson gson = new Gson();
            Dados dados = gson.fromJson(new String(output.getBytes()), Dados.class);

            System.out.println("TIME: " + dados.getTime());
            System.out.println("STATES: " + Arrays.toString(dados.getStates()[0]));

        } catch (IOException ex) {
            Logger.getLogger(APIRest.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;A saída será algo assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TIME: 1559738039
STATES: [3c6671, DLH1153 , Germany, 1559738039, 1559738039, 6.6706, 46.3694, 10363.2, false, 259.33, 5.24, 0.33, null, 10599.42, 5507, false, 0]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;[]’s&lt;/p&gt;

</description>
      <category>java</category>
      <category>ptbr</category>
      <category>restapi</category>
      <category>json</category>
    </item>
    <item>
      <title>Manutenção de repositório SVN no Linux</title>
      <dc:creator>Paulo Collares</dc:creator>
      <pubDate>Fri, 17 May 2019 13:23:18 +0000</pubDate>
      <link>https://dev.to/pcollares/manutencao-de-repositorio-svn-no-linux-55pg</link>
      <guid>https://dev.to/pcollares/manutencao-de-repositorio-svn-no-linux-55pg</guid>
      <description>&lt;p&gt;Por mais que o GIT tenha dominado o mercado de controladores de versões, o SVN ainda é bastante usado, por isso, trouxe esse breve tutorial com as principais ações que podem ser feitas nesta ferramenta.&lt;/p&gt;

&lt;p&gt;Para fim de demonstração, vou considerar que temos um projeto de nome ‘my-project’, hospedado em um repositório na rede local, no endereço ‘&lt;a href="https://192.168.1.20/%E2%80%99"&gt;https://192.168.1.20/’&lt;/a&gt; e vou trabalhar no meu diretório home, em /home/pcollares/.&lt;/p&gt;

&lt;p&gt;Também vou considerar que a estrutura inicial já foi criada, como descrito abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-project
├─ branches 
├─ tags
└─ trunk
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Checkout do repositório
&lt;/h2&gt;

&lt;p&gt;Navegue até o diretório que deseja baixar o repositório:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd /home/pcollares
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Execute o comando para realizar o checkout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ svn co https://192.168.1.20/svn/my-project
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Criação de um novo Branche
&lt;/h2&gt;

&lt;p&gt;Navegue até a raiz do repositório:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd /home/pcollares/my-project
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Rode o comando de criação do branche:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ svn copy https://192.168.1.20/svn/my-project/trunk/ /home/pcollares/my-project/branches/[nome_do_branche]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Faça o commit da criação do Branche:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd branches/[nome_do_branche]

$ svn commit -m "Criação do branche [nome_do_branche]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Atualização de um Branche com as alterações do Trunk
&lt;/h2&gt;

&lt;p&gt;Navegue até o branche:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd /home/pcollares/my-project/branches/[nome_do_branche]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Atualize o branche:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ svn update
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Teste possíveis conflitos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ svn merge --dry-run https://192.168.1.20/svn/my-project/trunk
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Rode efetivamente o merge com o Branche:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ svn merge https://192.168.1.20/svn/my-project/trunk
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Faça commit do Branche:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ svn commit -m "Merge entre o trunk e o branche [nome_do_branche]"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Reintegração de um Branche
&lt;/h2&gt;

&lt;p&gt;Navegue até o trunk:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd /home/pcollares/my-project/trunk/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Atualize o trunk:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ svn update
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Teste possíveis conflitos com o &lt;em&gt;–dry-run&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ svn merge --reintegrate --dry-run https://192.168.1.20/svn/my-project/branches/[nome_do_branche]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Rode efetivamente a reintegração o Trunk:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ svn merge --reintegrate https://192.168.1.20/svn/my-project/branches/[nome_do_branche]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Resolva os possíveis conflitos.&lt;/p&gt;

&lt;p&gt;Faça commit do trunk:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ svn commit -m "Reintegração do Branche [nome_do_branche] com o Trunk"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Como esta linha de desenvolvimento se encerrou, remova este branche:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ svn delete https://192.168.20.1/svn/my-project/branches/[nome_do_branche] -m "Remoção do branche [nome_do_branche] após a reintegração com o trunk"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Remova o diretório local do Branche:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ rm -Rf /home/pcollares/my-project/branches/[nome_do_branche]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Criação de uma Tag
&lt;/h2&gt;

&lt;p&gt;Navegue até o diretório do projeto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd /home/pcollares/my-project/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Crie a nova tag a partir do trunk:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ svn copy https://192.168.1.20/svn/my-project/trunk/ tags/[nome_da_tag]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Faça commit da criação da tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd tags

$ svn commit -m "Fechamento da criação da tag [nome_da_tag]"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Referências
&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://svnbook.red-bean.com/en/1.7/svn.branchmerge.basicmerging.html"&gt;http://svnbook.red-bean.com/en/1.7/svn.branchmerge.basicmerging.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[]’s&lt;/p&gt;

</description>
      <category>linux</category>
      <category>svn</category>
      <category>ptbr</category>
    </item>
    <item>
      <title>Exemplo de uso do MQTT com Java</title>
      <dc:creator>Paulo Collares</dc:creator>
      <pubDate>Wed, 24 Apr 2019 12:14:57 +0000</pubDate>
      <link>https://dev.to/pcollares/exemplo-de-uso-do-mqtt-com-java-mgo</link>
      <guid>https://dev.to/pcollares/exemplo-de-uso-do-mqtt-com-java-mgo</guid>
      <description>&lt;p&gt;MQTT (Message Queuing Telemetry Transport) é um protocolo de mensagens leve e simples de se usar, tem sido muito usado para desenvolvimento de soluções para IoT (Internet das coisas), mas que também atende aplicações mais pesadas, já que o seu broker é muito robusto.&lt;/p&gt;

&lt;p&gt;O MQTT é um padrão &lt;em&gt;publish/subscribe,&lt;/em&gt; onde o servidor (broker) recebe as mensagens e distribui para quem tem interesse. Isso é feito por meio de tópicos, em que cada mensagem publicada possui, e os clientes interessados se inscrevem.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zjFzF0Un--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.paulocollares.com.br/wp-content/uploads/2019/04/mqtt-1024x768.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zjFzF0Un--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.paulocollares.com.br/wp-content/uploads/2019/04/mqtt-1024x768.jpg" alt=""&gt;&lt;/a&gt;Diagrama descrevendo o do funcionamento do MQTT&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependências
&lt;/h2&gt;

&lt;p&gt;Há apenas uma dependência para o projeto, que é o cliente Paho para o MQTT, desenvolvido pela Eclipse , que pode ser baixado aqui: &lt;a href="https://www.eclipse.org/paho/clients/java/"&gt;https://www.eclipse.org/paho/clients/java/&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Classes
&lt;/h2&gt;

&lt;p&gt;Segue abaixo as três classes necessárias para a execução do projeto: Main, que contem a classe principal do projeto e inicia o cliente e o ouvinte e publica as mensagens de teste, ClienteMQTT, que contém os métodos de conexão, inscrição e publicação e Ouvinte, que se inscreve em um tópico e exibe a mensagem no terminal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Main.java
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package javamqtt;

import java.text.SimpleDateFormat;

public class Main {

    public static void main(String[] args) throws InterruptedException {
        ClienteMQTT clienteMQTT = new ClienteMQTT("tcp://broker.mqttdashboard.com:1883", null, null);
        clienteMQTT.iniciar();

        new Ouvinte(clienteMQTT, "br/com/paulocollares/#", 0);

        while (true) {
            Thread.sleep(1000);
            String mensagem = "Mensagem enviada em " + new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(System.currentTimeMillis()) + " - Teste de MQTT disponivel em www.paulocollares.com.br";

            clienteMQTT.publicar("br/com/paulocollares/teste", mensagem.getBytes(), 0);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  ClienteMQTT.java
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package javamqtt;

import java.util.Arrays;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttMessageListener;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence;

public class ClienteMQTT implements MqttCallbackExtended {

    private final String serverURI;
    private MqttClient client;
    private final MqttConnectOptions mqttOptions;

    public ClienteMQTT(String serverURI, String usuario, String senha) {
        this.serverURI = serverURI;

        mqttOptions = new MqttConnectOptions();
        mqttOptions.setMaxInflight(200);
        mqttOptions.setConnectionTimeout(3);
        mqttOptions.setKeepAliveInterval(10);
        mqttOptions.setAutomaticReconnect(true);
        mqttOptions.setCleanSession(false);

        if (usuario != null &amp;amp;&amp;amp; senha != null) {
            mqttOptions.setUserName(usuario);
            mqttOptions.setPassword(senha.toCharArray());
        }
    }

    public IMqttToken subscribe(int qos, IMqttMessageListener gestorMensagemMQTT, String... topicos) {
        if (client == null || topicos.length == 0) {
            return null;
        }
        int tamanho = topicos.length;
        int[] qoss = new int[tamanho];
        IMqttMessageListener[] listners = new IMqttMessageListener[tamanho];

        for (int i = 0; i &amp;lt; tamanho; i++) {
            qoss[i] = qos;
            listners[i] = gestorMensagemMQTT;
        }
        try {
            return client.subscribeWithResponse(topicos, qoss, listners);
        } catch (MqttException ex) {
            System.out.println(String.format("Erro ao se inscrever nos tópicos %s - %s", Arrays.asList(topicos), ex));
            return null;
        }
    }

    public void unsubscribe(String... topicos) {
        if (client == null || !client.isConnected() || topicos.length == 0) {
            return;
        }
        try {
            client.unsubscribe(topicos);
        } catch (MqttException ex) {
            System.out.println(String.format("Erro ao se desinscrever no tópico %s - %s", Arrays.asList(topicos), ex));
        }
    }

    public void iniciar() {
        try {
            System.out.println("Conectando no broker MQTT em " + serverURI);
            client = new MqttClient(serverURI, String.format("cliente_java_%d", System.currentTimeMillis()), new MqttDefaultFilePersistence(System.getProperty("java.io.tmpdir")));
            client.setCallback(this);
            client.connect(mqttOptions);
        } catch (MqttException ex) {
            System.out.println("Erro ao se conectar ao broker mqtt " + serverURI + " - " + ex);
        }
    }

    public void finalizar() {
        if (client == null || !client.isConnected()) {
            return;
        }
        try {
            client.disconnect();
            client.close();
        } catch (MqttException ex) {
            System.out.println("Erro ao desconectar do broker mqtt - " + ex);
        }
    }

    public void publicar(String topic, byte[] payload, int qos) {
        publicar(topic, payload, qos, false);
    }

    public synchronized void publicar(String topic, byte[] payload, int qos, boolean retained) {
        try {
            if (client.isConnected()) {
                client.publish(topic, payload, qos, retained);
                System.out.println(String.format("Tópico %s publicado. %dB", topic, payload.length));
            } else {
                System.out.println("Cliente desconectado, não foi possível publicar o tópico " + topic);
            }
        } catch (MqttException ex) {
            System.out.println("Erro ao publicar " + topic + " - " + ex);
        }
    }

    @Override
    public void connectionLost(Throwable thrwbl) {
        System.out.println("Conexão com o broker perdida -" + thrwbl);
    }

    @Override
    public void connectComplete(boolean reconnect, String serverURI) {
        System.out.println("Cliente MQTT " + (reconnect ? "reconectado" : "conectado") + " com o broker " + serverURI);
    }

    @Override
    public void deliveryComplete(IMqttDeliveryToken imdt) {
    }

    @Override
    public void messageArrived(String topic, MqttMessage mm) throws Exception {
    }

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Ouvinte.java
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package javamqtt;

import org.eclipse.paho.client.mqttv3.IMqttMessageListener;
import org.eclipse.paho.client.mqttv3.MqttMessage;

public class Ouvinte implements IMqttMessageListener {

    public Ouvinte(ClienteMQTT clienteMQTT, String topico, int qos) {
        clienteMQTT.subscribe(qos, this, topico);
    }

    @Override
    public void messageArrived(String topico, MqttMessage mm) throws Exception {
        System.out.println("Mensagem recebida:");
        System.out.println("\tTópico: " + topico);
        System.out.println("\tMensagem: " + new String(mm.getPayload()));
        System.out.println("");
    }

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Brokers MQTT gratuitos e públicos para teste
&lt;/h2&gt;

&lt;p&gt;No exemplo eu uso um broker publico para testes, porém deve ser usado apenas para esse propósito, já que não há privacidade no conteúdo publicado. Para uso em seu projeto, recomendo o &lt;a href="https://projects.eclipse.org/projects/technology.mosquitto"&gt;Mosquitto&lt;/a&gt;, também da Eclipse.&lt;/p&gt;

&lt;h3&gt;
  
  
  Baixe o projeto
&lt;/h3&gt;

&lt;p&gt;Baixe o projeto deste exemplo no meu Github: &lt;a href="https://github.com/pcollares/exemplos-blog/tree/master/JavaMQTT"&gt;https://github.com/pcollares/exemplos-blog/tree/master/JavaMQTT&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[]’s&lt;/p&gt;

</description>
      <category>java</category>
      <category>mqtt</category>
      <category>ptbr</category>
    </item>
  </channel>
</rss>
