摘要
最近也在網上找了些教程,試著使用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、一定要有耐心。一個個解決問題,也是一種積累。