Вы находитесь на странице: 1из 24

Learn Spring By Example Struts+Spring+Hibernate Integration

Deepesh Darshan K R June 26, 2013 1 Comment Hi friends, Finally after a long time, we are back. Here weve yet another example, as the title says, it is an Integration example in which we are going to see how Struts, Spring and Hibernate are getting integrated together. In the following example, Struts is used for view layer and also works as a controller, spring for IOC and transaction layers, hibernate for ORM (model layer).

Platform
OS: Windows XP Professional SP3. IDE: Eclipse Juno. Java: 1.6.0 Application Server: Apache Tomcat 6.0.37 Frameworks: Struts 2.1.8, Spring 3.2.1, Hibernate 3.2.0. Databse: MySQL 5.1.32-community. Ok, lets start. The heart of the application is applicationContext.xml, where these frameworks are integrated. The file looks like this. applicationContext.xml 1 2 3 4 5 6 7 8 9 1 0 1 1 1 2 1
<?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" xmlns:p="http://www.springframework.org/schema/p" 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.xsd"> <tx:annotation-driven transaction-manager="transactionManager" /> <context:annotation-config /> <context:component-scan

3 1 4 1 5 1 6 1 7 1 8 1 9 2 0 2 1 2 2 2 3 2 4 2 5 2 6 2 7 2 8 2 9 3 0 3 1 3 2 3 3 3 4 3 5 3

base-package="com.stringer.action,com.stringer.bo,com.stringer.dao" /> <context:property-placeholder location="/WEB-INF/jdbc.properties" /> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessi onFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="hibernateProperties" ref="hibernateProperties" /> <property name="packagesToScan" value="com.stringer.model"></property> </bean> <bean id="hibernateProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBea n"> <property name="locations"> <list> <value>/WEB-INF/hibernate.properties</value> </list> </property> </bean> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManage r" p:sessionFactory-ref="sessionFactory"> </bean> </beans>

6 3 7 3 8 3 9 4 0 4 1 4 2 4 3 4 4 4 5 4 6 4 7 Its sorry to say that Im not going to explain each and every point of the above configuration file. You can find out these definitions in every nook and corner of the web. Anyway I shall explain in brief. 1<context:property-placeholder location="/WEB-INF/jdbc.properties" /> The above line tells spring to load property file from the specified location. We can also load multiple property files simultaneously like this. 1 <bean id="dataSource" 2 class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 3 <property name="driverClassName" value="${driver}" /> <property name="url" value="${url}" /> 4 <property name="username" value="${username}" /> 5 <property name="password" value="${password}" /> 6 </bean> 7 The above bean definition says all about the database connection, i.e., driver, username, password, url etc. 1<bean id="hibernateProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean 2">

3 4 5 6 7 8

<property name="locations"> <list> <value>/WEB-INF/hibernate.properties</value> </list> </property> </bean>

The above bean definition tells spring to load hibernate properties from the specified file. 1<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessio 2 nFactoryBean"> 3 <property name="dataSource" ref="dataSource" /> 4 <property name="hibernateProperties" ref="hibernateProperties" /> 5 <property name="packagesToScan" value="com.stringer.model"></property> </bean> 6 The above definition creates a sessionFactory object using dataSource and hibernateProperties. The property packagesToScan specifies the path where the scanning for hibernate entities is to be performed. In this example, all model entities are encapsulated in com.stringer.model package. Here comes the definition for creating a transaction manger object. 1<bean id="transactionManager" 2 class="org.springframework.orm.hibernate3.HibernateTransactionManager" p:sessionFactory-ref="sessionFactory"> 3 </bean> 4 The given piece of line used to enable spring annotation. 1<context:annotation-config /> Finally, the below tag is used to scan for spring components in an application. The location of where to scan for classes is also specified. 1<context:component-scan base-package="com.stringer.action,com.stringer.bo,com.stringer.dao" 2/> As it is already discussed in one of the previous post, spring scans for classes that are annotated with one of the following annotations.

@Component @Controller @Repository @Service Any custom annotation that is itself annotated with @Component

