Spring 3 MVC com Validator e Converter

Neste tutorial a abordagem será sobre o Spring MVC e sua capacidade de validar dados inseridos no formulário (view), como também a conversão de valores que vem do formulário em formato String, mas que devem ser recebidos como um objeto de outro tipo especifico. Para exemplificar um validator e também o processo de conversão de valores, teremos um pequeno projeto como exemplo.

1. Classes de Entidade

Como o projeto será simples, serão utilizadas apenas duas classes de entidades, a classe Profile que terá um atributo identificador e um atributo de descrição para o perfil. A classe User conterá além de um identificador, um atributo java.lang.String para o nome do usuário, um atributo java.util.Date para a data de nascimento, e por fim, um atributo do tipo Profile, para vincular o usuário a um perfil. O relacionamento será do tipo 1-N, onde um perfil poderá ser encontrado entre vários usuários enquanto um usuário terá apenas um único perfil.

Listagem 1. Classe Profile.
package com.mballem.springconverter.entity;

import javax.persistence.*;
import java.io.Serializable;
import java.util.List;

/**
* http://www.mballem.com/
*/
@Entity
@Table(name = "PROFILES")
public class Profile implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "PROFILE_ID")
    private Long id;
    @Column(name = "PROFILE_DESC")
    private String profile;
    @OneToMany(cascade=CascadeType.REFRESH, fetch=FetchType.EAGER)
    @JoinColumn(name="USER_ID")
    private List user;

    //getters and setters 

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Profile profile = (Profile) o;

        if (id != null ? !id.equals(profile.id) : profile.id != null) {
            return false;
        }

        return true;
    }

    @Override
    public int hashCode() {
        return id != null ? id.hashCode() : 0;
    }
}
Listagem 2. Classe User.
package com.mballem.springconverter.entity;

import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;

/**
* http://www.mballem.com/
*/
@Entity
@Table(name = "USERS")
public class User implements Serializable, Comparable {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "USER_ID")
    private Long id;
    @Column(name = "USER_NAME")
    private String name;
    @Temporal(value = TemporalType.DATE)
    @Column(name = "USER_DATE_OF_BIRTH")
    private Date birthDate;
    @ManyToOne
    @JoinColumn(name="PROFILE", nullable=false, updatable=true)
    private Profile profile;

    //getters and setters

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        User user = (User) o;

        if (id != null ? !id.equals(user.id) : user.id != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        return id != null ? id.hashCode() : 0;
    }

    @Override //usado para ordenar por nome.
    public int compareTo(User user) { 		
        return this.name.compareTo(user.getName());
    }
}

2. Padrão DAO

O segundo passo será o desenvolvimento das classes de interação com o banco de dados. Para isso, vamos usar o padrão DAO e também a SessionFactory do Hibernate 4 que será injetada nos dao’s através do Spring e seu componente de inversão de controle e injeção de dependências. Nas Listagens 3 e 4 temos respectivamente a interface IProfileDao e a classe concreta ProfileDao, já nas Listagens 5 e 6, teremos a interface IUserDao e a classe concreta UserDao.

Listagem 3. Interface IProfileDao.
package com.mballem.springconverter.dao;

import java.io.Serializable;
import java.util.List;

/**
* http://www.mballem.com/
*/
public interface IProfileDao {
    Profile find(Long id);

    List findAll();
}
Listagem 4. Classe ProfileDao.
package com.mballem.springconverter.dao;

import java.io.Serializable;
import java.util.List;

public interface IProfileDao {
    Profile find(Long id);

    List findAll();
}
package com.mballem.springconverter.dao;

import com.mballem.springconverter.entity.Profile;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Repository
@Transactional
public class ProfileDao implements IProfileDao {

    @Autowired
    private SessionFactory sessionFactory;

    public Session getSession() {
        return sessionFactory.getCurrentSession();
    }

