Software, Java & afins

Fabricio Braga, Sun Certified

Integrando Spring, Struts 2 e Hibernate

escrito por Fabricio Braga em Jul 2009

Aqui um pequeno tutorial de como desenvolver uma aplicação web integrando Struts 2, Spring e Hibernate.  A idéia básica é usar a implementação do padrão MVC do Struts 2, a Injeção de Dependência do Spring e o Mapeamento Objeto-Relacional do Hibernate.

Ao final do post coloquei um link com a aplicação de exemplo para download.

As ferramentas utilizadas neste exemplo são o Banco de dados MySQL, Eclipse IDE, Spring Framework (versão 2.5.6), Struts (versão 2.1.6) e Hibernate 3.

Vamos dar início ao nosso passo-a-passo…

Montando e configurando o ambiente:

Faça o download do MySQL: aqui

Faça o download do Eclipse IDE: aqui

Faça o download do Spring Framework: aqui

Faça o Download do Struts 2: aqui

Instale o Banco de Dados MySQL, e crie um schema para o nosso tutorial, neste caso vou chama-lo de “example“.  Inicie o Eclipse e crie um projeto do tipo Dynamic Web Project, aqui vou chama-lo também de “example“.

Feito isso, você já tem a estrutura básica de sua aplicação montada.  Agora precisamos de alguns arquivos de biblioteca, para fazer nossa aplicação funcionar, vamos utilizar os seguintes arquivos, que podem ser encontrados nas distruições do Spring e do Struts que você baixou:

Copie estes arquivos para a pasta WebContent/WEB-INF/lib do seu projeto:

commons-collections.jar
commons-dbcp.jar
commons-fileupload-1.2.1.jar
commons-io-1.3.2.jar
commons-logging-1.1.jar
commons-pool.jar
dom4j-1.6.1.jar
freemarker-2.3.13.jar
hibernate-annotations.jar
hibernate-commons-annotations.jar
hibernate-entitymanager.jar
hibernate3.jar
javassist.jar
jaxen-1.1-beta-7.jar
junit-3.8.1.jar
log4j-1.2.15.jar
mysql-connector-java-5.1.7-bin.jar
ognl-2.6.11.jar
persistence.jar
slf4j-api-1.5.0.jar
slf4j-log4j12-1.5.0.jar
spring-aop.jar
spring-beans-2.5.3.jar
spring-context-2.5.3.jar
spring-core.jar
spring-mock-2.0.8.jar
spring-orm.jar
spring-test-2.5.6.jar
spring-web-2.5.3.jar
spring.jar
struts2-core-2.1.6.jar
struts2-spring-plugin-2.1.6.jar
xwork-2.1.2.jar

commons-collections.jar
commons-dbcp.jar
commons-fileupload-1.2.1.jar
commons-io-1.3.2.jar
commons-logging-1.1.jar
commons-pool.jar
dom4j-1.6.1.jar
freemarker-2.3.13.jar
hibernate-annotations.jar
hibernate-commons-annotations.jar
hibernate-entitymanager.jar
hibernate3.jar
jaxen-1.1-beta-7.jar
junit-3.8.1.jar
log4j-1.2.15.jar
ognl-2.6.11.jar
persistence.jar
slf4j-api-1.5.0.jar
slf4j-log4j12-1.5.0.jar
spring-aop.jar
spring-beans-2.5.3.jar
spring-context-2.5.3.jar
spring-core.jar
spring-mock-2.0.8.jar
spring-orm.jar
spring-test-2.5.6.jar
spring-web-2.5.3.jar
spring.jar
struts2-core-2.1.6.jar
struts2-spring-plugin-2.1.6.jar
xwork-2.1.2.jar

Você precisará também do driver JDBC do MySQL, qude pode ser baixado aqui.  Depois, copie o jar mysql-connector-java-5.1.7-bin.jar para o mesmo diretório lib da nossa aplicação.

Precisaremos também da API javassist, que é usada pelo Hibernate, e pode ser encontrada aqui.  Coloque o jar do Javassist no diretório lib da aplicação.

Pronto!  Agora vamos finalmente começar a desenvolver…

Vamos primeiro criar nosso Action, chamaremos ele de WelcomeAction, e o colocaremos no pacote “example.actions“.  Abaixo o código do Action, bem simples:

