Spring Boot 2.x基礎教程:MyBatis的多數據源配置

前两天,我們已經介紹了關於JdbcTemplate的多數據源配置以及Spring Data JPA的多數據源配置,接下來具體說說使用MyBatis時候的多數據源場景該如何配置。

添加多數據源的配置

先在Spring Boot的配置文件application.properties中設置兩個你要鏈接的數據庫配置,比如這樣:

spring.datasource.primary.jdbc-url=jdbc:mysql://localhost:3306/test1
spring.datasource.primary.username=root
spring.datasource.primary.password=123456
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver

spring.datasource.secondary.jdbc-url=jdbc:mysql://localhost:3306/test2
spring.datasource.secondary.username=root
spring.datasource.secondary.password=123456
spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver

說明與注意

  1. 多數據源配置的時候,與單數據源不同點在於spring.datasource之後多設置一個數據源名稱primary和secondary來區分不同的數據源配置,這個前綴將在後續初始化數據源的時候用到。
  2. 數據源連接配置2.x和1.x的配置項是有區別的:2.x使用spring.datasource.secondary.jdbc-url,而1.x版本使用spring.datasource.secondary.url。如果你在配置的時候發生了這個報錯java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName.,那麼就是這個配置項的問題。
  3. 可以看到,不論使用哪一種數據訪問框架,對於數據源的配置都是一樣的。

初始化數據源與MyBatis配置

完成多數據源的配置信息之後,就來創建個配置類來加載這些配置信息,初始化數據源,以及初始化每個數據源要用的MyBatis配置。

這裏我們繼續將數據源與框架配置做拆分處理:

  1. 單獨建一個多數據源的配置類,比如下面這樣:
@Configuration
public class DataSourceConfiguration {

    @Primary
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }

}

可以看到內容跟JdbcTemplate、Spring Data JPA的時候是一模一樣的。通過@ConfigurationProperties可以知道這兩個數據源分別加載了spring.datasource.primary.*spring.datasource.secondary.*的配置。@Primary註解指定了主數據源,就是當我們不特別指定哪個數據源的時候,就會使用這個Bean真正差異部分在下面的JPA配置上。

  1. 分別創建兩個數據源的MyBatis配置。

Primary數據源的JPA配置:

@Configuration
@MapperScan(
        basePackages = "com.didispace.chapter39.p",
        sqlSessionFactoryRef = "sqlSessionFactoryPrimary",
        sqlSessionTemplateRef = "sqlSessionTemplatePrimary")
public class PrimaryConfig {

    private DataSource primaryDataSource;

    public PrimaryConfig(@Qualifier("primaryDataSource") DataSource primaryDataSource) {
        this.primaryDataSource = primaryDataSource;
    }

    @Bean
    public SqlSessionFactory sqlSessionFactoryPrimary() throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(primaryDataSource);
        return bean.getObject();
    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplatePrimary() throws Exception {
        return new SqlSessionTemplate(sqlSessionFactoryPrimary());
    }

}

Secondary數據源的JPA配置:

@Configuration
@MapperScan(
        basePackages = "com.didispace.chapter39.s",
        sqlSessionFactoryRef = "sqlSessionFactorySecondary",
        sqlSessionTemplateRef = "sqlSessionTemplateSecondary")
public class SecondaryConfig {

    private DataSource secondaryDataSource;

    public SecondaryConfig(@Qualifier("secondaryDataSource") DataSource secondaryDataSource) {
        this.secondaryDataSource = secondaryDataSource;
    }

    @Bean
    public SqlSessionFactory sqlSessionFactorySecondary() throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(secondaryDataSource);
        return bean.getObject();
    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplateSecondary() throws Exception {
        return new SqlSessionTemplate(sqlSessionFactorySecondary());
    }

}

說明與注意

  1. 配置類上使用@MapperScan註解來指定當前數據源下定義的Entity和Mapper的包路徑;另外需要指定sqlSessionFactory和sqlSessionTemplate,這兩個具體實現在該配置類中類中初始化。
  2. 配置類的構造函數中,通過@Qualifier註解來指定具體要用哪個數據源,其名字對應在DataSourceConfiguration配置類中的數據源定義的函數名。
  3. 配置類中定義SqlSessionFactory和SqlSessionTemplate的實現,注意具體使用的數據源正確(如果使用這裏的演示代碼,只要第二步沒問題就不需要修改)。

