1. 程式人生 > >Spring Boot 實踐折騰記(三):三板斧,Spring Boot下使用Mybatis

Spring Boot 實踐折騰記(三):三板斧,Spring Boot下使用Mybatis

你要搞清楚自己人生的劇本:不是你父母的續集,不是你子女的前傳,更不是你朋友的外篇。對待生命你不妨大膽冒險一點,因為好歹你要失去它。——源自尼采

開始前…

上面的金句是被轉載很多的一句話,Spring Boot也有自己的舞臺,只是這個舞臺還沒有大量展開。今天接著上一篇的內容開始正式的切入到Spring Boot,按照從Spring mvc裡的xml配置匯入使用到class類配置,最後使用starter的方法來實戰,到最後,大家就能看到是怎麼過渡到的了,還能體會到最後那快速的暢快感。

實戰

1、建立啟動類

建包: com.hjf.boot.demo.boot_mybatis

首先建立StartApp啟動程式類

// StartApp.class

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication //1
public class StartApp {
    public static void main(String[] args) {
        SpringApplication.run(StartApp.class,args);
    }
}

說明:
1:用這個註解,就能實現自動掃描包和自動配置預設配置的功能,它包含了@ComponentScan和@EnableAutoConfiguration這兩個註解,同時這個類自身也是一個配置類@Configuration,可以直接在這個類裡新增@Bean來注入java bean,第一章用的註解組合實現的和這個註解功能是一致的,這也是Spring Boot官方推薦的配置方式,是不是覺得很簡單,以前需要在xml裡寫自動掃描的bean,現在只需要一個註解就搞定,快速、快速、快速,重要的原則說三遍,這也是Spring Boot的目標。

2、建立演示用服務類

我們使用現在基本通用的設計模式來設計類,包含controller(我更喜歡叫api),dao,domain,service,每一個都只有一個類。

模型類:domain—>TestPOJO.class

public class TestPOJO {
    private Long id;
    private String name;
    private int age;

   //省略 get、set
}

服務類:service—>TestServices.class

import com.hjf.boot.demo.boot_mybatis.dao.TestDao;
import com.hjf.boot.demo.boot_mybatis.domain.TestPOJO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class TestServices { //1

    @Autowired
    private TestDao testDao; 


    public String show(){
        return "hello world!";
    }

    public List<TestPOJO> showDao(int age){
        return testDao.get(age);
    }
}

說明:
1:這裡提供兩個方法,一個只是簡單返回字串,另個從mysql資料庫裡去取出資料顯示。

介面控制器類:api—>TestController.class

import com.hjf.boot.demo.boot_mybatis.services.TestServices;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController //1
public class TestController {

    @Autowired
    private TestServices testServices; //2

    @RequestMapping(value = "/show")  //3
    public String show(){
        return testServices.show();
    }

    @RequestMapping(value = "/showDao")  //4
    public Object showDao(int age){
        return testServices.showDao(age);
    }

}

說明:
1:使用這個方法代表rest風格的控制器,這個是Spring MVC的特性。主要是方便不寫@ResponseBody;
2:注入服務方法;
3:呼叫普通服務介面方法;
4:呼叫查詢資料庫介面方法。

檔案結構配置完後,接下來我們開始配置連結資料庫的dao介面和配置,這裡就會有三種方法:

三板斧

方法1:引用xml配置

在Spring Boot裡其實是不推薦使用匯入xml配置的,但不是說就不能匯入xml,只能用starter,之前也看過有關的整合的文章,都是一筆帶過,我還是那個感觸,不能一篇文章就成功過的,反正我自己折騰了很久才成功。

第1步:新增pom依賴。這需要新增mybatis相關的驅動依賴和jdbc連線池的依賴。

第2步:建立檔案applicationContext.xml。我們要在resources下新建applicationContext.xml並將上一章同名xml檔案裡的datasource和mybatis的配置放入這裡(我們不用profile配置,直接使用datasource簡單一點):

applicationContext.xml

<!-- 資料來源配置, 使用Tomcat JDBC連線池 -->
    <bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
        <!-- Connection Info -->
        <property name="driverClassName" value="${jdbc.driver}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />

        <!-- Connection Pooling Info -->
        <property name="maxActive" value="10" />
        <property name="maxIdle" value="50" />
        <property name="minIdle" value="0" />
        <property name="defaultAutoCommit" value="false" />
    </bean>

    <!-- MyBatis配置 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!-- 自動掃描entity目錄, 省掉Configuration.xml裡的手工配置 -->
        <property name="typeAliasesPackage" value="com.hjf.boot.api.domain" />
        <!-- 顯式指定Mapper檔案位置 -->
        <property name="mapperLocations" value="classpath:/mybatis/*Mapper.xml" />
    </bean>
    <!-- 掃描basePackage下所有以@MyBatisRepository標識的 介面-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.hjf.boot.demo.boot_mybatis.domain" />
        <property name="annotationClass" value="com.hjf.boot.demo.boot_mybatis.dao.Mapper"/>
    </bean>

