跳至內容

Java 程式設計/Spring 框架

來自華夏公益教科書

本教程旨在簡要介紹使用 Spring 框架編寫 Java 應用程式。請注意,本教程面向那些具有中等程度的Java 背景知識和對XML 的基本工作了解的人員。

在本教程中,我們將建立一個從 Spring bean 配置檔案讀取短篇故事的應用程式。(為了這個例子,這些短篇故事是非常短的故事。)將有三個 Java 類和一個 Spring 配置檔案。所以讓我們開始吧…

步驟 1:設定您的環境

[編輯 | 編輯原始碼]

在我們直接建立檔案之前,我們首先需要設定 Spring。我假設您已經安裝了最新版本的 Java。如果沒有,您可以從這裡下載 Java 開發工具包。

Spring 建議使用 Maven 或 Gradle 來設定您的依賴項。[1]如果您尚未安裝它們或它們沒有由您的IDE(例如Eclipse)提供,您可以找到關於如何使用和下載它們的說明這裡這裡。Maven 或 Gradle 將確保您的依賴項及其依賴項在您的專案中載入。

請參閱http://projects.spring.io/spring-framework/中的“快速入門”部分,瞭解如何將 Spring 依賴項新增到您的專案。使用 Maven,您需要在專案根目錄中提供一個包含以下內容的 pom.xml 檔案

如果您使用的是 Maven,請確保您提供一個包含以下行的 pom.xml 檔案。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.mygroup</groupId>
  <artifactId>spring</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <!-- Copy the following lines from http://projects.spring.io/spring-framework/ to depend on the latest version of spring -->
  <dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.1.3.RELEASE</version>
    </dependency>
</dependencies>
</project>

從這裡開始,您可以將文字複製貼上到步驟 2、3 和 4 的檔案中;跳過說明;並自行執行程式。這些說明只是為了向您提供關於 Spring 將所有內容組合在一起的方式的背景資訊。好的,現在讓我們進入正題,story_configuration.xml

步驟 2:建立 Spring bean 配置檔案

[編輯 | 編輯原始碼]

在您計劃放置 Java 檔案的目錄中建立一個新的 XML 檔案。將其命名為 story_configuration.xml。然後將下面的文字複製貼上到檔案中並儲存它

story_configuration.xml

[編輯 | 編輯原始碼]
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
      "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
   <bean id="StoryList" class="spring.StoryList">
      <property name="stories">
         <list>
           <ref bean="HelloWorld"/>
           <ref bean="OnceUpon"/>
         </list>
       </property>
   </bean>

   <bean id="HelloWorld" class="spring.Story">
      <property name="title">
         <value>Hello World!</value>
      </property>
      <property name="author">
         <value>User:Hyad</value>
      </property>
      <property name="content">
         <value>This is a simple story.
This is a story about a man who said, "Hello, World."
See, now wasn't that simple.</value>
      </property>
   </bean>
	
   <bean id="OnceUpon" class="spring.Story">
      <property name="title">
         <value>Once Upon a Time</value>
      </property>
      <property name="author">
         <value>Rob Yates</value>
      </property>
      <property name="content">
         <value>Once upon a time there were some interesting things going on.
The end.</value>
      </property>
   </bean>
</beans>

前兩行只是標準的 XML 宣告。從技術上講,我們並不真正需要它們,但無論如何我們會把它們放在這裡。接下來,您會看到 <beans> 標籤,這是所有 Java bean 的存放位置。

在它下面您會看到 <bean class="spring.StoryList">。這將是我們 Java 類 StoryList.java(位於 spring 包中)的 bean。這個類只是一個 List 的佔位符,我們將在這裡存放我們的故事。請注意 bean 元素的屬性:必須始終有一個類屬性來表示 bean 使用的 Java 類。id 屬性是可選的;它由 XMLBeanFactory 類使用,來告訴它使用 getBean 方法獲取哪個 bean:例如,getBean("這裡是我的 id 屬性名稱")。如果沒有提供 ID 屬性,例如 <bean class="StoryList">,則類名將被用作它的 id 屬性。想象一下:<bean id="StoryList" class="spring.StoryList">。還要注意,bean 的 id 值不能包含任何空格,例如,不要寫 id="Story List"

接下來我們有 <property name="stories">。property 標籤只是指定我們要用 bean 屬性指定 Java bean 檔案中的哪個屬性變數。<list> 標籤接下來用於告訴 Spring 我們正在處理一個 List 的東西,而不是僅僅一個東西。接下來我們有 <ref bean="HelloWorld"/>,它告訴 Spring 返回此 List 中的 <bean id="HelloWorld" class="spring.Story"> bean。在另一個示例中,您可能只需要一個值的列表,例如 String。對於購物清單,您可能會有類似以下的內容,

<list>
	<value>milk</value>
	<value>eggs</value>
	<value>bread</value>
