SSM框架整合 Spring層
SSM框架整合 Spring層
搭建完了 MyBatis 層,就要把它納入 Spring 的框架中來了!
1. 整合MyBatis配置
引入 Spring 後,MyBatis 的配置可以由 Spring 來進行,在 resources 目錄下建立 spring-dao.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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> </beans>
配置連線池(這裡使用 c3p0 連線池),本來在 MyBatis 配置檔案中做的事情交給 Spring(資料庫配置檔案在 MyBatis 層寫好了)!
<!--關聯資料庫配置檔案--> <context:property-placeholder location="classpath:db.properties"/> <!--配置連線池 dbcp: 半自動化操作 不能自動連線 c3p0: 自動化操作 自動載入配置檔案 還有 druid hikari 以後再說--> <!--這裡用 c3p0 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <!-- 配置連線池屬性 --> <property name="driverClass" value="${driver}"/> <property name="jdbcUrl" value="${url}"/> <!-- 這裡 name 叫 user 和 MyBatis 不一樣(username)!--> <property name="user" value="${user}"/> <property name="password" value="${password}"/> <!-- c3p0 連線池的私有屬性 --> <property name="maxPoolSize" value="30"/> <property name="minPoolSize" value="10"/> <!-- 關閉連線後不自動 commit --> <property name="autoCommitOnClose" value="false"/> <!-- 獲取連線超時時間 --> <property name="checkoutTimeout" value="10000"/> <!-- 獲取連線失敗重試次數 --> <property name="acquireRetryAttempts" value="2"/> </bean>
註冊 SqlSessionFactory 的 bean,繫結 MyBatis 配置檔案
<!-- SqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 引用上面的資料來源 --> <property name="dataSource" ref="dataSource"/> <!-- 繫結 MyBatis 配置檔案 --> <property name="configLocation" value="classpath:mybatis-config.xml"/> </bean>
重點來了!在之前( https://www.cnblogs.com/qiyuanc/p/Spring_MyBatis.html ),需要將介面虛擬的實現類 Mapper.xml 例項化為一個真實的實現類 MapperImpl,才能注入到 Service 層的物件中(總不能注入 Mapper.xml 吧)!
這裡通過使用 MapperScannerConfigurer
,把這種工作交給 Spring 去做!
<!-- 配置掃描 Dao 介面的包,動態地將 Dao 介面實現類注入到 Spring 容器中 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 注入 sqlSessionFactory,注意是 BeanName!所以不用 ref! -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!-- 給出需要掃描 Dao 介面的包 -->
<property name="basePackage" value="com.qiyuan.dao"/>
</bean>
basePackage 屬性是讓你為對映器介面檔案設定基本的包路徑,可以使用分號或逗號作為分隔符設定多於一個的包路徑。每個對映器將會在指定的包路徑中遞迴地被搜尋到。
注意,沒有必要去指定 SqlSessionFactory 或 SqlSessionTemplate,因 為 MapperScannerConfigurer 將會建立 MapperFactoryBean,之後自動裝配。(Qiyuan:也就是說會自動建立 SqlSession 並注入到實現類中)
但是,如果你使用了一個以上的 DataSource,那麼自動裝配可能會失效。這種情況下,可以使用 sqlSessionFactoryBeanName 或 sqlSessionTemplateBeanName 屬性來設定正確的 bean 名稱來使用。這就是它如何來配置的,注意 bean 的名稱是必須的,而不是 bean 的引用。
MapperScannerConfigurer
會掃描指定包下的介面和其對應的 Mapper.xml,通過反射自動生成介面實現類(真),也就是說我們雖然沒有寫 BookMapperImpl,但它已經幫我們生成了!
2. 配置Service層
上面是 Spring 對應 Dao 層的配置了。現在還需要將 Dao 層的物件注入到 Service 層中,Service 層才能用這些物件執行相應的業務。建立 spring-service.xml 檔案,模板同上。
將業務層物件交給 Spring 管理,同時在其中注入 Dao 層物件
<bean id="BookServiceImpl" class="com.qiyuan.service.BookServiceImpl">
<!-- 這個 bookMapper 就是之前自動建立的實現類! -->
<property name="bookMapper" ref="bookMapper"/>
</bean>
這裡的 bookMapper 就是 MapperScannerConfigurer
掃描介面和其對應的 Mapper.xml 建立的實現類!
也可以通過註解的方式把業務層物件交給 Spring,不過要在業務層的類上添加註解和開啟註解掃描,這裡先不用這種方式了
<!-- 類上 @Service -->
<!-- 掃描註解,不過這裡其實沒用到 -->
<context:component-scan base-package="com.qiyuan.service"/>
下一步就是配置事務管理器了
<!-- 配置事務管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入資料庫連線池 -->
<property name="dataSource" ref="dataSource" />
</bean>
開啟事務管理器後,就可以使用 AOP 進行事務的織入了!不過這裡沒什麼事要幹,織入包也沒導,就先這樣吧!不過這樣就可以管理到資料庫事務了嗎······
3. Spring層測試
和之前一樣,寫完一層測試一下,不然以後出問題找誰去!
在測試前,先在 applicationContext.xml 這個總的配置檔案中匯入其他配置檔案
<import resource="classpath:spring-dao.xml"/>
<import resource="spring-service.xml"/>
這樣載入的時候只加載這一個檔案就行了。
寫個測試方法測試一下
public class MyTest { @Test public void Test(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); BookService bookServiceImpl = context.getBean("BookServiceImpl", BookService.class); // 增加 Book book1 = new Book(5, "Python教程", 6, "起飛級Python教程"); bookServiceImpl.addBook(book1); // 查詢所有 List<Book> books = bookServiceImpl.queryAllBook(); for (Book book : books) { System.out.println(book.toString()); } }}
載入配置檔案,獲取業務物件,執行業務,三步!
執行的時候遇到了資料庫連線錯誤
java.sql.SQLException: Access denied for user 'ASUS'@'localhost' (using password: YES)
經過排查(百度),這個弱智 c3p0 居然會把 ${username}
當成計算機使用者名稱!
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> ... <!-- 弱智 c3p0!!! --> <property name="user" value="${username}"/> ... </bean>
解決方法就是把 db.properties 和 spring-dao.xml(即上面)中的 username 改成 user 即可,這樣連線時的使用者名稱就是 db.properties 中的 user 了。氣死我了!
改完 BUG 再次執行,結果正常!
Book(bookID=1, bookName=Java教程, bookCounts=1, detail=入門級JAVA教程)Book(bookID=2, bookName=MySQL教程, bookCounts=10, detail=提升級MySQL教程)Book(bookID=3, bookName=Linux教程, bookCounts=5, detail=入土級Linux教程)Book(bookID=4, bookName=C++教程, bookCounts=3, detail=復活級C++教程)Book(bookID=6, bookName=Python教程, bookCounts=6, detail=起飛級Python教程)
可以看到插入也是成功的,說明事務確實是開啟了也提交成功了;至於 bookID 對不上的問題,就是資料庫自增的問題了,後面再研究!
未完,沒有總結。