1. 程式人生 > 其它 >【Spring Framework】Spring入門教程(三)

【Spring Framework】Spring入門教程(三)

本文主要介紹四個方面:

(1) 註解版本IOC和DI

(2) Spring純註解

(3) Spring測試

(4) SpringJDBC - Spring對資料庫的操作

使用註解配置Spring入門

說在前面

學習基於註解的IoC配置,大家腦海裡首先得有一個認知,即註解配置和xml配置要實現的功能都是一樣的,都是要降低模組間的耦合度。僅僅只是配置的形式不一樣。

關於實際的開發中到底使用xml還是註解,每家公司有著不同的使用習慣。所以這兩種配置方式我們都需要掌握。

基於註解配置的方式也已經逐漸代替xml配置。所以我們必須要掌握使用註解的方式配置Spring。

配置步驟

注意:如果使用Eclipse需要先安裝了STS外掛,或者使用STS開發工具建立專案。本文使用IDEA進行演示。

1.2.1. 第一步:拷貝必備jar包到工程的lib目錄。

注意:在基於註解的配置中,我們還要多拷貝一個aop的jar包。如下圖:

1.2.2. 第二步:在類的根路徑下建立一個任意名稱的xml檔案(不能是中文)

注意:基於註解整合時,Spring配置檔案匯入約束時需要多匯入一個context名稱空間下的約束。

<?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
       http://www.springframework.org/schema/context/spring-context.xsd">
    
</beans>

1.2.3. 第二步:建立一個服務類

建立一個測試的服務類,並且加入使用@Component註解,宣告該類允許注入到Spring容器

package org.cjw.service;

import org.springframework.stereotype.Component;

/*
    使用註解配置時,需要將Spring框架啟動就建立物件的類表示為元件類
    表示元件類使用@Component註解
 */
@Component
public class CustomerService {

    public void save() {
        System.out.println("-儲存資料-");
    }
}

1.2.4. 第四步在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: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
       http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 宣告掃描包及其子包的類,如果發現有元件註解的類,就建立物件並加入到容器中去 -->
    <context:component-scan base-package="org.cjw" />
</beans>

1.2.5. 第五步:測試呼叫程式碼

package org.cjw.test;

import org.cjw.service.CustomerService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class CustomerServiceTest {

    @Test
    public void testSave() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        CustomerService customerService = context.getBean(CustomerService.class);
        customerService.save();
    }
}

--測試結果,如果可以呼叫服務方法,測試成功。

1.2.6. 設定註解掃描的元件的名稱

預設情況下,被註解@Component 掃描的類的名稱就是當前類名的首字母小寫名稱,開發者可以自定義元件的名稱。

--元件類

package org.cjw.service;

import org.springframework.stereotype.Component;

/*
    使用註解的方式配置IOC:
        標註了@Component註解表示當前類被Spring管理,Spring框架啟動的時候就會建立此類的物件到spring容器中去
    設定當前Bean的名稱:
        預設當前Bean的名稱就是簡單類名的首字母小寫(customerService)
        @Component註解的value屬性可以自定義元件的名稱,等價於<bean id/name="bean名稱" />
        @Component(value="service")表示將bean的名稱設定service
        當註解的屬性只有一個,並且名為value的時候,可以省略value,
        即@Component(value="service")等價於@Component("service")
 */
@Component("service")
public class CustomerService {

    public void save() {
        System.out.println("-儲存資料-");
    }
}

--測試程式碼

Test
public void testSave() {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    CustomerService customerService = (CustomerService) context.getBean("service");
    customerService.save();
}

--測試結果

Spring常用註解說明

2.1. 用於物件的註解-元件註解

我們將用於被掃描建立物件的註解,統稱為元件註解。

元件包括:@Controller@Service@Repository@Component

元件註解的功能就是標識那些在Spring框架啟動時,需要建立物件並儲存在IOC容器中的類。意味著,只有加了這四個註解中的任何一個註解的類,在Spring框架啟動的時候,Spring就通過配置檔案指定的路徑將該路徑下的所有帶元件註解的類建立物件並且放在容器裡面。

元件註解的功能類似原來配置檔案的<bean>標籤。

問題:明明一個@Component註解就可以滿足了掃描的需要,為什麼要有四個呢?

答:其實Spring第一版註解的實現(spring 2.5),只有@Component元件註解。從spring3.0以後,作者認為根據分層的需要,把它拆成了四個。為了可以讓開發人員可見即可得,一看到註解,立即知道類的性質。所以分成了四個。

