Spring 3 (annotations) + Struts 2 + Hibernate 3 = Dúvida

Caros, já é possível utilizar o Spring 3 com Struts 2?

Estou tentando implementar o Spring 3 como IoC e para integrar com o Hibernate 3, porem quando rodo tudo isso no Struts 2 me dá a impressão que a injeção não acontece na classe UsuarioServiceImpl:

LoginAction.java (ainda não aplicado o IoC)

package br.com.internetsistemas.nucleo.action;

import br.com.internetsistemas.nucleo.model.Usuario;
import br.com.internetsistemas.nucleo.service.UsuarioServiceImpl;

import com.opensymphony.xwork2.ActionSupport;

public class LoginAction extends ActionSupport {
	private static final long serialVersionUID = 1L;
	
	public String login() {
		UsuarioServiceImpl usuarioService = new UsuarioServiceImpl();
		
		Usuario usuario = usuarioService.retrieveUser(1L); 
		
		System.out.println(">>>" + usuario);
		
		return SUCCESS;
	}
}

UsuarioServiceImpl.java

package br.com.internetsistemas.nucleo.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import br.com.internetsistemas.nucleo.model.Usuario;
import br.com.internetsistemas.nucleo.model.UsuarioDAO;

@Service
public class UsuarioServiceImpl implements UsuarioService {
	@Autowired(required = true)
	private UsuarioDAO usuarioDAO;

	@Transactional
	public Usuario createUser(Usuario usuario) {
		return this.usuarioDAO.persistOrMerge(usuario);
	}

	@Transactional(readOnly = true)
	public Usuario retrieveUser(Long id) {
		System.out.println(usuarioDAO); // Aqui o resultado é null
		
		return this.usuarioDAO.findById(id);
	}
}

UsuarioDAOImpl.java

package br.com.internetsistemas.nucleo.model;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
public class UsuarioDAOImpl implements UsuarioDAO {
	@Autowired(required = true)
	private SessionFactory sessionFactory;

	public Usuario findById(Long id) {
		return (Usuario) this.sessionFactory.getCurrentSession().createQuery(
				"SELECT u FROM nuc_usuarios u WHERE u.cod_usuarios = ?")
				.setParameter(0, id).uniqueResult();
	}

	public Usuario persistOrMerge(Usuario usuario) {
		return (Usuario) this.sessionFactory.getCurrentSession().merge(usuario);
	}
}

Usuario.java

package br.com.internetsistemas.nucleo.model;

import java.util.Calendar;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

/**
 * Classe bean de usuário.
 * 
 * @version 1.0
 * @author felipe.fontoura
 */

@Entity
@Table(name = "nuc_usuarios")
public class Usuario {

	@Id
	@GeneratedValue
	@Column(name = "cod_usuarios")
	private Long id;

	@Column(name = "usuario", nullable = false, length = 45)
	private String login;

	@Column(name = "senha", nullable = false, length = 45)
	private String senha;

	@Column(name = "nome", nullable = true, length = 45)
	private String nome;

	@Column(name = "email", nullable = true, length = 80)
	private String email;

	@Column(name = "ultimo_login", nullable = false)
	@Temporal(TemporalType.TIMESTAMP)
	private Calendar ultimoLogin;

	public Usuario() {
		ultimoLogin = Calendar.getInstance();
	}

	public Long getId() {
		return id;
	}

	public String getLogin() {
		return login;
	}

	public String getSenha() {
		return senha;
	}

	public String getNome() {
		return nome;
	}

	public String getEmail() {
		return email;
	}

