terça-feira, 26 de novembro de 2013

Formulário de Edição em Spring Web MVC com o NetBeans IDE

Nos artigos anteriores:



vimos como usar o Hibernate e a framework Spring Web MVC para listar dados da BD numa página Web, obedecendo a uma arquitetura Model-View-Controller.

Usámos o NetBeans para o nosso projeto e, portanto, fizemos por utilizar os "wizards" disponibilizados por este para criar o controller para fazer o nosso exemplo de listagem de Livros.

Para a criação de uma página de formulário (form), o NetBeans também nos fornece um "wizard" que cria uma classe descendente de SimpleFormController... Esta classe, no entanto, caiu em desuso (deprecated) e, apesar dos meus esforços para a usar no exemplo de Form que quero aqui criar, isso não foi possível por, no final, o evento submit não ocorrer como esperado pela framework, ou o event handler onSubmit não ser, por alguma razão, despoletado.

Alguns exemplos de utilização do SimpleFormController são:

Há males que vêm por bem, e os problemas com o SimpleFormController levam-me a fazer o exemplo de hoje usando um Controller baseado em anotações, como estabelecido pelas versões mais recentes da framework Spring.

Assim, pegando no exemplo anterior, queremos criar um Form para edição de Livro (Book), guardar o livro na BD, e terminar com um ecrã de confirmação de gravação. E queremos colocar o form acessível da nossa página inicial.



Vamos começar por acrescentar métodos de Get e Set da data de edição (dateEdition), que é um atributo de Book, como String, pois a framework tem que conseguir converter o formato de texto do respetivo campo do form no formato Date da classe Book, e vice-versa.

Classe Book:


package exemploModel;

import java.sql.Date;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.Session;

public class Book {
    private int ID;
    private String isbn;
    private String title;
    private java.sql.Date dateEdition;
    private String edition;
    private String editor;

    public int getID() {
        return ID;
    }

    public void setID(int ID) {
        this.ID = ID;
    }

...

    public Date getDateEdition() {
        return dateEdition;
    }

    public void setDateEdition(Date dateEdition) {
        this.dateEdition = dateEdition;
    }

    public String getDateEditionSTR() {
        return (this.dateEdition == null)?"":this.dateEdition.toString();
    }

    public void setDateEditionSTR(String dateEditionSTR) {
        String[] data;
        data = dateEditionSTR.split("-");
        this.dateEdition = new Date(Integer.parseInt(data[0]), 
                                  Integer.parseInt(data[1]), 
                                  Integer.parseInt(data[2]));

    }

...

}


O ficheiro Web.xml  não precisa de qualquer alteração:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>*.htm</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>redirect.jsp</welcome-file>
    </welcome-file-list>
</web-app>

Já o ficheiro de configuração do serviço de dispatcher precisa de ver acrescentado o novo controller para gestão do formulário.

Ficheiro dispatcher-servlet.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:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xmlns:lang="http://www.springframework.org/schema/lang"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

    <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>

    <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="index.htm">indexController</prop>
                <prop key="listBooks.htm">listBooksController</prop>
                <prop key="addBook.htm">bookController</prop>
                <prop key="confirmSave.htm">bookController</prop>
            </props>
        </property>
    </bean>

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

    <bean name="indexController"           class="org.springframework.web.servlet.mvc.ParameterizableViewController">
        <property name="viewName" value="index" />
    </bean>


    <bean name="olaController" class="exemplo.OlaController">
    </bean>


    <bean name="listBooksController" class="exemplo.ListBooksController">
    </bean>

    <bean name="bookController" class="exemplo.BookController">
    </bean>
    
    <bean id="sessionFactory" 
        class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="configLocation">
            <value>classpath:hibernate.cfg.xml</value>
        </property>
        <property name="configurationClass">
            <value>org.hibernate.cfg.AnnotationConfiguration</value>
        </property>
    </bean>

</beans>

Neste ficheiro dispatcher-servlet.xml, acrescentámos, relativamente ao do exemplo anterior, as linhas
                <prop key="addBook.htm">bookController</prop>
                <prop key="confirmSave.htm">bookController</prop>

nos mappings do SimpleUrlHandlerMapping, e o controller:

    <bean name="bookController" class="exemplo.BookController">
    </bean>


O novo controller anotado, para gestão do form de edição,

BookController:


package exemplo;

import exemploModel.Book;
import exemploModel.Services.BookService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

/**
 * @author ASUS
 */

@Controller
public class BookController{

    private BookService bookservice;

    public BookController()
   {
        this.setBookService(new exemploModel.Services.BookService());
    }