@Controller:用於宣告表示層的元件註解

@Service:用於宣告服務層的元件註解

@Repository:用於宣告持久層的元件註解

@Component:用於宣告三層以外的元件註解

問題:那麼,這四個註解交換使用會報錯嗎。如:持久層,我放@Service標記。

答:@Controller在SpringMVC裡面有強制的要求,SpringMVC的表示層必須使用@Controller元件註解。其他情況,用亂了是不會報錯的,不過我們必須不能用亂。不遵守規範,不然別人就無法跟我們一起開發了。

2.1.1. @Scope用於設定物件的生命週期註解

Xml配置需要配置物件的作用範圍

<bean id="" class="" scope="作用域"/>

如果使用註解配置bean,那麼bean的作用範圍也需要使用註解配置。

@Scope("作用範圍")

singleton:單例,在ioc容器中僅存在一個Bean例項(預設的scope)。

prototype:多例,每次從容器中呼叫Bean時,都返回一個新的例項,即每次呼叫getBean()時 ,相當於執行newInstance(),並且ioc容器不會管理多例物件。

request:用於web開發,將Bean放入request作用域中,request.setAttribute("xxx") , 在同一個request物件中獲取同一個Bean。

session:用於web開發,將Bean 放入Session作用域中,在同一個Session物件中獲取同一個Bean。

--元件程式碼

@Component("customerService")
@Scope("singleton")
public class CustomerService {

}
@Service("customerService2")
@Scope("prototype")
public class CustomerService2 {
    
}

--測試程式碼

 @Test
public void testSave() {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    CustomerService customerService = (CustomerService) context.getBean("customerService");
    CustomerService customerService2 = (CustomerService) context.getBean("customerService");
    System.out.println("singleton: " + (customerService == customerService2));

    CustomerService2 customerService3 = (CustomerService2) context.getBean("customerService2");
    CustomerService2 customerService4 = (CustomerService2) context.getBean("customerService2");
    System.out.println("prototype: " + (customerService3 == customerService4));
}

--測試結果

在開發中主要使用 scope="singleton"、 scope="prototype"

對於MVC中的Action/Controller使用prototype型別,其他使用singleton。

2.1.2. @PostConstruct @PreDestroy初始化和銷燬方法註解

在xml配置中可以配置物件的初始化方法和銷燬方法。

<bean id="someBean" class="org.cjw.pojo.SomeBean"
      init-method="init"
      destroy-method="destory"/>

如果使用註解配置bean,那麼bean的作用範圍也需要使用註解配置。

@PostConstruct // 相當於<bean init-method="init" />
public void init() {
    System.out.println("初始化方法執行了");
}
@PreDestroy// 相當於<bean destroy-method="destory" />
public void destory() {
    System.out.println("銷燬方法執行了");
}

--測試程式碼

@Test
public void testXml() {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    context.close();
}

--測試結果

用於依賴注入的註解

回顧:XML配置檔案使用<property name=”” value/ref=””><constructor-arg name="" value/ref="" />實現setter注入和構造注入。通過注入註解也可以實現DI。

Spring提供了兩套註解可以解決物件依賴注入的方案:

1. @Autowired +@Qualifier():是Spring定義的標籤

2. @Resouce:是JavaEE的規範

2.2.1. @Autowired註解

@Autowired註解:用於標識需要依賴注入的物件屬性。

  1. @Autowired註解貼在欄位或者setter方法上。

  2. 預設情況下@Autowired註解必須要能找到對應的物件,否則報錯。不過,可使用required=false來避免該問題:@Autowired(required=false)

  3. @Autowired找bean的方式:

(1) 首先按照依賴物件的型別找,如果只找到一個則使用欄位或者setter方法直接注入。

(2) 如果在Spring上下文中找到多個匹配的型別,則再按照名字去找,如果沒有匹配則報錯(NoSuchBeanDefinitionException)。

(3) 可以通過使用@Qualifier("otherBean")註解來規定依賴物件按照型別+bean的id去找。

使用@Autowired注入的三種情況

2.2.1.1. 欄位注入

@Controller("customerController")
public class CustomerController {

    // 反射欄位直接注入:Field.set(obj, value);
    @Autowired
    private CustomerService customerService;

    public void save() {
        customerService.save();
    }
}

2.2.1.2. setter方法注入

@Controller("customerController")
public class CustomerController {

    private CustomerService customerService;