</list>

無論哪種方式,您的屬性都對映到一個 LIST

對於我們的 HelloWorld 故事,我們有 <bean id="HelloWorld" class="spring.Story">。希望這沒什麼太奇怪的。此 bean 有三個屬性,<property name="title"><property name="author"><property name="content">。這些再次對映到屬性變數:Story 類中的 title、author 和 content。在每個值中我們有:<value>Hello World!</value>、<value>User:Hyad</value>、<value>這是一個簡單的故事。

這是一個關於一個男人說“你好,世界”的故事。

看吧,現在是不是很簡單?</value>由於我們正在處理 String,因此開始和結束 value 標籤之間的所有內容都被轉換為 String。因此,要新增一個換行符,我們實際上必須將文字放在單獨的行上,並且沒有任何縮排。請注意,值不必對映到 String,它們可以是基本型別(如 int 或 char),也可以是物件(如 Integer 或 Float)。Spring 會自動知道如何轉換它們。

我們不會介紹 OnceUpon bean,它基本上與 HelloWorld 相同,只是值不同。事實上,這就是使用 Spring 的主要目的,將 Java 類的不同值集儲存為 bean,而不是建立一個新類。接下來是 Java Bean 類本身。

步驟 3:製作 JavaBean 類

[編輯 | 編輯原始碼]

有兩個 JavaBean 類:Story.javaStoryList.java,它們都在 spring 包中。將以下文字複製貼上到各自的類中。

Story.java

[編輯 | 編輯原始碼]
package spring;

public class Story {
	
	private String title;
	private String author;
	private String content;
	
	public Story () {
	}	
	public void setTitle(String title) {
		this.title = title;
	}
	public String getTitle() {
		return title;
	}
	public void setAuthor(String author) {
		this.author = author;
	}
	public String getAuthor() {
		return author;
	}
	public void setContent(String content) {
		this.content = content;
	}
	public String getContent() {
		return content;
	}
}

StoryList.java

[編輯 | 編輯原始碼]
package spring;

import java.util.List;

public class StoryList {

	private List stories;
	
	public StoryList (){
	}
	public void setStories(List stories) {
		this.stories = stories;
	}
	public List getStories() {
		return stories;
	}
}

並不太複雜,對吧?這些是 JavaBean;簡單的類,具有用於屬性變數的 getter 和 setter,以及一個沒有引數的建構函式。有關 JavaBean 的更深入討論,請訪問維基百科:JavaBeans。setter,如 setTitle(String title),是 Spring 用於在 XmlBeanFactory 中建立 bean 的內容。setter 必須遵循特定的 bean 命名約定。例如,settitle(String title)(使用小寫的“t”)將不起作用。但是,作為示例,setURL(String url)(使用屬性名稱“URL”)將起作用,因為除了第一個“U”之外,第二個字母“R”也大寫了。Spring 在此示例中實際上沒有使用 getter,但是 StoryReader 需要它們,我們將在後面看到。此外,我們實際上不必指定一個無引數建構函式,我們可以將其省略,Java 編譯器在編譯時會自動將一個放到類中。但是,在沒有無引數建構函式的情況下編寫一個具有一個或多個引數的建構函式將使該類不再是一個 bean。

步驟 4:一個將所有內容組合在一起的 main 方法

[編輯 | 編輯原始碼]

與之前一樣,複製貼上文字。並將您的類儲存為 StoryReader.java

StoryReader.java

[編輯 | 編輯原始碼]
package spring;

import java.util.List;

import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
 
public class StoryReader {
 
	public static void main(String args[]) {
		ClassPathXmlApplicationContext springApplicationContext = new ClassPathXmlApplicationContext("story_configuration.xml");
 
		StoryList storyList = (StoryList) springApplicationContext.getBean("StoryList");
 
		List myStories = storyList.getStories();
 
		for (int i = 0; i < myStories.size(); i++) {
			Story currentStory = (Story) myStories.get(i);
			System.out.println("\"" + currentStory.getTitle() + "\" by "
					+ currentStory.getAuthor() + ":");
			System.out.println(currentStory.getContent());
			System.out.println();
		}
	}//end main
 
}//end StoryReader

這是我們的主類,StoryReader.java,位於spring包中。首先,我們需要匯入兩個Spring類:XmlBeanFactoryClassPathResourceXmlBeanFactory本質上是Spring XML配置檔案story_configuration.xml的Java類表示。但是,在我們獲取XML檔案之前,我們必須告訴Spring在我們的類路徑中查詢該檔案。這就是ClassPathResource的作用。它會在類路徑中搜索指定的story_configuration.xml檔案,而我們的.class檔案就儲存在類路徑中。任何其他實現了Resource介面的類都可以使用,比如org.springframework.core.io.FileSystemResource。因此,我們可以看到XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("story_configuration.xml"));story_configuration.xml建立一個新的bean工廠。