    public void setBookService(BookService bookservice){
        this.bookservice = bookservice;
    }
    
    
    @RequestMapping(value = "/confirmSave", method = RequestMethod.POST)
    public ModelAndView onSubmit(@ModelAttribute Book book, 
        ModelMap model) {
    
        this.bookservice.addBook(book);
        return new ModelAndView("viewBook", "book", book);
    }
    
    
    @RequestMapping(value = "/addBook", method = RequestMethod.GET)
    protected ModelAndView setupBookForm(){
        
Book book = new Book();
book.setDateEdition(null);
        book.setEdition("");
        book.setEditor("ASAS");
        book.setID(0);
        book.setIsbn("");
        book.setTitle("");
        
        return new ModelAndView("addBook", "bookForm", book);
    }
    
}

Assim, de acordo com as definições em web.xml e os mappings no dispatcher-servlet.xml, quando é requerida a página addBook.htm, o dispatcher encaminha o pedido para o controlador bookController (<prop key="addBook.htm">bookController</prop>), que instanciou a partir da classe BookController (<bean name="bookController" class="exemplo.BookController"/>).

O controlador BookController, verifica o mapeamento do pedido de addBook e corre o método correspondente, neste caso o método setupBookForm, o qual foi anotado com:
@RequestMapping(value = "/addBook", method = RequestMethod.GET)

Esse método instancía e inicia um novo Book, e passa-o para a view addBook.jsp:
               new ModelAndView("addBook", "bookForm", book);


View addBook.jsp:


<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>

<html:html lang="true">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Add Book</title>
        <html:base/>
    </head>
    <body style="background-color: white">       
        <div style="background-color:blueviolet;height:30px;font-weight:bold;">
            <h2>Add Book</h2>
        </div>
        <br/>
        <form:form method="POST" commandName="bookForm" action="confirmSave.htm" >
            ISBN
            <form:input path="isbn"/><br/>
            TITLE
            <form:input path="title"/><br/>
            Date Edition
            <form:input path="dateEditionSTR" /><br/>
            Edition
            <form:input path="edition"/><br/>
            Editor
            <form:input path="editor"/><br/>

            <input  type="submit" value="Save" />
        </form:form>
</body>
</html:html>



Quando submetermos o form preenchido, premindo o botão "Save", o form é enviado para o recurso confirmSave.htm, o que, de acordo com as nossas definições de mapeamento no dispatcher-servlet.xml, faz com que o mesmo seja reenviado para o controlador BookController (<prop key="confirmSave.htm">bookController</prop>).


O controlador BookController, verifica o mapeamento do pedido de confirmSave e corre o método correspondente, neste caso o método onSubmit, o qual foi anotado com:
@RequestMapping(value = "/confirmSave", method = RequestMethod.POST)

Esse método pega no Book instanciado ao submeter o form, e cria-o na BD, usando this.bookservice.addBook(book); e depois envia o Book para a view viewBook.jsp para mostrar os dados criados na BD:
               new ModelAndView("viewBook", "book", book);


View viewBook.jsp:


<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>

<html:html lang="true">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Book Details</title>
        <html:base/>
    </head>
    <body style="background-color: white">       
        <div style="background-color:blueviolet;height:30px;font-weight:bold;">
            <h2>Book Details</h2>
        </div>
        <br/>
        <table>
            <tr><td>ISBN: ${book.isbn}</td></tr>
            <tr><td>TITLE: ${book.title}</td></tr>
            <tr><td>Date Edition: ${book.dateEdition.toString()}</td></tr>
            <tr><td>Edition: ${book.edition}</td></tr>
            <tr><td>Editor: ${book.editor}</td></tr>
        </table>
    </body>
</html:html>




Para terminar, falta apenas listar o serviço que cria os dados na BD, o qual usa Hibernate, tal como tratado no artigo "Primeiro Exemplo de Aplicação Spring Web MVC com o NetBeans IDE - 3".

package exemploModel.Services;

import exemploModel.Book;
import exemploModel.HibernateUtil;
import org.hibernate.Session;

public class BookService {
    
    public void addBook(Book book)
    {
        Session session = HibernateUtil.getSessionFactory().openSession();
        session.beginTransaction();
        session.saveOrUpdate(book);
        session.getTransaction().commit();
        session.close();
    }
}


Algumas referências:
      - http://www.mkyong.com/spring-mvc/spring-mvc-hello-world-annotation-example/
      - http://www.tutorialspoint.com/spring/spring_mvc_form_handling_example.htm
      - http://fruzenshtein.com/spring-mvc-form-handling/

Outros artigos relacionados:





Sem comentários:

Enviar um comentário