上一篇介紹JPA的時候,因為之前介紹JPA的使用時候,說過實體和Repository定義的方法,所以省略了 User 和 Repository的定義代碼,但是還是有讀者問怎麼沒有這個,其實都有說明,倉庫代碼里也都是有的。未避免再問這樣的問題,所以這裏就貼一下吧。

根據上面Primary數據源的定義,在com.didispace.chapter39.p包下,定義Primary數據源要用的實體和數據訪問對象,比如下面這樣:

@Data
@NoArgsConstructor
public class UserPrimary {

    private Long id;

    private String name;
    private Integer age;

    public UserPrimary(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
}

public interface UserMapperPrimary {

    @Select("SELECT * FROM USER WHERE NAME = #{name}")
    UserPrimary findByName(@Param("name") String name);

    @Insert("INSERT INTO USER(NAME, AGE) VALUES(#{name}, #{age})")
    int insert(@Param("name") String name, @Param("age") Integer age);

    @Delete("DELETE FROM USER")
    int deleteAll();

}

根據上面Secondary數據源的定義,在com.didispace.chapter39.s包下,定義Secondary數據源要用的實體和數據訪問對象,比如下面這樣:

@Data
@NoArgsConstructor
public class UserSecondary {

    private Long id;

    private String name;
    private Integer age;

    public UserSecondary(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
}

public interface UserMapperSecondary {

    @Select("SELECT * FROM USER WHERE NAME = #{name}")
    UserSecondary findByName(@Param("name") String name);

    @Insert("INSERT INTO USER(NAME, AGE) VALUES(#{name}, #{age})")
    int insert(@Param("name") String name, @Param("age") Integer age);

    @Delete("DELETE FROM USER")
    int deleteAll();
}

測試驗證

完成了上面之後,我們就可以寫個測試類來嘗試一下上面的多數據源配置是否正確了,先來設計一下驗證思路:

  1. 往Primary數據源插入一條數據
  2. 從Primary數據源查詢剛才插入的數據,配置正確就可以查詢到
  3. 從Secondary數據源查詢剛才插入的數據,配置正確應該是查詢不到的
  4. 往Secondary數據源插入一條數據
  5. 從Primary數據源查詢剛才插入的數據,配置正確應該是查詢不到的
  6. 從Secondary數據源查詢剛才插入的數據,配置正確就可以查詢到

具體實現如下:

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class Chapter39ApplicationTests {

    @Autowired
    private UserMapperPrimary userMapperPrimary;
    @Autowired
    private UserMapperSecondary userMapperSecondary;

    @Before
    public void setUp() {
        // 清空測試表,保證每次結果一樣
        userMapperPrimary.deleteAll();
        userMapperSecondary.deleteAll();
    }

    @Test
    public void test() throws Exception {
        // 往Primary數據源插入一條數據
        userMapperPrimary.insert("AAA", 20);

        // 從Primary數據源查詢剛才插入的數據,配置正確就可以查詢到
        UserPrimary userPrimary = userMapperPrimary.findByName("AAA");
        Assert.assertEquals(20, userPrimary.getAge().intValue());

        // 從Secondary數據源查詢剛才插入的數據,配置正確應該是查詢不到的
        UserSecondary userSecondary = userMapperSecondary.findByName("AAA");
        Assert.assertNull(userSecondary);

        // 往Secondary數據源插入一條數據
        userMapperSecondary.insert("BBB", 20);

        // 從Primary數據源查詢剛才插入的數據,配置正確應該是查詢不到的
        userPrimary = userMapperPrimary.findByName("BBB");
        Assert.assertNull(userPrimary);

        // 從Secondary數據源查詢剛才插入的數據,配置正確就可以查詢到
        userSecondary = userMapperSecondary.findByName("BBB");
        Assert.assertEquals(20, userSecondary.getAge().intValue());
    }

}

代碼示例

本文的相關例子可以查看下面倉庫中的chapter3-9目錄:

  • Github:https://github.com/dyc87112/SpringBoot-Learning/
  • Gitee:https://gitee.com/didispace/SpringBoot-Learning/

如果您覺得本文不錯,歡迎Star支持,您的關注是我堅持的動力!

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

新北清潔公司,居家、辦公、裝潢細清專業服務

※推薦評價好的iphone維修中心

電動車進駐大樓,ChargePoint 推出公寓大樓用電動車充電座

在美國,許多人都擁有寬敞的車庫,買了電動車就在車庫中設置充電座,然而若是市區中的大樓住戶,只能停在大樓地下室密密麻麻的停車格,買電動車可就麻煩了。電動車充電座製造商 ChargePoint 看見了這個問題,計劃推出公寓大樓用電動車充電座,解除大樓住戶購買電動車的障礙。    
  《富比世》報導,當特斯拉 Model S 電動車上市時,Gogoro 創辦人陸學森原本想要擁有一輛,但是第一個問題是在台灣沒有上市,就算進口一輛,台灣的住處大樓沒有獨立車庫,無法安裝幫 Model S 電動車充電的充電座,若非要開 Model S 電動車,只能在公司裝設充電座在公司充電,但這樣一來,週末就無法開出去兜風,豈不是大煞風景,最後陸學森在女友說服下,還是打退堂鼓。   這個困擾,其實也是各國所有大樓住戶的困擾,雖然以美國來說,如加州等地區路上設有充電站,不過電動車車主總是想要在家把電充飽飽才開出門,以免半路沒電,據美國能源部統計,80% 電動車都是在家充電,要是在家不能充電,購買電動車的意願就會降低,ChargePoint  執行長帕斯奎‧羅曼諾(Pasquale Romano)表示,除了少數例外,住大樓的人通常不買電動車,正是因為如此。   那要如何改善這個情況?羅曼諾認為,過去為了讓少數電動車主能在大樓停車場充電,大樓業主得全數自掏腰包在停車場設置充電座,投資風險很高,因此意願低落,但大樓業主如果並不用負擔充電座的設置費用,像大樓附設的投幣式自助洗衣機一樣,由業者來設置機器,這樣就成了。      
可吸引高收入使用者   2015 年 4 月,ChargePoint 宣布推出大樓專用的充電座系統,大樓業主不用負擔設置費用,這部分完全由 ChargePoint  吸收,大樓業主只需要為充電座連接電力即可,ChargePoint 會向用戶收取每月 39.99 美元的月費,電費部分則由住戶直接交給大樓業主,如果有電動車的住戶搬走了,ChargePoint 可以暫時關閉住戶所屬停車格的充電座,直到下一位有電動車的住戶入住才重新啟動,這樣一來,大樓業主的風險可說降到極低,勢必能提高安裝充電座的意願。   對大樓來說,提供停車場充電座設施,可吸引電動車車主,讓大樓更快租出,電動車車主又通常是高收入、高社經地位的良好住戶,對大樓有額外幫助;而對 ChargePoint 來說,能打進大樓這片處女地,是開拓新市場的絕佳機會,估計至 2020 年,美國將有 230 萬電動車主,其中有 10% 將會住在大樓內,這種合作方式對大樓與 ChargePoint 可說是雙贏局面。   想出免費贈送充電座商業模式的也不只 ChargePoint,曾經推出低價「開源碼」充電座的新創事業 EMotorWerks,2014 年推出特別活動,免費贈送原本售價 299 美元的 JuiceBox 充電座,條件是用戶要有可用的 Wi-Fi,讓充電座能將資訊傳給 EMotorWerks,以及用戶同意可由 EMotorWerks 來調整充電速度。    
 

