摘要
最近也在網上找了些教程,試着使用maven進行包依賴關系的管理,也嘗試着通過注解的方式來整合ssh框架。在這個過程中,踩了不少的坑。折騰很長時間,才算把架子折騰起來。這里把結果整理下,作為以后工作中的參考。
項目結構
關於maven如何使用,可自行搜索,默認你有一定的maven基礎。maven建議中央倉庫配置成阿里雲的,可以下載速度快一些。地址
1、開始之前,需要通過maven進行ssh jar包引入。可以參考下面的pom.xml

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.demo</groupId> <artifactId>mavenapp</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>mavenapp Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <!--源碼編碼--> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> <!-- spring版本號 --> <spring.version>4.3.8.RELEASE</spring.version> <!-- hibernate版本號 --> <hibernate.version>5.1.7.Final</hibernate.version> <!-- struts2版本號 --> <struts2.version>2.5.10</struts2.version> </properties> <dependencies> <!--JUnit4依賴--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- Spring 核心依賴 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <!-- Spring web依賴 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <!-- Spring整合ORM框架依賴 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring.version}</version> </dependency> <!-- Struts2 核心依賴 --> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-core</artifactId> <version>${struts2.version}</version> </dependency> <!-- Struts2和Spring整合依賴 --> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-spring-plugin</artifactId> <version>${struts2.version}</version> </dependency> <!-- Hibernate 核心依賴 --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>${hibernate.version}</version> </dependency> <!-- MySQL 依賴 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.42</version> </dependency> <!-- C3P0 依賴 --> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5</version> </dependency> <!-- AspectJ依賴 --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.10</version> </dependency> <!-- SLF4J依賴 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.25</version> </dependency> </dependencies> <build> <finalName>mavenapp</finalName> <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.0.0</version> </plugin> <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging --> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.20.1</version> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>3.2.0</version> </plugin> <plugin> <artifactId>maven-install-plugin</artifactId> <version>2.5.2</version> </plugin> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>2.8.2</version> </plugin> </plugins> </pluginManagement> </build> </project>
2、將resources設置為資源目錄,並添加如上圖所示的jdbc屬性文件,struts2配置文件,日志屬性文件,spring配置文件
內容分別如下:

<?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:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 打開spring的annotation的支持 --> <context:annotation-config/> <!--引入jdbc屬性配置文件--> <context:property-placeholder location="classpath:jdbc.properties"/> <!--對me.demo下所有類文件進行掃描--> <context:component-scan base-package="me.demo.*"/> <!--c3p0連接池配置--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="driverClass" value="${jdbc.driverClass}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <!--sessionFactory配置 可以省略hibernate.cfg.xml配置文件--> <!--使用jpa注解形式的pojo對象,而去掉*.hbm.xml的Hibernate映射文件--> <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"> <!--配置數據源--> <property name="dataSource" ref="dataSource"/> <!-- 設置spring去哪個包中查找相應的實體類 --> <property name="packagesToScan"> <list> <value>me.demo.domain</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> <!--是否自動創建表結構--> <prop key="hibernate.hbm2ddl.auto">update</prop> <!--方言--> <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop> <!--hibernate中事務是需要在dao執行sql相關語句時來手動開啟的, 然后底層實現代碼時由getCurrentSession得到的session中可以得到transaction,所以可以正常運行. 這里,需要因為我們把sessionFactory的產生放在spring配置文件中,即讓服務器啟動時就創建這個對象,這樣的話它就被存在一個上下文環境中,即在SpringSessionContext中保存 所以我們要把綁定當前線程session改成綁定這個spring上下文環境,即設置為由spring環境管理(因為事務aop也是在spring中),這時spring中的事務配置才會起作用(當然,以前是thread上下文環境的session, 而事務托管在spring上下文中,當然spring無法管理到thread上下文的session的事務)。--> <prop key="hibernate.current_session_context_class"> org.springframework.orm.hibernate5.SpringSessionContext </prop> </props> </property> <!--自動掃描注解方式的hibernate類文件--> </bean> <!--事務管理器--> <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/> </bean> <!-- 基於注解的事務,當注解中發現@Transactional時,使用id為“transactionManager”的事務管理器 --> <!-- 如果沒有設置transaction-manager的值,則spring以缺省默認的事務管理器來處理事務, 默認事務管理器為第一個加載的事務管理器 --> <tx:annotation-driven transaction-manager="transactionManager"/> <!--配置事務的傳播性--> <!--<tx:advice id="transactionInterceptor" transaction-manager="transactionManager">--> <!--<tx:attributes>--> <!--<tx:method name="find*" read-only="true" />--> <!--<tx:method name="get*" read-only="true" />--> <!--<tx:method name="login*" read-only="true" />--> <!--<tx:method name="add*" propagation="REQUIRED" />--> <!--<tx:method name="update*" propagation="REQUIRED" />--> <!--<tx:method name="delete*" propagation="REQUIRED" />--> <!--<tx:method name="save*" propagation="REQUIRED" />--> <!--<tx:method name="test*" propagation="REQUIRED" />--> <!--<tx:method name="*Transaction" propagation="REQUIRED" />--> <!--<tx:method name="*" propagation="REQUIRED" />--> <!--</tx:attributes>--> <!--</tx:advice>--> <!--<!–配置哪些類的哪些方法參與事務 因為業務處理發生在service層,這里配置在service中的類–>--> <!--<aop:config proxy-target-class="true">--> <!--<aop:pointcut id="all-method" expression="execution(public * me.demo.service.*.*(..))"></aop:pointcut>--> <!--<aop:advisor advice-ref="transactionInterceptor" pointcut-ref="all-method"/>--> <!--</aop:config>--> </beans>

