Ir para conteúdo
Faça parte da equipe! (2024) ×

[Artigo] O que é Spring MVC?


Arkanun1000
 Compartilhar

Posts Recomendados

  • Velha Guarda
[CENTER][SIZE=6][B]O que é Spring MVC?[/B][/SIZE] Gostaria de facilidade e flexibilidade para trabalhar com requisições web? O [B]Spring MVC[/B] é a ferramenta que dá isso para você! Hoje é difícil conceber uma aplicação sem a parte web, concorda? Além das numerosas aplicações web, a maioria dos aplicativos móveis (para Android e iOS, por exemplo) precisam de uma APIs RESTful para consumir. Por isso, conhecer um framework que ajuda nesse trabalho [B]é vantajoso para qualquer programador[/B]. Essa é a ideia de agora: explicar como o Spring MVC funciona. Continue lendo para [B]aprender sobre[/B]: [LIST] [*]O que é Spring MVC? [*]Criação de controladores web [*]Novas anotações de mapeamento [*]Recebendo dados de um formulário [*]Enviando dados para a página [*]Como configurar o ViewResolver [*]Como usar o Spring MVC para criar uma API RESTful [/LIST] “Vambora”!? [SIZE=5][B]O que é Spring MVC?[/B][/SIZE] O Spring MVC é um framework que ajuda no desenvolvimento de aplicações web. Com ele nós conseguimos construir [B]aplicações web robustas e flexíveis[/B]. Ele já tem todas as funcionalidades que precisamos para (1) atender as requisições HTTP, (2) delegar responsabilidades de processamento de dados para outros componentes e (3) preparar a resposta que precisa ser dada. É uma excelente implementação do [B]padrão MVC[/B]. MVC é acrônimo de Model, View e Controller, e é bacana entender o papel de cada um deles dentro do sistema. Esse entendimento vai te ajudar a trabalhar com Spring MVC de forma a construir aplicações mais organizadas e de fácil manutenção. Vamos começar com a imagem abaixo que representa o fluxo de uma requisição do ponto de vista do Spring MVC: [URL='http://s3.amazonaws.com/algaworks-blog/wp-content/uploads/Fluxo-do-Spring-MVC.png'][IMG]http://s3.amazonaws.com/algaworks-blog/wp-content/uploads/Fluxo-do-Spring-MVC.png[/IMG][/URL] Detalhadamente, os passos mostrados na imagem acima, são: 1. Acessamos uma URL no browser que envia a requisição HTTP para o servidor que roda a aplicação web com Spring MVC. Perceba que quem recebe a requisição é o controlador do framework, o Spring MVC. 2. O controlador do framework irá procurar qual classe é responsável por tratar essa requisição, entregando a ela os dados enviados pelo browser. Essa classe faz o papel do controller. 3. O controller passa os dados para o model, que por sua vez executa todas as regras de negócio, como cálculos, validações e acesso ao banco de dados. 4. O resultado das operações realizadas pelo model é retornado ao controller. 5. O controller retorna o nome da view, junto com os dados que ela precisa para renderizar a página. 6. O Framework encontra a view que processa os dados, transformando o resultado em um HTML. 7. Finalmente, o HTML é retornado ao browser do usuário. Na prática, o [I]controller[/I] é a classe Java com os métodos que tratam essas requisições. Portanto, tem acesso a toda informação relacionada a ela como parâmetros da URL, dados submetidos através de um formulário, cabeçalhos HTTP, etc. Veja um exemplo simples: [CODE]@Controller public class HomeController { @RequestMapping("/") public String index() { return "index.jsp"; } }[/CODE] O método index() atende a requisição para / (que é a raiz da aplicação) e devolve a página index.jsp na resposta. Fique tranquilo, ainda veremos mais detalhes. O [I]model[/I] seria algo como as famosas classes de serviços, repositórios e as entidades de banco de dados. Um pequeno exemplo poderia ser: [CODE]@Autowired private Funcionarios funcionarios; // <<< Nosso repositório. @RequestMapping(method = RequestMethod.GET) public ModelAndView listar() { ModelAndView modelAndView = new ModelAndView("funcionario-lista.jsp"); modelAndView.addObject("funcionarios", funcionarios.findAll()); return modelAndView; }[/CODE] Não se assuste. Olhe o código acima com calma e no decorrer da nossa conversa isso ficará mais claro. Por ora, veja nosso [I]model[/I] entrando em ação nas linhas 2 e 7. Por fim temos nossa [I]view[/I]. Essa dispensa exemplos aqui, pois, são nossas páginas JSP que irão tornar-se em HTML para chegar aos usuários. [SIZE=5][B]Criação de controladores web[/B] [B][/B][/SIZE] Agora nós vamos estudar as opções que temos para criar e configurar nossos controladores. Contudo, vamos precisar de uma aplicação já configurada com o [URL='http://projects.spring.io/spring-framework/']Spring Framework[/URL]. Você pode escolher dentre duas opções na hora de configurar. A primeira opção é utilizar a configuração de um projeto web comum. Um exemplo disso será o [URL='http://github.com/algaworks/artigo-spring-mvc']código fonte que irei disponibilizar para você[/URL]. Você vai observar o pacote com.algaworks.mvc. Nele tem as classes de configuração que criei. Em especial, veja as classes SpringWebInitializer e WebConfig, pois, elas representam o mínimo para o Spring MVC funcionar. Não deixe de olhar também o pom.xml. De qualquer forma vou deixar aqui o mínimo de dependências para trabalhar com Spring MVC: [CODE]<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.4.RELEASE</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency>[/CODE] A segunda é criar uma aplicação com o Spring Boot. Com o projeto configurado, podemos continuar. ;) A primeira coisa é criar uma classe comum e anotá-la com @controller. Essa anotação fará com que o Spring reconheça a classe como um controlador. Depois disso criamos nossas ações. Elas são métodos Java comuns que, através de anotações, serão configuradas para responder as requisições web. [CODE]@Controller @RequestMapping("/funcionarios") public class FuncionariosController { @Autowired private Funcionarios funcionarios; @RequestMapping(method = RequestMethod.GET) public ModelAndView listar() { ModelAndView modelAndView = new ModelAndView("funcionario-lista.jsp"); modelAndView.addObject("funcionarios", funcionarios.findAll()); return modelAndView; } }[/CODE] Vamos começar a analisar o código acima linha a linha, mais especialmente a ação listar(), para entendermos tudo isso melhor: Na primeira linha temos, como já falamos, a anotação que torna nossa classe um controlador. A segunda linha, com a anotação @RequestMapping, configura qual o [I]path[/I] inicial para todas as ações do nosso controlador. Já nas linhas 5 e 6 vemos nossa propriedade funcionarios, referente ao nosso repositório, anotada com @Autowired e, portanto, será injetada pelo Spring Framework. Nós temos aqui, no blog, um artigo sobre injeção de dependências para quem quiser saber mais sobre o assunto. Essa parte não é diretamente relacionada ao Spring MVC. Pulando para a linha 8, vemos novamente a anotação @RequestMapping que está especificando como será a requisição que a ação listar() vai atender. [CODE]@RequestMapping(method = RequestMethod.GET)[/CODE] A primeira coisa a se observar é que a propriedade method da nossa anotação está especificando um método HTTP que é o GET, ou seja, para a ação atender a requisição, a mesma deve ser do tipo GET. A propriedade method pode ser omitida. Se assim fosse, a ação passaria a responder a todos os métodos HTTP (GET, POST, PUT, DELETE, etc.). Veja também que a anotação não tem um [I]path[/I] configurado. Isso quer dizer que o método listar() é a ação padrão do nosso controlador e vai responder para uma requisição do tipo GET com o [I]path[/I] /funcionarios. Para configurar um, poderíamos utilizar as propriedades value ou path da anotação: [CODE]@RequestMapping(method = RequestMethod.GET, path = "/lista")[/CODE] Agora o mais importante: nossa ação que começa na linha 9: [CODE]public ModelAndView listar() { ModelAndView modelAndView = new ModelAndView("funcionario-lista.jsp"); modelAndView.addObject("funcionarios", funcionarios.findAll()); return modelAndView; }[/CODE] Ela começa instanciando a classe ModelAndView. Essa classe foi utilizada para especificar a [I]view[/I] que será renderizada para o usuário final e para informarmos quais os dados ela utilizará para isso. Repare que no construtor temos a nossa página funcionario-lista.jsp e o método addObject é utilizado para adicionarmos uma lista de objetos que serão exibidos por ela. Por fim, o objeto do tipo é ModelAndView retornado. Você pode implementar essa ação de outra maneira se quiser. Veja uma alternativa: [CODE]public String lista(Model model) { model.addAttribute("funcionarios", funcionarios.findAll()); return "funcionario-lista.jsp"; }[/CODE] Neste caso, recebemos a interface Model como parâmetro (ela é passada pelo Spring MVC) e utilizamos o método addAttribute para adicionar nossa lista de objetos. A página foi, simplesmente, colocada como retorno. [SIZE=5][B]Recebendo dados de um formulário[/B][/SIZE] Vou te mostrar agora como fazer com que os dados de um formulário cheguem até a ação do nosso controlador. Preparei um formulário, para cadastro de funcionários, e a ação que receberá essa submissão. Como temos uma classe importante envolvida, que é a classe Funcionario, então quero mostrá-la pra você. São os dados dela que serão submetidos pelo formulário e recebidos pela ação: [CODE]public class Funcionario { private Long id; private String nome; private String cpf; //getters e setter omitidos }[/CODE] Agora tenho aqui o formulário construído em duas versões. Uma com as tags do Spring: [CODE]Formulário de cadastroXHTML <s:url value="/funcionarios/salvar" var="acao" /> <sf:form method="post" modelAttribute="funcionario" action="${acao}"> <div> <label for="nome">Nome:</label> <sf:input path="nome" /> </div> <div> <label for="cpf">CPF:</label> <sf:input path="cpf" /> </div> <button type="submit">Salvar</button> </sf:form> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <s:url value="/funcionarios/salvar" var="acao" /> <sf:form method="post" modelAttribute="funcionario" action="${acao}"> <div> <label for="nome">Nome:</label> <sf:input path="nome" /> </div> <div> <label for="cpf">CPF:</label> <sf:input path="cpf" /> </div> <button type="submit">Salvar</button> </sf:form> [/CODE] E outra, para quem preferir, em HTML puro: [CODE]<form id="funcionario" action="/app/funcionarios/salvar" method="post"> <div> <label for="nome">Nome:</label> <input id="nome" name="nome" type="text"/> </div> <div> <label for="cpf">CPF:</label> <input id="cpf" name="cpf" type="text"/> </div> <button type="submit">Salvar</button> </form>[/CODE] A vantagem do formulário com as tags Spring é que ele já irá exibir as informações do funcionário caso elas já venham preenchidas. Isso é útil no caso de edição de registros. Já a ação para capturar os dados, referentes a submissão desse formulário, fica assim: [CODE]@Controller @RequestMapping("/funcionarios") public class FuncionariosController { @Autowired private FuncionarioService funcionarioService; @RequestMapping(method = RequestMethod.POST, path = "/salvar") public RedirectView salvar( Funcionario funcionario, RedirectAttributes redirectAttributes) { funcionarioService.salvar(funcionario); redirectAttributes.addFlashAttribute( "mensagem", "Cadastro feito com sucesso!"); return new RedirectView("/funcionarios", true); } }[/CODE] Da forma como fizemos com a ação listar(), deixa eu mostrar agora a ação salvar(). Nossa ação está recebendo dois parâmetros sendo que o primeiro – do tipo Funcionario – será preenchido com os dados que virão do formulário e o segundo – do tipo RedirectAttributes – utilizaremos para incluir o atributo com a mensagem que será exibida após o redirecionamento. Com nossa instância do tipo Funcionario preenchida podemos manipulá-la como quisermos. No caso, simplesmente, salvamos ela: [CODE]funcionarioService.salvar(funcionario);[/CODE] Como já dei a entender, não será renderizada uma página após essa ação, será feito um redirecionamento. Para isso, foi utilizado um objeto do tipo RedirectView. [CODE]new RedirectView("/funcionarios", true);[/CODE] O primeiro argumento do construtor desse objeto é a URL, ou [I]path[/I] de destino e o segundo é somente para quando utilizamos um [I]path[/I]. Passando true, a classe entende que é para incluir o contexto de nossa aplicação ao [I]path[/I] informado. O resultado seria algo como: [URL]http://localhost:8080/app/funcionarios[/URL]. Acima mostrei o formulário e a ação que recebe os dados, mas qual ação criar para imprimir o formulário para o usuário? Pode usar essa daqui: [CODE]@RequestMapping(method = RequestMethod.GET, path = "/novo") public ModelAndView novo() { ModelAndView modelAndView = new ModelAndView("funcionario-formulario.jsp"); modelAndView.addObject("funcionario", new Funcionario()); return modelAndView; }[/CODE] E, se o seu formulário for em HTML puro, pode trocar por essa: [CODE]@RequestMapping(method = RequestMethod.GET, path = "/novo") public String novo() { return "funcionario-formulario.jsp"; }[/CODE] [SIZE=5][B]Enviando dados para a página[/B][/SIZE] Como já sabemos receber dados de um formulário, vamos entender como enviar dados para as nossas páginas. Na verdade, a gente já fez isso quando utilizamos os métodos addAttribute da interface Model, addObject da classe ModelAndView e até no método addFlashAttribute da classe RedirectAttributes. Mas agora quero fazer isso formalmente simulando a função de edição. Aqui o formulário construído com as tags do Spring MVC é importante, pois, já vai mostrar os dados do objeto que a gente passar para ser utilizado na nossa [I]view[/I]. Quanto ao formulário, ele teve uma leve mudança para incluir também o campo [I]hidden[/I] que irá armazenar o identificador do funcionário (veja linha 8): [CODE]<s:url value="/funcionarios/salvar" var="acao" /> <sf:form method="post" modelAttribute="funcionario" action="${acao}"> <c:if test="${not empty funcionario.id}"> <div> <label>Código:</label> <p>${funcionario.id}</p> <sf:hidden path="id" /> </div> </c:if> <div> <label for="nome">Nome:</label> <sf:input path="nome" /> </div> <div> <label for="cpf">CPF:</label> <sf:input path="cpf" /> </div> <button type="submit">Salvar</button> </sf:form>[/CODE] Repare que a ação que o formulário acima vai chamar, ao ser submetido, continua sendo a mesma que apresentei pra você antes, ou seja, a ação salvar(). Isso não vai mudar. Agora vou mostrar a ação edicao() que vai ser chamada para abrir esse formulário. Ela é praticamente igual a ação novo() que já vimos também. Olhe só: [CODE]@RequestMapping(method = RequestMethod.GET, path = "/edicao") public ModelAndView edicao(@RequestParam Long id) { ModelAndView modelAndView = new ModelAndView("funcionario-formulario.jsp"); modelAndView.addObject("funcionario", funcionarios.findOne(id)); return modelAndView; }[/CODE] Basta invocarmos essa ação passando o identificador do funcionário que queremos editar para que ele faça a pesquisa do mesmo e devolva para nossa [I]view[/I] preparar o formulário que será enviado ao [I]browser[/I]. Um exemplo de URL para invocação seria: [URL]http://localhost:8080/app/funcionarios/edicao?id=1[/URL]. A única coisa de novo que a nova ação tem é a anotação @RequestParam. Como podemos ver, ela nos ajuda a ter acesso aos parâmetros da requisição de uma maneira mais simples. Uma observação aqui é que, se o parâmetro que vem pela URL for diferente do parâmetro da ação, então é preciso especificá-lo: [CODE]public ModelAndView edicao(@RequestParam("id") Long funcionario) { ... }[/CODE] Outra forma para anotar nosso método que deixaria a URL da página mais elegante, seria essa aqui: [CODE]@RequestMapping(method = RequestMethod.GET, path = "/{id}/edicao") public ModelAndView edicao(@PathVariable Long id) { ... }[/CODE] Não coloquei a implementação do método acima, pois, ela não se altera. O que muda é a URL para invocar a ação com esse novo mapeamento: [URL]http://localhost:8080/app/funcionarios/1/edicao[/URL]. Quanto a anotação @PathVariable, veremos ela ainda mais uma vez. Tem mais uma questão que envolve esse tópico aqui como um todo que é o seguinte: O Spring MVC é um framework [I]action-based[/I] e isso é pelo fato da própria ação enviar os dados para serem utilizados na página. Como fizemos aqui, enviando o objeto Funcionariopara ser editado. A ação recebe a requisição e ela mesma já trata de disponibilizar a informação (que seriam os objetos Java) que vai dinamizar as páginas que serão exibidas para o usuário final. [SIZE=5][B]Novas anotações de mapeamento[/B][/SIZE] A partir de versão 4.3.X do Spring Framework já temos disponíveis as seguintes anotações: [LIST] [*]@GetMapping [*]@PostMapping [*]@PutMapping [*]@DeleteMapping [*]@PatchMapping [/LIST] Podemos utilizá-las como alternativa a anotação @RequestMapping. Ao invés de utilizar assim: [CODE]@RequestMapping(method = RequestMethod.GET, path = "/novo")[/CODE] Usamos assim: [CODE]@GetMapping("/novo")[/CODE] É melhor porque além de não termos de configurar a propriedade method, melhora também a semântica dos nossos controladores. Veja como nosso controlador fica melhor com essas anotações: [CODE]@RequestMapping("/funcionarios") public class FuncionariosController { ... @GetMapping public ModelAndView listar() { ... } @GetMapping("/novo") public ModelAndView novo() { ... } @GetMapping("/edicao") public ModelAndView edicao(@RequestParam Long id) { ... } @PostMapping("/salvar") public RedirectView salvar(Funcionario funcionario, RedirectAttributes redirectAttributes) { ... } }[/CODE] [SIZE=5][B]Como configurar o ViewResolver[/B][/SIZE] ViewResolver é uma interface que ajuda o Spring MVC a encontrar as páginas que são retornadas por nossas ações. Para o código-fonte de exemplo que estou utilizando aqui (e irei disponibilizar para você) eu utilizei uma configuração diferente da padrão. A resolução padrão das páginas é feita em conjunto com a URL da requisição. No caso de, por exemplo, utilizarmos a URL [URL]http://localhost:8080/app/funcionarios/novo[/URL] para invocar nossa ação novo(): [CODE]@GetMapping("/novo") public String novo() { return "funcionario-formulario.jsp"; }[/CODE] Então, o Spring MVC iria procurar pela página funcionario-formulario.jsp em um diretório da nossa aplicação web chamada “funcionarios”. A configuração que utilizei é um pouco diferente. Foi estipulado a pasta “/WEB-INF/paginas/” para ser o diretório raiz de nossas páginas. Se quiséssemos um subdiretório com o nome “funcionarios”, teríamos que fazer o seguinte: [CODE]@GetMapping("/novo") public String novo() { return "funcionarios/funcionario-formulario.jsp"; }[/CODE] Assim o Spring MVC vai procurar nosso arquivo dentro da pasta “/WEB-INF/paginas/funcionarios/”. A configuração foi feita através do Java. Veja como ficou: [CODE]@Configuration public class ViewResolverConfig { @Bean public ViewResolver internalResourceViewResolver(){ InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setViewClass(JstlView.class); viewResolver.setPrefix("/WEB-INF/paginas/"); viewResolver.setViewNames(new String[] {"*.jsp"}); return viewResolver; } }[/CODE] [SIZE=5][B]Como usar o Spring MVC para criar uma API RESTful[/B][/SIZE] Quero terminar falando um pouco sobre os recursos que temos no Spring MVC para criarmos APIs RESTful. Mas não quero aqui falar sobre arquitetura e nem de boas práticas de APIs RESTful. Vou, simplesmente, mostrar o caminho de como fazer isso, beleza? Imagine que você precise retornar todos os funcionários da sua base no formado JSON. Olhe só como ficaria: [CODE]@Controller @RequestMapping("/funcionarios") public class FuncionariosController { ... @ResponseBody @GetMapping("/todos") public List<Funcionario> todos() { return funcionarios.findAll(); } }[/CODE] Veja que já devolvemos a lista de funcionários diretamente. Isso é porque estamos utilizando a anotação @ResponseBody. Ela diz ao Spring MVC para jogar o retorno do método na resposta. E antes de fazer uma requisição para nossa nova ação, que vai retornar a resposta em JSON, não podemos esquecer de adicionar a seguinte dependência em nosso pom.xml: [CODE]<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.8.5</version> </dependency>[/CODE] Aqueles que optaram por uma configuração com o Spring Boot, não precisaram adicionar a dependência acima, pois, ele já faz isso por você. Agora sim podemos fazer uma requisição para [URL]http://localhost:8080/app/funcionarios/todos[/URL]. Teríamos um JSON de retorno com os funcionários parecido com este: [CODE][ { "id": 1, "nome": "João", "cpf": "11111111111" }, { "id": 2, "nome": "Maria", "cpf": "11111111112" }, { "id": 3, "nome": "Mateus", "cpf": "11111111113" } ][/CODE] Melhor ainda se criarmos um novo controlador e, ao invés de anotá-lo com @controller, usarmos @RestController. Veja como ficaria: [CODE]@RestController @RequestMapping("/api/funcionarios") public class FuncionariosResource { @Autowired private Funcionarios funcionarios; @GetMapping public List<Funcionario> todos() { return funcionarios.findAll(); } }[/CODE] A URL para invocar a ação todos(), nesse novo controlador, fica assim agora: [URL]http://localhost:8080/app/api/funcionarios[/URL]. Repare que, como estamos utilizando a anotação @RestController, nosso método não precisou da anotação @ResponseBody. Para o caso da construção de APIs, essa última opção com @RestController, fica mais elegante. :) Vamos a um último exemplo para utilizarmos, mais uma vez, a anotação @PathVariable. Essa é uma anotação que serve para pegarmos informações do [I]path[/I] da nossa ação [CODE]@RestController @RequestMapping("/api/funcionarios") public class FuncionariosResource { @Autowired private Funcionarios funcionarios; @GetMapping("/{id}") public Funcionario buscar(@PathVariable Long id) { return funcionarios.findOne(id); } }[/CODE] O que vai acontecer agora com nossa ação buscar() é que, quando fizermos uma requisição para [URL]http://localhost:8080/app/api/funcionarios/1[/URL] o parâmetro id, especificado na anotação @GetMapping, será passado para nossa ação. Veja o resultado dessa última requisição: [CODE]{"id":1,"nome":"João","cpf":"11111111111"}[/CODE] [SIZE=5][B]Conclusão: Spring MVC é um framework web cheio de recursos[/B][/SIZE] Espero ter passado a você um boa impressão do Spring MVC, pois, é um excelente framework web, cheio de recursos. Vimos aqui a estrutura de um controlador e como configurar nossas ações. Depois mostrei as novas anotações de mapeamento para as ações. Ensinei como customizar a configuração do ViewController. Expliquei como receber dados de um formulário e como enviar objetos para serem utilizados em nossas páginas JSP. Por último, vimos como utilizar o Spring MVC para construir uma API RESTful. Espero que tenha gostado. ;) [SPOILER="Fonte:"] [URL]http://blog.algaworks.com/spring-mvc/[/URL] [/SPOILER] [/CENTER]

qRXaV1L.png

Link para o comentário
Compartilhar em outros sites

Este tópico está impedido de receber novos posts.
 Compartilhar

×
×
  • Criar Novo...

Informação Importante

Nós fazemos uso de cookies no seu dispositivo para ajudar a tornar este site melhor. Você pode ajustar suas configurações de cookies , caso contrário, vamos supor que você está bem para continuar.