Olá Pessoal, tudo bom? Como vão vocês?
Este é o terceiro artigo da série Spring MVC 3.0. Se vocês não tiveram um contato inicial com o framework, recomendo ver este artigo primeiro.
Para acompanhar esta terceira parte, recomendo ter criado o projeto do segundo artigo.
Como sempre, dúvidas e críticas são bem vindas.
Alterando o CRUD criado com o Spring MVC
O projeto neste artigo é o mesmo do segundo artigo da série. Entretanto, faremos algumas alterações para que passe a utilizar validações do Bean Validation.
Adicionando as bibliotecas ao projeto utilizando o Maven
Mais uma vez, recorreremos ao Maven para adicionar as bibliotecas que necessitamos. Neste caso, teremos que baixar o Hibernate Validator. Para utilizar o Bean Validation, utilizaremos dois JARs: hibernate-validator-4.0.2.GA.jar e validation-api-1.0.0.GA.jar.
Abram o arquivo pom.xml , encontrado na view Package Explorer para que possamos adicionar as configurações que necessitamos.
Criando a propriedade
Na aba Overview, em Properties, cliquem no botão Create. Na caixa de diálogo Add property, preencham como na Figura 1.
Criando a dependência
Com a propriedade definida para informar qual versão desejamos utilizar, no qual o Maven deverá baixar, resta configurar as dependências.
Na aba Dependencies, cliquem no botão Create e preencham conforme a Figura 2 ilustra.
Alterando a entidade Contato
A entidade do artigo, chamada de Contato, será a primeira coisa que iremos modificar no projeto.
Graças a JSR 303, chamada de Bean Validation, podemos anotar as entidades com validações. Com as anotações de Bean Validation na entidade, concentramos a validação em um único local, de forma padronizada, tornando possível portar estas validações para as classes controladoras do Spring MVC.
A Listagem 1 exibe a entidade Contato modificada. Note as anotações de validação onde colocamos as mensagens de erro embutidas. Mais adiante iremos capturá-las para exibir o problema ao usuário.
Listagem 1. A entidade Contato com anotações Bean Validation.
package br.com.integrator; import javax.persistence.*; import javax.validation.constraints.*; @Entity @Table(name = "contato") public class Contato { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private Long id; @NotNull @Size(min=5, message="O nome não pode ter menos que 5 caracteres!") private String nome; @NotNull @Pattern(regexp = "^[\\w\\-]+(\\.[\\w\\-]+)*@([A-Za-z0-9-]+\\.)+[A-Za-z]{2,4}$", message="E-mail com formato incorreto.") private String email; @Pattern(regexp = "\\(?\\b([0-9]{2})\\)?[-. ]?([0-9]{4})[-. ]?([0-9]{4})\\b", message="Telefone em formato incorreto") private String telefone; //getters e setters }
A infra-estrutura definida pela JSR 303 nos permite descrever as restrições, usando anotações no modelo de classes de persistência, como definir se um campo aceitará uma quantidade mínima de caracteres ou se não aceitará nulo, por exemplo.
Cada anotação é associada a uma validação, verificando se a instância da entidade anotada obedece à regra ou não.
A Tabela 1 apresenta todas as anotações possíveis de serem usadas e suas funcionalidades.
Annotation | O que faz? |
@AssertFalse | Checa se a propriedade anotada é falsa. |
@AssertTrue | Checa se a propriedade anotada é verdadeira. |
@DecimalMax(value=) | A propriedade anotada precisa ser um número, cujo valor deve estar menor ou igual ao valor máximo previsto. O parâmetro value é a representação em string do valor máximo aceito de acordo com o formato representado em BigDecimal. Suporta tipos como BigDecimal, BigInteger, String, byte, short, int, long e os respectivos wrappers de tipos primitivos. |
@DecimalMin(value=) | A propriedade anotada precisa ser um número, cujo valor deve estar maior ou igual ao valor mínimo previsto. O parâmetro value é a representação em string do valor mínimo de acordo com a representação de sequência de BigDecimal. Suporta tipos como BigDecimal, BigInteger, String, byte, short, int, long e os respectivos wrappers de tipos primitivos. |
@Digits(integer=, fraction=) | Verifica se a propriedade possui a quantidade de dígitos antes e depois do separador de casa decimal. Por exemplo: @Digits(integer=9, fraction=2) significa que espera-se 9 dígitos inteiros e 2 dígitos fracionários. Suporta os tipos: BigDecimal, BigInteger, String, byte, short, int, long e os respectivos wrappers de tipos primitivos. |
@Future | Checa se a data está no futuro. Suporta os tipos java.util.Date e java.util.Calendar. |
@Max(value=) | Verifica se o valor é menor ou igual ao valor anotado. Suporta os tipos: BigDecimal, BigInteger, String, byte, short, int, long e os respectivos wrappers de tipos primitivos. |
@Min(value=) | Verifica se o valor é maior ou igual ao valor anotado. Suporta os tipos: BigDecimal, BigInteger, String, byte, short, int, long e os respectivos wrappers de tipos primitivos. |
@NotNull | Checa se o valor anotado não é nulo (null). Uma String cujo valor seja vazio (“”) vai passar. |
@Null | Checa se o valor anotado é nulo (null). |
@Past | Checa se uma data está no passado. Suporta os tipos java.util.Date e java.util.Calendar. |
@Pattern(regex=, flag=) | Checa se a propriedade obedece à expressão regular. |
@Size(min=, max=) | Confere se a quantidade de elementos está entre o mínimo e o máximo, suportando tipos como: Strings, Collections, Maps e arrays. |
@Valid | Impõe uma validação recursiva aos objetos associados. Digamos que, no bean Post, houvesse a anotação @Valid no atributo comments. Já na classe Comment, temos um atributo de validação anotado. Se um valor transmitido a comments, de Post, não estiver de acordo com a validação existente na classe Comment, de acordo com o atributo anotado, um erro será gerado em tempo de execução. A notação @Valid está sendo usada no PostController para validar os erros existentes em Post ou Comment. |
Tabela 1. Anotações e regras para criar restrições (Constraints).
Alterando o controlador
Alteraremos a classe ContatoController, criada no pacote br.com.integrator.web, de acordo com o mostrado na Listagem 2.
Listagem 2. A classe ContatoController alterada.
package br.com.integrator.web; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.*; import br.com.integrator.dao.ContatoDAO; import br.com.integrator.Contato; @Controller @RequestMapping("/contato/**") public class ContatoController { @Autowired private ContatoDAO contatoDao; @RequestMapping(value = "/contato/{id}", method = RequestMethod.GET) public String show(@PathVariable("id") Long id, ModelMap modelMap) { modelMap.addAttribute("contato", contatoDao.find(id)); return "contato/show"; } @RequestMapping(value = "/contato", method = RequestMethod.GET) public String list(ModelMap modelMap) { modelMap.addAttribute("contatos", contatoDao.findAll()); return "contato/list"; } @RequestMapping(value = "/contato/{id}", method = RequestMethod.DELETE) public String delete(@PathVariable("id") Long id) { contatoDao.remove(contatoDao.find(id)); return "redirect:/contato"; } @RequestMapping(value = "/contato/form", method = RequestMethod.GET) public String form(ModelMap modelMap) { modelMap.addAttribute("contato", new Contato()); return "contato/create"; } @RequestMapping(value = "/contato", method = RequestMethod.POST) public String create(@Valid Contato contato, BindingResult result) { if (result.hasErrors()) return "contato/create"; contatoDao.persist(contato); return "redirect:/contato"; } @RequestMapping(value = "/contato/{id}/form", method = RequestMethod.GET) public String updateForm(@PathVariable("id") Long id, ModelMap modelMap) { modelMap.addAttribute("contato", contatoDao.find(id)); return "contato/update"; } @RequestMapping(method = RequestMethod.PUT) public String update(@Valid Contato contato, BindingResult result) { if (result.hasErrors()) return "contato/update"; contatoDao.merge(contato); return "redirect:/contato"; } }
Como visto na Listagem 1, as anotações @Size e @Pattern possuem o atributo message, que capturamos pelo Spring MVC na classe ContatoController (Listagem 2) – através da classe javax.validation.Valid (anotação @Valid). Assim como a anotação @Controller, as anotações pertencentes a Bean Validation são obtidas graças a adição do elemento <mvc:annotation-driven />. Isto permite que as informações anotadas sejam injetadas onde a validação é necessária na sua aplicação.Caso haja um erro, o método hasErrors(), de org.springframework.validation.BindingResult, retorna true, nos possibilitando conduzir a navegação da página, com seus respectivos erros, inclusive paralisando a ação ao qual se encontra. A utilização de hasErrors() ocorre em ContatoController, nos métodos create() e update() com o seguinte if:
if (result.hasErrors()) //executa uma ação para conduzir a página com os erros ao usuário
As informações recebidas da validação pela classe Controller são transmitidas para o formulário e capturadas. Veja como isto ocorre na descrição da Listagem 3.
Alterando as views
Temos três páginas que representam nosso CRUD feitas. Estas páginas foram criadas dentro do diretório chamado WEB-INF/jsp/contato(fisicamente na ferramenta: src/main/webapp/WEB-INF/jsp/contato). Teremos que alterá-las para permitir que os erros sejam exibidos.
O formulário de cadastro
Abra o arquivo create.jsp e altere como na Listagem 3, adicionando as tags <form:errors />.
Listagem 3. A página create.jsp.
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <!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"> <style type="text/css" media="screen"> @import url("<c:url value="/static/styles/style.css"/>"); </style> <title>Cadastrar</title> </head> <body> <div id="wrap"> <div id="menu"> <%@ include file="/menu.jsp" %> </div> <div id="main"> <div id="body"> <c:url var="url" value="/contato" /> <form:form action="${url}" method="POST" modelAttribute="contato"> <div> <label for="nome">Nome:</label> <form:errors path="nome" cssClass="errors"/><br /> <form:input cssStyle="width:250px" maxlength="30" path="nome" size="30"/> </div> <br/> <div> <label for="email">Email:</label> <form:errors path="email" cssClass="errors"/><br /> <form:input cssStyle="width:250px" maxlength="30" path="email" size="30"/> </div> <br/> <div> <label for="telefone">Telefone:</label> <form:errors path="telefone" cssClass="errors"/><br /> <form:input cssStyle="width:250px" maxlength="30" path="telefone" size="20"/> </div> <br/><div> <input id="criar" type="submit" value="Criar Contato"/> </div> </form:form> </div> </div> </div> </body> </html>
Podemos ter uma idéia de como ficará a página create.jsp depois das alterações visualizando a Figura 4.
Alterando a página de atualização de dados
Como feito na página create.jsp, a página update.jsp também receberá as tags <form:errors />. A Listagem 4 exibe a página com as mudanças, na íntegra.
Listagem 4. A página update.jsp.
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <!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"> <style type="text/css" media="screen"> @import url("<c:url value="/static/styles/style.css"/>"); </style> <title>Atualizar</title> </head> <body> <div id="wrap"> <div id="menu"> <%@ include file="/menu.jsp" %> </div> <div id="main"> <div id="body"> <c:url var="url" value="/contato/${contato.id}" /> <form:form action="${url}" method="PUT" modelAttribute="contato"> <div> <label for="nome">Nome:</label> <form:errors path="nome" cssClass="errors"/><br /> <form:input cssStyle="width:250px" maxlength="30" path="nome" size="30"/> </div> <br/> <div> <label for="email">Email:</label> <form:errors path="email" cssClass="errors"/><br /> <form:input cssStyle="width:250px" maxlength="30" path="email" size="30"/> </div> <br/> <div> <label for="telefone">Telefone:</label> <form:errors path="telefone" cssClass="errors"/><br /> <form:input cssStyle="width:250px" maxlength="30" path="telefone" size="20"/> </div> <br/> <div> <input id="atualizar" type="submit" value="Atualizar Contato"/> </div> <form:hidden path="id"/> </form:form> </div> </div> </div> </body> </html>
O projeto para download
Clique aqui para baixar o projeto e alterá-lo como desejar.
Considerações finais
Com as validações, boa parte dos problemas iniciais de um desenvolvimento usando o Spring MVC foram resolvidos. Mas vejam só: é o começo. Caso haja interesse do leitor em aprender um exemplo mais complexo, a revista JavaMagazine #78 publicou, um artigo meu com o Spring MVC 3 na criação de um blog, do começo ao fim. É um bom início para se desenvolver um projeto mais completo e complexo.
Para os que acompanham o blog, o assunto Spring MVC não para por aqui. Veremos em breve um site completo, feito com o framework, unindo várias características do Spring, de seu framework MVC e a parte de segurança com Spring Security.
novembro 1st, 2010 15:20
Fala Edson,
Muito bacana mesmo o artigo. Ainda não tive a oportunidade de brincar ou ler mais afundo sobre Beans Validation, mas trabalhei bastante com Hibernate Validator. Há muitas features diferentes entre um e outro. Mesmo embora o Beans Validator seja baseado no Hibernate Validator.
Abraços,
Breno Oliveira
novembro 10th, 2010 15:37
Obrigado mais uma vez Edson! Estava esperando anciosamente por esse artigo. Todos os outros que achei de validação com Spring 3 não estavam muito legais.
Agradeço mais uma vez pela força!
Abraços!
novembro 14th, 2010 17:51
Fala Edson! Consegue me ajudar com o seguinte erro ao aplicar essa validação:
SEVERE: Servlet.service() for servlet SalesDashBoardManager threw exception
java.lang.NoSuchMethodError: javax.persistence.Persistence.getPersistenceUtil()Ljavax/persistence/PersistenceUtil;
at org.hibernate.validator.engine.resolver.JPATraversableResolver.isReachable(JPATraversableResolver.java:33)
at org.hibernate.validator.engine.resolver.DefaultTraversableResolver.isReachable(DefaultTraversableResolver.java:112)
at org.hibernate.validator.engine.resolver.SingleThreadCachedTraversableResolver.isReachable(SingleThreadCachedTraversableResolver.java:47)
at org.hibernate.validator.engine.ValidatorImpl.isValidationRequired(ValidatorImpl.java:764)
at org.hibernate.validator.engine.ValidatorImpl.validateConstraint(ValidatorImpl.java:331)
at org.hibernate.validator.engine.ValidatorImpl.validateConstraintsForRedefinedDefaultGroup(ValidatorImpl.java:278)
at org.hibernate.validator.engine.ValidatorImpl.validateConstraintsForCurrentGroup(ValidatorImpl.java:260)
at org.hibernate.validator.engine.ValidatorImpl.validateInContext(ValidatorImpl.java:213)
at org.hibernate.validator.engine.ValidatorImpl.validate(ValidatorImpl.java:119)
at org.springframework.validation.beanvalidation.SpringValidatorAdapter.validate(SpringValidatorAdapter.java:74)
at org.springframework.validation.DataBinder.validate(DataBinder.java:684)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.doBind(HandlerMethodInvoker.java:746)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments(HandlerMethodInvoker.java:296)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:163)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:414)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:402)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:771)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:716)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:647)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:563)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:71)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.doFilterInternal(OpenEntityManagerInViewFilter.java:113)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:378)
at org.springframework.security.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109)
at org.springframework.security.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.ui.SessionFixationProtectionFilter.doFilterHttp(SessionFixationProtectionFilter.java:67)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.ui.ExceptionTranslationFilter.doFilterHttp(ExceptionTranslationFilter.java:101)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.providers.anonymous.AnonymousProcessingFilter.doFilterHttp(AnonymousProcessingFilter.java:105)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.ui.rememberme.RememberMeProcessingFilter.doFilterHttp(RememberMeProcessingFilter.java:116)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter.doFilterHttp(SecurityContextHolderAwareRequestFilter.java:91)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.ui.basicauth.BasicProcessingFilter.doFilterHttp(BasicProcessingFilter.java:174)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.ui.AbstractProcessingFilter.doFilterHttp(AbstractProcessingFilter.java:277)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.ui.logout.LogoutFilter.doFilterHttp(LogoutFilter.java:89)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.context.HttpSessionContextIntegrationFilter.doFilterHttp(HttpSessionContextIntegrationFilter.java:235)
at org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:390)
at org.springframework.security.util.FilterChainProxy.doFilter(FilterChainProxy.java:175)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at com.springsource.insight.collection.tcserver.request.HttpRequestOperationCollectionValve.invoke(HttpRequestOperationCollectionValve.java:60)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:379)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
dezembro 7th, 2010 16:40
Edson, parabéns pelos livro que são de linguagem simples e fácil de entender. Qual a diferença ou o papel do Spring, EJB 3 e JBoss Seam ?
dezembro 10th, 2010 2:16
@Erika,
O Spring (se for a parte do framework de IoC) e EJB são tecnologias diferentes com propósitos similares em algumas situações, como inversão de controle/injeção de dependencias. Mas os EJBs são mais complexos no que se propõem, com características mais “avançadas” em seu meio, exigindo um servidor Java EE completo, como o JBoss ou GlassFish.
O Spring também é complexo e se divide em módulos com várias características de propósitos diferenciados.
O JBoss Seam, se comparado com o Spring, seria com seu módulo de framework MVC, chamado Spring MVC, pois ambos renderizam páginas de forma dinâmica. A diferença é que o JBoss Seam tem base no JSF e trabalha com componentes e o Spring MVC tem base nos Servlets.
Resumindo: você pode misturar as tecnologias citadas, mas escolhendo em cada situação um módulo diferente do Spring.
setembro 17th, 2011 19:29
Poxa uma pena ter parado, o tutorial está ótimo e com certeza ajudando diversas pessoas, eu tenho algumas dúvidas no modo de navegação como eu posso controlá-las, seria o próximo post seu, espero que em breve termine, pois está ótimo.
Parabéns
setembro 17th, 2011 22:54
@Eduardo,
Estou arrumando um tempo para finalizar os tutoriais que comecei e não terminei. Espero em breve postar.
Abraço,
fevereiro 9th, 2012 11:32
Edson, estou iniciando com o Framework e não encontre o “artigo primeiro” que você recomenda no início do Tópico “Spring MVC 3 na Prática com Bean Validation”. Ao clicar no link disponibilizado não aparece nada. Fico no aguardo!
fevereiro 9th, 2012 13:47
@Willamis,
Está funcionando sim. Copie e cole na barra de endereços do seu navegador:
http://www.edsongoncalves.com.br/2010/02/27/spring-mvc-3-0-na-pratica-parte-1/
março 15th, 2012 16:24
Ola amigo, vc esta ajudando bastantes.
Se possivel me tire a seguinte duvida:
a tag eh criticada pelo eclipse ao colocar no XML do spring.
qua Jar preciso adcionar na lib para usa-la?
Um abraço
abril 10th, 2012 23:37
@Davi,
Precisa ver o primeiro artigo. Lá existem listadas as bibliotecas que deve usar no exemplo.
dezembro 13th, 2012 11:26
Belo tutorial, ótimo para mim que sou iniciante. Porém surgiu uma duvida na hora da atualização. Por exemplo: o e-mail deve ser único na base de dados. No momento do cadastro está beleza, mas na hora da atualização ele sempre retorna o erro sendo que o e-mail é o mesmo e não será alterado. Qual seria a solução?
janeiro 12th, 2013 12:59
Valeu! Artigo Muito Bom.
junho 5th, 2018 20:58
Se me permitir, eu criei um mini curso profissional em video com 5 aulas e queria deixar aqui pra quem estiver passando pelo seu blog.
Segue o link abaixo.
https://www.javaavancado.com/curso-de-hibernate-bean-validation-gratuito/