package example.actions;

import java.util.Date;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.opensymphony.xwork2.ActionSupport;

public class WelcomeAction extends ActionSupport {

private Log logger = LogFactory.getLog(this.getClass());
public static final String MESSAGE = “Struts 2 Hello World Tutorial!”;

public String execute() throws Exception {

logger.info(”returning welcome action”);
setMessage(MESSAGE);
return SUCCESS;

}

private String message;

public void setMessage(String message) {
this.message = message;

}

public String getMessage() {

return message;

}

public String getCurrentTime() {

return new Date().toString();

}

}

No próximo passo criaremos nossas páginas, a páginal inicial, index.html é simples e apenas faz o redirecionamento para nossa página de boas-vindas, ela ficará assim:

<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.0 Transitional//EN”>

<html>
<head>
<META HTTP-EQUIV=”Refresh” CONTENT=”0;URL=pages/welcomeAction.action”>
</head>

<body>
<p>Loading …</p>
</body>
</html>

E a nossa página welcome.jsp:
<%@ taglib prefix=”s” uri=”/struts-tags”%>
<html>
<head>
<title>Struts 2 Hello World Application!</title>
</head>
<body>
<s:property value=”message” />
<p>Current date and time is: <b><s:property value=”currentTime” /></b>
</body>
</html>

No próximo passo, criaremos nosso arquivo de mapeamento dos Actions, chamado struts.xml, no diretório raiz das classes.  Coloque este arquivo na pasta “src”, isso fará com que o Eclipse o copie automaticamente para o diretório das classes compiladas.

O arquivo struts.xml mapeando nosso WelcomeAction ficará assim:

<?xml version=”1.0″ encoding=”UTF-8″ ?>
<!DOCTYPE struts PUBLIC

“-//Apache Software Foundation//DTD Struts Configuration 2.0//EN”

“http://struts.apache.org/dtds/struts-2.0.dtd”>

<struts>
<constant name=”struts.enable.DynamicMethodInvocation” value=”false” />
<constant name=”struts.devMode” value=”true” />

<package name=”pages” namespace=”/pages” extends=”struts-default”>
<action name=”welcomeAction” class=”example.actions.WelcomeAction”> <result>/pages/welcome.jsp</result>
</action>
</package>

</struts>

Bem simples.  O arquivo apenas mapeia nosso WelcomeAction.  Agora vamos adicionar ao nosso web.xml o filter do Struts 2, que cuidará de processar as requisições:

<?xml version=”1.0″ encoding=”UTF-8″?>
<web-app id=”WebApp_9″ version=”2.4″ xmlns=”http://java.sun.com/xml/ns/j2ee”

xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”

xsi:schemaLocation=”http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd”>

<display-name>Exemplo</display-name>

<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>

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

</web-app>

Vamos também adicionar um arquivo básico de log, usando o Log4J.  Crie o arquvo log4j.properties no diretório src, no mesmo lugar onde está o struts.xml.  O arquivo log4j.properties, ficará assim:

# ***** Set root logger level to DEBUG and its only appender to A.
log4j.rootLogger=info, A

# ***** A is set to be a ConsoleAppender.
log4j.appender.A=org.apache.log4j.ConsoleAppender

# ***** A uses PatternLayout.
log4j.appender.A.layout=org.apache.log4j.PatternLayout
log4j.appender.A.layout.ConversionPattern=%-4r [%t] %-5p %c %x – %m%n

Como as libs do plugin para o Spring jã estão lá, precisamos também colocar o arquivo “applicationContext.xml” no diretório WEB-INF, por hora ele ficará vazio (ainda não temos beans mapeados pelo Spring), assim:

<beans xmlns=”http://www.springframework.org/schema/beans” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:aop=”http://www.springframework.org/schema/aop” xmlns:tx=”http://www.springframework.org/schema/tx” xsi:schemaLocation=”         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd         http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd”
default-autowire=”byName”>

</beans>

Agora você deve fazer o deploy da aplicação, e verá a tela do struts, com a data e nossa mensagem de Hello World.  Passado este primeiro e básico passo, vamos integrar tudo ao Spring e ao Hibernate.  Vamos adicionar este arquivo de properties ao diretório “src”, ele diz ao Struts para permitir que o Spring gerencie nossos objetos.  Aqui o arquivo “struts.xml”:

