Introdução
Recentemente dei um treinamento na companhia onde trabalho, e resolvi transformá-lo em um tutorial, dividido em quatro partes, bem mão na massa, sem entrar em detalhes sobre as tecnologias, deixando ao leitor que busque maiores informações. A intenção aqui é tem um exemplo funcional dessas tecnologias, abrindo caminho para que com a curiosidade e interesse de quem estiver lendo, possa então se aprofundar em cada um dos assuntos envolvidos.
Nesse tutorial vamos criar uma aplicação usando SpringBoot, com SpringMVC, com SpringDataJpa para camada de persitência, H2 Database para base de dados, SpringDataRest para criação automatizada de API Restful, e SpringFox para documentação com Swagger. Pretendo em breve criar tutoriais mais detalhados sobre cada tecnologia.
Setup Inicial
Vamos criar um projeto que possa nos fornecer as interfaces de Serviço Rest. Esse serviço é apenas um exemplo e demonstra como contruir um projeto rest, simples. No nosso desenvolvimento diário, vamos utilizar serviços já implementados em outro framework/linguagem.
Vamos implementar duas interfaces rest, para listagem e busca por id de um livro.
Primeiro vamos criar o projeto usando o maven
1 2 3 4 5 |
mvn archetype:generate \ -DgroupId=br.com.marcelferry.workshop \ -DartifactId=book-rest \ -DarchetypeArtifactId=maven-archetype-quickstart \ -DinteractiveMode=false |
Abrindo o projeto no Eclipse
Vamos importar o projeto no Eclipse usando o item de menu File -> Import...
, na caixa de dialógo Import...
, escolha Maven -> Existing Maven Projects
.
Na caixa de dialógo Import Maven Projects
, utilize o botão Browse...
para localizar a pasta onde criamos nosso projeto book-rest
, e selecionar o arquivo pom.xml
. Clique em Finish
, para o projeto ser importado.
Vamos utilizar o Eclipse para facilitar o processo de edição mas continuaremos a usar a linha de comando para compilar o nosso projeto.
Vamos acessar esse projeto e apagar os arquivos padrões: App.java
e AppTest.java
, que serão substituídos pelos arquivos que ainda iremos criar.
SpringBoot
Vamos utilizá-lo para agilizar a construção de nossos projetos, e auxiliar nas dependências necessárias, reduzindo o processo de configuração.
Veja que essa dependência que estamos inserindo é tambem um projeto parent, que personalizará completamente o nosso projeto. Insira o bloco abaixo no pom.xml
1 2 3 4 5 6 |
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.3.RELEASE</version> <relativePath /> </parent> |
Ele fornecerá as dependências e plugins necessários para configuração, compilação e execução do seu projeto.
Propriedades
Podemos definir configurações em comum para todos os projetos, essas configurações podem ser palavras chaves já reservadas e utilizadas pelo maven ou por outros plugins, como também criar novas variáveis que poderão ser utilizadas no próprio contexto do pom.
1 2 3 4 5 |
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> |
Plugins
Podemos configurar plugins para adicionar funcionalidades em nosso processo de build.
O trecho de exemplo abaixo define o plugin padrão de compilação do pacote. Perceba que no código temos um ${maven-compiler-plugin.version}
utilizado para definir a versão do plugin que será utilizada. Esse valor, maven-compiler-plugin.version
, terá que ser definido em um bloco
no pom.xml ou em um projeto parent. (Não vamos inserir esse código em nosso projeto)
1 2 3 4 5 6 7 8 9 10 |
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>${maven-compiler-plugin.version}</version> <inherited>true</inherited> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> |
Insira o trecho abaixo em seu pom.xml
, o qual insere as funcionalidades de compilação do SpringBoot ao seus projetos.
1 2 3 4 5 6 7 8 |
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> |
Após configurarmos o nosso pom.xml
, teremos que realizar o processo de build, para que ele esteja disponível para os nossos projetos futuros. Use mvn clean install
.
Para inclusão do spring, faremos inserção de uma dependência:
1 2 3 4 |
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> |
Abra o pom.xml
adicione a referência a projeto parent que acabamos de criar, substituindo todo conteúdo da tag
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
<modelVersion>4.0.0</modelVersion> <groupId>br.com.marcelferry.workshop</groupId> <artifactId>book-rest</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>Serviço REST para acesso as informações de Livros</name> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.3.RELEASE</version> <relativePath /> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.7</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> |
Quando usamos o eclipse, ele automaticamente baixa as dependências do projeto, permitindo assim que possamos continuar o desenvolvimento sem precisar executar o maven para baixá-las a cada vez que alteramos o pom.xml
.
Caso ele não faça, ou estivermos usando a linha de comando, vamos executar o comando mvn clean install
, e se quiser forçar o Eclipse, use o botão direito no projeto, clique em Run as... -> maven install
.
Nos dois casos, por causa do uso do spring boot, o maven deverá baixar todas as bibliotecas, mas poderá ocorrer um erro conforme abaixo:
1 2 3 4 5 6 7 8 9 10 |
<span class="pl-c1">[INFO] BUILD FAILURE</span> <span class="pl-c1">[INFO] ------------------------------------------------------------------------</span> <span class="pl-c1">[INFO] Total time: 53.017 s</span> <span class="pl-c1">[INFO] Finished at: 2017-07-06T10:34:29-03:00</span> <span class="pl-c1">[INFO] Final Memory: 25M/229M</span> <span class="pl-c1">[INFO] ------------------------------------------------------------------------</span> <span class="pl-c1">[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:1.5.3.RELEASE:repackage (default) on project book-rest: Execution def</span> <span class="pl-c1">ault of goal org.springframework.boot:spring-boot-maven-plugin:1.5.3.RELEASE:repackage failed: Unable to find main class -> [Help 1]</span> <span class="pl-c1">[ERROR]</span> <span class="pl-c1">...</span> |
Esse erro será aceitável nesse momento, pois indica que o plugin do spring-boot não localizou uma classe main para usar como executável inicilizador do projeto.
Caso após esse processo, o eclipse continuar a exibir o seu projeto com erro (ícone vermelho) sem ter erro em código fonte ou xml, use o botão direito no projeto, clique em Maven -> Update Project...
. Para que o eclipse possa acessar todas as bibliotecas utilizadas pelo maven no seu projeto.
Vamor agora criar a classe Application.java para iniciar o SpringBoot.
1 2 3 4 5 6 7 |
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } |
Com essa pequena estrutura nós ja temos um projeto web, pronto para ser executado. Para testá-lo vamos executar o comando mvn clean install
e em seguinda executaremos o comando mvn spring-boot:run
.
Assim que processo estiver pronto você verá a mensagem:
1 |
<span class="pl-c1">Started Application in X.xxx seconds (JVM running for X.xxx)</span> |
Basta acessar o seu navegador com o seguinte endereço:
1 2 |
http://localhost:8080/ |
Hávera um erro, parecido ao trecho abaixo, já que ainda não colocamos nenhum conteúdo para ser visiualizado em nosso projeto.
1 2 3 4 5 6 7 8 |
Whitelabel Error Page This application has no explicit mapping for /error, so you are seeing this as a fallback. Thu Jul 06 07:19:26 BRT 2017 There was an unexpected error (type=Not Found, status=404). No message available |
Esse erro arrumaremos assim que disponibilizarmos conteúdo.
Por default o projeto é executado na porta 8080. Para mudarmos essa configuração podemos criar uma arquivo application.properties
na pasta src/main/resources
com o seguinte conteúdo:
1 |
server.port=8083 |
Assim, basta executar novamente o mvn spring-boot:run
, e o nosso servidor estará disponível em:
1 2 |
http://localhost:8083/ |
POJO, ValueObject, DTO – Model
Vamos adicionar a nossa classe de Pojo:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class Book { private Long id; private String titulo; private String autor; private String categoria; private BigDecimal preco; private LocalDate dataCadastro; private boolean ativo; /* ... getter e setter omitido ... */ } |
Veremos que a classe apresenta um erro no campo LocalDate (Se você já estiver usando Java8 a classe poderá ser importada diretamente do JDK, mas nesse projeto a intenção é utilizar a biblioteca joda-time).
Para fazer a correção, primeiramente vamos incluir a biblioteca JodaTime que melhora o comportamento e resolve problemas comuns da biblioteca original de java.util.Date
da Linguagem (pré JDK 8). Inclua o seguinte bloco no pom.xml
de nosso projeto.
1 2 3 4 5 |
<dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>2.9.7</version> </dependency> |
Controller
Vamos criar uma classe chamada BookController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@RestController @RequestMapping("books") public class BookController { @RequestMapping(method= RequestMethod.GET) public List<Book> list() { return Arrays.asList(new Book(), new Book()); } @RequestMapping(value="{id}", method= RequestMethod.GET) public Book findById( @PathVariable("id") Long bookId ) { return new Book(); } } |
Observe que a classe está com a anotação @RestController
, que já expoe os métodos da classe e já faz os tratamentos para que o retorno seja tratado como Json.
A anotação @RequestMapping
no nível de classe ajuda a compor o endpoint da api.
Agora podemos executar novamente o comando mvn spring-boot:run
, que irá subir o nossa aplicação e poderemos chamar os dois endpoints definidos.
Lista de Todos os Livros
1 2 |
http://localhost:8083/books |
Recupera o livro com Id igual a 1
1 2 |
http://localhost:8083/books/1 |