Ok, now lets look into property files. jdbc.properties 1driver=com.mysql.jdbc.Driver 2url=jdbc:mysql://localhost:3306/Stringer 3username=root 4password=password hibernate.properties 1hibernate.dialect=org.hibernate.dialect.MySQL5Dialect 2hibernate.show_sql=true 3hibernate.hbm2ddl.auto=update Now weve finished spring configuration. Next we are going to see struts configuration. struts.xml
version="1.0" encoding="UTF-8" ?> 1 <?xml <!DOCTYPE struts PUBLIC 2 "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" 3 "http://struts.apache.org/dtds/struts-2.0.dtd"> 4 5 <struts> 6 <package name="default" extends="struts-default" namespace="/"> 7 8 <global-results> 9 <result name="StringerException" type="chain"> 10 <param name="actionName">StringerExceptionAction</param> </result> 11 <result name="error">/WEB-INF/Content/error.jsp</result> 12 </global-results> 13 14 <global-exception-mappings> 15 <exception-mapping exception="java.lang.Exception" 16 result="StringerException" /> </global-exception-mappings> 17 18 <action name="StringerExceptionAction" 19 class="com.stringer.util.StringerException"> 20 <result name="StringerExceptionResult">/WEB21INF/Content/error.jsp</result> 22 </action> 23 </package> 24 25 <include file="struts-user.xml" /> 26 <include file="struts-account.xml" /> 27 <include file="struts-index.xml" />

28 29</struts> 30 31 32 In the above file, we can see global-results and global-exceptions are mapped. Also, it includes some other action mapping files. Struts supports split the overall mappings into several mapping files. One of the mapping file is given below. The given file is used for action mappings of user module. struts-user.xml 1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE struts PUBLIC 3 "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" 4 "http://struts.apache.org/dtds/struts-2.0.dtd"> 5 6 <struts> 7 <package name="User" extends="default" namespace="/User"> 8 9 <action name="*" method="{1}" class="UserAction"> 10 <result name="success">/WEB-INF/Content/User/home.jsp</result> 11 <result name="input">/WEB-INF/Content/User/login.jsp</result> <result name="list">/WEB-INF/Content/User/list.jsp</result> 12 <result name="profile">/WEB13 INF/Content/User/profile.jsp</result> 14 <result name="home">/WEB-INF/Content/User/home.jsp</result> 15 <result name="create">/WEB16INF/Content/User/register.jsp</result> <result name="redirect" type="redirect">list.htm</result> 17 </action> 18 19 </package> 20 21</struts> 22 Just look into the highlighted line given above, where we can see an attribute namely class and its value UserAction. Here, its not the class name actually, but the name of a spring bean. Just scroll up to the UserAction.java and we can see that the class has been annotated(@Controller) as a Controller and the controllers name is given as UserAction. When we annotate a class as a controller, it becomes a spring component and we can reuse it anywhere in the application. How we could use it in this way because we add struts-spring integration plugin to the application and it helps us out. struts.properties

1 struts.action.extension=htm 2struts.ognl.allowStaticMethodAccess=true 3struts.objectFactory= org.apache.struts2.spring.StrutsSpringObjectFactory 4struts.objectFactory.spring.autoWire=type 5struts.convention.result.path=/WEB-INF/content/ 6struts.devMode=true struts.custom.i18n.resources=global 7 Here some of the struts properties defined, in which struts objectFactory and spring autowire default mode are notable. Here, we set default autowire mode as type. It allows a property to be autowired if exactly one bean of the property type exists in the container. If more than one exists, a fatal exception is thrown. You can get to know more about spring autowiring from here. This is for logging, which is optional. log4j.properties 1log4j.rootLogger = INFO, FILE 2log4j.appender.FILE=org.apache.log4j.FileAppender log4j.appender.FILE.File=C://log.out 3log4j.appender.FILE.layout=org.apache.log4j.PatternLayout 4log4j.appender.FILE.layout.conversionPattern=#[%d{dd/MMM/yyyy HH:mm:ss}] 5File[%F] - Method[%M] - Line[%L] - Priority[%p] - Message[%m]%n And the following two files stand for struts internationalization(i18n) or localization(i10n) purpose. package.properties 1 2 lbl.user.fname=First Name 3 lbl.user.lname=Last Name 4 lbl.user.age=Age 5 lbl.user.place=Place lbl.user.uname=Username 6 lbl.user.pwd=Password 7 lbl.acc.no=Account Number 8 lbl.acc.name=Account Name 9 lbl.acc.desc=Account Description Type 10lbl.acc.type=Account lbl.acc.opbal=Opening Balance 11btn.login=Login 12btn.reg=Register 13btn.sou=Save / Update 14btn.home=Home 15 global.properties

