Spring Boot(一):快速開始
本系列文章旨在使用最小依賴、最簡單配置,幫助初學者快速掌握Spring Boot各元件使用,達到快速入門的目的。全部文章所使用示例程式碼均同步Github倉庫和Gitee倉庫。
1. Spring Boot是什麼?
Spring Boot 是由 Pivotal 團隊提供的全新框架,其設計目的是用來簡化新 Spring 應用的初始搭建以及開發過程。該框架使用了特定的方式來進行配置,從而使開發人員不再需要定義樣板化的配置。
講的通俗一點就是Spring Boot並不是一個新的框架,它只是整合和預設實現了很多框架的配置方式。
2. 好處是什麼?
最大的好處就是簡單、快捷、方便,在Spring Boot之前,我們如果要搭建一個框架需要做什麼?
- 配置web.xml,載入Spring和Spring MVC,載入各種過濾器、攔截器
- 在配置檔案application.xml中配置資料庫、配置快取、配置連線池等等
- 配置日誌檔案
- 配置各種配置檔案的讀取
- 配置上下文、配置定時任務
- ...
- 各種各樣的配置
- ...
筆者手邊正好有一個很久之前的專案,當時還是使用的Spring3.x,可以給各位看一下當時一個專案的配置檔案有多少:
而我如果需要新建一個專案,這裡面大量的配置檔案都要copy過去,並且重新除錯,非常的不方便且浪費時間,當Spring Boot橫空出世的時候,這些噩夢都結束了。
Spring Boot的優勢:
- 為所有Spring開發者更快的入門
- 開箱即用,提供各種預設配置來簡化專案配置
- 內嵌式容器簡化Web專案
- 沒有冗餘程式碼生成和XML配置的要求
3. 快速入門
目標設定:構建一個簡單的RESTful API並實現對應的單元測試
3.1 工程構建方式
Spring Boot提供兩種工程構建方式:
關於建立springcloud專案,目前有兩種比較方便的方案,核心都是一樣的,大家自行選擇自己使用方便的。
方式一:
開啟spring的官方連結:
在 Group 中填入自己的組織,一般填寫公司的域名的到寫,例如 com.jd 或者 com .baidu ,這裡我直接寫 com.springboot
在 Artifact 中填寫工程的名稱,這裡我直接寫 spring-boot-quick-start 。
package 選擇 jar ,java 選擇11(目前最新的LTS版本),至此,基礎選擇已經全都選完,接下來要開始選擇我們使用的 Spring Boot 的元件了。
在 Dependencies 中找到 Spring Web ,選擇 Spring Web ,結果如下圖:
最後點選下方的綠色長條按鈕 Generate the project 進行下載,等待下載完成後,直接將壓縮包解壓匯入我們的編輯工具idea裡即可。
方式二:
基於 idea 建立,開啟 idea ,首先 file->new->project ,選中 Spring Initializr ,這時可以看到右側讓我們選擇一個初始化的服務url,預設的就是上面的官方連結,start.spring.io/
點選 next 下一步,填寫和上面一樣的 Group 、 Artifact 、 java 版本、 package 方式等資訊,繼續 next 下一步,選擇依賴,和前面的方法的一樣,在 Dependencies 中找到 Spring Web ,選擇 Spring Web ,點選 next ,選擇專案名稱和儲存路徑,點選 finish ,靜靜等一會,第一個專案 spring-boot-quick-start 就新鮮出爐了~~~
我一般選擇第一種方式建立 Spring Boot 專案,這種方式不依賴IDE工具。
3.2 工程結構解析
首先先看一下我們建立的工程結構,如下圖:
- pom.xml:maven工程配置檔案,主要配置當前工程的一些基本資訊,包含我們當前使用的元件,版本等資訊。
- src/main/java下的程式入口:Chapter1Application。
- src/main/resources下的配置檔案:application.properties。
- src/test/下的測試入口:Chapter1ApplicationTests。
3.3 pom.xml
這裡我們重點關注 <dependencies>
標籤,這裡寫明瞭我們引入的元件
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
複製程式碼
-
spring-boot-starter-web
:Web模組 -
spring-boot-starter-test
:測試模組,包括JUnit、Hamcrest、Mockito
3.4 使用 Spring MVC 實現一組對 User 物件的 RESTful API
RESTful API 設計如下:
請求型別 | URL | 功能 |
---|---|---|
GET | / | 查詢使用者列表 |
POST | / | 建立User |
GET | /{id} | 根據 url 中的 id 獲取 user 資訊 |
PUT | /{id} | 根據 id 更新使用者資訊 |
DELETE | /{id} | 根據 id 刪除使用者資訊 |
**注意:**RESTful介面在設計的時候應該遵循標準的方法以及語義,這些語義包含了安全性和冪等性等方面的考量,例如GET和HEAD請求都是安全的, 無論請求多少次,都不會改變伺服器狀態。而GET、HEAD、PUT和DELETE請求都是冪等的,無論對資源操作多少次, 結果總是一樣的,後面的請求並不會產生比第一次更多的影響。
下面列出了GET,DELETE,PUT和POST的典型用法:
GET
- 安全且冪等
- 獲取表示
- 變更時獲取表示(快取)
POST
- 不安全且不冪等
- 使用服務端管理的(自動產生)的例項號建立資源
- 建立子資源
- 部分更新資源
- 如果沒有被修改,則不過更新資源(樂觀鎖)
PUT
- 不安全但冪等
- 用客戶端管理的例項號建立一個資源
- 通過替換的方式更新資源
- 如果未被修改,則更新資源(樂觀鎖)
DELETE
- 不安全但冪等
- 刪除資源
使用者Model類如下:
public class UserModel {
private Long id;
private String name;
private int age;
// 省略 getter 和 setter
}
複製程式碼
REST API 實現類如下:
@RestController
public class UserController {
// 建立執行緒安全的Map,用作資料儲存
static Map<Long,UserModel> users = new ConcurrentHashMap<>();
/**
* 查詢使用者列表
* @return
*/
@GetMapping("/")
public List<UserModel> getUserList() {
List<UserModel> list = new ArrayList<UserModel>(users.values());
return list;
}
/**
* 建立User
* @param userModel
* @return
*/
@PostMapping("/")
public UserModel postUser(@ModelAttribute UserModel userModel) {
users.put(userModel.getId(),userModel);
return users.get(userModel.getId());
}
/**
* {id} 根據 url 中的 id 獲取 user 資訊
* url中的id可通過@PathVariable繫結到函式的引數中
* @param id
* @return
*/
@GetMapping("/{id}")
public UserModel getUser(@PathVariable Long id) {
return users.get(id);
}
/**
* 根據 id 更新使用者資訊
* @param id
* @param userModel
* @return
*/
@PutMapping("/{id}")
public UserModel putUser(@PathVariable Long id,@ModelAttribute UserModel userModel) {
UserModel u = users.get(id);
u.setName(userModel.getName());
u.setAge(userModel.getAge());
users.put(id,u);
return users.get(userModel.getId());
}
/**
* 根據 id 刪除使用者資訊
* @param id
* @return
*/
@DeleteMapping("/{id}")
public String deleteUser(@PathVariable Long id) {
users.remove(id);
return "success";
}
}
複製程式碼
- @Controller:修飾class,用來建立處理http請求的物件
- @RestController:Spring4之後加入的註解,原來在@Controller中返回json需要@ResponseBody來配合,如果直接用@RestController替代@Controller就不需要再配置@ResponseBody,預設返回json格式。
可以看一下 @RestController
,可以看到 @RestController
本身就是由 @ResponseBody
和 @Controller
組成的,原始碼如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
/**
* The value may indicate a suggestion for a logical component name,* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name,if any (or empty String otherwise)
* @since 4.0.1
*/
@AliasFor(annotation = Controller.class)
String value() default "";
}
複製程式碼
單元測試類如下:
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootQuickStartApplicationTests {
private MockMvc mvc;
@Before
public void setUp() throws Exception {
mvc = MockMvcBuilders.standaloneSetup(new UserController()).build();
}
@Test
public void contextLoads() throws Exception {
RequestBuilder request = null;
// 1、get查一下user列表,應該為空
request = MockMvcRequestBuilders.get("/")
.contentType(MediaType.APPLICATION_JSON);
mvc.perform(request)
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print())
.andReturn();
// 2、post提交一個user
request = MockMvcRequestBuilders.post("/")
.param("id","1")
.param("name","Spring Boot")
.param("age","18")
.contentType(MediaType.APPLICATION_JSON);
mvc.perform(request)
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print())
.andReturn();
// 3、get獲取user列表,應該有剛才插入的資料
request = MockMvcRequestBuilders.get("/")
.contentType(MediaType.APPLICATION_JSON);
mvc.perform(request)
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print())
.andReturn();
// 4、put修改id為1的user
request = MockMvcRequestBuilders.put("/1")
.param("name","Spring Boot Test")
.contentType(MediaType.APPLICATION_JSON);
mvc.perform(request)
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print())
.andReturn();
// 5、get一個id為1的user
request = MockMvcRequestBuilders.get("/1")
.contentType(MediaType.APPLICATION_JSON);
mvc.perform(request)
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print())
.andReturn();
// 6、del刪除id為1的user
request = MockMvcRequestBuilders.delete("/1")
.contentType(MediaType.APPLICATION_JSON);
mvc.perform(request)
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print())
.andReturn();
// 7、get查一下user列表,應該為空
request = MockMvcRequestBuilders.get("/")
.contentType(MediaType.APPLICATION_JSON);
mvc.perform(request)
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print())
.andReturn();
}
}
複製程式碼
啟動測試類,控制檯列印如下,這裡僅擷取一段內容做展示:
MockHttpServletRequest:
HTTP Method = POST
Request URI = /
Parameters = {id=[1],name=[Spring Boot],age=[18]}
Headers = [Content-Type:"application/json"]
Body = <no character encoding set>
Session Attrs = {}
Handler:
Type = com.springboot.springbootquickstart.controller.UserController
Method = public com.springboot.springbootquickstart.model.UserModel com.springboot.springbootquickstart.controller.UserController.postUser(com.springboot.springbootquickstart.model.UserModel)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = [Content-Type:"application/json;charset=UTF-8"]
Content type = application/json;charset=UTF-8
Body = {"id":1,"name":"Spring Boot","age":18}
Forwarded URL = null
Redirected URL = null
Cookies = []
複製程式碼
從控制檯列印中可以完整的看到整個模擬請求的過程以及引數。