    用戶只需要在行動裝置的專屬 App 上,告訴 EMotorWerks 何時要用車要充飽電力,EMotorWerks 會根據電力的離峰尖峰情況,自動調整充電速度,盡可能讓電力都在離峰時充電。在加州,尖峰電價可能高出平均電價 30 倍以上,避開尖峰時段充電可以為用戶節省大量電費;另一方面,也相當於為電網平衡離尖峰電力需求,如夜間風力發電過剩,可加速充電把多餘的電力用掉,尖峰時暫停充電,緩和尖峰負載。   EMotorWerks 未來的營收可望來自為用戶節省電費的服務、為電網調節平衡的服務,以及出售所收集的數據,為此,免費贈送充電座也划算。   EMotorWerks 的點子,也可能為 ChargePoint 採用,ChargePoint 充電座也可能成為大樓業主調節電力負載與電費支出的利器。無論如何,在充電座業者的推波助瀾下,電動車的充電障礙,將漸漸減輕。     本文全文授權轉載自《科技新報》─〈〉

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

新北清潔公司,居家、辦公、裝潢細清專業服務

※推薦評價好的iphone維修中心

一起玩轉微服務(14)——單元測試

作為一名java開發者,相信你或多或少的接觸過單元測試,對於測試來講它是一門能夠區分專業開發人員與業餘開發人員的重要學科,這篇文章將對java中最常見的一個單元測試框架junit進行一個梳理和講解。

為什麼需要單元測試

在平時的開發當中,一個項目往往包含了大量的方法,可能有成千上萬個。如何去保證這些方法產生的結果是我們想要的呢?當然了,最容易想到的一個方式,就是我們通過System.out來輸出我們的結果,看看是不是滿足我們的需求,但是項目中這些成千上萬個方法,我們總不能在每一個方法中都去輸出一遍嘛。這也太枯燥了。這時候用我們的單元測試框架junit就可以很好地解決這個問題。

junit如何解決這個問題的呢?答案在於內部提供了一個斷言機制,他能夠將我們預期的結果和實際的結果進行比對,判斷出是否滿足我們的期望。

預備工作

junit4是一個單元測試框架,既然是框架,這也就意味着jdk並沒有為我們提供api,因此在這裏我們就需要導入相關的依賴。

junit4是一個單元測試框架,既然是框架,這也就意味着jdk並沒有為我們提供api,因此在這裏我們就需要導入相關的依賴。

這裏的版本是4.12。當然還有最新的版本。你可以手動選擇。這裏選用的是4的版本。

案例

這裏我們要測試的功能超級簡單,就是加減乘除法的驗證。

然後我們看看如何使用junit去測試。

以上就是我們的單元測試,需要遵循一下規則:

  • •每一個測試方法上使用@Test進行修飾
  • •每一個測試方法必須使用public void 進行修飾
  • •每一個測試方法不能攜帶參數
  • •測試代碼和源代碼在兩個不同的項目路徑下
  • •測試類的包應該和被測試類保持一致
  • •測試單元中的每個方法必須可以獨立測試

以上的6條規則,是在使用單元測試的必須項,當然junit也建議我們在每一個測試方法名加上test前綴,表明這是一個測試方法。

assertEquals是一個斷言的規則,裏面有兩個參數,第一個參數表明我們預期的值,第二個參數表示實際運行的值。

我們運行一下測試類,就會運行每一個測試方法,我們也可以運行某一個,只需要在相應的測試方法上面右鍵運行即可。如果運行成功編輯器的控制台不會出現錯誤信息,如果有就會出現failure等信息。

運行流程

在上面的每一個測試方法中,代碼是相當簡單的,就一句話。現在我們分析一下這個測試的流程是什麼:

在上面的代碼中,我們使用了兩個測試方法,還有junit運行整個流程方法。我們可以運行一下,就會出現下面的運行結果:

從上面的結果我們來畫一張流程圖就知道了:

如果我們使用過SSM等其他的一些框架,經常會在before中添加打開數據庫等預處理的代碼,也會在after中添加關閉流等相關代碼。

註解

對於@Test,裏面有很多參數供我們去選擇。我們來認識一下

  • •@Test(expected=XX.class) 這個參數表示我們期望會出現什麼異常,比如說在除法中,我們1/0會出現ArithmeticException異常,那這裏@Test(expected=ArithmeticException.class)。在測試這個除法時候依然能夠通過。
  • •@Test(timeout=毫秒 ) 這個參數表示如果測試方法在指定的timeout內沒有完成,就會強制停止。
  • •@Ignore 這個註解其實基本上不用,他的意思是所修飾的測試方法會被測試運行器忽略。•@RunWith 更改測試運行器。

測試套件

如果我們的項目中如果有成千上萬個方法,那此時也要有成千上萬個測試方法嘛?如果這樣junit使用起來還不如System.out呢,現在我們認識一下測試嵌套的方法,他的作用是我們把測試類封裝起來,也就是把測試類嵌套起來,只需要運行測試套件,就能運行所有的測試類了。

下面我們使用測試套件,把這些測試類嵌套在一起。

 

 

 

參數化設置

什麼是參數化設置呢?在一開始的代碼中我們看到,測試加法的時候是1+1,不過我們如果要測試多組數據怎麼辦?總不能一個一個輸入,然後運行測試吧。這時候我們可以把我們需要測試的數據先配置好。

這時候再去測試,只需要去選擇相應的值即可,避免了我們一個一個手動輸入。

spring boot + junit

通過spring suite tools新建工程

 

 

1. Controller

@RestController
@RequestMapping
public class BookController {
    @RequestMapping("/books")
    public String book() {
        System.out.println("controller");
        return "book";
    }
}

Test1 引入Spring上下文,但不啟動tomcat

@RunWith(SpringRunner.class)
@SpringBootTest  //引入Spring上下文 -> 上下文中的 bean 可用,自動注入
public class BookControllerTest {
    