1msg.user.invalid=Invalid Username or Password ! 2msg.user.notfound=A User with username "$1" not found ! Finally, the most indispensable configuration. web.xml 1 2 3 4 5 6 7 8 9 1 0 1 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 2 0 2 1 2 2 2 3 2 4

<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>Stringer</display-name> <welcome-file-list> <welcome-file>/redirect.jsp</welcome-file> </welcome-file-list> <filter> <filter-name>struts2</filter-name> <filterclass>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter< /filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <listener> <listener-class> com.stringer.util.StringerListener </listener-class> </listener> <session-config> <session-timeout>600</session-timeout> </session-config> </web-app>

2 5 2 6 2 7 2 8 2 9 3 0 3 1 3 2 3 3 3 4 3 5 3 6 Please note how struts filter and spring listener are configured up here. We could see a user defined listener, namely StringerListener, which has also been set up there. Ok, finally all the configurations come to an end. Next we shall go to the source. First off, lets see the welcome page. redirect.jsp 1<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> 2<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 3"http://www.w3.org/TR/html4/loose.dtd"> 4<META HTTP-EQUIV="Refresh" CONTENT="0;URL=index.htm"> Here, we are going to discuss the complete flow of user registration. register.jsp 1 2 3 4
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%@taglib prefix="s" uri="/struts-tags"%>

5 <html> 6 <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 7 <title>Register</title> 8 </head> 9 <body> <fieldset style="width: 20%; background-color: lightyellow"> 10 <s:form action="saveOrUpdate" namespace="/User"> 11 <s:hidden name="user.id" /> 12 <s:hidden name="user.version" /> 13 <s:textfield name="user.firstName" key="lbl.user.fname" /> <s:textfield name="user.lastName" key="lbl.user.lname" /> 14 <s:textfield name="user.userName" key="lbl.user.uname" /> 15 <s:password name="user.password" key="lbl.user.pwd" /> 16 <s:textfield name="user.age" key="lbl.user.age" /> 17 <s:textfield name="user.place" key="lbl.user.place" /> <s:submit key="btn.sou" /> 18 </s:form> 19 </fieldset> 20</body> 21</html> 22 23 24 25 UserPOJO.java 1 2 import com.opensymphony.xwork2.conversion.annotations.TypeConversion; 3 4 public class UserPOJO { 5 private String firstName, lastName, userName, password, place; private int age; 6 private Long id, salt, version; 7 private Boolean isObsolete; 8 9 public Boolean getIsObsolete() { 10 return isObsolete; } 11 12 public void setIsObsolete(Boolean isObsolete) { 13 this.isObsolete = isObsolete; 14 } 15 16 public Long getId() { 17 return id; } 18 19 public void setId(Long id) { 20 this.id = id; 21 } 22
package com.stringer.pojo;

23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68

public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getPlace() { return place; } public void setPlace(String place) { this.place = place; } public int getAge() { return age; } @TypeConversion(converter = "com.stringer.util.IntegerConverter") public void setAge(int age) { this.age = age; } public Long getVersion() { return version; } public void setVersion(Long version) {

69 70 71 72 73 74 75 76 77} 78 79 80 81 82 83 84 85 86 87 88 89 90 91

this.version = version; } public Long getSalt() { return salt; } public void setSalt(Long salt) { this.salt = salt; }