	public Calendar getUltimoLogin() {
		return ultimoLogin;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public void setLogin(String login) {
		this.login = login;
	}

	public void setSenha(String senha) {
		this.senha = senha;
	}

	public void setNome(String nome) {
		this.nome = nome;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public void setUltimoLogin(Calendar ultimoLogin) {
		this.ultimoLogin = ultimoLogin;
	}
}

struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
	<package name="nucleo" extends="struts-default">
		<action name="login" method="login"
			class="br.com.internetsistemas.nucleo.action.LoginAction">
			<result name="success">/jsp/nucleo/login.jsp</result>
		</action>
	</package>
</struts>    

applicationContext.xml

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

	<context:annotation-config />
	<context:component-scan base-package="br.com.internetsistemas" />
	
	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
		<property name="configLocation" value="classpath:hibernate.cfg.xml">
		</property>
	</bean>

	<tx:annotation-driven />

	<bean id="transactionManager"
		class="org.springframework.orm.hibernate3.HibernateTransactionManager">
		<property name="sessionFactory" ref="sessionFactory" />
	</bean>
</beans>

web.xml

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

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

	<filter>
		<filter-name>struts2</filter-name>
		<filter-class>
			org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
	</filter>

	<filter-mapping>
		<filter-name>struts2</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
</web-app>

Obrigado, abraços!

Só uma coisa:

package br.com.internetsistemas.nucleo.action;

import br.com.internetsistemas.nucleo.model.Usuario;
import br.com.internetsistemas.nucleo.service.UsuarioServiceImpl;

import com.opensymphony.xwork2.ActionSupport;

public class LoginAction extends ActionSupport {
	private static final long serialVersionUID = 1L;
	
	public String login() {
		UsuarioServiceImpl usuarioService = new UsuarioServiceImpl(); // porque você instancia essa classe? não era pra ser trazido via Spring???
		
		Usuario usuario = usuarioService.retrieveUser(1L); 
		
		System.out.println(">>>" + usuario);
		
		return SUCCESS;
	}
}

Injeção de dependência só ocorre com os beans do Spring, não com classes instanciadas dentro do código.

Existe uma documentação que diz como configurar o Struts 2 pra entender o Spring, tá em http://struts.apache.org/2.1.8.1/docs/struts-2-spring-2-jpa-ajax.html . Dê uma olhada, basicamente você vai ter que adicionar uns parâmetros em struts.xml, além de remover a instanciação no seu controller, óbvio.

Faltam algumas configurações na sua aplicação. Siga esse tutorial, ele é bem simples, e demonstra bem como fazer a integração.

Blz? Flw! :thumbup:

Pessoal, obrigado pela ajuda! Olha eu noobando de novo :slight_smile:

Ainda não consegui fazer funcionar! :frowning:

Fiz um teste com um bean mais básico ainda:

TesteService.java

package br.com.internetsistemas.nucleo.service;

import org.springframework.stereotype.Service;

@Service
public class TesteService {
	private String mensagem;
	
	public TesteService() {
		System.out.println("TesteService criado.");
		
		mensagem = "Mensagem de teste";
	}
	
	public String getMensagem() {
		return mensagem;
	}
}

LoginAction.java

package br.com.internetsistemas.nucleo.action;

import org.springframework.beans.factory.annotation.Autowired;
import com.opensymphony.xwork2.ActionSupport;

import br.com.internetsistemas.nucleo.service.TesteService;

public class LoginAction extends ActionSupport {
	private static final long serialVersionUID = 1L;

	@Autowired
	private TesteService teste;

	public String login() {
		if(teste != null)
		{
			System.out.println(">>>" + teste.getMensagem());
		}
		else
		{
			System.out.println("Erro: testeService null!"); // <-- Sempre cai nesta condição :(
		}
		
		return SUCCESS;
	}
}

O tomcat sobe normalmente, ou seja, teoricamente ele “cria” o bean. Comprovei isso porque a mensagem “TesteService criado.” é exibida. Porem quando rodo a action, sempre cai na condição em que o objeto teste é nulo, ou seja, não ocorreu a injeção.

Para funcionar no struts basta apenas colocar o annotation @AutoWired no atributo?

Abraços!!!

Não é só isso, precisa configurar o struts.xml para ler beans do Spring, como no link que eu passei.

Leonardo, obrigado!

Agora já está funcionando o IoC com um service simples (que eu mesmo criei), porem, quando adiciono o DAO a seguinte exception acontece quando subo o Tomcat:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'usuarioServiceImpl': Autowiring of fields failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private br.com.internetsistemas.nucleo.model.UsuarioDAOImpl br.com.internetsistemas.nucleo.service.UsuarioServiceImpl.usuarioDAOImpl; nested exception is java.lang.IllegalArgumentException: Can not set br.com.internetsistemas.nucleo.model.UsuarioDAOImpl field br.com.internetsistemas.nucleo.service.UsuarioServiceImpl.usuarioDAOImpl to $Proxy17

Segue as classes:

UsuarioDAOImpl.java

package br.com.internetsistemas.nucleo.model;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@Repository
public class UsuarioDAOImpl implements UsuarioDAO {
	private static Logger logger = Logger.getRootLogger();
	
	@PersistenceContext  
	private EntityManager entityManager;  
	
	public void setEntityManager(EntityManager entityManager) {
		this.entityManager = entityManager;
	}
	
	public UsuarioDAOImpl() {
		logger.info("Criado: " + entityManager);
	}

	@Transactional
	public void save(Usuario Usuario) {
		if (Usuario.getId() == null) {
			entityManager.persist(Usuario);
		} else {
			entityManager.merge(Usuario);
		}
	}

	@Transactional
	public void remove(int id) {
		Usuario Usuario = find(id);
		
		if (Usuario != null) {
			entityManager.remove(Usuario);
		}
	}

	public Usuario find(int id) {
		return entityManager.find(Usuario.class, id);
	}
	
	@SuppressWarnings("unchecked")
	public List<Usuario> findAll() {
		return entityManager.createQuery("SELECT u FROM nuc_usuarios u")
				.getResultList();
	}
}

UsuarioServiceImpl.java

package br.com.internetsistemas.nucleo.service;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import br.com.internetsistemas.nucleo.model.Usuario;
import br.com.internetsistemas.nucleo.model.UsuarioDAOImpl;

@Service
public class UsuarioServiceImpl implements UsuarioService {
	private static Logger logger = Logger.getRootLogger();

	@Autowired
	private UsuarioDAOImpl usuarioDAOImpl;

	public UsuarioServiceImpl() {
		logger.info("Criado: " + usuarioDAOImpl);
	}

	public void criarUsuario(Usuario usuario) {
		usuarioDAOImpl.save(usuario);
	}
}

E finalmente a action:

package br.com.internetsistemas.nucleo.action;

import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;

import br.com.internetsistemas.nucleo.model.Usuario;
import br.com.internetsistemas.nucleo.service.UsuarioServiceImpl;

import com.opensymphony.xwork2.ActionSupport;

public class LoginAction extends ActionSupport {
	private static final long serialVersionUID = 1L;
	private static Logger logger = Logger.getRootLogger();
	private List<Usuario> usuarios;

	@Autowired
	private UsuarioServiceImpl usuarioService;

	public String login() {
		logger.info("ACTION: " + usuarioService);

		return SUCCESS;
	}

	public List<Usuario> getUsuarios() {
		return usuarios;
	}
}

applicationContex.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">

	<context:property-placeholder location="classpath:/config.properties"/>

	<bean
		class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="${bd_driver_jdbc}" />
		<property name="url" value="${bd_url}" />
		<property name="username" value="${bd_usuario}" />
		<property name="password" value="${bd_senha}" />
	</bean>

	<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		
		<property name="dataSource" ref="dataSource"></property>
		<property name="jpaDialect">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"></bean>
		</property>
		<property name="jpaVendorAdapter">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
				<property name="database" value="${bd_tipo_banco}"></property>
				<property name="showSql" value="${bd_exibir_sql}"></property>
				<property name="generateDdl" value="${bd_criar_tabelas}"></property>
			</bean>
		</property>
	</bean>

	<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory"></property>
		<property name="dataSource" ref="dataSource"></property>
	</bean>

	<tx:annotation-driven transaction-manager="transactionManager" />

	<context:annotation-config />
	<context:component-scan base-package="br.com.internetsistemas.*.service" />
	<context:component-scan base-package="br.com.internetsistemas.*.model" />
</beans>

Ahh, consgui funcionar o conjunto apenas com Spring 2.5, mas isso já é outro post de ajuda :slight_smile:

Abraços e obrigado novamente!