### specifies the autoWiring logic when using the SpringObjectFactory.
### valid values are: name, type, auto, and constructor (name is the default)
struts.objectFactory.spring.autoWire = name

### indicates to the struts-spring integration if Class instances should be cached
### this should, until a future Spring release makes it possible, be left as true
### unless you know exactly what you are doing!
### valid values are: true, false (true is the default)
struts.objectFactory.spring.useClassCache = true

### ensures the autowire strategy is always respected.
### valid values are: true, false (false is the default)
struts.objectFactory.spring.autoWire.alwaysRespect = false

Agora vamos adicionar ao nosso “applicationContext.xml” o mapeamento do banco, e as instruções para que o Hibernate faça o mapeamento dos nossos beans anotados:
<bean id=”entityManagerFactory”
class=”org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean”>
<property name=”jpaVendorAdapter”>
<bean class=”org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter”>
<property name=”showSql” value=”true” />
<property name=”generateDdl” value=”true” />
<property name=”databasePlatform” value=”org.hibernate.dialect.MySQLDialect” />
</bean>
</property>
</bean>
<bean id=”dataSource” class=”org.apache.commons.dbcp.BasicDataSource”
destroy-method=”close”>
<property name=”driverClassName” value=”com.mysql.jdbc.Driver” />
<property name=”url” value=”jdbc:mysql://localhost:3306/example” />
<property name=”username” value=”usuario />
<property name=”password” value=”senha” />
</bean>
<bean id=”transactionManager” class=”org.springframework.orm.jpa.JpaTransactionManager” />
<tx:annotation-driven />
<bean
class=”org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor” />
Substitua o nome de usuário e senha pelos correspondentes da sua máquina.  Precisamos também criar o nosso Persistence Unit, que será usado pelo Spring para injetar EntityManager.  Crie um diretório chamado “META-INF” do diratório “src”, e dentro dele o arquivo “persistence.xml”, que ficará assim:
<?xml version=”1.0″ encoding=”UTF-8″?>
<persistence xmlns=”http://java.sun.com/xml/ns/persistence”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xsi:schemaLocation=”http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd”
version=”1.0″>
<persistence-unit name=”example” transaction-type=”RESOURCE_LOCAL” />
</persistence>
Nossa integração está pronta!  Faça novamente o deloy da aplicação e ela deve subir sem erros.  Vejamos rapidamente como o Hibernate mapeia automaticamente nossos beans e faz o trabalho para nós,  crie uma classe chamada “Usuario”, assim:
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table
public class Usuario {
private Integer id;
private String username;
private String senha;
@Id
@GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Column
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Column
public String getSenha() {
return senha;
}
public void setSenha(String senha) {
this.senha = senha;
}
}
Faça novamente o deploy da sua aplicação e verifique o banco de dados, nossa tabela “usuario” foi criada pelo Hibernate que reconheceu nossas annotations e fez o trabalho para nós.
Após isso, o EntityManager pode ser injetado no seu Dao ou Service (dependendo dos padrões que você for utilizar), com a simples annotation:
@PersistenceContext(name=”example”)
private EntityManager em;
É isso!  Apesar do trabalho inicial de configuração do ambiente, a integração Hibernate, Spring e Struts 2 proporciona ao desenvolvimento de aplicações web bastante produtividade e ganhos enormes na manutenção, já que o código fica bastante limpo.  Você também pode automatizar a criação e configuração do ambiente com ferramentas como Maven, por exemplo.Espero ter ajudado com este pequeno tutorial.

Clique aqui para baixar uma aplicação de exemplo
.  Basta descompactar e fazer o deploy no Tomcat, alterando os dados do seu banco de dados, claro.  Os fontes estão na mesma pasta dos arquivos “.class”.