jdbc.driverClass=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/sshdemo jdbc.username=root jdbc.password=abcd

log4j.rootCategory=INFO, console log4j.appender.console=org.apache.log4j.ConsoleAppender log4j.appender.console.layout=org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %5p %t %c{2}:%L - %m%n

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <!--常量配置--> <constant name="struts.objectFactory" value="spring"/> <constant name="struts.i18n.encoding" value="utf-8"/> <!--默認action配置--> <package namespace="/" name="default" extends="struts-default"> <default-action-ref name="default"/> <action name="default"> <result>/index.jsp</result> </action> </package> <!--通過通配符的方式配置action--> <package name="user" namespace="/" extends="struts-default"> <action name="user_*" method="{1}" class="userAction"> <result name="success">/index.jsp</result> <allowed-methods> register </allowed-methods> </action> </package> </struts>
3、三層結構,以及注解的使用

package me.demo.action; import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.ModelDriven; import me.demo.domain.User; import me.demo.service.UserService; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; @Controller("userAction") @Scope("prototype") //默認是單例模式,需配置多例 public class UserAction extends ActionSupport implements ModelDriven<User> { private static final Logger log = LogManager.getLogger (UserAction.class); private User user = new User (); @Autowired private UserService userService; @Override public User getModel() { return user; } public String login() { String login = userService.login (user); return login; } public String register() { System.out.println (user); log.info (user); String register = userService.register (user); return register; } }

package me.demo.dao.Impl; import me.demo.dao.UserDao; import me.demo.domain.User; import org.hibernate.SessionFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.orm.hibernate5.support.HibernateDaoSupport; import org.springframework.stereotype.Repository; import java.util.List; @Repository() @Scope("prototype") public class UserDaoImpl extends HibernateDaoSupport implements UserDao { @Autowired public void setSessionFactoryOverride(SessionFactory sessionFactory) { super.setSessionFactory (sessionFactory); } @Override public void save(User user) { if (this.getHibernateTemplate () == null) System.out.println ("getHibernateTemplate == null"); this.getHibernateTemplate ().save (user); } @Override public User find(String username, String password) { List<User> users = (List<User>) this.getHibernateTemplate ().find ("from User where username=? and password=?", username, password); if (users.size () > 0) return users.get (0); return null; } }