    @SuppressWarnings("unchecked")
    @Override
    @Transactional(readOnly = true, propagation = Propagation.REQUIRED)
    public Profile find(Long id) {
        return (Profile) getSession().createCriteria(Profile.class)
                .add(Restrictions.idEq(id)).uniqueResult();
    }

    @SuppressWarnings("unchecked")
    @Override
    @Transactional(readOnly = true, propagation = Propagation.REQUIRED)
    public List findAll() {
        return getSession().createCriteria(Profile.class).list();
    }
}
Listagem 5. Interface IUserDao.
package com.mballem.springconverter.dao;

import java.io.Serializable;
import java.util.List;

public interface IUserDao {

    void saveOrUpdate(User entity);

    void delete(User entity);

    User find(Long id);

    List findAll();
}
Listagem 6. Classe UserDao.
package com.mballem.springconverter.dao;

import com.mballem.springconverter.entity.User;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;

@Repository
@Transactional
public class UserDao implements IUserDao {

    @Autowired
    private SessionFactory sessionFactory;

    public Session getSession() {
        return sessionFactory.getCurrentSession();
    }

    @Override
    public void saveOrUpdate(User entity) {
        getSession().saveOrUpdate(entity);
    }

    @Override
    public void delete(User entity) {
        getSession().delete(entity);
    }

    @SuppressWarnings("unchecked")
    @Override
    @Transactional(readOnly = true, propagation = Propagation.REQUIRED)
    public User find(Long id) {
        return (User) getSession().createCriteria(User.class)
                .add(Restrictions.idEq(id)).uniqueResult();
    }

    @SuppressWarnings("unchecked")
    @Override
    @Transactional(readOnly = true, propagation = Propagation.REQUIRED)
    public List findAll() {
        List users = getSession().createCriteria(User.class).list();
        Collections.sort(users); //ordena a lista por name de a-z.
        return users;
    }
}

Sobre as anotações do Spring, estamos usando a @Repository para marcar a classe como um bean do tipo repositório, usado comumente em classes de persistência. A anotação @Autowired serve como indicação de que a propriedade terá uma instancia de sua classe injetada pelo Spring sempre que seu uso for necessário. A anotação @Transactional define os requisitos de transação para a classe ou para métodos específicos.

3. Pacote web

Dentro do pacote web vamos adicionar três pacotes que serão, validator, controller e converter. O pacote validator conterá a classe de validação dos dados inseridos no formulário JSP, o pacote converter terá as classes conversoras de dados entre páginas JSP e entidades. O controller, conterá a classe UserController da aplicação.

A classe UserValidator, da Listagem 7, deve implementar a interface org.springframework.validation.Validator, assim, devemos programar dois métodos referentes a interface, o método supports() que valida se a classe a ser validada é realmente a classe que está acessando o validador e o método validate(). Neste último será onde vamos aplicar a validação propriamente dita. O método possui dois parâmetros, um Object que neste caso conterá o objeto da classe User e o Errors, o qual teremos acesso aos tipos de métodos de validação do Spring e também responsavel por repassar para a JSP, as mensagens de erro. As mensagens de erros estão armazenadas em um arquivo de propriedades chamado ValidationMessages.properties, o qual está descrito abaixo:

required.name = User name is required!

required.profile = Select a profile, please!

required.birthDate = Date of birth is required (dd/mm/yyyy).
Listagem 7. Classe UserValidator.
package com.mballem.springconverter.web.validator;

import com.mballem.springconverter.entity.User;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

import java.util.Date;

@Component
public class UserValidator implements Validator {
    @Override
    public boolean supports(Class<?> aClass) {
        return User.class.equals(aClass);
    }

    @Override
    public void validate(Object obj, Errors errors) {
        // verifica se o campo name está fazio ou apenas com espaços em branco
        ValidationUtils
                .rejectIfEmptyOrWhitespace(errors, "name", "required.name");

        User user = (User) obj;

        // se o objeto profile for null o estoura o erro
        if (user.getProfile() == null || user.getProfile().equals("0")) {
            errors.rejectValue("profile", "required.profile");
        }

        // se o objeto birthDate for null estoura o erro
        if (user.getBirthDate() == null) {
            errors.rejectValue("birthDate", "required.birthDate");
        }
    }
}