Dúvidas? Poste sua dúvida aqui nos comentários ou envie ela direto para mim aqui.

  1. Thiago Felipe Festa Said,

    Olá,

    Excelente o seu blog! parabéns!

    Estou com alguns problemas aqui, segui todos os passos antes do hibernate.
    Porém não funciona, eu acho que é esses filters lá no web.xml

    Olha o erro que da:
    [code]HTTP Status 404 -

    type Status report

    message

    description The requested resource () is not available.[/code]

  2. Fabricio Braga Said,

    Thiago,

    Primeiramente gostaria de agradecer o o feedback!

    Um erro 404 significa um erro por motivo de mapeamento errado ou aplicação não disponível no Tomcat. Verifique seu web.xml (se quiser, envie o conteúdo dele pra mim), ok?

  3. HANNYERE Said,

    EXCELENTE ARTIGO, MAS COMO FAZ PRA FAZER ISSO:

    “Agora você deve fazer o deploy da aplicação, e verá a tela do struts, com a data e nossa mensagem de Hello World. Passado este primeiro e básico passo, vamos integrar tudo ao Spring e ao Hibernate. Vamos adicionar este arquivo de properties ao diretório “src”, ele diz ao Struts para permitir que o Spring gerencie nossos objetos. Aqui o arquivo “struts.xml”:”

    Eu startei meu tomcat mas o projeto nao esta lá, eu exportei o war dele e quando tento fazer deploy no tomcat ele diz:
    “HTTP Status 500 -

    type Exception report

    message

    description The server encountered an internal error () that prevented it from fulfilling this request.

    exception

    javax.servlet.ServletException: Servlet execution threw an exception

    root cause

    java.lang.NoClassDefFoundError: org/apache/commons/io/output/DeferredFileOutputStream
    org.apache.commons.fileupload.DefaultFileItemFactory.createItem(DefaultFileItemFactory.java:103)
    org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:350)
    org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:302)
    org.apache.catalina.manager.HTMLManagerServlet.doPost(HTMLManagerServlet.java:157)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)

    root cause

    java.lang.ClassNotFoundException: org.apache.commons.io.output.DeferredFileOutputStream
    org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1363)
    org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1209)
    java.lang.ClassLoader.loadClassInternal(Unknown Source)
    org.apache.commons.fileupload.DefaultFileItemFactory.createItem(DefaultFileItemFactory.java:103)
    org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:350)
    org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:302)
    org.apache.catalina.manager.HTMLManagerServlet.doPost(HTMLManagerServlet.java:157)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)

    note The full stack trace of the root cause is available in the Apache Tomcat/5.5.26 logs.
    Apache Tomcat/5.5.26″

    ME AJUDA, QUERIA VER ISSO FUNCIONANDO.
    GRATO! E PARABENS

  4. HANNYERE Said,

    cara, resolvi. era o tomcat que nao tinha o jar commons-io.jar. Resolvido. Agora estou com o mesmo problema do Thiago Felipe Festa, segue meu web.xml:

    example

    index.html
    index.htm
    index.jsp
    default.html
    default.htm
    default.jsp

    Exemplo

    struts2
    org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter

    struts2
    /*

    index.html

  5. HANNYERE Said,

    MEU WEB.XML

    Exemplo

    struts2
    org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter

    struts2
    /*

    index.html

  6. HANNYERE Said,

    Exemplo

    struts2
    org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter

    struts2
    /*

    index.html

  7. Fabricio Braga Said,

    Enviei para o seu email um exemplo de web.xml, ok?

    Qualquer dúvida, só falar.

  8. Ilton Barbosa Said,

    Qual a diferença da minha Action extender ActionSupport ou Dispatcher ?
    Favor enviar resposta para meu e-mail: jittobr@gmail.com

  9. Fabricio Braga Said,

    Ilton,

    Teoricamente você pode ter um Action sem extender ActionSupport, entretanto a classe ActionSupport possui diversos métodos que serão utilizados para validação, manipulação de erros, internacionalização, etc.

    Se você não extende ActionSupport, terá sérios problemas em usufruir destas vantagens já implementadas pelo Struts, e provavlemente terá que re-implementa-las na mão.

    []s!

  10. Ilton Barbosa Said,

    Também parei no mesmo erro 404.
    Não tenho nem idéia no que devo mexer no struts.xml e no web.xml

  11. Fabricio Braga Said,

    Pessoal,

    Coloquei uma aplicação de exemplo para download ao final do post, ok? É só descompactar e copiar para dentro da pasta “webapps” do Tomcat, e após reinicia-lo acessar no seu browser:

    http://localhost:8080/struts2spring

    Os fontes estão no mesmo diretório dos “.class”.