    // 如果將@Autowired放在方法的上面,意思就是將物件注入到該方法的引數
    // 意味著,spring會自動根據引數型別匹配容器中對應的物件給這個方法
    // 能夠使用@Autowired註解的方法必須是有引數的
    @Autowired
    public void setCustomerService(CustomerService customerService) {
        // 問題:加了@Autowired註解的方法在什麼時候執行?
        // 加了@Autowired註解的方法在建立完spring容器之後就會立即執行
        System.out.println("-setCustomerService被執行了-");
        this.customerService = customerService;
    }

    public void save() {
        customerService.save();
    }
}

2.2.1.3. 構造器注入

@Controller("customerController")
public class CustomerController {

    private CustomerService customerService;

    /*
    * 方式三 : 構造器注入
    * 使用註解的IOC建立bean的情況下
    * 預設bean中有什麼樣的構造器,spring就呼叫那個構造器去建立對應的bean物件
    * 並且會自動注入構造器中對應型別引數的物件
    *
    * 問題: 如果建構函式有多個,預設會無參構造
    * 解決方案:只提供有參構造
    * 
     * 問題: 如果建構函式的引數型別對應的bean有多個,會丟擲異常
    * org.springframework.beans.factory.NoUniqueBeanDefinitionException 不是唯一的bean異常
    * 解決方案: 在引數前面 使用 @Qualifier("service1") 註解
    * 從多個bean 獲取指定 id 對應的bean即可
    */

    public CustomerController(@Qualifier("customerService") CustomerService customerService) {
        System.out.println("-CustomerController構造器被執行了-");
        this.customerService = customerService;
    }


    public void save() {
        customerService.save();
    }
}

2.2.2. @Qualifier註解

@Qualifier註解:用於指定注入的物件名,使用@Autowired注入物件時,@Autowired沒有指定物件名的屬性,只能通過@Qualifier註解來指定物件名。

value屬性:指定注入Spring容器中對應物件名的物件。

@Controller("customerController")
public class CustomerController {

    @Autowired
    @Qualifier("customerService")
    private CustomerService customerService;

    public void save() {
        customerService.save();
    }
}

2.2.3. @Resource註解

@Resource註解是Spring框架支援Sun官方制定的JSR-250標準注入物件的實現。

JSR-250就是Sun公司制定,對注入的物件的標準。

@Resource功能等同@Autowired + @Qualifier等同配置檔案標籤<proprty name="..." ref="...">

@Resource註解:用於給引用注入容器的物件,可以通過name屬性指定物件名。

注意事項:@Resource只能使用欄位和setter注入,不能使用構造注入

2.2.3.1. 欄位注入

@Controller("customerController")
public class CustomerController {

    // 型別+id注入
    @Resource(name = "customerService")
    private CustomerService customerService;

    public void save() {
        customerService.save();
    }
}

2.2.3.2. setter方法注入

@Controller("customerController")
public class CustomerController {

    private CustomerService customerService;

    // 型別+id
    @Resource(name = "customerService")
    public void setCustomerService(CustomerService customerService) {
        this.customerService = customerService;
    }

    public void save() {
        customerService.save();
    }
}

2.2.4. @Value註解

property標籤中的value屬性只能注入基本資料型別、包裝型別、String型別。

@Value註解:注入基本資料型別以及它們的包裝類和String型別資料的,支援${}注入properties檔案的鍵值對,等同 <proprty name="..." value="${Key}" />

2.2.4.1. 案例程式碼

--db.properties檔案(在src路徑下建立)

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/users
jdbc.username=root
jdbc.password=root
jdbc.macActive=10

--在applicationContext.xml配置檔案中載入db.properties

<?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
       http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 宣告掃描包及其子包的類,如果發現有元件註解的類,就建立物件並加入到容器中去 -->
    <context:component-scan base-package="org.cjw" />

    <!-- 載入classpath下的db.properties配置檔案 -->
    <context:property-placeholder location="classpath:db.properties"/>
</beans>

--UserDaoImpl程式碼

@Repository
public class UserDaoImpl {

    /**
     * @Value(value="")
     * 可以從Spring容器讀取 .properties 配置檔案內容
     * value :配置檔案的對應的key -->使用 ${key} 獲取
     * 程式執行中自動將 properties的key對應的value值獲取出來設定給欄位
     */
    @Value("${jdbc.driverClassName}")
    private String driverClassName;

    @Value("${jdbc.url}")
    private String url;

    @Value("${jdbc.username}")
    private String username;

    @Value("${jdbc.password}")
    private String password;

