1. 程式人生 > 其它 >SSM框架整合 Spring層

SSM框架整合 Spring層

整合MyBatis配置、配置Service層、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 對不上的問題,就是資料庫自增的問題了,後面再研究!

未完,沒有總結。