Vamos agora conhecer as classes de conversão. Na Listagem 8 temos a classe de conversão chamada BirthdatePropertyEditor, responsável por converter o objeto String que retorna da JSP em um objeto java.util.Date e também mantém esse objeto em um formado especifico que será: dd/MM/yyyy. A classe de conversão, por padrão, contém como parte do seu nome as palavras PropertyEditor. Isto acontece porque essa classe herda métodos necessário para a conversão da super-classe PropertyEditorSupport. Os métodos herdados e os quais você deverá implementar são: setAsText() e getAsText(). O método setAsText() recebe como par mentro uma String contendo o conteúdo que foi digitado pelo usuário na página JSP. Já o método getAsText() retorna para a página JSP o objeto no formato String.

Listagem 8. Classe BirthdatePropertyEditor.
package com.mballem.springconverter.web.converter;

import org.apache.log4j.Logger;

import java.beans.PropertyEditorSupport;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Date;

public class BirthdatePropertyEditor extends PropertyEditorSupport {
    private static final Logger LOG =
            Logger.getLogger(BirthdatePropertyEditor.class);

    private final DateFormat dateFormat;

    public BirthdatePropertyEditor(DateFormat dateFormat) {
        this.dateFormat = dateFormat;
    }

    @Override
    public void setAsText(String text) {
        try {
            Date date = (Date) dateFormat.parseObject(text);
            setValue(date);
        } catch (ParseException e) {
            LOG.fatal("error setting date for String: " + text, e);
        }
    }

    /**
     * Format the Date as String, using the specified DateFormat.
     */
    @Override
    public String getAsText() {
        Date value = (Date) getValue();
        return (value != null ? this.dateFormat.format(value) : "");
    }
}

Na Listagem 9 temos a classe ProfilePropertyEditor. Ela trabalha da seguinte forma. Na JSP temos um componente HTML do tipo combo, onde o usuário poderá escolher o a descrição do perfil entre varias opções, que neste caso serão apenas três: ADM, USER e GUEST. Porém, quando o usuário selecionar entre um deles na JSP, o retorno será o id referente a descrição. O objeto User no controller, espera por um objeto do tipo Profile e não por um id do tipo String. Então, precisamos converter esse id em um objeto Profile. Para isso, usamos o método de consulta find() que receber como parâmetro um id que será usado como critério na query. O retorno desta consulta será um objeto Profile o qual é devolvido para o objeto User pelo método setValue(). Neste caso não precisamos implementar o método getAsText() porque para a JSP não retornamos o objeto Profile e sim sua descrição que já é uma String.

Listagem 9. Classe ProfilePropertyEditor.
package com.mballem.springconverter.web.converter;

import com.mballem.springconverter.dao.IProfileDao;
import com.mballem.springconverter.entity.Profile;

import java.beans.PropertyEditorSupport;

public class ProfilePropertyEditor extends PropertyEditorSupport {
    private IProfileDao dao;

    public ProfilePropertyEditor(IProfileDao dao) {
        this.dao = dao;
    }

    @Override
    public void setAsText(String text) {
        //transforma a string com o id em um long
        Long id = new Long(text);
        //recupera no db o profile do id referido
        Profile profile = dao.find(id);
        //add o objeto profile, o qual faz parte do objeto user no controller
        super.setValue(profile);
    }
}

Na Listagem 10 temos a classe controller e primeiramente vamos dar atenção ao método initBinder(). Este método será o primeiro método a ser executado quando o controller for chamado. Através do parâmetro ServletRequestDataBinder, temos acesso ao método setValidator(), o qual recebe uma instancia da classe de validação, neste caso UserValidator. Vamos ter acesso também ao método registerCustomEditor(), o qual recebe o tipo de objeto que será convertido e uma instancia da classe conversora. A anotação @Controller da classe UserController é necessária para informar ao Spring que esta é uma classe do tipo controller. Já a anotação @RequestMapping é usada para a URL que irá acessar este controller. No caso a URL principal do nosso sistema será http://localhost:8080/spring-converter/.