使用同樣注入自定義@Mapper的方式來發現介面,並且使用xml的真實Mapper來執行sql,這裡沒有寫propertites的讀取,是因為Spring Boot會預設自動讀取application.properties裡的內容。

第3步:建立application.properties,並寫入如下屬性內容。

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=UTF-8
jdbc.username=test
jdbc.password=123456
jdbc.pool.minIdle=0
jdbc.pool.maxIdle=10
jdbc.pool.maxActive=50

第4步:在dao資料夾下新建dao介面和@Mapper註解類。

TestDao.class

import com.hjf.boot.demo.boot_mybatis.domain.TestPOJO;

import java.util.List;

@Mapper
public interface TestDao {

    //根據age查詢info
    List<TestPOJO> get(int age);

}

Mapper.class

import org.springframework.stereotype.Component;
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Component
public @interface Mapper {
    String value() default "";
}

TestDaoMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- namespace必須指向Dao介面 -->
<mapper namespace="com.hjf.boot.demo.boot_mybatis.dao.TestDao">

    <!-- 所有列 -->
    <sql id="Column_list">
        id,
        name,
        age
    </sql>

    <resultMap id="ListTest" type="TestPOJO" >
        <id  column="id" property="id" />
        <result column="name" property="name" />
        <result column="age" property="age" />
    </resultMap>

    <!-- 根據ID查詢資料 -->
    <select id="get" parameterType="int" resultMap="ListTest">
        SELECT
        <include refid="Column_list" />
        FROM info
        WHERE age = #{age}
    </select>

</mapper>

到此類已經建立完畢了,啟動,然後報錯!為什麼呢?通過idea的上下文關聯圖可以看得比較明白:

這裡寫圖片描述

這個圖是生成的,其實用boot,可以不用在專案工程里加載spring的上下文的,這裡是為了方便說明,我手動建立了spring的上下文,那什麼啟動會報錯呢,這個跟Spring Boot的啟動機制有關,boot在啟動啟動類以後,才會根據類檔案間的依賴去載入spring的bean類,boot本身並不會自動去讀取xml檔案,所以boot是不知道我們在xml裡注入的bean的,所以肯定找不到datasource和mybatis配置,所以,我們要在StartApp類裡增加一個註解@@ImportResource,讓boot主動載入我們的bean。

@ImportResource(locations = "classpath*:/applicationContext.xml")

這時啟動還是會報錯,因為boot本著自動配置的原則,會幫你去載入mybatias的自動配置類,但自動配置類又是用的包內自有的mapper,導致找不到包,這時我們排除一下自動配置:

@SpringBootApplication(exclude = MybatisAutoConfiguration.class)

啟動,成功,測試資料成功。

這裡寫圖片描述

方法2:使用class類配置

雖然我們能夠使用匯入xml的配置,但是還是顯得有點麻煩,並且配置xml檔案有一個很大的缺點:容易出現拼寫錯誤。上一個例子中我自己寫的類的位置很多時候檢查不夠充分,也因為寫錯兩個字母,一直報類找不到,spring 從4.x開始推薦使用class配置的方式來配置bean,我剛開始其實還是挺不喜歡class的方式的,覺得,這就是寫程式碼了配置了,有時想修改下配置變數也需要提交上線,豈不是太麻煩了。class有class的好處,保密性比配置檔案好,但不如xml方便,具體使用看使用場景和個人習慣。我是覺得,小專案配置改動比較小的可以使用class方式,對於協作比較多的專案還是使用xml和配置的方式。接下來使用class的方法來配置dao。

第1步:建立配置類檔案config。這裡需要三個類檔案:
DataSourceConfig —>datasource源配置
MyBatisConfig —> 配置sqlSessionFactory
MyBatisMapperScannerConfig —> 配置mapperScannerConfigurer
這裡需要說明一下:最後一個配置因為依賴前兩個,需要最後一個載入,否則會報錯。

DataSourceConfig .class

import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration //1
public class DataSourceConfig {

    @Bean //2
    public DataSource dataSource(){ //3
        DataSource dataSource = new DataSource(); 
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=UTF-8");
        dataSource.setUsername("test");
        dataSource.setPassword("123456");
        return dataSource;
    }

}

說明:
1:代表此類為配置類;
2:代表需要注入的bean;
3:使用程式碼的方式傳入值到物件。

MyBatisConfig .class

import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.tomcat.jdbc.pool.DataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;

@Configuration
public class MyBatisConfig implements TransactionManagementConfigurer {//1