    @Value("${jdbc.maxActive}")
    private String maxActive;

    public void testValueAnnotation() {
        System.out.println("driverClassName:" + driverClassName);
        System.out.println("url:" + url);
        System.out.println("username:" + username);
        System.out.println("password:" + password);
        System.out.println("maxActive:" + maxActive);
    }
}

--測試程式碼

@Test
public void testXml() {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserDaoImpl userDaoImpl = context.getBean(UserDaoImpl.class);
    userDaoImpl.testValueAnnotation();
}

--測試結果

模擬註冊功能(使用註解方式)

3.1. DAO層程式碼

public interface UserDao {
    void register(User user);
}
@Repository
public class UserDaoImpl implements UserDao {

    @Override
    public void register(User user) {
        System.out.println("dao層執行了register方法");
    }
}

3.2. Service層程式碼

public interface UserService {
    void register(User user);
}
@Service
public class UserServiceImpl implements UserService {

    @Resource(name = "userDaoImpl")
    private UserDao userDao;

    @Override
    public void register(User user) {
        System.out.println("service層執行了register方法");
        userDao.register(user);
    }
}

3.3. 表現層程式碼

@Controller
public class UserController {

    @Autowired
    @Qualifier("userServiceImpl")
    private UserService userService;

    public void register() {
        System.out.println("control層執行了register方法");
        User user = new User();
        userService.register(user);
    }
}

3.4. 測試程式碼

@Test
public void testXml() {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserController userController = context.getBean(UserController.class);
    userController.register();
}

3.5. 測試結果

3.6. applicationContext.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
       http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 宣告掃描包及其子包的類,如果發現有元件註解的類,就建立物件並加入到容器中去 -->
    <context:component-scan base-package="org.cjw" />
</beans>

純註解配置

4.1. 問題

我們發現,之所以我們現在離不開xml配置檔案,是因為我們有一句很關鍵的配置:

<context:component-scan base-package="cn.zj.spring" />

如果他要是也能用註解配置,那麼我們就可以脫離xml檔案了。

通過@Configuration註解和@ComponentScan註解

模擬註冊功能(純註解方式)

5.1. 說明

需求:建立一個配置類使用@Configuration註解和@ComponentScan註解替換xml檔案。

5.2. 第一步:建立一個Java專案

建立一個Java專案,匯入必須的jar包以及編寫好需要的類結構。程式碼目錄如下:

5.3. 第二步:在classpath下建立db.properties配置檔案

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/users
jdbc.username=root
jdbc.password=root
jdbc.maxActive=10

5.4. 第三步:編寫配置類程式碼

--通過該配置類的程式碼替換掉Spring配置檔案

@Configuration // xml配置檔案
@PropertySource("classpath:db.properties") // 代替了<contenxt:property-placeholder/>
@ComponentScan(basePackages = "org.cjw") // 代替了<contenxt:component-scan/>
public class SpringConfig {

    @Value("${jdbc.driverClassName}") // 代替了<property>
    private String driverClassName;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    @Value("${jdbc.maxActive}")
    private String maxActive;

    @Bean(name = "dataSource")  // 代替了<bean/>
    public DataSource getDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setMaxActive(Integer.valueOf(maxActive));
        return dataSource;
    }
}

5.5. 第四步:編寫三層程式碼

5.5.1. 表示層

@Controller
public class UserController {

    @Autowired
    @Qualifier("userServiceImpl")
    private UserService userService;

    public void register() {
        System.out.println("control層register方法執行了");
        User user = new User();
        userService.register(user);
    }
}

5.5.2. 服務層

public interface UserService {
    void register(User user);
}
@Service
public class UserServiceImpl implements UserService {

    @Resource(name = "userDaoImpl")
    private UserDao userDao;

    @Override
    public void register(User user) {
        System.out.println("service層register方法執行了");
        userDao.register(user);
    }
}

5.5.3. 持久層

public interface UserDao {
    void register(User user);
}
@Repository
public class UserDaoImpl implements UserDao {

    @Autowired
    private DataSource dataSource;