Theres another class, namely UserDTO.java, which is used to transfer values between action and service. UserDTO.java 1 package com.stringer.dto; 2 public class UserDTO { 3 private String firstName, lastName, userName, password, place; 4 private int age; private Long id, salt, version; 5 private Boolean isObsolete; 6 7 public Long getId() { 8 return id; 9 } 10 11 public void setId(Long id) { this.id = id; 12 } 13 14 public String getFirstName() { 15 return firstName; 16 } 17

18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63

public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getPlace() { return place; } public void setPlace(String place) { this.place = place; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Long getVersion() { return version; } public void setVersion(Long version) { this.version = version; } public Long getSalt() { return salt;

64 65 66 67 68 69 70 71 72 73 74 75 76} 77 78 79 80 81 82 83 84 85 86 87 88 89

} public void setSalt(Long salt) { this.salt = salt; } public Boolean getIsObsolete() { return isObsolete; } public void setIsObsolete(Boolean isObsolete) { this.isObsolete = isObsolete; }

UserAction.java 1 2 import org.springframework.beans.factory.annotation.Autowired; 3 import org.springframework.context.annotation.Scope; 4 import org.springframework.stereotype.Controller; 5 import com.stringer.bo.UserBO; import com.stringer.dto.UserDTO; 6 import com.stringer.pojo.FetchType; 7 import com.stringer.pojo.SortBy; 8 import com.stringer.pojo.SortOrder; 9 import com.stringer.pojo.UserPOJO; 10import com.stringer.util.ApplicationUtils; 11 @Controller("UserAction") 12@Scope("prototype") 13public class UserAction extends BaseAction { 14 private UserPOJO user = null; 15 private UserDTO userDto = null; 16 private @Autowired 17 UserBO userBO;
package com.stringer.action;

18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 } 44 45 46 47 48 49 50 51 52

public UserPOJO getUser() { return user; } public void setUser(UserPOJO user) { this.user = user; } public String Register() { return CREATE; } public String Login() { return INPUT; } public String saveOrUpdate() throws StrutsActionException { try { userDto = ApplicationUtils.copyProperties(user, UserDTO.class); userBO.saveOrUpdate(userDto); if (isNull(session.get("loggedUser"))) { session.put("loggedUser", userDto); } return HOME; } catch (Exception e) { throw new StrutsActionException(e); } }

Here, UserAction.java works as a controller; see the highlighted line. UserBO.java 1package com.stringer.bo; 2 import com.stringer.dto.UserDTO; 3 4public interface UserBO extends BaseBO { 5 6 public void saveOrUpdate(final UserDTO userDTO) throws BOException;

7 8} 9 It provides an interface to the Service layer. UserBOImpl.java 1 2 import java.io.Serializable; 3 import java.util.Collection; 4 5 import org.springframework.beans.BeanUtils; 6 import org.springframework.beans.factory.annotation.Autowired; org.springframework.stereotype.Service; 7 import import org.springframework.transaction.annotation.Isolation; 8 import org.springframework.transaction.annotation.Propagation; 9 import org.springframework.transaction.annotation.Transactional; 10import com.stringer.dao.UserDAO; 11import com.stringer.dto.UserDTO; import com.stringer.model.Account; 12import com.stringer.model.User; 13import com.stringer.pojo.FetchType; 14import com.stringer.pojo.GenericPojo; 15import com.stringer.pojo.SortBy; 16import com.stringer.pojo.SortOrder; import com.stringer.util.ApplicationUtils; 17 18@Service("userBO") 19@Transactional(value = "transactionManager", timeout = 30, readOnly = true, 20propagation = Propagation.REQUIRED, isolation = Isolation.SERIALIZABLE, 21rollbackFor = java.lang.Exception.class) 22public class UserBOImpl extends BaseBOImpl implements UserBO { 23 private User user = null; 24 private @Autowired 25 BaseDAO baseDAO; 26 @Override 27 @Transactional(readOnly = false) 28 public void saveOrUpdate(final UserDTO userDTO) throws BOException { 29 try { 30 user = isNull(userDTO.getId()) ? ApplicationUtils .createInstance(User.class) : (User) userDAO 31 .findEntityById(User.class, userDTO.getId()); 32 ApplicationUtils.copyProperties(userDTO, user); 33 Long salt = ApplicationUtils.salt(); 34 user.setPassword(ApplicationUtils.uniquePassword( 35 userDTO.getPassword(), salt)); user.setSalt(salt); 36 user.setIsObsolete(Boolean.FALSE); 37 baseDAO.saveOrUpdate(user); 38 } catch (Exception e) {
package com.stringer.bo;

39 40 41 42} 43 44 45 46 47 48 49

throw new BOException(e); } }

This is the implementation class of UserBO.java. BaseDAO.java 1 package com.stringer.dao; 2 3 package com.stringer.dao; 4 5 public interface BaseDAO { 6 public <T> void saveOrUpdate(final T entity) throws DAOException; 7 8 9 } 10 } 11 This is an interface to the DAO layer. BaseDAOImpl.java 1 2 import org.hibernate.Session; 3 import org.hibernate.SessionFactory; 4 import org.springframework.beans.factory.annotation.Autowired; 5 import org.springframework.stereotype.Repository; 6 7 @Repository("baseDAO") 8 public class BaseDAOImpl implements BaseDAO { 9 10 private @Autowired SessionFactory sessionFactory; 11 12 protected final Session getSession() { 13 return sessionFactory.getCurrentSession(); 14 }
package com.stringer.dao;

15 16 17 18 19 20 21 22 23} 24 25 26 27 28

