Controlando o Spring MVC
Veja nesse artigo, diversos casos de como utilizar o @Controller, e o quão abrangente e flexível é essa ferramenta do Spring Framework.
Afinal, o que é Spring MVC?
Atualmente no desenvolvimento de software, o grande “bam bam bam” dos modelos de desenvolvimento é o MVC (“Model-View-Controller”), que foi descrito pela primeira vez por volta de 1970 por Trygve Reenskaug que trabalhavam com o Smalltalk (Linguagem de programação orientada a objeto). Foi criado para fugir da antiga bagunça, onde o código se misturava entre a página e a persistência. Esse modelo facilita a manutenabilidade do código, pois a mudança na view (página) não afeta o “Controller” ou o “model”, e vice versa.
O Spring, como não poderia ficar de fora, foi criado baseado no Spring MVC, onde temos o @Controller (que abordaremos mais a fundo nesse artigo), @Service (facilitador para acessar os Models a partir de um framework de persistência de sua escolha ou JDBC puro) e as Views. As nossas views são JSP, pois não é apenas isso que o framework possui.
Agora, vamos nos aprofundar nos Controllers do Spring e entender o que é possível criar com eles.
Relacionado: O Que é o Spring Framework?
Requisitos
Um Dinamic Web Project configurado com as bibliotecas do Spring e rodando corretamente.
Nota: Ver referência no fim do artigo para acessar artigo com exemplos de configuração - usaremos o mesmo projeto contido no artigo.
Um Controller é responsável tanto por receber requisições como por enviar a resposta ao usuário, algo bem parecido com o Servlet do JSP. Porém, é feito de forma mais elegante e fácil. O Controller se responsabiliza por informar a View, os atributos que serão visíveis para a mesma e também por receber parâmetros vindos da View. E, por último, responder ao usuário o que foi requisitado. Veja uma exemplo na Listagem 1.
@Controller //Define que minha classe será um controller
public class HomeController {
}
Veja como é simples criar um Controller, mas veja que este não possui nenhum “mapping” atrelado a ele. Então criemos uma view (.jsp) chamada “home.jsp” dentro da pasta “/WEB-INF/views” e criaremos o mapping “/home” para exibir a view criada. Veja a Listagem 2.
@Controller //Define que minha classe será um controller
public class HomeController {
@RequestMapping("/home") //Define a url que quando for requisitada chamara o metodo
public ModelAndView home(){
//Retorna a view que deve ser chamada, no caso home (home.jsp) aqui o .jsp é omitido
return new ModelAndView("home");
}
}
Agora sabemos como fazer uma requisição e retornar uma pagina, mas vamos supor que minha sessão home possuam várias páginas dentro dela, por exemplo /home/principal e /home/secundaria. Para isso, vamos fazer uma pequena alteração no nosso “HomeController”, conforme a Listagem 3.
@Controller //Define que minha classe será um controller
@RequestMapping("/home") //Define que qualquer ação desse controler deve preceder /home
public class HomeController {
//Define a url que quando for requisitada chamara o metodo no caso /home/principal ou /home/ ou /home
//Note que não é obrigado apenas uma url, pode-se mapear varias para o mesmo metodo
@RequestMapping( value = { "/" , "" ,"/principal" })
public ModelAndView homePrincipal(){
//Retorna a view que deve ser chamada, no caso principal (principal.jsp) que esta dentro da pasta /home
return new ModelAndView("home/principal");
}
//Define a url que quando for requisitada chamara o metodo
@RequestMapping( "/secundaria" )
public ModelAndView homeSecundaria(){
//Retorna a view que deve ser chamada, no caso secundaria (secundaria.jsp) que esta dentro da pasta /home
return new ModelAndView("home/secundaria");
}
}
Nota: Não necessariamente as views deverão estar contidas na pasta “/home”, é apenas uma forma de organizá-las melhor.
Passando parâmetros
Agora já entendemos melhor como funcionam as requisições e as respostas do “Controller”, agora veremos como receber parâmetros e passar atributos para a “View”. Para isso, criaremos um novo “Controller” chamado “ParamController” e seguiremos o mesmo caminho do “HomeController”, mas agora acessando o a url “/param”. Observe a Listagem 4.
@Controller
@RequestMapping("/param")
public class ParamController {
@RequestMapping(value = { "" , "/" } )
public ModelAndView recebeParam(@RequestParam String nome , Model model){
//@RequestParam indica que recebera um parametro "nome" que é uma String
//Model é um auxuliar que ajudara a adicionar atributos a nossa view
model.addAttribute("nome" , nome);
return new ModelAndView("param/index");
}
}
Não esqueça de criar dentro de “WEB-INF/views” a pasta “param” e dentro dela a view “index.jsp”, como descrito naListagem 5.
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Controllers Spring</title>
</head>
<body>
<h1>Param - Index</h1>
<p>Parametro nome = "<%= request.getAttribute("nome") %>"</p>
<p>Pagina chamada a partir do mapping em ParamController</p>
</body>
</html>
Explicando o que foi feito: ao mapear o @RequestParam eu estou dizendo ao método que ele deve esperar como parâmetro de nome “nome” uma String, ou seja, ao acessar “/param?nome=SeuNomeAqui” o parâmetro nome será atribuído a variável “nome”, e o “Model” se encarregará de enviá-lo como atributo a tela.
Muito fácil não? Mas espere: e se o parâmetro não for passado, o que acontecerá? Será retornado um erro: “Required String parameter 'nome' is not presente”. Para a segurança e garantia do funcionamento da aplicação isso é ótimo, mas caso não queria que o parâmetro seja obrigatório, basta mapeá-lo como “@RequestParam(required = false)”, e veja como o nome recebe null, e nenhum erro será retornado. O uso dependerá de sua necessidade.
Limitando os tipos de métodos recebidos
Agora veremos como podemos limitar um mapping para receber apenas as requisições via “POST” ou “GET”.
Nota: Não será abordado RESTful nesse artigo.
Para limitarmos um Mapping para receber apenas requisições “GET” ou “POST” adicionaremos ao nosso “ParamController” dois novos métodos (Mappings). Veja na Listagem 6.
@Controller
@RequestMapping("/param")
public class ParamController {
@RequestMapping(value = { "" , "/" } )
public ModelAndView recebeParam(@RequestParam(required = false) String nome , Model model){
//@RequestParam indica que recebera um parametro "nome" que é uma String
//Model é um auxuliar que ajudara a adicionar atributos a nossa view
model.addAttribute("nome" , nome);
return new ModelAndView("param/index");
}
@RequestMapping(value="/postonly" , method = RequestMethod.POST)
public ModelAndView postOnly(){
// o method define que tipo de requisição esse mapping vai aceitar
return new ModelAndView("param/postonly");
}
@RequestMapping(value="/getonly" , method = RequestMethod.GET)
public ModelAndView getOnly(){
return new ModelAndView("param/getonly");
}
}
Ao definir o “method” dizemos ao nosso controller que só será executado o método caso seja uma requisição do tipo especificado. Caso nenhum “method” seja definido no @RequestMapping, por default ele receberá tanto GET quanto POST. Caso tente acessar um mapping POST via GET ou vice versa, será retornado um erro:” Request method 'GET' not supported”. O recebimento de parâmetros e envio de atributos para a view continuam iguais sem nenhuma alteração.
Acesse a URL no seu servidor “param/getonly” e veja que ocorre tudo normalmente. Agora tente acessar “param/postonly” e veja o erro.
Recebendo formulários completos
Já vimos como receber parâmetros, como limitar o tipo de requisição aceita. E os formulários? Calma, não será necessária uma lista gigante de @RequestParam, a não ser que goste de escrever!
O Spring fornece uma anotação chamada @ModelAttribute que pode ser um POJO, um Domain etc... Utilizaremos um POJO (Plain Old Java Object - classe contendo apenas um construtor padrão, atributos e getters and setters) como exemplo e usaremos também a tag de formulário do Spring para nos auxiliar no envio. Criemos então um controller chamado “FormController”, como na Listagem 7.
@Controller
@RequestMapping("/form")
public class FormController {
@RequestMapping(value = { "/" , "" } , method = RequestMethod.GET)
public ModelAndView carregaForm(Model model){
model.addAttribute("form", new Form());
return new ModelAndView("form/form");
}
@RequestMapping(value = { "/" , "" } , method = RequestMethod.POST)
public ModelAndView recebeForm(@ModelAttribute("form") Form form, Model model){
model.addAttribute("msg", "Você enviou: " + form.getNome() + " " + form.getSobrenome() );
return new ModelAndView("form/form");
}
}
Como devem ter percebido, temos dois @RequestMapping apontando para o mesmo caminho. O Spring fará a diferença de que método será chamado pelo tipo de requisição que está sendo feita. Veja também que está sendo adicionado a nossa view um objeto ”Form”. Criaremos agora o nosso objeto Form, como na Listagem 8.
public class Form {
private String nome;
private String sobrenome;
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public String getSobrenome() {
return sobrenome;
}
public void setSobrenome(String sobrenome) {
this.sobrenome = sobrenome;
}
}
Agora criaremos a nossa view contendo o formulário. Para isso, adicionaremos uma jsp em “/WEB-INF/views/form/” com o nome “form.jsp”. Veja a Listagem 9.
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Controllers Spring</title>
</head>
<body>
<jsp:include page="/WEB-INF/views/_menu.jsp" />
<h1>Form</h1>
<p>Pagina chamada a partir do mapping em FormController</p>
<form:form id="frmForm" action="" method="post" modelAttribute="form">
<div>
<form:label path="nome" css>Nome:</form:label>
<form:input path="nome"/>
</div>
<div>
<form:label path="sobrenome" css>Sobrenome:</form:label>
<form:input path="sobrenome"/>
</div>
<form:button>Enviar</form:button>
</form:form>
<%= (request.getAttribute("msg") != null) ? request.getAttribute("msg") : "" %>
</body>
</html>
Veja que importamos a taglib “form” do Spring. Ela irá nos auxiliar a ler um objeto que tenha sido passado pelo “Controller”. Vamos dissecar o nosso formulário:
<form:form id="frmForm" action="" method="post" modelAttribute="form">
Perceba o atributo “modelAttribute=’form’”, com ele dizemos ao nosso formulário com que objeto estamos trabalhando, no casso o objeto “form” que foi adicionado ao chamar a view.
<form:label path="nome" css>Nome:</form:label>
A tag form:label criará um label para o atributo “nome”, como foi especificado através de “path”. “cssStyle” é o mesmo que o “style” do HTML e foi adicionado apenas para deixar um pouco mais apresentável o formulário.
<form:input path="nome"/>
A tag “form:input” criará um campo para o atributo “nome” do nosso objeto “form”.
<form:button>Enviar</form:button>
A tag “form:button” criará um botão de envio do formulário.
Agora com tudo pronto rode sua aplicação, acesse a página do formulário e veja o resultado na Figura 1.
E a Figura 2 mostra após o envio do formulário.
Veja que o formulário já vem preenchido, o Spring faz isso por você. Note também que tudo que foi enviado ao formulário será inserido no @ModelAttribute do nosso método “recebeForm()”e no nosso Controller.
Concluindo
O Spring nos fornece várias ferramentas de fácil uso e de rápido aprendizado. Veja que é um framework bastante rápido e sem muito peso para o nosso servidor.
Até a próxima.
Links Úteis
Saiba mais sobre Spring ;)
-
Introdução ao Spring Framework:
Veja nesse artigo uma introdução ao Spring Framework, um dos mais utilizados em projetos na linguagem Java. Conheça um pouco sobre o framework e implemente um exemplo de Hello World. -
Spring MVC: Construa aplicações responsivas com
Bootstrap:
Desenvolva aplicações responsivas integrando o framework web da Spring com o Bootstrap, uma das bibliotecas de front-end mais conhecidas. -
Persistência de dados: JPA ou Spring Data JPA?:
Conheça as diferenças entre a especificação JPA e o módulo Spring Data JPA e facilite o seu dia a dia na implementação de funcionalidades relacionadas à persistência de dados.
Artigos relacionados
-
Artigo
-
Artigo
-
Artigo
-
Artigo
-
Vídeo