Está en la página 1de 59

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 9
Corrección del mapeo buleano 10
Mejoras al session Factory 10
Prueba de la parte de Hibernate 11
Problema de PostgreSQL 15
Generación de la lógica del negocio 16
Creación de una clase para la lógica del negocio 16
Creación de los diálogos 22
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 32
Edición del código fuente de la clase Form Action 32
Edición del código fuente de la clase Action 33
Muestra de la lista de libros en el archivo jsp. 33
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 50
Caso de uso: añadir, editar, suprimir clientes 51
Nuevo Form Bean 53
Edición del código fuente de la clase Action 56
Edición del código fuente del archivo jsp 57
Prueba de la aplicación 58
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();
Book book = (Book) session.get(Book.class, primaryKey);
if (book != null) // session.get returns null when no entry is
found
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>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</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>
&nbsp;
<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();">
Back
</html:button>
&nbsp;
<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();">
Back
</html:button>
&nbsp;
<html:submit>Save</html:submit>
</html:form>
</body>
</html>

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>
&nbsp;
<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.