@Override public <T> void saveOrUpdate(final T obj) throws DAOException { try { getSession().saveOrUpdate(obj); } catch (Exception e) { throw new DAOException(e); } }

This is the implementation class of BaseDAO.java. Finally the hibernate entity class, User.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
package com.stringer.model; import import import import import import import import import import java.io.Serializable; javax.persistence.Column; javax.persistence.Entity; javax.persistence.GeneratedValue; javax.persistence.GenerationType; javax.persistence.Id; javax.persistence.Table; javax.persistence.TableGenerator; javax.persistence.Version; com.stringer.util.ApplicationConstants;

@Entity @Table(name = ApplicationConstants.USER_TABLE, catalog = ApplicationConstants.CATALOG) public class User implements Serializable { private private private private String firstName, lastName, place, userName, password; Integer age; Long salt, id, version; Boolean isObsolete;

public void setIsObsolete(Boolean isObsolete) { this.isObsolete = isObsolete; } public Boolean getIsObsolete() { return isObsolete; }

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71

@Column(unique = true, nullable = false) public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } @Column(unique = true, nullable = false) public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Column(unique = true, nullable = false) public Long getSalt() { return salt; } public void setSalt(Long salt) { this.salt = salt; } @TableGenerator(name = ApplicationConstants.GENERATOR_NAME, table = ApplicationConstants.GENERATOR_TABLE, pkColumnName = ApplicationConstants.GENERATOR_PK_COLUMN_NAME, valueColumnName = ApplicationConstants.GENERATOR_VALUE_COLUMN_NAME, pkColumnValue = ApplicationConstants.USER_TABLE, allocationSize = ApplicationConstants.USER_ALOC_SIZE, initialValue = ApplicationConstants.USER_INIT_VALUE) @GeneratedValue(strategy = GenerationType.TABLE, generator = ApplicationConstants.GENERATOR_NAME) @Id @Column(unique = true, nullable = false, updatable = false) public Long getId() { return id; } public void setId(Long id) { this.id = id; } @Column(nullable = false) public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; }

72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103} 104 105 106 107 108 109 110 111 112 113 114

@Column public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } @Column public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Column public String getPlace() { return place; } public void setPlace(String place) { this.place = place; } @Version public Long getVersion() { return version; } public void setVersion(Long version) { this.version = version; }

The folder structure and the list of libraries used are given below.

antlr-2.7.6 aopalliance asm-3.2 asm-attrs cglib-2.2.3 commons-beanutils-1.8.3 commons-collections-2.1.1

commons-fileupload-1.2.1 commons-io-1.3.2 commons-lang3-3.1 commons-logging-1.0.4 commons-logging-1.1.1 dom4j-1.6.1 ehcache-1.2.3 ejb3-persistence freemarker-2.3.15 hibernate3 hibernate-annotations hibernate-commons-annotations hibernate-entitymanager hibernate-tools javassist jdbc2_0-stdext jta log4j-1.2.14 mysql-connector-java-5.1.6-bin ognl-2.7.3 spring-aop-3.2.1.RELEASE spring-aspects-3.2.1.RELEASE spring-beans-3.2.1.RELEASE spring-build-src-3.2.1.RELEASE spring-context-3.2.1.RELEASE spring-context-support-3.2.1.RELEASE spring-core-3.2.1.RELEASE spring-expression-3.2.1.RELEASE spring-instrument-3.2.1.RELEASE spring-instrument-tomcat-3.2.1.RELEASE spring-jdbc-3.2.1.RELEASE spring-jms-3.2.1.RELEASE spring-orm-3.2.1.RELEASE spring-oxm-3.2.1.RELEASE spring-struts-3.2.1.RELEASE spring-test-3.2.1.RELEASE spring-tx-3.2.1.RELEASE spring-web-3.2.1.RELEASE spring-webmvc-3.2.1.RELEASE spring-webmvc-portlet-3.2.1.RELEASE struts2-core-2.1.8.1 struts2-spring-plugin-2.1.8 xwork-core-2.1.6

Conclusion

Вам также может понравиться