Para acessar os métodos do UserController, devemos ter a url http://localhost:8080/spring-converter/users. Nos métodos das classes temos também a anotação @RequestMapping, o valor dessa anotação é necessário para se saber qual método se está acessando a partir da JSP, então, para acessar o método saveUser() a url será http://localhost:8080/spring-converter/users/save. Veja também, que no método editUser() temos na anotação @RequestMapping a instrução /edit/{id}. Esta instrução diz que o método acessado será o editUser() e que este método receberá como parâmetro um id. Para o Spring receber este id no controller, devemos informar a ele através da anotação @PathVariable, informando também o tipo deste id, que neste caso é um Long.

As anotações @ModelAttribute recebem no controller o objeto enviado da página e a anotação @Valid recebe o objeto da página como também indica que ele deve ser validado pela classe de validação. No método saveUser() usamos o parametro BindindResult para testar se existe algum erro no formulário da JSP, quando enviado para o controller, se houver, a execução do método entra no if() do método e retorna para a página de cadastro exibindo as mensagens de erro da classe de validação.

Listagem 10. Classe UserController.
package com.mballem.springconverter.web.controller;

import com.mballem.springconverter.dao.IProfileDao;
import com.mballem.springconverter.dao.IUserDao;
import com.mballem.springconverter.entity.Profile;
import com.mballem.springconverter.entity.User;
import com.mballem.springconverter.web.converter.BirthdatePropertyEditor;
import com.mballem.springconverter.web.converter.ProfilePropertyEditor;
import com.mballem.springconverter.web.validator.UserValidator;
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.ServletRequestDataBinder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
 * http://www.mballem.com/
 */
@Controller
@RequestMapping(value = "/users")
public class UserController {
    @Autowired
    private IUserDao userDao;
    @Autowired
    private IProfileDao profileDao;
    @Autowired
    private UserValidator userValidator;

    @InitBinder
    protected void initBinder(HttpServletRequest request,
                              ServletRequestDataBinder binder) throws Exception {
        binder.setValidator(userValidator);
        binder.registerCustomEditor(
                Profile.class,
                new ProfilePropertyEditor(profileDao)
        );
        binder.registerCustomEditor(
                Date.class,
                new BirthdatePropertyEditor(new SimpleDateFormat("dd/MM/yyyy"))
        );
    }

    //index é encaminhado para este metodo e abre a pagina addUser
    @RequestMapping(value = "/add", method = RequestMethod.GET)
    public ModelAndView showForm(@ModelAttribute("user") User user,
                                 BindingResult result) {

        //adiciona a pagina destino e a lista de profiles
        return new ModelAndView("userAdd", modelProfiles());
    }

    //quando clicar no botao salvar, vem para este metodo
    @RequestMapping(value = "/save", method = RequestMethod.POST)
    public ModelAndView saveUser(@Valid User user, BindingResult result) {
        if (result.hasFieldErrors()) {
            return new ModelAndView("userAdd", modelProfiles());
        }

        userDao.saveOrUpdate(user);

        //redireciona para a pagina que lista os users
        return new ModelAndView("redirect:/users");
    }

    //lista os users
    @RequestMapping(method = RequestMethod.GET)
    public ModelAndView listUsers() {
        //recupera do db todos os users
        Map model = new HashMap();
        model.put("users", userDao.findAll());
        //adiciona no objeto ModelAndView a pagina que deve abrir e
        // a lista de users
        return new ModelAndView("userList", model);
    }

