Integrar Struts con Spring - holamundoStruts138Spring
Vamos al turrón, vamos a implementar lo que hemos visto a nivel teórico.
Creamos un nuevo proyecto web dinámico, holamundoStruts138Spring. Copiamos todo lo que tenemos en holamundoStruts138 sobre este nuevo proyecto para no partir de cero.
Básicamente sobreescribermos el controlador de Struts y utilizaremos la configuración de Spring para inyectar las dependencias a nuestros objetos.
LyckaRequestProcessor
package es.lycka.holamundoStruts138.action;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.action.RequestProcessor;
import org.apache.struts.config.ModuleConfig;
import org.apache.struts.util.RequestUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.struts.DelegatingActionUtils;
public class LyckaRequestProcessor extends RequestProcessor{
private WebApplicationContext webApplicationContext;
public void init(ActionServlet actionServlet, ModuleConfig moduleConfig) throws ServletException {
super.init(actionServlet, moduleConfig);
if (actionServlet != null) {
this.webApplicationContext = initWebApplicationContext(actionServlet, moduleConfig);
}
}
protected WebApplicationContext initWebApplicationContext(
ActionServlet actionServlet, ModuleConfig moduleConfig) throws IllegalStateException {
return DelegatingActionUtils.findRequiredWebApplicationContext(actionServlet, moduleConfig);
}
protected final WebApplicationContext getWebApplicationContext() {
return webApplicationContext;
}
/**
* Método que sobreescribimos para utilizar beans de Spring.
*/
protected Action processActionCreate(HttpServletRequest request,
HttpServletResponse response, ActionMapping mapping)
throws IOException {
// Acquire the Action instance we will be using (if there is one)
String className = mapping.getType();
if (log.isDebugEnabled()) {
log.debug(" Looking for Action instance for class " + className);
}
// If there were a mapping property indicating whether
// an Action were a singleton or not ([true]),
// could we just instantiate and return a new instance here?
Action instance;
//Acceso sincronizado al HasMaps de actions
synchronized (actions) {
// Return any existing Action instance of this class
instance = (Action) actions.get(className);
if (instance != null) {
if (log.isTraceEnabled()) {
log.trace(" Returning existing Action instance");
}
return (instance);
}
// Create and return a new Action instance
if (log.isTraceEnabled()) {
log.trace(" Creating new Action instance");
}
try {
//String beanName = determineActionBeanName(mapping);
String beanName = mapping.getType();
if (getWebApplicationContext().containsBean(beanName))
instance = (Action)getWebApplicationContext().getBean(beanName, Action.class);
else
instance = (Action) RequestUtils.applicationInstance(className);
// Maybe we should propagate this exception
// instead of returning null.
} catch (Exception e) {
log.error(getInternal().getMessage("actionCreate",
mapping.getPath()), e);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
getInternal().getMessage("actionCreate", mapping.getPath()));
return (null);
}
actions.put(className, instance);
}
if (instance.getServlet() == null) {
instance.setServlet(this.servlet);
}
return (instance);
}
}
Para que funcione correctamente además de las librerías de Struts que ya tenemos importadas, debemos utilizar spring.jar y spring-struts.jar.
Bases, Interfaces e Implementaciones
Ya aprovechamos que vamos a utilizar Spring para desdoblar nuestras clases en una clase Base por cada capa, y para cada clase utilizaremos un interfaz y una implementación.
Para no poner todas las implementaciones, que ya bastante larga va a quedar la entrada, sólo transcribo la implementación de IdentificarBOImpl. Sólo sería necesario el set del bean identificarDAO, pero por comodidad dejo ambas. Las demás implementaciones serían similares.
package es.lycka.holamundoStruts138Spring.negocio.impl;
import es.lycka.holamundoStruts138Spring.model.Usuario;
import es.lycka.holamundoStruts138Spring.negocio.IdentificarBO;
import es.lycka.holamundoStruts138Spring.persistencia.IdentificarDAO;
public class IdentificarBOImpl extends BaseBOImpl implements IdentificarBO {
private IdentificarDAO identificarDAO;
public boolean esUsuarioAutorizado (Usuario usuario) throws Exception {
boolean esAutorizado = false;
try {
if (identificarDAO.consultarUsuario (usuario) != null ) {
esAutorizado = true;
}
} catch (Exception e) {
throw e;
}
return esAutorizado;
}
public IdentificarDAO getIdentificarDAO() {
return identificarDAO;
}
public void setIdentificarDAO(IdentificarDAO identificarDAO) {
this.identificarDAO = identificarDAO;
}
}
web.xml
Vale, ahora debemos modificar el web.xml para utilizar también Spring.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/applicationContext-*.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
Así, podemos crear varios archivos XML para configurar nuestra aplicación:
- applicationContext-struts.xml, que contendrá los beans que representan a nuestras Acciones de Struts.
- applicationContext-negocio.xml, que contendrá los beans que representan a nuestros objetos de la capa de negocio.
- applicationContext-persistencia.xml, que contendrá los beans que representan a nuestros objetos de la capa de persistencia. Meteremos iBATIS en otro ejemplo.
applicationContext-struts.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean name="parentAction" class="es.lycka.holamundoStruts138Spring.control.action.AppBaseAction" abstract="true" />
<bean name="es.lycka.holamundoStruts138Spring.control.action.IdentificarAction" class="es.lycka.holamundoStruts138Spring.control.action.IdentificarAction" singleton="false" parent="parentAction">
<property name="identificarBO"><ref bean="identificarBO" /></property>
</bean>
</beans>
applicationContext-negocio.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean name="baseBO" class="es.lycka.holamundoStruts138Spring.negocio.impl.BaseBOImpl" abstract="true"/>
<bean id="identificarBO" class="es.lycka.holamundoStruts138Spring.negocio.impl.IdentificarBOImpl" parent="baseBO">
<property name="identificarDAO" ref="identificarDAO" />
</bean>
</beans>
applicationContext-persistencia.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="dao" class="es.lycka.holamundoStruts138Spring.persistencia.impl.BaseDAOImpl" abstract="true" />
<bean id="identificarDAO" class="es.lycka.holamundoStruts138Spring.persistencia.impl.IdentificarDAOImpl" parent="dao"/>
</beans>
struts-config.xml
Debemos declarar como controlador nuestra nueva clase es.lycka.holamundoStruts138Spring.action.LyckaRequestProcessor
<controller>
<set-property property="processorClass"
value="es.lycka.holamundoStruts138Spring.action.LyckaRequestProcessor" />
</controller>
Probamos y … bene !