Upload
others
View
34
Download
0
Embed Size (px)
Citation preview
Spring Framework Parte 03 – Spring MVC
Spring MVC
• Módulo do Spring Framework que permite o desenvolvimento de aplicações web baseadas em ações (action based) bem como o desenvolvimento de serviços REST.
• Integra-se à API de Servlets. • Suporta:
– Diversas tecnologias de visão tais como JSP/JSTL, Velocity, FreeMarker, Thymeleaf, Tiles, XSLT e Groovy Markup Templates.
– Processamento assíncrono. – Internacionalização.
• Oferece funcionalidades de segurança e de testes.
2
Padrão front controller
3
Dispatcher Servlet
Web controller
Handler mapping
View resolver
View
1: HTTP request
2: HTTP request
3: Web controller
4: HTTP request
5: model and view name
6: view name
7: view 8: model 9: HTTP Response
10: HTTP Response
Controlador web
• Objeto responsável por responder um conjunto de requisições HTTP.
• As requisições atendíveis podem ser especificadas através de padrões de URL, por cabeçalhos HTTP e por métodos HTTP.
4
Anotações e classes
• @Controller: define um controlador web. • @RequestMapping: definições das requisições HTTP
a serem atendidas. • @RequestParam: define um parâmetro query string. • @PathVariable: referencia parâmetros em URLs
estilo REST. • org.springframework.ui.Model: para armazenar
objetos acessados pela view. • org.springframework.web.servlet.ModelAndView:
para armazenar o nome da view e objetos acessados pela view.
5
Atualizando as configurações
• Adicionar JSTL como dependência no pom.xml:
6
<dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> </dependency>
Atualizando as configurações
• Disponibilizando o contexto do Spring para o contexto da aplicação web:
7
... public class SpringMVCServlet extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[]{AppConfig.class}; } ... }
CRUD Fabricante: listagem
• Controlador web (1):
8
package cursoSpring.revenda_veiculos.web; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import cursoSpring.revenda_veiculos.dominio.FabricanteRepository; @Controller @RequestMapping("/fabricantes") public class CRUDFabricante { @Autowired private FabricanteRepository repositorio;
CRUD Fabricante: listagem
• Controlador web (2):
9
@RequestMapping public String inicio(Model model){ model.addAttribute("fabricantes", repositorio.todos()); return "fabricantes/inicio"; } }
CRUD Fabricante: listagem
• Controlador web (2):
10
@RequestMapping public String inicio(Model model){ model.addAttribute("fabricantes", repositorio.todos()); return "fabricantes/inicio"; } }
Visão (página) a ser renderizada com os dados inseridos em model.
CRUD Fabricante: listagem
• Página src/main/webapp/WEB-INF/views/fabricantes/inicio.jsp (1):
11
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <!DOCTYPE html> <html> <head> <title>Fabricantes</title> </head> <body> <h2>Fabricantes</h2> <table> <tr> <th>Fabricante</th> <th colspan="2">Opções</th> </tr>
CRUD Fabricante: listagem
• Página src/main/webapp/WEB-INF/views/fabricantes/inicio.jsp (2):
12
<c:forEach var="fabricante" items="${fabricantes}"> <tr> <td>${fabricante.descricao}</td> <td> EXCLUIR </td> <td> ALTERAR </td> </tr> </c:forEach> </table> </body> </html>
CRUD Fabricante: exclusão
• Controlador web (1):
13
... import org.springframework.web.bind.annotation.RequestParam; @Controller @RequestMapping("/fabricantes") public class CRUDFabricante { ...
CRUD Fabricante: exclusão
• Controlador web (2):
14
... @RequestMapping("/excluir") public String excluir(@RequestParam("id") Integer idFabricante, Model model){ try{ repositorio.excluir(idFabricante); model.addAttribute("mensagem", "Fabricante excluído com sucesso."); }catch(Exception ex){ ex.printStackTrace(); model.addAttribute("mensagem", "Ocorreu um erro durante a operação."); } return "forward:/fabricantes"; } }
CRUD Fabricante: exclusão
• Controlador web (2):
15
... @RequestMapping("/excluir") public String excluir(@RequestParam("id") Integer idFabricante, Model model){ try{ repositorio.excluir(idFabricante); model.addAttribute("mensagem", "Fabricante excluído com sucesso."); }catch(Exception ex){ ex.printStackTrace(); model.addAttribute("mensagem", "Ocorreu um erro durante a operação."); } return "forward:/fabricantes"; } }
Como queremos voltar à listagem de fabricantes após a exclusão, aproveitamos o método inicio
realizando um forward para a URL /fabricantes.
CRUD Fabricante: exclusão
• fabricante/inicio.jsp:
16
<h2>Fabricantes</h2> <c:url var="actionUrl" value="/fabricantes" /> <c:if test="${not empty mensagem}"> <p style="border: 1px solid black;">${mensagem}</p> </c:if> <table> ... <td>${fabricante.descricao}</td> <td> <a href="${actionUrl}/excluir?id=${fabricante.id}"> EXCLUIR </a> </td> ...
Forward e Redirect
• É comum que após processar uma requisição o controlador web direcione o fluxo da aplicação para uma página diferente da utilizada na submissão.
• Temos duas formas disponíveis: forward e redirect.
• Diferença básica:
– No forward o processamento é realizado no servidor.
– No redirect a mudança de página é feita pelo browser.
17
Forward
• As mudanças de URL são todas processadas no servidor antes da resposta ser enviada ao cliente.
• Por haver apenas uma requisição, o mesmo contexto de requisição é utilizado pelas páginas e métodos envolvidos no processamento.
– O mesmo model fica disponível a todos os métodos Java.
• Ao final do processamento da requisição, a URL na barra de endereços do navegador não muda. Assim, o reload da página resultante irá executar a requisição original.
18
Forward
19
Redirect
• É um mecanismo especificado pelo HTTP. • Dois passos. Ao receber uma requisição, a aplicação
pede ao browser para acessar uma segunda URL. – Por isso a URL na barra de endereços muda. – O “pedido” é um recurso do HTTP: código 301 ou 302 e
cabeçalho Location.
• O reload de página não repetirá a requisição original, mas sim a segunda URL.
• Como acontecem duas requisições, os dados da primeira requisição, não estarão disponíveis no contexto da segunda requisição. – Um model diferente por método Java.
20
Redirect
21
Flash scope
• Utilizado para manter dados que devem estar disponíveis após um redirect.
• Para utilizar o flash scope basta declarar um parâmetro do tipo RedirectAttributes.
22
CRUD Fabricante: exclusão com redirect
• Controlador web (1):
23
... import org.springframework.web.servlet.mvc.support.RedirectAttributes; ... public class CRUDFabricante { ...
CRUD Fabricante: exclusão com redirect
• Controlador web (2):
24
... @RequestMapping("/excluir") public String excluir(@RequestParam("id") Integer idFabricante, RedirectAttributes redAttr){ try{ repositorio.excluir(idFabricante); redAttr.addFlashAttribute("mensagem", "Fabricante excluído com sucesso."); }catch(Exception ex){ ex.printStackTrace(); redAttr.addFlashAttribute("mensagem", "Ocorreu um erro durante a operação."); } return "redirect:/fabricantes"; } }
CRUD Fabricante: novo registro
• Atualizando pom.xml com bean validation:
25
<dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> </dependency>
CRUD Fabricante: novo registro
• Decorando Fabricante com anotações da bean validation:
26
... import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; @Entity @Table(name="FABRICANTES") public class Fabricante extends Entidade{ @NotNull @Size(min=2) private String descricao; ...
CRUD Fabricante: novo registro
• inicio.jsp – link para um novo registro:
27
... <h2>Fabricantes</h2> <c:url var="actionUrl" value="/fabricantes" /> <c:if test="${not empty mensagem}"> <p style="border: 1px solid black;">${mensagem}</p> </c:if> <a href="${actionUrl}/novo">Novo fabricante</a> <table> ...
CRUD Fabricante: novo registro
• Controlador web – método novo:
28
import org.springframework.web.servlet.ModelAndView; import cursoSpring.revenda_veiculos.dominio.Fabricante; ... @RequestMapping("/novo") public ModelAndView novo(){ ModelAndView modelAndView = new ModelAndView("fabricantes/edicao"); modelAndView.addObject("fabricante", new Fabricante()); modelAndView.addObject("titulo", "Novo Fabricante"); return modelAndView; } ...
CRUD Fabricante: novo registro
• Controlador web – método novo:
29
import org.springframework.web.servlet.ModelAndView; import cursoSpring.revenda_veiculos.dominio.Fabricante; ... @RequestMapping("/novo") public ModelAndView novo(){ ModelAndView modelAndView = new ModelAndView("fabricantes/edicao"); modelAndView.addObject("fabricante", new Fabricante()); modelAndView.addObject("titulo", "Novo Fabricante"); return modelAndView; } ... O objeto fabricante será utilizado
para receber os valores do campos do formulário.
CRUD Fabricante: novo registro
• Controlador web – método novo:
30
import org.springframework.web.servlet.ModelAndView; import cursoSpring.revenda_veiculos.dominio.Fabricante; ... @RequestMapping("/novo") public ModelAndView novo(){ ModelAndView modelAndView = new ModelAndView("fabricantes/edicao"); modelAndView.addObject("fabricante", new Fabricante()); modelAndView.addObject("titulo", "Novo Fabricante"); return modelAndView; } ...
É informado o título da página pois a mesma página será utilizada nas operações de novo fabricante e edição de fabricante.
CRUD Fabricante: novo registro
• Página edicao.jsp (1):
31
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %> <!DOCTYPE html> <html> <head> <title>${titulo}</title> </head> <body> <h2>${titulo}</h2> <c:url var="actionUrl" value="/fabricantes/salvar" />
CRUD Fabricante: novo registro
• Página edicao.jsp (1):
32
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %> <!DOCTYPE html> <html> <head> <title>${titulo}</title> </head> <body> <h2>${titulo}</h2> <c:url var="actionUrl" value="/fabricantes/salvar" />
Biblioteca de tags Spring para manipulação de formulários.
CRUD Fabricante: novo registro
• Página edicao.jsp (2):
33
<form:form action="${actionUrl}" method="post" modelAttribute="fabricante"> <label for="descricao">DESCRIÇÃO</label> <form:input path="descricao"/> <form:errors path="descricao" cssStyle="color: red"/> <form:hidden path="id"/> <input type="hidden" name="titulo" value="${titulo}"> <br> <button type="submit">Salvar</button> </form:form> </body> </html>
CRUD Fabricante: novo registro
• Página edicao.jsp (2):
34
<form:form action="${actionUrl}" method="post" modelAttribute="fabricante"> <label for="descricao">DESCRIÇÃO</label> <form:input path="descricao"/> <form:errors path="descricao" cssStyle="color: red"/> <form:hidden path="id"/> <input type="hidden" name="titulo" value="${titulo}"> <br> <button type="submit">Salvar</button> </form:form> </body> </html>
Define o identificador do objeto que será utilizado (binding) para receber/preencher os
campos do formulário. O objeto será inserido no contexto do model. Note que este é o
identificador a ser utilizado no controlador para acessar os campos do formulário.
CRUD Fabricante: novo registro
• Controlador web – método salvar (1):
35
import javax.validation.Valid; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMethod; ... @RequestMapping(value="/salvar", method=RequestMethod.POST) public String salvar( @Valid @ModelAttribute("fabricante") Fabricante fabricante, BindingResult br, @RequestParam("titulo") String titulo, Model model, RedirectAttributes rAttrs){ if(br.hasErrors()){ model.addAttribute("titulo", titulo); return "fabricantes/edicao"; }
CRUD Fabricante: novo registro
• Controlador web – método salvar (1):
36
import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMethod; ... @RequestMapping(value="/salvar", method=RequestMethod.POST) public String salvar( @Valid @ModelAttribute("fabricante") Fabricante fabricante, BindingResult br, @RequestParam("titulo") String titulo, Model model, RedirectAttributes rAttrs){ if(br.hasErrors()){ model.addAttribute("titulo", titulo); return "fabricantes/edicao"; }
Indica que os atributos do objeto devem ser validados
segundo as anotações da Bean Validation.
Indica que o spring deve injetar um objeto presente no contexto do model e que é identificado pela string fabricante. Na
página, usamos o mesmo identificador.
Armazena o resultado da validação.
CRUD Fabricante: novo registro
• Controlador web – método salvar (2):
37
try{ if(fabricante.getId() == null) repositorio.inserir(fabricante); else repositorio.atualizar(fabricante); rAttrs.addFlashAttribute("mensagem", "Fabricante salvo com sucesso."); }catch(Exception ex){ ex.printStackTrace(); rAttrs.addFlashAttribute("mensagem", "Ocorreu um erro durante a operação."); } return "redirect:/fabricantes"; } ...
CRUD Fabricante: alterar registro
• inicio.jsp – link de edição:
38
... <td> <a href="${actionUrl}/editar/${fabricante.id}"> ALTERAR </a> </td> ...
CRUD Fabricante: alterar registro
• Controlador web:
39
import org.springframework.web.bind.annotation.PathVariable; ... @RequestMapping("/editar/{id}") public String editar(@PathVariable Integer id, Model model){ Fabricante f = repositorio.getPorId(id); if(f == null) return "forward:/fabricantes"; model.addAttribute("fabricante", f); model.addAttribute("titulo", "Alterar Fabricante"); return "fabricantes/edicao"; } }
Outras tags Spring para formulários
• checkbox: produz um campo input do tipo checkbox. Pode ser associada a atributos com um ou muitos valores (coleções e arrays). Quando seu valor não é indicado, é assumido o tipo boolean.
• checkboxes: gera vários campos do tipo checkbox a partir de uma coleção.
• radiobutton: produz uma tag input do tipo radio. • radiobuttons: gera um conjunto relacionado de radio buttons a
partir de uma coleção. • password: gera uma tag input do tipo password. • option: gera uma tag option para um campo select. • options: opções de um campo select gerados a partir de uma
coleção. • textarea: produz uma tag textarea.
40
CRUD Veículo
• Classe Foto:
41
package cursoSpring.revenda_veiculos.dominio; import javax.persistence.Embeddable; @Embeddable public class Foto { @Basic(fetch=FetchType.LAZY) private byte[] bytes; private String mimeType; public Foto() {} public Foto(byte[] bytes, String mimeType) { this.bytes = bytes; this.mimeType = mimeType; } //getters e setters... }
CRUD Veículo
• Classe Veiculo (1):
42
package cursoSpring.revenda_veiculos.dominio; import javax.persistence.Basic; import javax.persistence.Embedded; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; @Entity @Table(name="VEICULOS") public class Veiculo extends Entidade {
CRUD Veículo
• Classe Veiculo (2):
43
@Min(1900) @NotNull private Integer anoFabricacao; @Pattern(regexp="[A-Z]{3}\\d{4}") @NotNull private String placa; private String chassi; @Embedded private Foto foto; @Min(50) private Integer cilindradas;
CRUD Veículo
• Classe Veiculo (3):
44
@NotNull @ManyToOne @JoinColumn(name="ID_MODELO") private Modelo modelo; public Veiculo() {} public Veiculo(Integer id, String placa){ super(id); this.placa = placa; }
CRUD Veículo
• Classe Veiculo (4):
45
public String getMimeTypeFoto() { if(foto != null) return foto.getMimeType(); return null; } //getters e setters ... }
CRUD Veículo
• create-schema.sql:
• drop-schema.sql:
46
... create table VEICULOS (ID int auto_increment, ANOFABRICACAO int not null, PLACA varchar(10) not null, CHASSI varchar(50), CILINDRADAS int, BYTES blob, MIMETYPE varchar(50), ID_MODELO int not null, primary key(ID), foreign key(ID_MODELO) references MODELOS);
drop table VEICULOS; ...
CRUD Veículo
• Interface VeiculoRepositorio:
47
package cursoSpring.revenda_veiculos.dominio; import java.util.List; public interface VeiculoRepositorio { public Integer inserir(Veiculo v); public void excluir(Integer id); public List<Veiculo> todos(); public Veiculo getPorId(Integer id); public Foto getFoto(Integer idVeiculo); }
CRUD Veículo
• Classe VeiculoDAO (1):
48
package cursoSpring.revenda_veiculos.dao; import java.util.List; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; import cursoSpring.revenda_veiculos.dominio.Foto; import cursoSpring.revenda_veiculos.dominio.Veiculo; import cursoSpring.revenda_veiculos.dominio.VeiculoRepositorio; @Repository @Transactional public class VeiculoDAO implements VeiculoRepositorio {
CRUD Veículo
• Classe VeiculoDAO (2):
49
@Autowired private SessionFactory sessionFactory; @Override public Integer inserir(Veiculo v) { sessionFactory.getCurrentSession().save(v); return v.getId(); } @Override public void excluir(Integer id) { String hql = "delete Veiculo where id = :idVeiculo"; Session session = sessionFactory.getCurrentSession(); Query q = session.createQuery(hql). setParameter("idVeiculo", id); q.executeUpdate(); }
CRUD Veículo
• Classe VeiculoDAO (3):
50
@Override public List<Veiculo> todos() { Session session = sessionFactory.getCurrentSession(); return session.createQuery("from Veiculo").list(); } @Override public Veiculo getPorId(Integer id) { Session session = sessionFactory.getCurrentSession(); return (Veiculo)session.get(Veiculo.class, id); }
CRUD Veículo
• Classe VeiculoDAO (4):
51
@Override public Foto getFoto(Integer idVeiculo) { String hql = "select v.foto from Veiculo v where v.id = :id "; Session session = sessionFactory.getCurrentSession(); Query q = session.createQuery(hql). setParameter("id", idVeiculo); return (Foto)q.uniqueResult(); } }
CRUD Veículo
• Página veiculos/inicio.jsp (1):
52
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <!DOCTYPE html> <html> <head> <title>Veículos</title> </head> <body> <h2>Veículos</h2> <c:url var="actionUrl" value="/veiculos" /> <c:if test="${not empty mensagem}"> <p style="border: 1px solid black;">${mensagem}</p> </c:if> <a href="${actionUrl}/novo">Novo veículo</a>
CRUD Veículo
• Página veiculos/inicio.jsp (2):
53
<table> <tr> <th>Placa</th> <th>Fabricante</th> <th>Modelo</th> <th>Ano</th> <th>Cilindradas</th> <th colspan="2">Opções</th> </tr> <c:forEach var="veiculo" items="${veiculos}"> <tr> <td>${veiculo.placa}</td> <td>${veiculo.modelo.fabricante.descricao}</td> <td>${veiculo.modelo.descricao}</td> <td>${veiculo.anoFabricacao}</td> <td>${veiculo.cilindradas}</td>
CRUD Veículo
• Página veiculos/inicio.jsp (3):
54
<td> <a href="${actionUrl}/excluir/${veiculo.id}"> EXCLUIR </a> </td> </tr> </c:forEach> </table> </body> </html>
CRUD Veículo
• Página veiculos/edicao.jsp (1):
55
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %> <!DOCTYPE html> <html> <head> <title>Novo veículo</title> </head> <body> <h2>Novo veículo</h2> <c:url var="actionUrl" value="/veiculos/salvar" /> <form:form action="${actionUrl}" method="post" modelAttribute="veiculo" >
CRUD Veículo
• Página veiculos/edicao.jsp (2):
56
<label for="placa">PLACA</label> <form:input path="placa"/>* <form:errors path="placa" cssStyle="color: red"/><br> <label for="anoFabricacao">ANO</label> <form:input path="anoFabricacao"/>* <form:errors path="anoFabricacao" cssStyle="color: red"/><br> <label for="cilindradas">CILINDRADAS</label> <form:input path="cilindradas"/> <form:errors path="cilindradas" cssStyle="color: red"/><br> <label for="chassi">CHASSI</label> <form:input path="chassi"/> <form:errors path="chassi" cssStyle="color: red"/><br>
CRUD Veículo
• Página veiculos/edicao.jsp (3):
57
<label for="selectModelo">MODELO</label> <form:select path="modelo.id" id="selectModelo" > <form:options items="${modelos}" itemValue="id" itemLabel="descricao" /> </form:select> <form:errors path="modelo" cssStyle="color: red"/><br> <button type="submit">Salvar</button> </form:form> </body> </html>
CRUD Veículo
• Classe CRUDVeiculo (1):
58
package cursoSpring.revenda_veiculos.web; import java.util.List; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import cursoSpring.revenda_veiculos.dominio.Modelo; import cursoSpring.revenda_veiculos.dominio.ModeloRepository;
CRUD Veículo
• Classe CRUDVeiculo (2):
59
import cursoSpring.revenda_veiculos.dominio.Veiculo; import cursoSpring.revenda_veiculos.dominio.VeiculoRepositorio; @Controller @RequestMapping("/veiculos") public class CRUDVeiculo { @Autowired private VeiculoRepositorio veiculoRepositorio; @Autowired private ModeloRepository modeloRepositorio; @ModelAttribute("modelos") public List<Modelo> listaDeModelos(){ return modeloRepositorio.todos(); }
CRUD Veículo
• Classe CRUDVeiculo (2):
60
import cursoSpring.revenda_veiculos.dominio.Veiculo; import cursoSpring.revenda_veiculos.dominio.VeiculoRepositorio; @Controller @RequestMapping("/veiculos") public class CRUDVeiculo { @Autowired private VeiculoRepositorio veiculoRepositorio; @Autowired private ModeloRepository modeloRepositorio; @ModelAttribute("modelos") public List<Modelo> listaDeModelos(){ return modeloRepositorio.todos(); }
@ModelAttribute insere o retorno do método no
contexto model. Assim, a lista de modelos ficará disponível
para as páginas acessadas através deste controlador.
CRUD Veículo
• Classe CRUDVeiculo (3):
61
@RequestMapping public ModelAndView inicio(){ ModelAndView modelAndView = new ModelAndView("veiculos/inicio"); modelAndView.addObject("veiculos", veiculoRepositorio.todos()); return modelAndView; } @RequestMapping("/novo") public ModelAndView novo(){ ModelAndView modelAndView = new ModelAndView("veiculos/edicao"); modelAndView.addObject("veiculo", new Veiculo()); return modelAndView; }
CRUD Veículo
• Classe CRUDVeiculo (4):
62
@RequestMapping(value="/salvar", method=RequestMethod.POST) public String salvar(@Valid @ModelAttribute("veiculo") Veiculo veiculo, BindingResult br, Model model, RedirectAttributes rAttrs){ if(br.hasErrors()){ return "veiculos/edicao"; } try{ veiculoRepositorio.inserir(veiculo); rAttrs.addFlashAttribute("mensagem", "Veículo salvo com sucesso."); }catch(Exception ex){ ex.printStackTrace(); rAttrs.addFlashAttribute("mensagem", "Ocorreu um erro durante a operação."); } return "redirect:/veiculos"; }
CRUD Veículo
• Classe CRUDVeiculo (5):
63
@RequestMapping("/excluir/{id}") public String excluir(@PathVariable Integer id, RedirectAttributes redAttr){ try{ veiculoRepositorio.excluir(id); redAttr.addFlashAttribute("mensagem", "Veículo excluído com sucesso."); }catch(Exception ex){ ex.printStackTrace(); redAttr.addFlashAttribute("mensagem", "Ocorreu um erro durante a operação."); } return "redirect:/veiculos"; } }
CRUD Veículo
• Classe ModeloDAO:
64
... import org.springframework.transaction.annotation.Transactional; @Repository @Transactional public class ModeloDAO implements ModeloRepository { ... }
CRUD Veículo: upload da foto
• Dependência para upload de arquivos:
65
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> </dependency>
CRUD Veículo: upload da foto
• Classe AppConfig – adição do bean gerenciador de uploads:
66
... import org.springframework.web.multipart.commons.CommonsMultipartResolver; ... @Bean public CommonsMultipartResolver multipartResolver(){ CommonsMultipartResolver resolver = new CommonsMultipartResolver(); resolver.setMaxUploadSize(1024 * 1024 * 5); resolver.setMaxInMemorySize(1024 * 1024 * 5); return resolver; } }
CRUD Veículo: upload da foto
• Página veiculos/edicao.jsp:
67
<form:form action="${actionUrl}" method="post" modelAttribute="veiculo" enctype="multipart/form-data"> ... <label for="arquivoFoto">FOTO</label> <input type="file" name="arquivoFoto" accept="image/*"/> <button type="submit">Salvar</button> </form:form> ...
CRUD Veículo: upload da foto
• CRUDVeiculo – atualização do método salvar (1):
68
... @RequestMapping(value="/salvar", method=RequestMethod.POST) public String salvar(@Valid @ModelAttribute("veiculo") Veiculo veiculo, BindingResult br, Model model, RedirectAttributes rAttrs, @RequestParam("arquivoFoto") MultipartFile file){ if(br.hasErrors()){ return "veiculos/edicao"; } try{ if(file != null){ Foto foto = new Foto(file.getBytes(), file.getContentType()); veiculo.setFoto(foto); }
CRUD Veículo: upload da foto
• CRUDVeiculo – atualização do método salvar (1):
69
... @RequestMapping(value="/salvar", method=RequestMethod.POST) public String salvar(@Valid @ModelAttribute("veiculo") Veiculo veiculo, BindingResult br, Model model, RedirectAttributes rAttrs, @RequestParam("arquivoFoto") MultipartFile file){ if(br.hasErrors()){ return "veiculos/edicao"; } try{ if(file != null){ Foto foto = new Foto(file.getBytes(), file.getContentType()); veiculo.setFoto(foto); }
Será preenchido com o arquivo submetido. Note que a string
arquivoFoto corresponde ao nome dado ao campo file presente no
formulário de submissão.
CRUD Veículo: upload da foto
• CRUDVeiculo – atualização do método salvar (2):
70
veiculoRepositorio.inserir(veiculo); rAttrs.addFlashAttribute("mensagem", "Veículo salvo com sucesso."); }catch(Exception ex){ ex.printStackTrace(); rAttrs.addFlashAttribute("mensagem", "Ocorreu um erro durante a operação."); } return "redirect:/veiculos"; } ...
CRUD Veículo: acessando a foto com Ajax
• veiculos/inicio.jsp (1):
71
... <head> <c:url var="actionUrl" value="/veiculos" /> <title>Veículos</title> <script src="http://code.jquery.com/jquery-1.11.3.min.js"> </script> <script src="http://code.jquery.com/ui/1.11.4/jquery-ui.min.js"> </script> <script> $(function() { $("#dialogFoto").dialog({ autoOpen: false }); });
CRUD Veículo: acessando a foto com Ajax
• veiculos/inicio.jsp (1):
72
... <head> <c:url var="actionUrl" value="/veiculos" /> <title>Veículos</title> <script src="http://code.jquery.com/jquery-1.11.3.min.js"> </script> <script src="http://code.jquery.com/ui/1.11.4/jquery-ui.min.js"> </script> <script> $(function() { $("#dialogFoto").dialog({ autoOpen: false }); });
Esta instrução foi movida para o início da tag head para que a URL já esteja
disponível aos scripts em JS.
CRUD Veículo: acessando a foto com Ajax
• veiculos/inicio.jsp (2):
73
function verFoto(idVeiculo){ var imgUrl = '${actionUrl}/foto/'+idVeiculo; $('#imgFoto').attr('src', imgUrl); $('#dialogFoto').dialog("open"); } </script> </head> ...
CRUD Veículo: acessando a foto com Ajax
• veiculos/inicio.jsp (3):
74
... <td>${veiculo.cilindradas}</td> <td> <c:choose> <c:when test="${not empty veiculo.foto}"> <a href="#" onclick="verFoto(${veiculo.id})"> VER FOTO </a> </c:when> <c:otherwise> -- </c:otherwise> </c:choose> </td> ...
CRUD Veículo: acessando a foto com Ajax
• veiculos/inicio.jsp (4):
75
... </table> <div id="dialogFoto" title="foto" style="border: 1px black solid;"> <img id="imgFoto"> </div> </body>
CRUD Veículo: acessando a foto com Ajax
• CRUDVeiculo – método foto:
76
... @RequestMapping("/foto/{id}") public ResponseEntity<byte[]> foto(@PathVariable Integer id){ Foto foto = veiculoRepositorio.getFoto(id); HttpHeaders headers = new HttpHeaders(); String[] tokens = foto.getMimeType().split("/"); MediaType mimeType = new MediaType(tokens[0], tokens[1]); headers.setContentType(mimeType); return new ResponseEntity<>(foto.getBytes(), headers, HttpStatus.OK); } }
CRUD Veículo: acessando a foto com Ajax
• CRUDVeiculo – método foto:
77
... @RequestMapping("/foto/{id}") public ResponseEntity<byte[]> foto(@PathVariable Integer id){ Foto foto = veiculoRepositorio.getFoto(id); HttpHeaders headers = new HttpHeaders(); String[] tokens = foto.getMimeType().split("/"); MediaType mimeType = new MediaType(tokens[0], tokens[1]); headers.setContentType(mimeType); return new ResponseEntity<>(foto.getBytes(), headers, HttpStatus.OK); } }
Um ResponseEntity representa dados a serem inseridos na resposta HTTP. Pelo tipo de retorno deste método,
SringMVC entende que não deve renderizar uma visão.
Pesquisa de veículo: Ajax + JSON
• Adicionar biblioteca Jackson ao pom.xml:
78
... <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency> ...
Pesquisa de veículo: Ajax + JSON
• VeiculoRepositorio: método getPorModelo
79
... import java.util.List; ... public interface VeiculoRepositorio { ... public List<Veiculo> getPorModelo(Integer idModelo); }
Pesquisa de veículo: Ajax + JSON
• VeiculoDAO: método getPorModelo
80
... @Repository @Transactional public class VeiculoDAO implements VeiculoRepositorio { ... @Override public List<Veiculo> getPorModelo(Integer idModelo) { String hql = "from Veiculo v where v.modelo.id = :id "; Session session = sessionFactory.getCurrentSession(); Query q = session.createQuery(hql).setParameter("id", idModelo); return q.list(); } }
Pesquisa de veículo: Ajax + JSON
• CRUDVeiculo:
81
package cursoSpring.revenda_veiculos.web; import java.util.List; import org.springframework.web.bind.annotation.ResponseBody; ... public class CRUDVeiculo { ... @RequestMapping("/busca") public String paginaDeBusca(){ return "veiculos/busca"; } @RequestMapping("/pesquisar") @ResponseBody public List<Veiculo> pesquisar(@RequestParam Integer idModelo){ return veiculoRepositorio.getPorModelo(idModelo); } }
Pesquisa de veículo: Ajax + JSON
• CRUDVeiculo:
82
package cursoSpring.revenda_veiculos.web; import java.util.List; import org.springframework.web.bind.annotation.ResponseBody; ... public class CRUDVeiculo { ... @RequestMapping("/busca") public String paginaDeBusca(){ return "veiculos/busca"; } @RequestMapping("/pesquisar") @ResponseBody public List<Veiculo> pesquisar(@RequestParam Integer idModelo){ return veiculoRepositorio.getPorModelo(idModelo); } }
Indica que a resposta do método deve ser colocada no payload da resposta
HTTP. Por padrão, Spring MVC converterá os objetos Java retornados
pelo método em uma string JSON.
Pesquisa de veículo: Ajax + JSON
• Página veiculos/busca.jsp (1):
83
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <!DOCTYPE html> <html> <head> <c:url var="actionUrl" value="/veiculos" /> <title>Veículos</title> <script src="http://code.jquery.com/jquery-1.11.3.min.js"> </script> <script> $(document).ready(function($){ $('#formPesquisa').submit(function(event){ event.preventDefault(); buscar(); }); })
Pesquisa de veículo: Ajax + JSON
• Página veiculos/busca.jsp (2):
84
function buscar(){ $.getJSON('${actionUrl}/pesquisar', $('#formPesquisa').serialize(), function(data){ var linhas = ''; for(var i=0; i<data.length; i++){ linhas += '<tr><td>'+data[i].placa+'</td>'+ '<td>'+data[i].modelo.descricao+'</td>'+ '<td>'+data[i].anoFabricacao+'</td></tr>'; } console.log(">>"+linhas); var $tbody = $('#tabelaVeiculos').children('tbody'); $tbody.empty(); $tbody.append(linhas); }); } </script>
Pesquisa de veículo: Ajax + JSON
• Página veiculos/busca.jsp (3):
85
</head> <body> <h2>Busca de Veículos</h2> <form id="formPesquisa"> <select name="idModelo"> <c:forEach var="modelo" items="${modelos}"> <option value="${modelo.id}">${modelo.descricao}</option> </c:forEach> </select> <input type="submit" value="Pesquisar"> </form> <table id="tabelaVeiculos"> <thead> <tr> <th>Placa</th> <th>Modelo</th> <th>Ano</th>
Pesquisa de veículo: Ajax + JSON
• Página veiculos/busca.jsp (4):
86
</tr> </thead> <tbody> </tbody> </table> </body> </html>
Servindo conteúdo estático
• É preciso registrar um gerenciador de recursos.
87
... import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; @EnableWebMvc @ComponentScan(basePackageClasses={OlaMundoController.class}) public class AppWebConfig extends WebMvcConfigurerAdapter{ @Override public void addResourceHandlers(ResourceHandlerRegistry registry){ registry.addResourceHandler("/resources/**") .addResourceLocations("/resources/"); } ... }
Servindo conteúdo estático
• É preciso registrar um gerenciador de recursos.
88
... import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; @EnableWebMvc @ComponentScan(basePackageClasses={OlaMundoController.class}) public class AppWebConfig extends WebMvcConfigurerAdapter{ @Override public void addResourceHandlers(ResourceHandlerRegistry registry){ registry.addResourceHandler("/resources/**") .addResourceLocations("/resources/"); } ... }
URL de acesso aos arquivos.
Diretório em que se encontram os arquivos (JS, CSS, imagens, etc).
Servindo conteúdo estático
• index.jsp:
89
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %> <html> <body> <h2>Hello World!</h2> <img src="resources/logo.jpg" > </body> </html>
Servindo conteúdo estático
• index.jsp:
90
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %> <html> <body> <h2>Hello World!</h2> <img src="resources/logo.jpg" > </body> </html>
Repare que não é necessário o uso da tag c:url para obter o endereço
completo da URL resources.
Referências
• Johnson, Rod et al. Spring Framework Reference Documentation, 4.2.1 release. Disponível em <http://docs.spring.io/spring/docs/current/spring-framework-reference/html/>
• Márcio d’Ávila. Informações úteis sobre cabeçalhos HTTP e tipos MIME. Disponível em <http://www.mhavila.com.br/topicos/web/http_mime.html>
• Paraschiv, Eugen. Serve static resources with Spring. Disponível em <http://www.baeldung.com/spring-mvc-static-resources>.
• Souza, Alberto. Spring MVC: domine o principal framework web Java. São Paulo: Casa do Código, 2015.
• Stack Overflow. JSTL tag wiki. Disponível em <http://stackoverflow.com/tags/jstl/info>
91
92
Instituto Federal de Educação, Ciência e Tecnologia do Rio Grande do Norte Campus Natal Central Diretoria Acadêmica de Gestão e Tecnologia da Informação
Curso de formação em Spring Framework 4 Parte 03 – Spring MVC Autor: Alexandre Gomes de Lima Natal, outubro de 2015.