    //editar usuario
    @RequestMapping(value = "/edit/{id}", method = RequestMethod.GET)
    public ModelAndView editUser(@PathVariable("id") Long id) {
        //recupera o user atraves do id vindo da pagina
        User user = userDao.find(id);
        //cria um objeto ModelAndView e adiciona no construtor
        // a pagina que deve abrir
        ModelAndView modelAndView = new ModelAndView("userAdd");
        //envia para a pagina os dados do objeto user
        modelAndView.addObject("user", user);
        //envia para a pagina a lista de profiles
        modelAndView.addAllObjects(modelProfiles());

        return modelAndView;
    }

    //remover usuario
    @RequestMapping(value = "/remove/{id}", method = RequestMethod.GET)
    public String removeUser(@PathVariable("id") Long id, Model model) {
        //recupera do database o user atraves do id vindo da jsp
        User user = userDao.find(id);
        //teste simples para saber se o usuario existe no db
        if (user.getId() != null) {
            userDao.delete(user);
        }
        //retorna para a pagina que lista os users
        return "redirect:/users";
    }

    private Map modelProfiles() {
        //recupera os profiles do database
        Map mapProfile = new HashMap();
        mapProfile.put("profiles", profileDao.findAll());
        return mapProfile;
    }
}

3. Configuração do Spring Framework

Vamos agora configurar o Spring Framework e o arquivo web.xml (Listagem 11).

Listagem 11. Arquivo web.xml.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
         http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">

    <display-name>spring-converter</display-name>

    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

    <servlet>
        <description>Configuracao do Spring</description>

        <servlet-name>spring</servlet-name>

        <servlet-class>
                 org.springframework.web.servlet.DispatcherServlet
         </servlet-class>

        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring-context.xml</param-value>
        </init-param>

        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

Na Listagem 12 temos o arquivo de configuração do dao, ou seja, onde configuramos a integração entre Spring 3 e Hibernate 4.

Listagem 12. Arquivo spring-dao.xml.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jdbc="http://www.springframework.org/schema/jdbc"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
              http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
              http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">

    <!-- Data Source Declaration -->
    <bean id="dataSource"
         >
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost/spring-converter"/>
        <property name="username" value="root"/>
        <property name="password" value=""/>
    </bean>

    <!-- Configura a SessionFactory do Hibernate -->
    <!-- Hibernate SessionFactory -->
    <bean id="sessionFactory"
         >

        <property name="dataSource">
            <ref local="dataSource"/>
        </property>
        <property name="packagesToScan" value="com.mballem.springconverter.entity"/>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">
                          org.hibernate.dialect.MySQLDialect
                 </prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
        </property>
    </bean>

    <!-- Enable the configuration of transactional behavior based on annotations -->
    <tx:annotation-driven transaction-manager="transactionManager"/>

    <!-- Transaction Manager is defined -->
    <bean id="transactionManager"
         >

        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>
</beans>

Na Listagem 13 vamos configurar o MVC. Através desta configuração o Spring saberá o tipo de página que vai trabalhar e também o local onde estas páginas se encontram dentro do pacote da aplicação. Outra configuração que temos aqui é a criação do bean messageSource para o Spring saber onde encontrar o arquivo de propriedades com as mensagens de erro, por padrão o Spring procura pelo arquivo denominado ValidatorMessages e no pacote raiz da aplicação, ou resource no padrão Maven.

Listagem 13. Arquivo spring-web.xml.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="jspViewResolver" 
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/WEB-INF/view/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <!-- Register the ValidationMessages.properties -->
    <bean id="messageSource"
          class="org.springframework.context.support.ResourceBundleMessageSource">
		  
        <property name="basename" value="ValidationMessages" />
    </bean>
</beans>

Por fim, temos o arquivo que inicializa o Spring, chamado de spring-context.xml, conforme Listagem 14. As configurações neste arquivo são bem básicas, como, indicar ao framework o pacote base contendo as classes com as anotações do Spring, a anotação que indica que vamos usar o Spring MVC e também a importação dos arquivos spring-dao.xml e spring-web.xml.