package me.demo.dao; import me.demo.domain.User; /** * 接口 */ public interface UserDao { void save(User user); User find(String username, String password); }

package me.demo.domain; import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; import java.io.Serializable; @Entity @Table(name = "t_users") public class User implements Serializable { @Id @GeneratedValue(generator = "autoGenerator")//根據數據庫的主鍵生成策略 @GenericGenerator(name = "autoGenerator", strategy = "native") private Integer id; @Column private String name; @Column private String password; @Column private Integer sex; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getSex() { return sex; } public void setSex(Integer sex) { this.sex = sex; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", sex=" + sex + '}'; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }

package me.demo.service.Impl; import me.demo.dao.UserDao; import me.demo.domain.User; import me.demo.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service() @Scope("prototype") @Transactional public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; public String login(User user) { User user1 = userDao.find (user.getName (), user.getPassword ()); if (user1 != null) return "success"; return "not found"; } public String register(User user) { userDao.save (user); return "success"; } }

package me.demo.service; import me.demo.domain.User; public interface UserService { String login(User user); String register(User user); }
4、web

<%-- Created by IntelliJ IDEA. User: Date: 2018/6/8 Time: 17:05 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>首頁</title> </head> <body> url:${pageContext.request.contextPath} <a href="${pageContext.request.contextPath}/login.jsp">登錄</a> <a href="${pageContext.request.contextPath}/register.jsp">注冊</a><br> </body> </html>

<%-- Created by IntelliJ IDEA. User: Date: 2018/6/8 Time: 17:06 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>登錄</title> </head> <body> <form action="${pageContext.request.contextPath}/login" method="post"> 姓名: <input name="name" type="text"> <br> <input type="submit" value="登錄"> </form> </body> </html>

<%-- Created by IntelliJ IDEA. User: Date: 2018/6/8 Time: 17:07 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>注冊</title> </head> <body> <form action="${pageContext.request.contextPath}/user_register.action" method="post"> 姓名: <input name="name" type="text"> <br> 密碼:<input name="password" value="1234" type="password"> 性別: <input name="sex" type="radio" value="1">男 <input name="sex" type="radio" value="0">女 <input type="submit" value="注冊"> </form> </body> </html>
5、配置tomcat服務器,然后啟動即可,會自動生成數據庫表結構(前提自己手動創建好數據庫)
6、測試
總結
1、雖然網絡上這樣的文章很多,但自己動手實現,發現還是有很多錯誤,發現最多的是,由jar的版本問題引起的,比如在配置問價中org.springframework.orm.hibernate5.LocalSessionFactoryBean這個類所在的包,在hibernate3,4,5中都有,如果你在配置文件中所寫的,和HibernateDaoSupport所使用的包版本不一致,就會出錯。
2、<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>,方言的配置,hibernate關於mysql的方言就有三個,這里采用MySQL5Dialect。
3、然后就是事務了,采用事務的注解,需要在配置文件中進行配置事務管理器。
annotation-driven:
這是xsd中 對事務管理器的描述。
Indicates that transaction configuration is defined by Java 5 annotations on bean classes, and that proxies are automatically to be created for the relevant annotated beans. The default annotations supported are Spring's @Transactional and EJB3's @TransactionAttribute (if available). Transaction semantics such as propagation settings, the isolation level, the rollback rules, etc are all defined in the annotation metadata. See org.springframework.transaction.annotation.EnableTransactionManagement Javadoc for information on code-based alternatives to this XML element. ]]></xsd:documentation> </xsd:annotation> <xsd:attribute name="transaction-manager" type="xsd:string" default="transactionManager"> <xsd:annotation> <xsd:documentation source="java:org.springframework.transaction.PlatformTransactionManager"><![CDATA[ The bean name of the PlatformTransactionManager that is to be used to drive transactions. This attribute is not required, and only needs to be specified explicitly if the bean name of the desired PlatformTransactionManager is not 'transactionManager'.
4、一定要有耐心。一個個解決問題,也是一種積累。