    @Autowired
    private BookController bookController;  //自動注入
    
    @Test
    public void testControllerExists() {
        Assert.assertNotNull(bookController);
    }
    
}

Test2 引入Spring上下文,且啟動Tomcat 模擬生產環境,接收Http請求

package com.cloud.skyme;

import org.junit.Assert;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.test.context.junit4.SpringRunner;

/** * @author zhangfeng * web單元測試 * */
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class Chapter0302junitApplicationTests {
	
	@LocalServerPort
    private int port;
	
	@Autowired
	private TestRestTemplate restTemplate;
    
    @Test
    public void testControllerExists() {
    	Assert.assertEquals(this.restTemplate.getForObject("http://localhost:" + port + "/books", String.class), "book");
    }

}

@RunWith(SpringRunner.class),讓測試運行於Spring測試環境,此註釋在org.springframework.test.annotation包中提供。
@SpringBootTest指定Sspring Bboot程序的測試引導入口。
TestRestTemplate是用於測試rest接口的模板類。
運行單元測試,測試上面邊構建的Wweb地址,可以看到輸出的測試結果與期望的結果相同.

運行單元測試,得到與期望相同的結果。

    
javascript    44行

13:31:03.722 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating CacheAwareContextLoaderDelegate from class [org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate] 13:31:03.739 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating BootstrapContext using constructor [public org.springframework.test.context.support.DefaultBootstrapContext(java.lang.Class,org.springframework.test.context.CacheAwareContextLoaderDelegate)] 13:31:03.801 [main] DEBUG org.springframework.test.context.BootstrapUtils - Instantiating TestContextBootstrapper for test class [com.cloud.skyme.Chapter0302junitApplicationTests] from class [org.springframework.boot.test.context.SpringBootTestContextBootstrapper] 13:31:03.830 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Neither @ContextConfiguration nor @ContextHierarchy found for test class [com.cloud.skyme.Chapter0302junitApplicationTests], using SpringBootContextLoader 13:31:03.837 [main] DEBUG org.springframework.test.context.support.AbstractContextLoader - Did not detect default resource location for test class [com.cloud.skyme.Chapter0302junitApplicationTests]: class path resource [com/cloud/skyme/Chapter0302junitApplicationTests-context.xml] does not exist 13:31:03.838 [main] DEBUG org.springframework.test.context.support.AbstractContextLoader - Did not detect default resource location for test class [com.cloud.skyme.Chapter0302junitApplicationTests]: class path resource [com/cloud/skyme/Chapter0302junitApplicationTestsContext.groovy] does not exist 13:31:03.838 [main] INFO org.springframework.test.context.support.AbstractContextLoader - Could not detect default resource locations for test class [com.cloud.skyme.Chapter0302junitApplicationTests]: no resource found for suffixes {-context.xml, Context.groovy}.
13:31:03.839 [main] INFO org.springframework.test.context.support.AnnotationConfigContextLoaderUtils - Could not detect default configuration classes for test class [com.cloud.skyme.Chapter0302junitApplicationTests]: Chapter0302junitApplicationTests does not declare any static, non-private, non-final, nested classes annotated with @Configuration. 13:31:03.918 [main] DEBUG org.springframework.test.context.support.ActiveProfilesUtils - Could not find an 'annotation declaring class' for annotation type [org.springframework.test.context.ActiveProfiles] and class [com.cloud.skyme.Chapter0302junitApplicationTests] 13:31:04.070 [main] DEBUG org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider - Identified candidate component class: file [C:\java\workspace\microservice\chapter0302junit\target\classes\com\cloud\skyme\Chapter0302junitApplication.class] 13:31:04.073 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Found @SpringBootConfiguration com.cloud.skyme.Chapter0302junitApplication for test class com.cloud.skyme.Chapter0302junitApplicationTests 13:31:04.225 [main] DEBUG org.springframework.boot.test.context.SpringBootTestContextBootstrapper - @TestExecutionListeners is not present for class [com.cloud.skyme.Chapter0302junitApplicationTests]: using defaults. 13:31:04.226 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener, org.springframework.boot.test.autoconfigure.webservices.client.MockWebServiceServerTestExecutionListener, org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener, org.springframework.test.context.event.EventPublishingTestExecutionListener] 13:31:04.243 [main] DEBUG org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Skipping candidate TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener] due to a missing dependency. Specify custom listener classes or make the default listener classes and their required dependencies available. Offending class: [org/springframework/transaction/interceptor/TransactionAttributeSource] 13:31:04.244 [main] DEBUG org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Skipping candidate TestExecutionListener [org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener] due to a missing dependency. Specify custom listener classes or make the default listener classes and their required dependencies available. Offending class: [org/springframework/transaction/interceptor/TransactionAttribute] 13:31:04.244 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@7133da86, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@3232a28a, org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener@73e22a3d, org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener@47faa49c, org.springframework.test.context.support.DirtiesContextTestExecutionListener@28f2a10f, org.springframework.test.context.event.EventPublishingTestExecutionListener@f736069, org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener@6da21078, org.springframework.boot.test.autoconfigure.restdocs.RestDocsTestExecutionListener@7fee8714, org.springframework.boot.test.autoconfigure.web.client.MockRestServiceServerResetTestExecutionListener@4229bb3f, org.springframework.boot.test.autoconfigure.web.servlet.MockMvcPrintOnlyOnFailureTestExecutionListener@56cdfb3b, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverTestExecutionListener@2b91004a, org.springframework.boot.test.autoconfigure.webservices.client.MockWebServiceServerTestExecutionListener@20ccf40b] 13:31:04.250 [main] DEBUG org.springframework.test.context.support.AbstractDirtiesContextTestExecutionListener - Before test class: context [DefaultTestContext@6cd28fa7 testClass = Chapter0302junitApplicationTests, testInstance = [null], testMethod = [null], testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@614ca7df testClass = Chapter0302junitApplicationTests, locations = '{}', classes = '{class com.cloud.skyme.Chapter0302junitApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true, server.port=0}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@3b07a0d6, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@14d3bc22, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@45b9a632, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@5e316c74, org.springframework.boot.test.context.SpringBootTestArgs@1], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> false]], class annotated with @DirtiesContext [false] with mode [null]. 13:31:04.267 [main] DEBUG org.springframework.test.context.support.DependencyInjectionTestExecutionListener - Performing dependency injection for test context [[DefaultTestContext@6cd28fa7 testClass = Chapter0302junitApplicationTests, testInstance = com.cloud.skyme.Chapter0302junitApplicationTests@31fa1761, testMethod = [null], testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@614ca7df testClass = Chapter0302junitApplicationTests, locations = '{}', classes = '{class com.cloud.skyme.Chapter0302junitApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true, server.port=0}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@3b07a0d6, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@14d3bc22, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@45b9a632, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@5e316c74, org.springframework.boot.test.context.SpringBootTestArgs@1], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> false]]].
13:31:04.306 [main] DEBUG org.springframework.test.context.support.TestPropertySourceUtils - Adding inlined properties to environment: {spring.jmx.enabled=false, org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true, server.port=0}

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.3.1.RELEASE) 2020-06-28 13:31:04.940 INFO 8376 --- [ main] c.c.s.Chapter0302junitApplicationTests : Starting Chapter0302junitApplicationTests on WIN-55FHBQI56BD with PID 8376 (started by Administrator in C:\java\workspace\microservice\chapter0302junit) 2020-06-28 13:31:04.942 INFO 8376 --- [ main] c.c.s.Chapter0302junitApplicationTests : No active profile set, falling back to default profiles: default 2020-06-28 13:31:09.134 INFO 8376 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 0 (http) 2020-06-28 13:31:09.160 INFO 8376 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2020-06-28 13:31:09.161 INFO 8376 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.36] 2020-06-28 13:31:09.372 INFO 8376 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2020-06-28 13:31:09.372 INFO 8376 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 4316 ms 2020-06-28 13:31:10.029 INFO 8376 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2020-06-28 13:31:10.655 INFO 8376 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 59724 (http) with context path '' 2020-06-28 13:31:10.673 INFO 8376 --- [ main] c.c.s.Chapter0302junitApplicationTests : Started Chapter0302junitApplicationTests in 6.362 seconds (JVM running for 8.218) 2020-06-28 13:31:11.423 INFO 8376 --- [o-auto-1-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2020-06-28 13:31:11.423 INFO 8376 --- [o-auto-1-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2020-06-28 13:31:11.461 INFO 8376 --- [o-auto-1-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 37 ms controller 2020-06-28 13:31:13.497 INFO 8376 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'

 

 這樣,一個web應用從構建到單元測試就都已經完成了,可見,構建一個Spring Web MVC的應用就是如此簡單。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

新北清潔公司,居家、辦公、裝潢細清專業服務

※推薦評價好的iphone維修中心

報名即將截止——第五屆中國國際新能源汽車論壇2015餘票有限

2015上海車展已圓滿落下帷幕。本屆上海車展吸引了18個國家和地區2000家中外汽車展商參展,新能源汽車無疑是此次車展最大的亮點之一。本次車展共展出新能源車103輛,其中51輛國內自主車型,52輛合資或進口車型。新能源汽車將成車市主流,也將成車市中有力的競爭者。在剛剛結束的2015上海車展上,幾乎國內的每個車企都有新能源汽車展出,比亞迪更是以“清一色”的新能源汽車參展,由此可見,新能源汽車的重要性。現階段,基礎設施和電池續航里程是影響其發展的重要因素,如何破解這些難題是中國政府和車企急需考慮的問題。

在新能源汽車發展的大形勢下,距離第五屆中國國際新能源汽車論壇2015舉辦還有一周,中國國際新能源汽車論壇組委會邀請到了100+企業, 200位左右行業高層領導,其中包括世界知名混合動力汽車生產廠商、純電動汽車生產廠商、純電動高檔跑車生產廠商、零部件一百強企業、鋰電池供應商、變速器供應商、生產設備供應商、充電樁服務商、運營商等。共同商討新能源汽車行業發展新變化、新趨勢、新契機。包括以下議題:

  • 新能源汽車產業發展規劃和節能減排計畫
  • 政府激勵政策和補貼
  • 新能源汽車市場資料分析及市場展望
  • 如何讓電動汽車更容易被消費者接受
  • 高性能電動車-清潔交通的革新
  • 新能源汽車的節能減排技術
  • 打造安全高性能的新能源汽車電子控制器
  • 未來制動系統的核心: 結合最新技術的基礎制動架構
  • 新能源汽車零部件開發測試
  • 力帆新能源汽車產業模式與創新技術
  • 圓桌論壇:零部件的技術創新與整合廠商設計融入
  • 充換電標準的發展與統一
  • 飛兆車載充電器及DC-DC轉換器解決方案
  • 全球充電基礎設施與行業標杆
  • 樂視生態與智慧互聯汽車的未來
  • 電動汽車動力和能源管理研究進展
  • 動力汽車在電動車及動力電池發展的前景探討
  • 新能源客車機動力電池發展的前景探討
  • 純電動客車運營策略分析
  • 車網互聯打造智能新能源汽車
  • 2015年中國車用動力電池產業經濟運行情況及展望
  • 圓桌討論:充電設施的落地途徑及商業模式
  • 整車廠商-零部件企業對接洽談會

欲瞭解詳情,請登錄論壇唯一官方網址,或聯繫Hill ZENG(曾先生) 電話:+86 21-6045 1760諮詢。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

新北清潔公司,居家、辦公、裝潢細清專業服務

※推薦評價好的iphone維修中心

易到用車APP上線數千輛新能源車 最低5元人民幣即可搭乘

日前,易到用車啟動了「E-Car計畫」,將陸續在北京、上海、廣州、深圳上線數千輛新能源車型,打造新能源出行平台;與此同時易到用車還宣佈將與普天新能源、龐大集團、騰勢等品牌展開深度合作,共同打造新能源出行聯盟,共建新能源城市。   屆時,易到用車App將上線開通「新能源」車型選項。此次加入易到「E-Car計畫」的車型包括混合動力的雙擎普銳斯、沃爾沃S60L、北汽EV系列以及特斯拉,用戶可通過易到用車App,在「新能源」車型中按需選擇,價格最低5元人民幣(下同)起步,0元/分鐘,0.99元/公里。   易到方面介紹,作為聯盟計畫的一部分,易到用車將與普天合作,在未來共同建設1000個充電樁設施,也同時尋找更多合作夥伴,提供場地共同建樁,而且充電樁建好後,將面向社會全面開放使用。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

新北清潔公司,居家、辦公、裝潢細清專業服務

※推薦評價好的iphone維修中心