    @Override
    public void register(User user) {
        try {
            System.out.println("dao層register方法執行了");
            Connection conn = dataSource.getConnection();
            System.out.println(conn);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

5.6. 第五步:測試程式碼

@Test
public void testRegister() {
    ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
    UserController userController = context.getBean(UserController.class);
    userController.register();
}

5.7. 第六步:測試結果

輸出元件類呼叫方法的輸出值,配置成功。

Spring的測試

6.1. 傳統的測試

存在問題:

  1. 每個測試都要重新啟動Spring容器,啟動容器的開銷大,測試效率低下。

  2. 不應該是測試程式碼管理Spring容器,應該是Spring容器在管理測試程式碼。

6.1.1. 正確使用Spring的測試

6.2. 如何使用Spring測試

6.2.1. 匯入spring測試的jar包

Spring測試必須保證單元測試的最低版本是4.12版本,如果使用的IDE版本很低,那麼IDE自帶的單元測試版本可能低於4.12,那麼需要開發者手動匯入單元測試的jar包。

如果使用Spring測試,必須使用兩個註解:

@RunWith註解:表示先啟動Spring容器,把junit執行在Spring容器中。

@ContextConfiguration註解:載入資原始檔,預設從src(源目錄)下面載入。

6.2.2. XML方式的配置

@ContextConfiguration(value)

value屬性: 讀取classpath下的配置檔案。

PS:只要是spring讀取配置檔案,都必須加上classpath:字首。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class UserControllerTest {

    @Autowired
    private ApplicationContext context;

    public void testRegister() {
        UserController userController = context.getBean(UserController.class);
        userController.register();
    }
}

6.2.3. 純註解方式的配置

@ContextConfiguration(classes)

classes 屬性: 讀取配置類。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class UserControllerTest {

    @Autowired
    private ApplicationContext context;

    public void testRegister() {
        UserController userController = context.getBean(UserController.class);
        userController.register();
    }
}

Spring的JDBC操作

Spring框架也支援JDBC,對JDBC只進行了薄薄的一層封裝。

問題: Java開發已經有JDBC,為什麼Spring還要支援JDBC操作呢?

最重要的原因: Spring操作JDBC能自動管理事務。

原生的JDBC一套程式碼下來,很沉重,很多的程式碼都是相同、相似的,因此可以將這些程式碼進行封裝,僅僅把那些複雜多變的程式碼交由開發者來完成,如sql語句的編寫、結果集的處理,這就是SpringJDBC,僅僅只是對原生JDBC進行一層薄薄的封裝、並且自動管理事務。但是結果集的處理部分還是交由開發者來完成,而且結果集的處理程式碼編寫是非常頭痛的,所以在目前javaWeb開發中,持久層的處理並沒有使用SpringJDBC,而是使用半自動對映的MyBatis框架或者全自動對映的Hibernate。

7.1. 前期準備

操作資料部分使用SpringJDBC,其他部分業務邏輯程式碼不變。

--建立資料庫 spring_jdbc

--建立資料表 t_user

CREATE TABLE `t_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  `email` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--建立對應的domain物件

package org.cjw.pojo;

public class User {
    private Integer id;
    private String name;
    private String email;
    // 省略get、set、toString、有參構造、無參構造方法 
}

--建立DAO層

@Repository
public class UserDaoImpl implements UserDao {

    @Override
    public void save(User user) {}

    @Override
    public void delete(Integer id) {}

    @Override
    public void update(User user) {}

    @Override
    public User findById(Integer id) {
        return null;
    }
}

--建立Service層

@Service
public class UserServiceImpl implements UserService {

    @Resource(name = "userDaoImpl")
    private UserDao userDao;

    @Override
    public void save(User user) {
        userDao.save(user);
    }

    @Override
    public void delete(Integer id) {
        userDao.delete(id);
    }

    @Override
    public void update(User user) {
        userDao.update(user);
    }

    @Override
    public User findById(Integer id) {
        return userDao.findById(id);
    }
}

--測試程式碼(XML方式)

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class UserServiceTest {

    @Autowired
    private UserService userService;

    @Test
    public void testSave() {
        User user = new User(null, "趙六", "[email protected]");
        userService.save(user);
    }

    @Test
    public void testDelete() {
        userService.delete(4);
    }

    @Test
    public void testUpdate() {
        User user = new User(2, "lisi", "[email protected]");
        userService.update(user);
    }

    @Test
    public void testFindById() {
        User user = userService.findById(1);
        System.out.println(user);
    }
}

--ApplicationContext.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 
       http://www.springframework.org/schema/context/spring-context.xsd">

    <context:property-placeholder location="classpath:db.properties"/>

    <bean id="dataSource"
          class="com.alibaba.druid.pool.DruidDataSource"
          init-method="init" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="maxActive" value="${jdbc.maxActive}"/>
    </bean>
</beans>

--測試程式碼(註解方式)

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class UserServiceTest {

    @Autowired
    private UserService userService;

    @Test
    public void testSave() {
        User user = new User(null, "趙六", "[email protected]");
        userService.save(user);
    }

    @Test
    public void testDelete() {
        userService.delete(4);
    }

    @Test
    public void testUpdate() {
        User user = new User(2, "lisi", "[email protected]");
        userService.update(user);
    }

    @Test
    public void testFindById() {
        User user = userService.findById(1);
        System.out.println(user);
    }
}

--配置類SpringConfig

@Configuration // xml配置檔案
@PropertySource("classpath:db.properties") // 代替了<contenxt:property-placeholder/>
@ComponentScan(basePackages = "org.cjw") // 代替了<contenxt:component-scan/>
public class SpringConfig {

    @Value("${jdbc.driverClassName}") // 代替了<property>
    private String driverClassName;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    @Value("${jdbc.maxActive}")
    private String maxActive;

    @Bean(name = "dataSource")  // 代替了<bean/>
    public DataSource getDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setMaxActive(Integer.valueOf(maxActive));
        return dataSource;
    }
}

7.2. JDBCTemplate模板類

Spring提供對應的模板類可以直接操作資料庫。

如果使用JDBC就使用JDBCTemplate類(將資料庫的基本操作方法已經封裝好了,直接呼叫即可)。

7.2.1. 匯入相關jar包

mysql-connector-java-5.x.jar:MySQL驅動包

spring-jdbc-4.3.2.RELEASE.jar:支援JDBC

spring-tx-4.3.2.RELEASE.jar:支援事務

druid1.1.9.jar:連線池

7.2.2. 配置檔案配置JDBCTemplate

--Xml方式配置

<!-- 配置jdbcTemplate 模板類  -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <!-- setter方法注入資料來源 -->
    <property name="dataSource" ref="dataSource" />
</bean>

--註解方式

@Bean
public JdbcTemplate getJdbcTemplate() {
    JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSource());
    return jdbcTemplate;
}

7.2.3. Dao層程式碼

@Repository
public class UserDaoImpl implements UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void save(User user) {
        jdbcTemplate.update("insert into t_user (name, email) values (?, ?)", user.getName(), user.getEmail());
    }

    @Override
    public void delete(Integer id) {
        jdbcTemplate.update("delete from t_user where id = ?", id);
    }

    @Override
    public void update(User user) {
        jdbcTemplate.update("update t_user set name = ?, email = ? where id = ?", user.getName(), user.getEmail(), user.getId());
    }

    @Override
    public User findById(Integer id) {
        User user = jdbcTemplate.queryForObject("select * from t_user where id = ?", new Object[]{id}, new RowMapper<User>() {
            @Override
            public User mapRow(ResultSet rs, int i) throws SQLException {
                User user = new User();
                user.setId(rs.getInt("id"));
                user.setName(rs.getString("name"));
                user.setEmail(rs.getString("email"));
                return user;
            }
        });
        return user;
    }
}

小結

Spring的IOC和DI的配置可以使用XML配置,也可以註解配置。

內容:使用註解配置。

  1. 註解配置IOC (控制反轉,將物件的建立權交給Spring)-重點

(1) @Component 通用IOC 元件,試用任意Spring物件管理

(2) @Controller 主要在表現層使用

(3) @Service 業務層使用

(4) @Repository DAO層使用

(5) 必須在xml配置包掃描的位置<context:component-scan base-package=”cn.zj.spring”>

(6) Scope 設定物件的生命週期(作用範圍)

​ ① Singleton 單例 預設

​ ② Prototype 多例

​ ③ Request Web開發一次請求有效

​ ④ Session Web開發一次會話有效

(7) PostConstructor 初始化方法

(8) PreDestory 銷燬方法

  1. 註解配置DI (依賴注入)注入物件的屬性(值,集合,引用)-重點

(1) @Autowired + @Qualifier Spring 框架提供

​ ① 欄位注入

​ ② Setter注入

​ ③ 構造器注入

(2) @Resource JavaEE 官方的規範

​ ① 欄位注入

​ ② Setter注入

​ ③ 沒有構造器注入

  1. Spring純註解配置-重點

純註解配置替代xml配置,但是所有配置依然存在,只是配置方式變換成在類上面貼註解的形式(未來的趨勢)--SpringBoot(純註解)

  1. Spring測試

(1) 為了更方便的開發Spring程式

  1. SpringJDBC

(1) 優點:主要能夠讓Spring自動控制事務

(2) JdbcTemplate 模板類進行資料表的增刪改查