Download Primeros pasos usando struts e Hibernate General
Document related concepts
no text concepts found
Transcript
Primeros pasos usando struts e Hibernate En esta tutorial demostraremos cómo los struts e Hibernate para persistencia de base de datos se pueden utilizar juntos. Aunque explicamos algo básico, usted debe probar los tutoriales introductorios primero si es un prinicpiante. General Autor: Sebastian Hennebrüder http://www.laliluna.de/tutorials.html Tutoriales para los struts, EJB, xdoclet y eclipse. Fecha: Revisado enero, 16 th 2005 Primera Edición Diciembre, 20 2004 Código fuente: http://www.laliluna.de/assets/tutorials/struts-hibernate-integration-tutorial.zip Uso del código fuente. El código fuente no incluye ninguna biblioteca solo los fuentes. Cree un proyecto web, agregue las bibliotecas manualmente o con la ayuda de MyEclipse y descomprima los fuentes que proporcionamos a su proyecto. Versión del pdf del tutorial : http://www.laliluna.de/assets/tutorials/struts-hibernate-integration-tutorial-es.pdf Herramientas de Desarrollo Eclipse 3.x MyEclipse 3,8 plugin (Una extensión barata y muy poderosa de eclipse para desarrollar aplicaciones web y aplicaciones de EJB (J2EE). Pienso que hay una versión de prueba disponible en MyEclipse.) Base de datos PostgreSQL 8,0 beta o MySQL Servidor de Aplicación Jboss 3,2,5 Puede utilizar Tomcat aquí si usted quiere. Importante: Cuando usted está utilizando Tomcat en forma independiente y no incluido en Jboss, no puede utilizar dos proyectos separados. Esto normalmente trabaja con Jboss mientras que Jboss comparte clases por defecto. Dos proyectos separados deben desarrollarse como proyecto EAR (MyEclipse - > new J2EE project) Un proyecto EAR puede incluir múltiples proyectos web. ¡Si usted cambió la carga de clases de Jboss, también debe utilizar un proyecto EAR! Tabla de contenidos Primeros pasos usando los struts e Hibernate 1 General 1 Crear un proyecto de la biblioteca Hibernate 2 Creación del Proyecto de Persistencia 2 Creación de la base de datos 6 Generación del archivo de Mapeo de Hibernate y las clases 6 Reparación del mapeo Hibernate Corrección del mapeo buleano Mejoras al session Factory Prueba de la parte de Hibernate Problema de PostgreSQL Generación de la lógica del negocio Creación de una clase para la lógica del negocio Creación de los diálogos 22 9 10 10 11 15 16 16 Configuración de la ruta de construcción de Java 25 Creación de una página de bienvenida por defecto 25 Global Action Forwards y Action Mappings (Acciones de redirección global y Mapeo de Acciones) 27 Lista de libros 30 Action Mapping y clase Action para la lista de libros Edición del código fuente de la clase Form Action 32 Edición del código fuente de la clase Action Muestra de la lista de libros en el archivo jsp. Prueba de la aplicación 36 Añadir, editar, pedir prestados y suprimir los libros 36 Nuevo Form Bean 36 Caso de uso: editar libro 40 Mapeo de Acción 40 Métodos de envío de la clase acción 44 Caso de uso: la lista de clientes 47 Edición del código fuente de la clase Form Action 50 Muestra de la lista de clientes Caso de uso: añadir, editar, suprimir clientes 51 Nuevo Form Bean 53 Edición del código fuente de la clase Action Edición del código fuente del archivo jsp 57 Prueba de la aplicación 58 32 33 33 50 56 Crear un proyecto de la biblioteca Hibernate Comenzaremos creando y probando un proyecto de Hibernate. El segundo paso es agregar la lógica de negocio y en el último integrar la parte de struts. Creación del Proyecto De Persistencia Cree un nuevo proyecto web. Comencemos. Presione "Ctrl + N" para abrir el diálogo "new...". Cree un proyecto web y seleccione el nombre del proyecto como se muestra abajo. Agregue las capacidades de Hibernate al hacer clic derecho en la vista del paquete del proyecto . Compruebe las dos casillas de verificación para agregar las bibliotecas al proyecto y seleccione crear un nuevo archivo de mapeo hibernate. El archivo de hibernate lleva a cabo la configuración de sus ajustes y mappings del hibernate. El paso siguiente es seleccionar un perfil para la conexión para la base de datos. Seleccione el botón "New profile" para crear un nuevo perfil. Cuando el controlador de Postgres falta. Clic en "New driver" para crear un nuevo controlador. Usted necesitará el archivo jar que tenga el driver de la base de datos. Llamamos nuestro perfil de libraryweb. Especifique el nombre del usuario y la contraseña. Cerciórese de que usted tenga marcado la casilla "Copy JDBC driver...". Vamos a utilizar PostgreSQL. No debería ser difícil hacer lo mismo con MySQL u otra base de datos. Cerciórese de que tenga el archivo jar del controlador de la base de datos en alguna parte en su disco. En el paso siguiente usted debe inventar un nombre descriptivo para su SessionFactory. ¿Qué es un SessionFactory? Hibernate espera que haya una sola instancia de la clase de sesión de Hibernate por cada conexión (thread). Tendría que tener para crear una implementación de la clase un ThreadLocal. MyEclipse hace esto para usted. La parte difícil es inventar un nombre para él. Si usted no está utilizando MyEclipse heche un vistazo a los fuentes. Reduzca Las Bibliotecas De Hibernate Por defecto MyEclipse incluye una carga pesada de bibliotecas. Algunas de ellas serán solamente necesarias para el desarrollo local otros solamente para implementaciones especiales de cache. Cuando desea optimizar su desarrollo después de que aprenda los fundamentos de la transferencia directa de Hibernate bajando Hibernate del website http://www.hibernate.org/ en el directorio lib usted encontrará un README.txt donde explica qué bibliotecas son opcionales. Ahora estamos preparados para comenzar el desarrollo. Abrochese los cinturones, esto ahora irá muy rápido. Creación la base de datos Cree la base de datos y las tablas siguientes. ¡No se olvide de la clave foránea! Script De PostgreSql CREATE TABLE customer ( id serial NOT NULL, name text, lastname text, age int4, CONSTRAINT customer_pk PRIMARY KEY (id) ) ; CREATE TABLE book ( id serial NOT NULL, title text, author text, customer_fk int4, available bool, CONSTRAINT book_pk PRIMARY KEY (id) ) ; ALTER TABLE book ADD CONSTRAINT book_customer FOREIGN KEY (customer_fk) REFERENCES customer (id) ON UPDATE RESTRICT ON DELETE RESTRICT; Script de MySQL CREATE TABLE customer ( id int( 11 ) NOT NULL AUTO_INCREMENT , name varchar( 255 ) , lastname varchar( 255 ) , age int( 11 ), CONSTRAINT customer_pk PRIMARY KEY (id) ) TYPE=INNODB; CREATE TABLE book( id int( 11 ) NOT NULL AUTO_INCREMENT , title varchar( 255 ) , author varchar( 255 ) , customer_fk int( 11 ), available TINYINT NOT NULL, CONSTRAINT book_pk PRIMARY KEY ( id ), INDEX (customer_fk) ) TYPE=INNODB; ALTER TABLE book ADD CONSTRAINT book_customer FOREIGN KEY ( customer_fk ) REFERENCES customer( id ) ON UPDATE RESTRICT ON DELETE RESTRICT ; Genere los archivos de mapeo Hibernate y las clases Abra la vista para examinar DB (MyEclipse). Si usted no puede encontrarlo abra "Show View" y seleccione en el escritorio de MyEclipse el browser de DB. Abra el perfil de la conexión que usted especificó antes.< > Seleccione las dos tablas que acabamos de crear. Botón derecho y elija "Create Hibernate Mapping". Seleccione como destino su proyecto LibraryPersistence. Cuando se está utilizando PostgreSQL seleccione la "secuence" como generador de la identificación. Cuando usted está utilizando MySQL seleccione "native". Clic en OK, !Ud. es realmente bueno! Acaba de crear su capa de persistencia; -) Ahora veremos más de cerca en nuestro explorador del paquete para ver qué sucedió. Primero abra el hibernate.cfg.xml. Hay dos nuevas entradas, que especificanddonde se localizan los dos archivos de mapeo. Es una buena idea mantener los archivos de mapeo separados del hibernate.cfg.xml . (lo qué MyEclipse hace realmente para usted.) <!-- mapping files --> <mapping resource="de/laliluna/library/Book.hbm.xml"/> <mapping resource="de/laliluna/library/User.hbm.xml"/> Mire en el archivo de mapeo Book.hbm.xml. En este archivo se especifica el mapeo de la clase y de sus atributos con los campos de la tabla. Incluso se ha reconocido nuestra clave foránea. <hibernate-mapping package="de.laliluna.library"> <class name="Book" table="book"> <id name="id" column="id" type="java.lang.Integer"> <generator class="sequence"/> </id> <property name="title" column="title" type="java.lang.String" /> <property name="author" column="author" type="java.lang.String" /> <property name="available" column="available" type="java.lang.Byte" /> <many-to-one name="customer" column="customer_fk" class="Customer" /> </class> </hibernate-mapping> Cuando usted está utilizando MySQL el mapeo es levemente diferente. <class name="Book" table="book"> <id name="id" column="id" type="java.lang.Integer"> <generator class="native"/> </id> ... MyEclipse creó dos archivos por clase. El primero es una clase abstracta. (AbstractBook) será sobreescrito cada vez que usted repita el procedimiento de la importación. En la segunda clase (libro) usted puede adaptar cualquier cambio que desee realizar. Se genera solamente una vez. Reparación del mapeo de Hibernate Vamos a realizar algunos cambios. Hibernate no genera una relación del cliente al libro. Agregaremos esto a mano. En el archivo Customer.class agregue lo siguiente. private List books; /** * @return Returns the books. */ public List getBooks() { return books; } /** * @param books The books to set. */ public void setBooks(List books) { this.books = books; } En el archivo Customer.hbm.xml tenemos que agregar el mapeo de la variable libros . Agregue la entrada "bag" al archivo. <hibernate-mapping package="de.laliluna.library"> <class name="Customer" table="customer"> <id name="id" column="id" type="java.lang.Integer"> <generator class="sequence"/> </id> <bag name="books" inverse="false"> <key column="customer_fk" /> <one-to-many class="Book"/> </bag> <property name="name" column="name" type="java.lang.String" /> <property name="lastname" column="lastname" type="java.lang.String" /> <property name="age" column="age" type="java.lang.Integer" /> </class> </hibernate-mapping> La especificamos como inverse="false " Esto especifica que queremos cambiar el atributo en "uno" de la relación “uno a muchos” para ser reflejados en la base de datos. Pro ejemplo: customer.getbooks().add(aBook); Deberemos escribir la clave foránea en la tabla Customer. Manualmente cambiar el archivo no es muy bueno pero no hay otra forma aquí. La desventaja de esto es que será sobreescrito cada vez qye regenere los archivos de mapeo. En nuestro caso no es importante pero en un proyecto grande esto es imposible para usar la autogeneración de MyEclipse excepto que lo haga al principio. La función de importación es realmente nueva en MyEclipse asi que seguramente habra grandes mejoras en las próximas versiones. Corrigiendo el mapeo Boolean La columna bool de postgreSQL es tomada como Byte y como Short cuando se usa MySql. No me pregunte por qué. Esto no es bueno, lo corregiremos. Cambie el mapeo de Hibernate en el archivo file Book.hmb.xml a <property name="available" column="available" type="java.lang.Boolean" /> Cambie la variable, los getter y setter en el archivo AbstractBook.java a tipo Boolean. private java.lang.Boolean available; /** * Return the value of the available column. * @return java.lang.Byte */ public java.lang.Boolean getAvailable() { return this.available; } /** * Set the value of the available column. * @param available */ public void setAvailable(java.lang.Boolean available) { this.available = available; } Mejoras al session factory El session factory generado por MyEclipse no es muy agradable porque deja errores cuando utilice el método session.close(). Session factory espera que utilice el método estático closeSession() de factory, que realmente fija session a nulo si está cerrado. Pero no hay problema, aquí están las modificaciones al metodo currentSession de factory. public static Session currentSession() throws HibernateException { Session session = (Session) threadLocal.get(); /* * [laliluna] 20.12.2004 * we want to use the standard session.close() method and not the closeSession() from this class. * For this we need the following line of code. */ if (session != null && !session.isOpen()) session = null; if (session == null) { if (sessionFactory == null) { try { cfg.configure(CONFIG_FILE_LOCATION); sessionFactory = cfg.buildSessionFactory(); } catch (Exception e) { System.err .println("%%%% Error Creating HibernateSessionFactory %%%%"); e.printStackTrace(); } } session = sessionFactory.openSession(); threadLocal.set(session); } return session; } Pruebas a la parte Hibernate Cree una clase nueva. Hagala como el siguiente ejemplo. public class LibraryTest { private Session session; private Logger log = Logger.getLogger(this.getClass()); public static void main(String[] args) { /* * hibernate needs log4j. Either specify a log4j.properties file * * PropertyConfigurator.configure ("D:\_projekte\workspace\LibraryPersistence\src\log4j.properties"); * * or alternatively make the following to create a standard configuration * BasicConfigurator.configure(); */ BasicConfigurator.configure(); try { LibraryTest libraryTest = new LibraryTest(); libraryTest.setSession(HibernateSessionFactory.currentSession()); libraryTest.createBook(); libraryTest.createCustomer(); libraryTest.createRelation(); libraryTest.deleteCustomer(); libraryTest.listBooks(); // [laliluna] 20.12.2004 always close the session at the end libraryTest.getSession().close(); } catch (HibernateException e) { e.printStackTrace(); } } /** * creates a book and saves it to the db. * */ private void createBook() { System.out.println("############# create book"); try { Transaction tx = session.beginTransaction(); Book book = new Book(); book.setAuthor("Karl"); book.setTitle("Karls biography"); book.setAvailable(Boolean.TRUE); session.save(book); tx.commit(); } catch (HibernateException e) { e.printStackTrace(); } } /** * creates a user and saves it to the db * */ private void createCustomer() { System.out.println("############# create user"); try { Transaction tx = session.beginTransaction(); Customer customer = new Customer(); customer.setLastname("Fitz"); customer.setName("John"); customer.setAge(new Integer(25)); session.save(customer); tx.commit(); } catch (HibernateException e) { e.printStackTrace(); } } /** * creates a book and a user + a relation between the two * */ private void createRelation() { System.out.println("############# create relation"); try { Transaction tx = session.beginTransaction(); Customer customer = new Customer(); customer.setLastname("Schmidt"); customer.setName("Jim"); customer.setAge(new Integer(25)); /* IMPORTANT You must save the customer first, before you can assign him to the book. * Hibernate creates and reads the ID only when you save the entry. * The ID is needed as it is the foreign key */ session.save(customer); Book book = new Book(); book.setAuthor("Gerhard Petter"); book.setTitle("Gerhards biography"); book.setAvailable(Boolean.TRUE); session.save(book); Book book2 = new Book(); book2.setAuthor("Karl May"); book2.setTitle("Wildes Kurdistan"); book2.setAvailable(Boolean.TRUE); session.save(book2); session.flush(); book.setCustomer(customer); book2.setCustomer(customer); tx.commit(); // [laliluna] 20.12.2004 the customer is not updated automatically, so we have to refresh him session.refresh(customer); tx = session.beginTransaction(); if (customer.getBooks() != null) { System.out.println("list books"); for (Iterator iter = customer.getBooks().iterator(); iter.hasNext();) { Book element = (Book) iter.next(); System.out.println("customer:" + element.getCustomer()); System.out.println("customer is now:" + element.getCustomer()); } } tx.commit(); } catch (HibernateException e) { e.printStackTrace(); } } private void deleteCustomer() { System.out.println("############# delete customer"); try { Transaction tx = session.beginTransaction(); Customer customer = new Customer(); customer.setLastname("Wumski"); customer.setName("Gerhard"); customer.setAge(new Integer(25)); /* IMPORTANT You must save the customer first, before you can assign him to the book. * Hibernate creates and reads the ID only when you save the entry. * The ID is needed as it is the foreign key */ session.save(customer); Book book = new Book(); book.setAuthor("Tim Tom"); book.setTitle("My new biography"); book.setAvailable(Boolean.TRUE); session.save(book); book.setCustomer(customer); tx.commit(); // [laliluna] 20.12.2004 and now we are going to delete the customer which will set the foreign key in the book table to null tx = session.beginTransaction(); // [laliluna] 20.12.2004 the customer is not updated automatically, so we have to refresh him session.refresh(customer); session.delete(customer); tx.commit(); } catch (HibernateException e) { e.printStackTrace(); } } /** * lists all books in the db * */ private void listBooks() { System.out.println("####### list customers"); Query query; Transaction tx; try { tx = session.beginTransaction(); query = session.createQuery("select c from Customer as c"); for (Iterator iter = query.iterate(); iter.hasNext();) { Customer element = (Customer) iter.next(); List list = element.getBooks(); System.out.println(element.getName()); if (list == null) System.out.println("list = null"); else { for (Iterator iterator = list.iterator(); iterator.hasNext();) { Book book = (Book) iterator.next(); System.out.println(book.getAuthor()); } } System.out.println(element); } tx.commit(); } catch (HibernateException e1) { e1.printStackTrace(); } System.out.println("####### list books"); try { tx = session.beginTransaction(); query = session.createQuery("select b from Book as b"); for (Iterator iter = query.iterate(); iter.hasNext();) { System.out.println((Book) iter.next()); } tx.commit(); } catch (HibernateException e) { e.printStackTrace(); } } /** * @return Returns the session. */ public Session getSession() { return session; } /** * @param session The session to set. */ public void setSession(Session session) { this.session = session; } } Botón derecho sobre la clase y seleccione Run -> Java Application. Y al menos cuando se usa PostgreSQL, obtendremos unos cuantos errores. ;-) java.sql.SQLException: ERROR: relation "hibernate_sequence" does not exist Problema con PostgreSQL Esto es porque hay un pequeño bug en la rutina de importación. Asume que la secuencia es llamada por hibernate_sequence. Esta secuencia se crea automáticamente cuando estamos usando una columna serial, es llamada table_column_seq, ej: book_id_seq. El tarea más fácil con respecto a esto es esperar hasta que MyEclipse mejore la rutina. La más rápida es crear una secuencia llamada hibernate_sequence. Una desventaja es que todas las tablas compartidas tiene la misma secuencia. Tendrá una tabla con una sobrecarga. CREATE SEQUENCE hibernate_sequence INCREMENT 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1; La forma más agradable, pero solo es posible cuando esté seguro de no generar sus archivos de mapeo (Debería sobreescribir sus cambios) es cambiar el mapeo de <generator class="sequence"/> a lo siguiente para book. Los cambios sobre Customer son semejantes. <generator class="sequence"> <param name="sequence">book_id_seq</param> </generator> Eso es para la capa de persistencia de nuestra aplìcación. Generación de la Lógica de Negocio Creación de una clase de lógica de negocio Pondremos toda la lógica de negocio en una sola clase. Nuestro struts utilizará más adelante solamente esta clase. No habrá acceso directa a la capa de la persistencia. Usted podría incluso pensar de substituir su capa de la persistencia por otra. Este clase mantendrá todos los métodos necesarios como lógica de negocio • crear, modificar y borrar libros • crear, modificar y borrar clientes • pedir prestado y devolver libros • leer todos los clientes o libros de la db para una lista Excepciones en Hibernate Cuando una excepción ocurre se recomienda hacer roll back a la transacción e inmediatamente cerrar la sesión. Eso es lo que hemos hecho con try catch {} finally{} Usamos Diseño Hibernate Una consulta hibernate devuelve una interface lista a una implementación especial de Lista de Hibernate. Esta implementación es directamente conectada con la sesión. No se puede cerrar la sesión cuando usa estas listas Hibernate. Usted tiene que desconectar la sesión de la base de datos y volverla a conectar, utilizar una de las soluciones de cache o hacerlo de la manera más fácil pero no hay mejor forma de trabajar con los Value Objects. Tomemos la manera más fácil: La consecuencia es que tenemos una copia de todos los elementos de una lista hibernate en una lista normal java.util.List. public class LibraryManager { /** * get all books from the database * @return Array of BookValue */ public Book[] getAllBooks() { /* will hold the books we are going to return later */ List books = new ArrayList(); /* a Hibernate session */ Session session = null; /* we always need a transaction */ Transaction tx = null; try { /* get session of the current thread */ session = HibernateSessionFactory.currentSession(); tx = session.beginTransaction(); Query query = session .createQuery("select b from Book as b order by b.author, b.title"); for (Iterator iter = query.iterate(); iter.hasNext();) { books.add((Book) iter.next()); } tx.commit(); } catch (HibernateException e) { e.printStackTrace(); // [laliluna] 17.12.2004 it is recommended to roll back the transaction after an error occured if (tx != null) try { tx.rollback(); } catch (HibernateException e1) { e1.printStackTrace(); } } finally { try { if (session != null) session.close(); } catch (HibernateException e1) { e1.printStackTrace(); } } return (Book[]) books.toArray(new Book[0]); } /** * get book by primary key * @param primaryKey * @return a Book or null */ public Book getBookByPrimaryKey(Integer primaryKey) { /* holds our return value */ Book book = null; /* a Hibernate session */ Session session = null; /* we always need a transaction */ Transaction tx = null; try { /* get session of the current thread */ session = HibernateSessionFactory.currentSession(); tx = session.beginTransaction(); book = (Book) session.get(Book.class, primaryKey); tx.commit(); } catch (HibernateException e) { e.printStackTrace(); // [laliluna] 17.12.2004 it is recommended to roll back the transaction after an error occured if (tx != null) try { tx.rollback(); } catch (HibernateException e1) { e1.printStackTrace(); } } finally { try { if (session != null) session.close(); } catch (HibernateException e1) { e1.printStackTrace(); } } return book; } /** * sets the book as borrowed to the user specified in the database * @param primaryKey * @param userPrimaryKey */ public void borrowBook(Integer primaryKey, Integer customerPrimaryKey) { /* a Hibernate session */ Session session = null; /* we always need a transaction */ Transaction tx = null; try { /* get session of the current thread */ session = HibernateSessionFactory.currentSession(); tx = session.beginTransaction(); Book book = (Book) session.get(Book.class, primaryKey); Customer customer = (Customer) session.get(Customer.class, customerPrimaryKey); if (book != null && customer != null) book.setCustomer(customer); tx.commit(); } catch (HibernateException e) { e.printStackTrace(); // [laliluna] 17.12.2004 it is recommended to roll back the transaction after an error occured if (tx != null) try { tx.rollback(); } catch (HibernateException e1) { e1.printStackTrace(); } } finally { try { if (session != null) session.close(); } catch (HibernateException e1) { e1.printStackTrace(); } } } /** * customer returns a book, relation in the db between customer and book is deleted * @param primaryKey */ public void returnBook(Integer primaryKey) { /* a Hibernate session */ Session session = null; /* we always need a transaction */ Transaction tx = null; try { /* get session of the current thread */ session = HibernateSessionFactory.currentSession(); tx = session.beginTransaction(); found Book book = (Book) session.get(Book.class, primaryKey); if (book != null) // session.get returns null when no entry is book.setCustomer(null); tx.commit(); } catch (HibernateException e) { e.printStackTrace(); // [laliluna] 17.12.2004 it is recommended to roll back the transaction after an error occured if (tx != null) try { tx.rollback(); } catch (HibernateException e1) { e1.printStackTrace(); } } finally { try { if (session != null) session.close(); } catch (HibernateException e1) { e1.printStackTrace(); } } } /** * updates/creates a book * @param bookValue */ public void saveBook(Book bookValue) { /* a Hibernate session */ Session session = null; /* we always need a transaction */ Transaction tx = null; try { /* get session of the current thread */ session = HibernateSessionFactory.currentSession(); tx = session.beginTransaction(); Book book; if (bookValue.getId() != null && bookValue.getId().intValue() != 0) { // [laliluna] 04.12.2004 load book from DB book = (Book) session.get(Book.class, bookValue.getId()); if (book != null) { book.setAuthor(bookValue.getAuthor()); book.setTitle(bookValue.getTitle()); book.setAvailable(bookValue.getAvailable()); session.update(book); } } else // [laliluna] 04.12.2004 create new book { book = new Book(); book.setAuthor(bookValue.getAuthor()); book.setTitle(bookValue.getTitle()); book.setAvailable(bookValue.getAvailable()); session.save(book); } tx.commit(); } catch (HibernateException e) { e.printStackTrace(); // [laliluna] 17.12.2004 it is recommended to roll back the transaction after an error occured if (tx != null) try { tx.rollback(); } catch (HibernateException e1) { e1.printStackTrace(); } } finally { try { if (session != null) session.close(); } catch (HibernateException e1) { } e1.printStackTrace(); } } /** * deletes a book * @param primaryKey */ public void removeBookByPrimaryKey(Integer primaryKey) { /* a Hibernate session */ Session session = null; /* we always need a transaction */ Transaction tx = null; try { /* get session of the current thread */ session = HibernateSessionFactory.currentSession(); tx = session.beginTransaction(); Book book = (Book) session.get(Book.class, primaryKey); if (book != null) session.delete(book); tx.commit(); } catch (HibernateException e) { e.printStackTrace(); // [laliluna] 17.12.2004 it is recommended to roll back the transaction after an error occured if (tx != null) try { tx.rollback(); } catch (HibernateException e1) { e1.printStackTrace(); } } finally { try { if (session != null) session.close(); } catch (HibernateException e1) { e1.printStackTrace(); } } } /** * returns all customers from the db * @return */ public Customer[] getAllCustomers() { /* will hold the books we are going to return later */ List customers = new ArrayList(); /* a Hibernate session */ Session session = null; /* we always need a transaction */ Transaction tx = null; try { /* get session of the current thread */ session = HibernateSessionFactory.currentSession(); tx = session.beginTransaction(); Query query = session .createQuery("select c from Customer as c order by c.name"); for (Iterator iter = query.iterate(); iter.hasNext();) { customers.add((Customer) iter.next()); } tx.commit(); } catch (HibernateException e) { e.printStackTrace(); // [laliluna] 17.12.2004 it is recommended to roll back the transaction after an error occured if (tx != null) try { tx.rollback(); } catch (HibernateException e1) { e1.printStackTrace(); } } finally { try { if (session != null) session.close(); } catch (HibernateException e1) { e1.printStackTrace(); } } return (Customer[]) customers.toArray(new Customer[0]); } /** * gets a customer from the db * @param primaryKey * @return the customer class or null, when no customer is found */ public Customer getCustomerByPrimaryKey(Integer primaryKey) { /* holds our return value */ Customer customer = null; /* a Hibernate session */ Session session = null; /* we always need a transaction */ Transaction tx = null; try { /* get session of the current thread */ session = HibernateSessionFactory.currentSession(); tx = session.beginTransaction(); customer = (Customer) session.get(Customer.class, primaryKey); tx.commit(); } catch (HibernateException e) { e.printStackTrace(); // [laliluna] 17.12.2004 it is recommended to roll back the transaction after an error occured if (tx != null) try { tx.rollback(); } catch (HibernateException e1) { e1.printStackTrace(); } } finally { try { if (session != null) session.close(); } catch (HibernateException e1) { e1.printStackTrace(); } } return customer; } /** * saves the customers to the db * @param customer */ public void saveCustomer(Customer customer) { /* a Hibernate session */ Session session = null; /* we always need a transaction */ Transaction tx = null; try { /* get session of the current thread */ session = HibernateSessionFactory.currentSession(); tx = session.beginTransaction(); if (customer.getId() == null || customer.getId().intValue() == 0) // [laliluna] 06.12.2004 create customer session.save(customer); else { Customer toBeUpdated = (Customer) session.get(Customer.class, customer .getId()); toBeUpdated.setAge(customer.getAge()); toBeUpdated.setLastname(customer.getLastname()); toBeUpdated.setName(customer.getName()); session.update(toBeUpdated); } tx.commit(); } catch (HibernateException e) { e.printStackTrace(); // [laliluna] 17.12.2004 it is recommended to roll back the transaction after an error occured if (tx != null) try { tx.rollback(); } catch (HibernateException e1) { e1.printStackTrace(); } } finally { try { if (session != null) session.close(); } catch (HibernateException e1) { e1.printStackTrace(); } } } /** * deletes a customer from the database * @param primaryKey */ public void removeCustomerByPrimaryKey(Integer primaryKey) { /* a Hibernate session */ Session session = null; /* we always need a transaction */ Transaction tx = null; try { /* get session of the current thread */ session = HibernateSessionFactory.currentSession(); tx = session.beginTransaction(); Customer customer = (Customer) session.get(Customer.class, primaryKey); if (customer != null) session.delete(customer); tx.commit(); } catch (HibernateException e) { e.printStackTrace(); // [laliluna] 17.12.2004 it is recommended to roll back the transaction after an error occured if (tx != null) try { tx.rollback(); } catch (HibernateException e1) { e1.printStackTrace(); } } finally { try { if (session != null) session.close(); } catch (HibernateException e1) { e1.printStackTrace(); } } } } Bueno, ya hemos creado nuestra lógica de negocio. Y ahora la última parte: los diálogos Creación de diálogos Cree un nuevo proyecto struts con File > New > Project o use el atajo Ctrl + n. Elija el Wizard de proyectos Web J2EE. Pongale un buen nombre a su proyecto. Por ahora su proyecto es como un proyecto Web común, lo que necesitamos es agregar las capacidades struts. Botón derecho en el proyecto y agregue estas capacidades con Add Struts Capabilities. Cambie Base package for new classes y Default application resource Configuración de la ruta de construcción java Abra las propiedades del proyecto Web and seleccione LibraryPersistence del proyecto Hibernate. Creación de una página de bienvenida Ok, ahora queremos crear una página por defecto. Botón derecho (sí de nuevo) en la carpeta Folder WebRoot del proyecto y elija New > JSP. Ponga el nombre index.jsp y seleccione en Template to use > Standard JSP using Struts 1.1 MyEcplise usará el esquema para crear el archivo JSP. Encontrará el archivo index.jsp en la carpeta WebRoot del proyecto. Al principio del archivo encontrará la declaración de la biblioteca de marcas de struts. Esto será usado para acceder a las marcas de struts. En este caso solo necesitamos la biblioteca de marcas lógicas. Inserte la siguiente linea que incluye la marca logic. <logic:forward name="welcome" /> Esta línea le dice a struts que busque una redirección (forward) con el nombre “welcome”. Si la aplicación no encuentra este forward, devolverá un error, en la sección siguiente explicaré brevemente la acción forward. Cree un segundo archivo index.jsp en la carpeta /WebRoot/jsp Cambie el body del archivo por lo siguiente: <body> Welcome! <br> <html:link action="bookList">Show the book list</html:link> <br> <html:link action="customerList">Show the customer list</html:link> </body Global Action Forwards y Action Mappings Qué es una acción de redirección (Action Forward)? Una acción forward puede ser usada para remitir a un jsp o a un mapeo de acción. Existen dos acciones de redirección distintos. La acción global y la local. Puede acceder a una acción global en cada jsp o action class. Una acción local solo puede ser accedida por la action class asignada. Qué es un action mapping? ¿Qué es un mapa de acción (action mapping)? El mapa de acción es el corazón de struts. Maneja todas las acciones entre la aplicación y el usuario. Usted puede definir qué acción será ejecutada creando un mapa de acción (Action Mapping). El diagrama le muestra, cómo el servidor de aplicación maneja la petición del index.jsp o una acción no mapeada. En el primer paso creamos una nueva acción mapeada. Abra el archivo struts-config.xml de la configuración de struts, que está situado en WebRoot/WEB-INF. Botón derecho en la vista outline del action-mapping. MyEclipse provee algunas buenas características para crear archivos struts. Abra struts-config.xml y la vista Outline. Clic con el botón derecho del mouse en action-mappings para crear una nueva acción con el asistente. Seleccione Use Case default y Action Type Forward. El Forward Path es la página de bienvenida / jsp/index.jsp Para atrapar todas las solicitudes de las acciones que no esten mapeadas, tenemos que agregar manualmente un parámetro unknow="true" en action forward. <action-mappings > <action forward="/jsp/index.jsp" path="/default" unknown="true"/> </action-mappings> Cree el jsp especifciado arriba y cambie el código a lo siguiente: <%@ page language="java"%> <%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html:html locale="true"> <head> <html:base /> <title>index.jsp</title> </head> <body> Welcome! <br> <html:link action="bookList">Show the book list</html:link> <br> <html:link action="customerList">Show the customer list</html:link> </body> </html:html> En el segundo paso va a crear un acción de redirección global. Vuelva a la ventana Outline de MyEclipse y seleccione Global Forward Elija Forward Scope Global Forward. Use el mismo nombre que puso en la página por defecto. Global Forward se refiere a su action mapping. Verá lo siguiente en su editor. <global-forwards > <forward name="welcome" path="/default.do" redirect="true" /> </global-forwards> <action-mappings > <action forward="/jsp/index.jsp" path="/default" /> </action-mappings> Lista de Libros Este caso de uso lista todo los libros disponibles. Seleccione el asistente para crear un nuevo Formulario, acción y JSP. El caso de uso es bookList, Superclass org.apache.struts.ActionForm. Elija public void reset.. para crear este método. Vaya a la lengüeta jsp y ponga el nombre del jsp a crear. Action mapping und action class of the book list Haga los siguientes cambios para la action class. Superclass org.apache.struts.Action En Optional Details seleccione el formulario Bean bookListForm. El código de ingreso está en /jsp/bookList.jsp Ahora agregue un forward showList al mapeo de acción. Eso es. Los archivos están generados. Edición del código fuente de la action form class Abra el archivo BookListForm.java y agregue las siguientes líneas. public class BookListForm extends ActionForm { private Book[] book = new Book[0]; /** * @return Returns the book. */ public Book[] getBooks() { return book; } /** * @param book The book to set. */ public void setBooks(Book[] bookValues) { this.book = bookValues; } /** * Method reset * @param mapping * @param request */ public void reset(ActionMapping mapping, HttpServletRequest request) { book = new Book[0]; } } No necesita tipear los métodos getter y setter. Clic con el botón derecho sobre el proyecto -> select Source -> Generate Getters/Setters. Edición del código de la action class Encontrará la clase bookListAction en su paquete de.laliluna.tutorial.library.action. Abra la clase bookListAction y edite el método execute. Guarde el array de libros devuelto por el método en el formulario bean. El comando mapping.findForward(„showList“) buscará un forward local con el nombre showList. public class BookListAction extends Action { /** * Method loads book from DB * @param mapping * @param form * @param request * @param response * @return ActionForward */ public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { BookListForm bookListForm = (BookListForm) form; // [laliluna] 27.11.2004 get busines logic LibraryManager libraryManager = new LibraryManager(); // [laliluna] 29.11.2004 update the form bean, from which the jsp will read the data later. bookListForm.setBooks(libraryManager.getAllBooks()); return mapping.findForward("showList"); } } Mostrar la lista de libros en el archivo jsp. Abra bookList.jsp y agregue el siguiente código. <%@ <%@ <%@ <%@ page language="java"%> taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean"%> taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html"%> taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic" %> <html> <head> <title>Show book list</title> </head> <body> <table border="1"> <tbody> <%-- set the header --%> <tr> <td>Author</td> <td>Book name</td> <td>Available</td> <td>Borrow by</td> <td> </td> <td> </td> <td> </td> </tr> <%-- start with an iterate over the collection books --%> <logic:iterate name="bookListForm" property="books" id="book"> <tr> <%-- book informations --%> <td><bean:write name="book" property="author" /></td> <td><bean:write name="book" property="title" /></td> <td><html:checkbox disabled="true" name="book" property="available"/> </td> <td> <%-- check if a customer borrowed a book, when its true display his name otherwise display nothing --%> <logic:notEmpty name="book" property="customer"> <bean:write name="book" property="customer.name" />, <bean:write name="book" property="customer.lastname" /> </logic:notEmpty> <logic:empty name="book" property="customer"> </logic:empty> </td> <%-- borrow, edit and delete link for each book --%> <td> <%-- check if a user borrowed a book, when its true display the return link otherwise display the borrow link --%> <logic:notEmpty name="book" property="customer"> <html:link action="bookEdit.do?do=returnBook" paramName="book" paramProperty="id" paramId="id">Return book</html:link> </logic:notEmpty> <logic:empty name="book" property="customer"> <html:link action="bookEdit.do?do=borrowBook" paramName="book" paramProperty="id" paramId="id">Borrow book</html:link> </logic:empty> </td> <td><html:link action="bookEdit.do?do=editBook" paramName="book" paramProperty="id" paramId="id">Edit</html:link> </td> <td><html:link action="bookEdit.do?do=deleteBook" paramName="book" paramProperty="id" paramId="id">Delete</html:link> </td> </tr> </logic:iterate> <%-- end interate --%> <%-- if books cannot be found display a text --%> <logic:notPresent name="book"> <tr> <td colspan="5">No books found.</td> </tr> </logic:notPresent> </tbody> </table> <br> <%-- add and back to menu button --%> <html:button property="add" onclick="location.href='bookEdit.do?do=addBook'">Add a new book </html:button> <html:button property="back" onclick="location.href='default.do'">Back to menu </html:button> </body> </html> La marca <logic:iterate> recorre el array de libros. Con la marca Ud. tiene acceso a las propiedades de los libros con el nombre “book”. La marca <bean:write> imprime una propiedad de un libro, por ejemplo el título (title). Con la marca <logic:notEmpty> y <logic:empty> vcerificamos, si un usuario a ha pedido prestado un libro o no. Sí eso es todo, ha creado su formulario bean con un action form class, un action mapping con un action class y el jsp que muestra algo. Prueba de la aplicación Arranque el jboss y despliegue el proyecto (LibraryPersistenceLibs, LibraryPersistence y LibraryWeb) como archivos adjuntos Llame al proyecto con su navegador favorito http://localhost:8080/LibraryWeb/ Problema de distribución de Jboss Cuando redistribuye un proyecto Jboss a menudo bloquea las bibliotecas. El resultado es que obtiene el siguiente mensaje: Undeployment failure on Jboss. File ....jar Unable to be deleted. Un solución sencilla es crear dos proyectos, uno que incluya las bibliotecas que no tiene que distribuir y el otro que incluya su proyecto Hibernate. Tenemos un tutorial expolicando esto. Si comienza a molestarle cuando redistribuya, pruebe este tutorial. Agregar, editar, prestar y eliminar libros En el próximo paso tenemos que agregar los siguientes casos de uso: • Agregar libros • Editar libros • Prestar / devolver libros • Eliminar libros Nuevo formulario bean Cree un nuevo formulario bean y una clase action form. Ponga como Use case a bookEdit y elmine todos los métodos en Optional details – Methods. MyEcplise crea un archivo jsp por nosotros. Abra la clase BookEditForm.java en de.laliluna.tutorial.library.form . Cree los atributos book y customerId. public class BookEditForm extends ActionForm { private Book book = new Book(); /** * we will need this field to save the customer id in the dialogs where a customer borrows a book */ private Integer customerId; Genere los getters y setters para los atributos. Luego genere todos los métodos delegados por el atributo book. El código será como el siguiente: public class BookEditForm extends ActionForm { private Book book = new Book(); /** * we will need this field to save the customer id in the dialogs where a customer borrows a book */ private Integer customerId; /** * @return Returns the book. */ public Book getBook() { return book; } /** * @param book The book to set. */ public void setBook(Book book) { this.book = book; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object arg0) { return book.equals(arg0); } /** * @return */ public String getAuthor() { return book.getAuthor(); } /** * @return */ public Boolean getAvailable() { return book.getAvailable(); } /** * @return */ public Customer getCustomer() { return book.getCustomer(); } /** * @return */ public Integer getId() { return book.getId(); } /** * @return */ public String getTitle() { return book.getTitle(); } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ public int hashCode() { return book.hashCode(); } /** * @param author */ public void setAuthor(String author) { book.setAuthor(author); } /** * @param available */ public void setAvailable(Boolean available) { book.setAvailable(available); } /** * @param customer */ public void setCustomer(Customer customer) { book.setCustomer(customer); } /** * @param id */ public void setId(Integer id) { book.setId(id); } /** * @param title */ public void setTitle(String title) { book.setTitle(title); } /* (non-Javadoc) * @see java.lang.Object#toString() */ public String toString() { return book.toString(); } } /** * @return Returns the customerId. */ public Integer getCustomerId() { return customerId; } /** * @param customerId The customerId to set. */ public void setCustomerId(Integer customerId) { this.customerId = customerId; } Caso de uso editar libro El próximo paso es crear lo necesario para editar los libros. Action Mapping Cree un nuevo action mapping. Hay una diferencia con nuestra primer first action class. La nueva action class extenderá la superclase org.apache.struts.DispatchAction. Una Dispatch action no llama al método execute pero si a otros métodos especificados por un parámetro. Cuando el usuario haga clic en un enlace de edición (Edit Link) la dispatch action llamará al método Edit, cuando él haga clic en un enlace para Agregar, la dispatch action llama al método create. En Parameter agregamos el parámetro do. Este parámetro lo necesita la dispatch action class. Agregue cuatro nuevos forwards. Uno para la página de edición, el segundo para la página que agrega, donde se podrá agregar libros, el tercer forward para la página de préstamo y la cuarta para redireccionar al usuaio al listado de libros. El último forward es distinto a los otros. Se refiere a una action mapping existente y redirecciona al usuario. Cree los archivos jsp faltantes con New > JSP. bookAdd.jsp bookEdit.jsp bookBorrow.jsp Edite el código de los archivos jsp. Abra el archivo bookAdd.jsp y agregue el siguiente código. <%@ <%@ <%@ <%@ page language="java"%> taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean"%> taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html"%> taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic" %> <html> <head> <title>Add a book</title> </head> <body> <%-- create a html form --%> <html:form action="bookEdit"> <%-- print out the form data --%> <table border="1"> <tbody> <tr> <td>Author:</td> <td><html:text property="author" /></td> </tr> <tr> <td>Title:</td> <td><html:text property="title" /></td> </tr> <tr> <td>Available:</td> <td><html:checkbox property="available" /></td> </tr> </tbody> </table> <%-- set the parameter for the dispatch action --%> <html:hidden property="do" value="saveBook" /> <br> <%-- submit and back button --%> <html:button property="back" onclick="history.back();"> </html:button> Back <html:submit>Save</html:submit> </html:form> </body> </html> La marca <html:form> crea un nuevo formulario HTML y se enlaza con el parámetro action=“bookEdit“ al action mapping. La marca <html:text> crea un campo de texto con la propiedad del autor del libro. <html:hidden> es un campo oculto con el nombre do. Necesitamos este campo oculto porque llama a la the dispatch action class con el método que querramos. Abra el archivo bookEdit.jsp. Ouede usar el código del archivo bookAdd.jsp y cambiar las siguientes líneas. <title>Edit a book</title> Agegue la siguiente línea arriba <html:hidden property="do" value="saveBook" /> <%-- hidden fields for id and userId --%> <html:hidden property="id" /> Abra el archivo bookBorrow.jsp y agregue <%@ <%@ <%@ <%@ <%@ page language="java"%> page isELIgnored="false"%> taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean"%> taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html"%> taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic" %> <html> <head> <title>Show customers</title> </head> <body> <html:form action="bookEdit"> <table border="1"> <tbody> <%-- set the header --%> <tr> <td>Last name</td> <td>Name</td> <td>Borrow</td> </tr> <%-- start with an iterate over the collection users --%> <logic:present name="customers"> <logic:iterate name="customers" id="customer"> <tr> <%-- book informations --%> <td><bean:write name="customer" property="lastname" /></td> <td><bean:write name="customer" property="name" /></td> <td><html:radio property="customerId" value="${customer.id}" /></td> </tr> </logic:iterate> </logic:present> <%-- end interate --%> <%-- if customers cannot be found display a text --%> <logic:notPresent name="customers"> <tr> <td colspan="5">No customers found.</td> </tr> </logic:notPresent> </tbody> </table> <%-- set the book id to lent --%> <html:hidden property="id" /> <%-- set the parameter for the dispatch action --%> <html:hidden property="do" value="saveBorrow" /> <%-- submit and back button --%> <html:button property="back" onclick="history.back();"> </html:button> <html:submit>Save</html:submit> </html:form> </body> </html> Back Métodos de la dispatch action class Abra el archivo bookEditAction.java agregue los siguientes métodos. public class BookEditAction extends DispatchAction { /** * loads the book specified by the id from the database and forwards to the edit form * @param mapping * @param form * @param request * @param response * @return ActionForward */ public ActionForward editBook( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { System.out.println("editBook"); BookEditForm bookEditForm = (BookEditForm) form; } /* lalinuna.de 04.11.2004 * get id of the book from request */ Integer id = Integer.valueOf(request.getParameter("id")); // [laliluna] 28.11.2004 get business logic LibraryManager libraryManager = new LibraryManager(); bookEditForm.setBook(libraryManager.getBookByPrimaryKey(id)); return mapping.findForward("showEdit"); /** * loads a book from the db and forwards to the borrow book form * @param mapping * @param form * @param request * @param response * @return ActionForward */ public ActionForward borrowBook( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { System.out.println("borrowBook"); BookEditForm bookEditForm = (BookEditForm) form; /* lalinuna.de 04.11.2004 * get id of the book from request */ Integer id = Integer.valueOf(request.getParameter("id")); /* lalinuna.de 16.11.2004 * load the session facade for book and user * get the book information and get all users */ LibraryManager libraryManager = new LibraryManager(); // [laliluna] 28.11.2004 save book in the form bookEditForm.setBook(libraryManager.getBookByPrimaryKey(id)); // [laliluna] 28.11.2004 save customers in the reqest request.setAttribute("customers", libraryManager.getAllCustomers ()); } return mapping.findForward("showBorrow"); /** * return a book from a customer * @param mapping * @param form * @param request * @param response * @return ActionForward */ public ActionForward returnBook( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { System.out.println("returnBook"); BookEditForm bookEditForm = (BookEditForm) form; /* lalinuna.de 04.11.2004 * get id of the book from request */ Integer id = Integer.valueOf(request.getParameter("id")); // [laliluna] 28.11.2004 get business logic LibraryManager libraryManager = new LibraryManager(); libraryManager.returnBook(id); } return mapping.findForward("showList"); /** * deletes a book from the database * @param mapping * @param form * @param request * @param response * @return ActionForward */ public ActionForward deleteBook( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { System.out.println("deleteBook"); BookEditForm bookEditForm = (BookEditForm) form; /* lalinuna.de 04.11.2004 * get id of the book from request */ Integer id = Integer.valueOf(request.getParameter("id")); // [laliluna] 28.11.2004 get business logic LibraryManager libraryManager = new LibraryManager(); libraryManager.removeBookByPrimaryKey(id); return mapping.findForward("showList"); } /** * forwards to the add book form * @param mapping * @param form * @param request * @param response * @return ActionForward */ public ActionForward addBook( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { System.out.println("addBook"); BookEditForm bookEditForm = (BookEditForm) form; return mapping.findForward("showAdd"); } /** * saves the borrow assigned in the form in the database * @param mapping * @param form * @param request * @param response * @return ActionForward */ public ActionForward saveBorrow( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { BookEditForm bookEditForm = (BookEditForm) form; // [laliluna] 28.11.2004 get business logc LibraryManager libraryManager = new LibraryManager(); libraryManager.borrowBook(bookEditForm.getId(), bookEditForm.getCustomerId()); } return mapping.findForward("showList"); /** * updates or creates the book in the database * @param mapping * @param form * @param request * @param response * @return ActionForward */ public ActionForward saveBook( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { BookEditForm bookEditForm = (BookEditForm) form; } } // [laliluna] 28.11.2004 get business logic LibraryManager libraryManager = new LibraryManager(); libraryManager.saveBook(bookEditForm.getBook()); return mapping.findForward("showList"); Caso de uso listado de clientes Creamos esta lista de la misma forma que la de los libros. Abra struts-config.xml. Elija el asistente para crear una acción, un formulario y los forwards a la vez. Nuestro caso de uso es customer list. Edite el diálogo como ya lo vió: No se olvide los cambios en las lengüetas de métodos. En la lengüeta JSP cree el siguiente JSP. El próximo paso es poner la acción que será llamada antes que su JSP se muestre. Haga los cambios como se muestra debajo. El último paso es crear el forwards la acción que redireccionará al JSP que muestra la lista de clientes. Por ahora, emos creado todos los archivos necesarios para nuestros casos de uso. El paso siguiente es rellenarlos con contenido. Edición del código de la action form class Abra el archivo CustomerListForm.java y agregue el código siguiente. public class CustomerListForm extends ActionForm { private Customer[] customers = new Customer[0]; /** * @return Returns the customers. */ public Customer[] getCustomers() { return customers; } /** * @param customers The customers to set. */ public void setCustomers(Customer[] customers) { this.customers = customers; } } No necesitamos un método reset aquí, como el bean es usado solamente para pasar los datos de la acción al JSP. Edite la action class. public class CustomerListAction extends Action { /** * loads customers from the db and saves them in the request * @param mapping * @param form * @param request * @param response * @return ActionForward */ public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { CustomerListForm customerListForm = (CustomerListForm) form; // [laliluna] 29.11.2004 get business logic LibraryManager libraryManager = new LibraryManager(); } } customerListForm.setCustomers(libraryManager.getAllCustomers()); return mapping.findForward("showCustomerList"); Mostrar la lista de clientes Abra el archivo jsp customerList.jsp y cambie el contenido del archivo por esto. <%@ page language="java"%> <%@ taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean"%> <%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html"%> <%@ taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic"%> <html> <head> <title>JSP for customerListForm form</title> </head> <body> <table border="1"> <tbody> <%-- set the header --%> <logic:present name="customerListForm" property="customers"> <tr> <td>Name</td> <td>Last name</td> <td>Age</td> <td></td> <td></td> </tr> <%-- start with an iterate over the collection books --%> <logic:iterate name="customerListForm" property="customers" id="customer"> <tr> <%-- book informations --%> <td><bean:write name="customer" property="name" /></td> <td><bean:write name="customer" property="lastname" /></td> <td><bean:write name="customer" property="age" /></td> <%-- edit and delete link for each customer --%> <td><html:link action="customerEdit.do?do=editCustomer" paramName="customer" paramProperty="id" paramId="id">Edit</html:link> </td> <td><html:link action="customerEdit.do?do=deleteCustomer" paramName="customer" paramProperty="id" paramId="id">Delete</html:link> </td> </tr> </logic:iterate> <%-- end interate --%> </logic:present> <%-- if customers cannot be found display a text --%> <logic:notPresent name="customerListForm" property="customers"> <tr> <td colspan="5">No customers found.</td> </tr> </logic:notPresent> </tbody> </table> <br> <%-- add and back to menu button --%> <html:button property="add" onclick="location.href='customerEdit.do?do=addCustomer'">Add a new customer </html:button> <html:button property="back" onclick="location.href='default.do'">Back to menu </html:button> </body> </html> Eso es. Hemos terminado el caso de uso, ahora debemos probarlo. Casos de uso Agegar, editar y borrar clientes En el siguiente paso queremos agregar los siguientes procesos. • Agregar un cliente • Editar un cliente • Borrar un cliente Seleccione „New Form, Action and JSP“. Seleccione para crear un archivo JSP. Siga hasta la página de acción. Seleccione DispatchAction como la Super Clase. Luego seleccione para crear un parámetro: Cree tres forwards como se muestra debajo. Formulario bean para Cliente Agregue un nuevo atributo del tipo Customer private Customer customer; Genere los métodos getter y setter y herede todos los métodos de la clase, al igual que hizo con el form bean de libros. El código de la clase es como el siguiente public class CustomerEditForm extends ActionForm { private Customer customer; /** * @return Returns the customer. */ public Customer getCustomer() { return customer; } /** * @param customer The customer to set. */ public void setCustomer(Customer customer) { this.customer = customer; } /** * Method reset * @param mapping * @param request */ public void reset(ActionMapping mapping, HttpServletRequest request) { customer=new Customer(); } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object arg0) { return customer.equals(arg0); } /** } * @return */ public Integer getAge() { return customer.getAge(); } /** * @return */ public Integer getId() { return customer.getId(); } /** * @return */ public String getLastname() { return customer.getLastname(); } /** * @return */ public String getName() { return customer.getName(); } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ public int hashCode() { return customer.hashCode(); } /** * @param age */ public void setAge(Integer age) { customer.setAge(age); } /** * @param id */ public void setId(Integer id) { customer.setId(id); } /** * @param lastname */ public void setLastname(String lastname) { customer.setLastname(lastname); } /** * @param name */ public void setName(String name) { customer.setName(name); } /* (non-Javadoc) * @see java.lang.Object#toString() */ public String toString() { return customer.toString(); } Edición del código de la action class Abra el archivo CustomerEditAction.class en el paquete de.laliluna.library.struts.action y agregue los métodos siguientes. Lo primero es el paso antes de editar un cliente. Cargar los datos del cliente desde la base de datos y guardarlos en el formulario bean. /** * loads customer from the db and forwards to the edit form * @param mapping * @param form * @param request * @param response * @return */ public ActionForward prepareEdit(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { CustomerEditForm customerEditForm = (CustomerEditForm) form; Integer id = Integer.valueOf(request.getParameter("id")); LibraryManager libraryManager = new LibraryManager(); customerEditForm.setCustomer(libraryManager.getCustomerByPrimaryKey(id)); return mapping.findForward("editCustomer"); } El próximo método es el anterior a agregar un cliente. Realmente solo es un forrward al JSP. /** * prepares the add form (actually only forwards to it) * @param mapping * @param form * @param request * @param response * @return */ public ActionForward prepareAdd(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { return mapping.findForward("addCustomer"); } La actualización y creación de clientes está hecho por el siguiente método. /** * saves the customers and forwards to the list * @param mapping * @param form * @param request * @param response * @return */ public ActionForward saveCustomer(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { CustomerEditForm customerEditForm = (CustomerEditForm) form; LibraryManager libraryManager = new LibraryManager(); libraryManager.saveCustomer(customerEditForm.getCustomer()); return mapping.findForward("customerList"); } Y finalmente cuando hace clic en eliminar, el siguiente método es llamado. /** * deletes the customers and forwards to the list * @param mapping * @param form * @param request * @param response * @return */ public ActionForward deleteCustomer(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { CustomerEditForm customerEditForm = (CustomerEditForm) form; LibraryManager libraryManager = new LibraryManager(); libraryManager.removeCustomerByPrimaryKey(customerEditForm.getCustomer(). getId()); } return mapping.findForward("customerList"); Cuando la lógica del negocio se mantiene separada, el código de acción es siempre mucho más corto y fácil de leer. Edit the source code of the jsp file Create a new file named editcustomer.jsp in the folder WebRoot/jsp/. Open the file editcustomer.jsp and change the content of the file. <%@ page language="java"%> <%@ taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean"%> <%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html"%> <html> <head> <title>JSP for customerEditForm form</title> </head> <body> <html:form action="/customerEdit"> <html:hidden property="id"/> <html:hidden property="do" value="saveCustomer"/> Name: <html:text property="name"/><br/> Last name <html:text property="lastname"/><br/> Age <html:text property="age"/><br/> <html:submit/><html:cancel/> </html:form> </body> </html> Test the applications Start the jboss and deploy the project as package archiv. Call the project in your favorite web browser. http://localhost:8080/LibraryWeb/ Nice, that's all. I hope you enjoyed the tutorial. If you have any feedback to us, feel free to contact us.