    @Autowired //2
    DataSource dataSource;

    @Bean(name = "sqlSessionFactory")//3
    public SqlSessionFactory sqlSessionFactoryBean() {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setTypeAliasesPackage("com.hjf.boot.demo.boot_mybatis.domain");

        //分頁外掛 //4
//        PageHelper pageHelper = new PageHelper();
//        Properties properties = new Properties();
//        properties.setProperty("reasonable", "true");
//        properties.setProperty("supportMethodsArguments", "true");
//        properties.setProperty("returnPageInfo", "check");
//        properties.setProperty("params", "count=countSql");
//        pageHelper.setProperties(properties);
        //新增外掛
//        bean.setPlugins(new Interceptor[]{pageHelper});

        //新增XML目錄
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        try {
            bean.setMapperLocations(resolver.getResources("classpath:/mybatis/*Mapper.xml"));
            return bean.getObject();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

    @Bean
    public PlatformTransactionManager annotationDrivenTransactionManager() {
        return new DataSourceTransactionManager(dataSource);
    }
}

說明:
1:實現TransactionManagementConfigurer介面,配置spring事務的管理;
2:注入datasource;
3:注入的名稱指定,如果不指定,預設方法名為bean的名字,命名規則需要遵守spring命名規範;
4:跳過分頁外掛,需要使用的,自行去了解mybatis分頁外掛的內容。

MyBatisMapperScannerConfig

import com.hjf.boot.demo.boot_mybatis.dao.Mapper;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@AutoConfigureAfter(MyBatisConfig.class)//1
public class MyBatisMapperScannerConfig {

    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
        mapperScannerConfigurer.setBasePackage("com.hjf.boot.demo.boot_mybatis");
        mapperScannerConfigurer.setAnnotationClass(Mapper.class);
        return mapperScannerConfigurer;
    }
}
說明:
1 : 讓此類在上一個類載入完畢後再載入,程式碼都是xml內容的轉化,比較簡單。

現在,我們來看一下上下文的依賴變化成什麼樣了,如下圖:

這裡寫圖片描述

這個圖很好的說明了boot在建立配置的方式,和xml是有一定區別的,所以才需要注意配置類的載入順序。

到此,方法2建立dao完畢,我們註釋掉方法1裡的@ImportResource和application.properties裡的所有內容,啟動,成功!測試資料成功!

這裡寫圖片描述

方法3:使用starter配置

終於來到最簡單的方法了,能夠自己實踐,然後讀到這裡的同學,是不是感覺到,xml反而比class的方式還麻煩呢,講了這麼多,也沒有覺得Spring Boot有多方便呢,但是在前兩個方法的過渡中,很多配置其實是逐漸減少了,比如web.xml,spring-mvc的serverlet配置檔案,讀取properties,是不是沒有配置了,雖然mvc裡的配置更自由,但boot也是載入了預設配置,適用於大多數場景,並且它同樣提供了強大的mvc的配置和自定義的配置,後續章節會涉及到。現在,我們繼續建立dao。

第1步:引入mybatis的starter的包。 Spring Boot將封裝的一系列支援boot的應用的工程都叫做starter,我們這裡引入mybatis對boot的支援的starter。如果是同一個的pom,要註釋掉mybatis的依賴,starter會自動引入依賴包。

pom.xml

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.1.1</version>
</dependency>

第2步:配置properties。

spring.datasource.driver-class-name=com.mysql.jdbc.Driver //1
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=test
spring.datasource.password=123456
spring.datasource.max-active=10
spring.datasource.max-idle=5
spring.datasource.min-idle=0

mybatis.mapper-locations=classpath:/mybatis/*Mapper.xml //2
mybatis.type-aliases-package=com.hjf.boot.demo.boot_mybatis.domain

說明:
1: spring.開頭的是spring boot自動配置的屬性開頭,後面我們會討論怎麼自定義自己型別安全的配置項。
2: 這是mybatis配置的自動配置的屬性。

第3步,新建dao。

import com.hjf.boot.demo.boot_mybatis.domain.TestPOJO;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper  //1
public interface TestDao {

    //根據age查詢info
    List<TestPOJO> get(int age);

}

說明:
1:這裡的Mapper是Mybatis自己定義的註解。
到此,結束,啟動,成功!測試成功!

這裡寫圖片描述

小結

到此,本章內容結束了,到方法3的時候,會不會覺得,這麼簡單?就這麼簡單,快速配置,快速啟動,你只需要關注你的核心業務。三種方法各有優缺點,適用的場景也不相同。
上面提到的要排除自動配置,其實是因為我的demo裡的pom引入了mybatis的starter,細心的同學可能已經發現,可以不用加exclude。

page 164 of 366 in chapter 2016