Listagem 14. Arquivo spring-context.xml.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--Pacote base com as anotações do Spring -->
    <context:component-scan base-package="com.mballem.springconverter"/>

    <!-- Configures the @Controller programming model -->
    <mvc:annotation-driven/>

    <import resource="spring-web.xml"/>
    <import resource="spring-dao.xml"/>
</beans>

5. Páginas JSP

Listagem 15. Página userAdd.jsp.
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@  taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>
<head>
    <title>Add User</title>
    <style>
        .error {
            color: #ff0000;
            font-style: italic;
        }
    </style>
</head>
<body>
<h1>Add User</h1>
<c:url var="viewUsersUrl" value="/users"/>
<a href="${viewUsersUrl}">Show All Users</a>
<br/>
<br/>
<table bgcolor="#f0f8ff">
    <c:url var="saveUserUrl" value="/users/save"/>
    <form:form name="userAdd" modelAttribute="user"
               method="POST" action="${saveUserUrl}">

        <form:hidden path="id"/>
        <tr>
            <td><form:label path="name">User name:</form:label></td>
            <td><form:input path="name"/></td>
            <td><form:errors path="name" cssClass="error"/></td>
        </tr>
        <tr>
            <td><form:label path="birthDate">User date of birth:</form:label></td>
            <td><form:input path="birthDate"/></td>
            <td><form:errors path="birthDate" cssClass="error"/></td>
        <tr/>
        <tr>
            <td><form:label path="profile">User profile:</form:label></td>
            <td>
                <form:select path="profile">
                    <form:option value="0" label="--- Select ---"/>
                    <form:options items="${profiles}"
                                  itemValue="id" itemLabel="profile"/>
                </form:select>
            </td>
            <td><form:errors path="profile" cssClass="error"/></td>
        <tr/>
        <tr>
            <td><input type="submit" value="Save User"/></td>
        </tr>
    </form:form>
</table>
</body>
</html>
Listagem 16. Página userList.jsp.
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>
<head>
    <title>All Users</title>
</head>
<body>
<h1>List Users</h1>
<a href="users/add">Add User</a>
<c:if test="${!empty users}">
    <table>
        <tr bgcolor=#f5f5dc>
            <th align="left" width="150px">User Name</th>
            <th align="left" width="150px">User Date of Birth</th>
            <th align="left" width="100px">User Profile</th>
            <th align="left" width="100px">Action</th>
        </tr>
        <c:forEach items="${users}" var="user" varStatus="id">
            <tr  bgcolor="#${id.count % 2 != 0 ? 'aaee88' : 'ffff00' }">
                <td align="left" width="150px">
                    <c:out value="${user.name}"/>
                </td>

                <fmt:formatDate var="formatDate"
                                value="${user.birthDate}"
                                type="date"
                                pattern="dd/MM/yyyy" />
                <td align="left" width="150px">
                    <c:out value="${formatDate}"/>
                </td>

                <td align="left" width="100px">
                    <c:out value='${user.profile.profile}'/>
                </td>

                <%--
                    é possivel usar a tag própria do Spring(spring:url)
                    ou a tag da Jstl(c:url)
                --%>
                <spring:url var="edit" value="users/edit/${user.id}"/>
                <c:url var="remove" value="users/remove/${user.id}"/>
                <td align="left" width="100px">
                    <a href='${edit}'>[edit]</a>|
                    <a href="${remove}">[remove]</a>
                </td>
            </tr>
        </c:forEach>
    </table>
</c:if>
</body>
</html>
Listagem 17. Página index.jsp.
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>
  <head><title>Index</title></head>
  <body>
      <c:redirect url="/users/add"/>
      <h1>Spring 3 MVC application conversor configuration.</h1>
  </body>
</html>

Estrutura do Projeto

Estrutura do Projeto

Saiba mais em:

Download do projeto

Ballem

Marcio Ballem é bacharel em Sistemas de Informação pelo Centro Universitário Franciscano em Santa Maria/RS. Tem experiência com desenvolvimento Delphi e Java em projetos para gestão pública e acadêmica. Possui certificação em Java, OCJP 6.

Você pode gostar...