Spring Boot(一):快速開始

Spring Boot(一):快速開始

本系列文章旨在使用最小依賴、最簡單配置,幫助初學者快速掌握Spring Boot各組件使用,達到快速入門的目的。所有文章所使用示例代碼均同步Github倉庫和Gitee倉庫。html

1. Spring Boot是什麼?

Spring Boot 是由 Pivotal 團隊提供的全新框架,其設計目的是用來簡化新 Spring 應用的初始搭建以及開發過程。該框架使用了特定的方式來進行配置,從而使開發人員再也不須要定義樣板化的配置。java

講的通俗一點就是Spring Boot並非一個新的框架,它只是整合和默認實現了不少框架的配置方式。git

2. 好處是什麼?

最大的好處就是簡單、快捷、方便,在Spring Boot以前,咱們若是要搭建一個框架須要作什麼?github

  • 配置web.xml,加載Spring和Spring MVC,加載各類過濾器、攔截器
  • 在配置文件application.xml中配置數據庫、配置緩存、配置鏈接池等等
  • 配置日誌文件
  • 配置各類配置文件的讀取
  • 配置上下文、配置定時任務
  • ...
  • 各類各樣的配置
  • ...

筆者手邊正好有一個好久以前的項目,當時仍是使用的Spring3.x,能夠給各位看一下當時一個項目的配置文件有多少:web

而我若是須要新建一個項目,這裏面大量的配置文件都要copy過去,而且從新調試,很是的不方便且浪費時間,當Spring Boot橫空出世的時候,這些噩夢都結束了。spring

Spring Boot的優點:數據庫

  • 爲全部Spring開發者更快的入門
  • 開箱即用,提供各類默認配置來簡化項目配置
  • 內嵌式容器簡化Web項目
  • 沒有冗餘代碼生成和XML配置的要求

3. 快速入門

目標設定:構建一個簡單的RESTful API並實現對應的單元測試json

3.1 工程構建方式

Spring Boot提供兩種工程構建方式:segmentfault

關於建立springcloud項目,目前有兩種比較方便的方案,核心都是同樣的,你們自行選擇本身使用方便的。api

方式一:

打開spring的官方連接:

https://start.spring.io/

在 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,默認的就是上面的官方連接,https://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;

        // 一、get查一下user列表,應該爲空
        request = MockMvcRequestBuilders.get("/")
                .contentType(MediaType.APPLICATION_JSON);
        mvc.perform(request)
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(MockMvcResultHandlers.print())
                .andReturn();

        // 二、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();


        // 三、get獲取user列表,應該有剛纔插入的數據
        request = MockMvcRequestBuilders.get("/")
                .contentType(MediaType.APPLICATION_JSON);
        mvc.perform(request)
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(MockMvcResultHandlers.print())
                .andReturn();

        // 四、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();

        // 五、get一個id爲1的user
        request = MockMvcRequestBuilders.get("/1")
                .contentType(MediaType.APPLICATION_JSON);

        mvc.perform(request)
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(MockMvcResultHandlers.print())
                .andReturn();

        // 六、del刪除id爲1的user
        request = MockMvcRequestBuilders.delete("/1")
                .contentType(MediaType.APPLICATION_JSON);

        mvc.perform(request)
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(MockMvcResultHandlers.print())
                .andReturn();

        // 七、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 = []

從控制檯打印中能夠完整的看到整個模擬請求的過程以及參數。

示例代碼-Github
示例代碼-Gitee

4. 參考

《Spring Boot(一):入門篇》
《Spring Boot構建RESTful API與單元測試》
若是您以爲個人文章對您有幫助,就關注一下吧

相關文章
相關標籤/搜索