下一行,StoryList storyList = (StoryList) beanFactory.getBean("StoryList");,告訴我們接下來要獲取哪個bean。getBean("StoryList")告訴bean工廠返回一個對應於id為“StoryList”的bean的物件,因為它是類名。由於它是一個Object,所以我們必須將其強制轉換為StoryList類。

接下來,我們從StoryList類中獲取故事列表,並遍歷它們。由於這是一個bean,故事已經存在於列表中,在故事中已經存在的數值中。我們只需要將它們打印出來;這就是我們所做的。注意:\"用於跳脫字元串中的引號。

步驟 5:執行程式

[編輯 | 編輯原始碼]

現在我們已經完成了類的建立和檔案的建立,讓我們執行程式!透過確保你正確地複製了所有內容來修復你遇到的任何錯誤。當你執行StoryReader的主方法時,你的輸出應該如下所示

Mar 12, 2006 5:42:30 PM org.springframework.core.CollectionFactory <clinit>
INFO: JDK 1.4+ collections available
Mar 12, 2006 5:42:30 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [story_configuration.xml]
"Hello World!" by User:Hyad:
This is a simple story.
This is a story about a man who said, "Hello, World."
See, now wasn't that simple.

"Once Upon a Time" by Rob Yates:
Once upon a time there were some interesting things going on.
The end.

當你自己執行它時,日期顯然會不同。此外,以日期或“INFO”開頭的四行會列印到System.err中,可能出現在其他輸出的上面、下面,甚至中間。這是因為一些作業系統可能在不同的時間列印到System.outSystem.err。請檢查你的輸出是否與顯示的輸出匹配,忽略Spring列印的四行的日期和順序。現在,你已經擁有了一個功能完善的Spring應用程式,接下來呢?

需要記住的事項

[編輯 | 編輯原始碼]

正如我之前提到的,Spring會自動將值轉換為基本型別和物件;intfloatcharDoublebooleanByte等等。還要注意,<list>(只是一個值列表)可以對映到List物件、Array物件或基本型別陣列(雙方括號型別)。甚至還有<set><map>標籤,可以分別對映到SetMap。並且,你可以隨時用對bean的引用替換值,比如用<ref bean="myBeanId"/>替換<value>myValue</value>。這個引用將返回相應的JavaBean,Spring會將其儲存為該變數。

此外,Spring還可以替代屬性檔案。它的優勢在於Spring是基於XML的,因此任何XML解析器都可以讀取它。同一個檔案中可以儲存同一類的多個bean。但是,你也可以將bean放置在多個檔案中,並使用<import resource="myOtherBeanConfigFile.xml"/>“匯入”其他bean,就像匯入Java類一樣。

最後,你可能還想了解的是,當你使用一個bean來引用其他bean、類、檔案等等時,Spring最有幫助。你可能有一個bean包含一個bean列表,該列表包含一個bean列表,每個bean列表又包含另一個bean列表,……這樣,只有最頂層bean的檔名和位置在Java類中“硬編碼”,而其他所有內容都由XML配置檔案指定。

自己嘗試

[編輯 | 編輯原始碼]

以下是一些可以使你的Spring應用程式更健壯的任務。你可以根據自己的喜好完成其中的一些或所有任務。

  • StoryList bean分離到另一個XML檔案中,在新檔案中使用<import resource="story_configuration.xml"/>
  • 為每個故事添加發布時間。你將如何儲存日期?
  • 為作者建立一個單獨的類。作者可能有哪些屬性?
  • StoryList中新增額外的功能。如何新增一個可以由StoryReader的主方法呼叫的printStories()方法?
  • 建立一個寫入器,以便所有輸出都寫入檔案。並將該檔名儲存為一個bean。
  • 新增更多故事。(我知道我的故事很爛。)
  • 除了故事之外,還可以新增電視劇或電子遊戲嗎?
  • 修改一些隨機程式碼,直到它崩潰。玩得開心!:)

關於作者

[編輯 | 編輯原始碼]

我在維基百科和華夏公益教科書上被稱為User:Hyad。因為其他Spring教程太長了,讓我感到沮喪,所以我決定在工作中真正學習(和使用)Spring之後,自己建立自己的教程。這個教程最接近我在一個好的教程中尋找的東西,但它有點太短了。所以我想,為什麼不舉一個可以在現實世界中使用的例子呢?我認為華夏公益教科書是釋出它的最佳場所,因為如果我將它釋出在我的網站上,1. 它將難以編輯,2. 其他使用者將無法輕鬆地編輯和更新它。所以,請在我的維基百科討論頁面上給我留言,告訴我你的想法。

參考資料

[編輯 | 編輯原始碼]
  1. Spring Boot 參考指南。 "構建系統".
華夏公益教科書