天天看點

3. SpringMVC Rest 風格1. REST 簡介2. RESTful 入門案例3. RESTful 快速開發4. 基于 RESTful 的頁面資料互動

文章目錄

  • 1. REST 簡介
  • 2. RESTful 入門案例
  • 3. RESTful 快速開發
  • 4. 基于 RESTful 的頁面資料互動
    • 4.1 需求分析
    • 4.2 背景接口開發
    • 4.2 頁面通路處理

1. REST 簡介

REST(Representational State Transfer),表現形式狀态轉換,它是一種軟體架構風格。

當要表示一個網絡資源的時候,可以使用兩種方式:

  • 傳統風格資源描述形式

    http://localhost/user/getById?id=1

    查詢 id 為 1 的使用者資訊

    http://localhost/user/saveUser

    儲存使用者資訊
  • REST風格描述形式

    http://localhost/user/1

    查詢 id 為 1 的使用者資訊

    http://localhost/user

    儲存使用者資訊

傳統方式一般是一個請求 url 對應一種操作,這樣做不僅麻煩,也不安全,因為會程式的人讀了請求 url 位址,就大概知道該 url 實作的是什麼操作。

檢視 REST 風格的描述,會發現請求位址變簡單了,并且隻看請求 URL 并不能輕易猜出該 URL 的具體功能。

是以 REST 的優點有:

  • 隐藏資源的通路行為,無法通過位址得知對資源是何種操作。
  • 書寫簡化。

但是問題也随之而來,一個相同的 url 位址既可以是新增也可以是修改或者查詢,該如何區分該請求到底是什麼操作呢?

按照 REST 風格通路資源時使用請求動作區分對資源進行了何種操作:

3. SpringMVC Rest 風格1. REST 簡介2. RESTful 入門案例3. RESTful 快速開發4. 基于 RESTful 的頁面資料互動

請求的方式比較多,但是比較常用的就 4 種,分别是 GET、POST、PUT、DELETE。不同的請求方式代表不同的操作類型:

  • 發送 GET 請求是用來做查詢
  • 發送 POST 請求是用來做新增
  • 發送 PUT 請求是用來做修改
  • 發送 DELETE 請求是用來做删除

上述行為是約定方式,約定不是規範,可以打破,是以稱REST風格,而不是REST規範。可以不這樣做,但不建議。

描述子產品的名稱通常使用複數,也就是加 “s”。這樣表示此類資源,而非單個資源,例如:users、books、accounts…

根據 REST 風格對資源進行通路稱為 RESTful。

在開發過程中,大多都遵從 REST 風格來通路背景服務,是以可以說以後都是基于 RESTful 來進行開發。

2. RESTful 入門案例

@PathVariable

注解綁定路徑參數與處理器方法形參間的關系,要求路徑參數名與形參名一一對應。

public class BookController {
    //用postman發post請求,請求路徑:http://localhost/books
    @RequestMapping(value = "/books",method = RequestMethod.POST)
    @ResponseBody
    public String save(@RequestBody Book book){
        System.out.println("book save..." + book);
        return "{'module':'book save'}";
    }
    //用postman發delete請求,請求路徑:http://localhost/books/1
    //請求路徑中的“1”傳給id
    @RequestMapping(value = "/books/{id}",method = RequestMethod.DELETE)
    @ResponseBody
    //@PathVariable:把請求路徑中的變量值傳給形參
    public String delete(@PathVariable Integer id){
        System.out.println("book delete..." + id);
        return "{'module':'book delete'}";
    }
    //用postman發put請求,請求路徑:http://localhost/books
    @RequestMapping(value = "/books",method = RequestMethod.PUT)
    @ResponseBody
    public String update(@RequestBody Book book){
        System.out.println("book update..." + book);
        return "{'module':'book update'}";
    }
    //用postman發get請求,請求路徑:http://localhost/books/1
    @RequestMapping(value = "/books/{id}",method = RequestMethod.GET)
    @ResponseBody
    //@PathVariable:把請求路徑中的變量值傳給形參
    public String getById(@PathVariable Integer id){
        System.out.println("book getById..." + id);
        return "{'module':'book getById'}";
    }
    //用postman發get請求,請求路徑:http://localhost/books
    @RequestMapping(value = "/books",method = RequestMethod.GET)
    @ResponseBody
    public String getAll(){
        System.out.println("book getAll...");
        return "{'module':'book getAll'}";
    }
}
           
3. SpringMVC Rest 風格1. REST 簡介2. RESTful 入門案例3. RESTful 快速開發4. 基于 RESTful 的頁面資料互動
3. SpringMVC Rest 風格1. REST 簡介2. RESTful 入門案例3. RESTful 快速開發4. 基于 RESTful 的頁面資料互動
3. SpringMVC Rest 風格1. REST 簡介2. RESTful 入門案例3. RESTful 快速開發4. 基于 RESTful 的頁面資料互動

@RequestBody、@RequestParam、@PathVariable 三個注解之間的差別和應用分别是什麼?

差別:

  • @RequestParam 用于接收 url 位址傳參或表單傳參。
  • @RequestBody 用于接收 json 資料。
  • @PathVariable 用于接收路徑參數,使用 {參數名稱} 描述路徑參數。

應用:

  • 後期開發中,發送請求參數超過 1 個時,以 json 格式為主,@RequestBody 應用較廣。
  • 如果發送非 json 格式資料,選用 @RequestParam 接收請求參數。
  • 采用 RESTful 進行開發,當參數數量較少時,例如 1 個,可以采用 @PathVariable 接收請求路徑變量,通常用于傳遞 id 值。

3. RESTful 快速開發

在前面基礎上,

  • 可以把相同的路徑字首寫在類上,即:把

    @RequestMapping("/books")

    提到類上。
  • 由于之前每個方法上都有

    @ResponseBody

    注解,是以可以統一寫在類上。

得到如下代碼:

@Controller
@ResponseBody
@RequestMapping("/books")
public class BookController {
    //用postman發post請求,請求路徑:http://localhost/books
    @RequestMapping(method = RequestMethod.POST)
    public String save(@RequestBody Book book){
        System.out.println("book save..."+ book);
        return "{'module':'book save'}";
    }
    //用postman發delete請求,請求路徑:http://localhost/books/1
    //請求路徑中的“1”傳給id
    @RequestMapping(value = "/{id}",method = RequestMethod.DELETE)
    //@PathVariable:把請求路徑中的變量值傳給形參
    public String delete(@PathVariable Integer id){
        System.out.println("book delete..." + id);
        return "{'module':'book delete'}";
    }
    //用postman發put請求,請求路徑:http://localhost/books
    @RequestMapping(method = RequestMethod.PUT)
    public String update(@RequestBody Book book){
        System.out.println("book update..." + book);
        return "{'module':'book update'}";
    }
    //用postman發get請求,請求路徑:http://localhost/books/1
    @RequestMapping(value = "/{id}",method = RequestMethod.GET)
    //@PathVariable:把請求路徑中的變量值傳給形參
    public String getById(@PathVariable Integer id){
        System.out.println("book getById..." + id);
        return "{'module':'book getById'}";
    }
    //用postman發get請求,請求路徑:http://localhost/books
    @RequestMapping(method = RequestMethod.GET)
    public String getAll(){
        System.out.println("book getAll...");
        return "{'module':'book getAll'}";
    }
}
           

在上面代碼的基礎上,

@Controller

@ResponseBody

注解可以用一個注解

@RestController

替代。

請求動作也可以用更簡單的注解表示。

// @Controller
// @ResponseBody
@RestController
@RequestMapping("/books")
public class BookController {
    //用postman發post請求,請求路徑:http://localhost/books
    // @RequestMapping(method = RequestMethod.POST)
    @PostMapping
    public String save(@RequestBody Book book){
        System.out.println("book save..."+ book);
        return "{'module':'book save'}";
    }
    //用postman發delete請求,請求路徑:http://localhost/books/1
    //請求路徑中的“1”傳給id
    // @RequestMapping(value = "/{id}",method = RequestMethod.DELETE)
    @DeleteMapping("/{id}")
    //@PathVariable:把請求路徑中的變量值傳給形參
    public String delete(@PathVariable Integer id){
        System.out.println("book delete..." + id);
        return "{'module':'book delete'}";
    }
    //用postman發put請求,請求路徑:http://localhost/books
    // @RequestMapping(method = RequestMethod.PUT)
    @PutMapping
    public String update(@RequestBody Book book){
        System.out.println("book update..." + book);
        return "{'module':'book update'}";
    }
    //用postman發get請求,請求路徑:http://localhost/books/1
    // @RequestMapping(value = "/{id}",method = RequestMethod.GET)
    @GetMapping("/{id}")
    //@PathVariable:把請求路徑中的變量值傳給形參
    public String getById(@PathVariable Integer id){
        System.out.println("book getById..." + id);
        return "{'module':'book getById'}";
    }
    //用postman發get請求,請求路徑:http://localhost/books
    // @RequestMapping(method = RequestMethod.GET)
    @GetMapping
    public String getAll(){
        System.out.println("book getAll...");
        return "{'module':'book getAll'}";
    }
}
           

上面的代碼去掉注釋後:

@RestController
@RequestMapping("/books")
public class BookController {
    //用postman發post請求,請求路徑:http://localhost/books
    @PostMapping
    public String save(@RequestBody Book book){
        System.out.println("book save..."+ book);
        return "{'module':'book save'}";
    }
    //用postman發delete請求,請求路徑:http://localhost/books/1
    //請求路徑中的“1”傳給id
    @DeleteMapping("/{id}")
    //@PathVariable:把請求路徑中的變量值傳給形參
    public String delete(@PathVariable Integer id){
        System.out.println("book delete..." + id);
        return "{'module':'book delete'}";
    }
    //用postman發put請求,請求路徑:http://localhost/books
    @PutMapping
    public String update(@RequestBody Book book){
        System.out.println("book update..." + book);
        return "{'module':'book update'}";
    }
    //用postman發get請求,請求路徑:http://localhost/books/1
    @GetMapping("/{id}")
    //@PathVariable:把請求路徑中的變量值傳給形參
    public String getById(@PathVariable Integer id){
        System.out.println("book getById..." + id);
        return "{'module':'book getById'}";
    }
    //用postman發get請求,請求路徑:http://localhost/books
    @GetMapping
    public String getAll(){
        System.out.println("book getAll...");
        return "{'module':'book getAll'}";
    }
}
           

4. 基于 RESTful 的頁面資料互動

4.1 需求分析

3. SpringMVC Rest 風格1. REST 簡介2. RESTful 入門案例3. RESTful 快速開發4. 基于 RESTful 的頁面資料互動

需求一:圖檔清單查詢,從背景傳回資料,将資料展示在頁面上。

需求二:新增圖書,将新增圖書的資料傳遞到背景,并在控制台列印。

說明:此次案例的重點是在 SpringMVC 中使用 RESTful 實作前背景互動,是以并沒有和資料庫進行互動,所有資料使用假資料來完成開發。

4.2 背景接口開發

@RestController
@RequestMapping("/books")
public class BookController {
    //儲存圖書
    @PostMapping
    public String save(@RequestBody Book book){
        System.out.println("儲存圖書:"+book);
        return "{'module':'save book success'}";
    }
    //查詢所有圖書
    @GetMapping
    public List<Book> getAll(){
        System.out.println("查詢所有圖書...");
        List<Book> bookList = new ArrayList<>();

        Book book1 = new Book();
        book1.setType("計算機");
        book1.setName("SpringMVC入門教程");
        book1.setDescription("小試牛刀");
        bookList.add(book1);

        Book book2 = new Book();
        book2.setType("計算機");
        book2.setName("SpringMVC實戰教程");
        book2.setDescription("一代宗師");
        bookList.add(book2);

        return bookList;
    }
}
           

postman 測試:

① 測試新增

3. SpringMVC Rest 風格1. REST 簡介2. RESTful 入門案例3. RESTful 快速開發4. 基于 RESTful 的頁面資料互動

② 測試查詢

3. SpringMVC Rest 風格1. REST 簡介2. RESTful 入門案例3. RESTful 快速開發4. 基于 RESTful 的頁面資料互動

4.2 頁面通路處理

(1) 拷貝靜态頁面:将資料\功能頁面下的所有内容拷貝到項目的 webapp 目錄下。

3. SpringMVC Rest 風格1. REST 簡介2. RESTful 入門案例3. RESTful 快速開發4. 基于 RESTful 的頁面資料互動

(2) 通路 pages 目錄下的 books.html

打開浏覽器輸入

http://localhost/pages/books.html

3. SpringMVC Rest 風格1. REST 簡介2. RESTful 入門案例3. RESTful 快速開發4. 基于 RESTful 的頁面資料互動

為什麼會出現錯誤?

3. SpringMVC Rest 風格1. REST 簡介2. RESTful 入門案例3. RESTful 快速開發4. 基于 RESTful 的頁面資料互動

SpringMVC 攔截了靜态資源,根據

/pages/books.html

去 controller 找對應的方法,找不到是以會報 404 的錯誤。

SpringMVC 為什麼會攔截靜态資源呢?

3. SpringMVC Rest 風格1. REST 簡介2. RESTful 入門案例3. RESTful 快速開發4. 基于 RESTful 的頁面資料互動

解決方案:SpringMVC 需要将靜态資源放行。

//設定靜态資源通路過濾,目前類需要設定為配置類,并被掃描加載
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        // 當通路/pages/...的時候,從/pages目錄下查找内容
        registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
        registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
    }
}
           

該配置類在 config 目錄下,SpringMVC 目前掃描的是 controller 包,是以該配置類還未生效,要想生效需要修改 SpringMvcConfig 配置類的掃描範圍。

@Configuration
@ComponentScan({"com.itheima.controller","com.itheima.config"})
@EnableWebMvc//開啟将JSON轉換成對象的功能
public class SpringMvcConfig {
}

//或者

@Configuration
@ComponentScan("com.itheima")
@EnableWebMvc
public class SpringMvcConfig {
}
           

(3) 修改 books.html 頁面

3. SpringMVC Rest 風格1. REST 簡介2. RESTful 入門案例3. RESTful 快速開發4. 基于 RESTful 的頁面資料互動

頁面完整代碼:

<!DOCTYPE html>

<html>
    <head>
        <!-- 頁面meta -->
        <meta charset="utf-8">
        <title>SpringMVC案例</title>
        <!-- 引入樣式 -->
        <link rel="stylesheet" href="../plugins/elementui/index.css">
        <link rel="stylesheet" href="../plugins/font-awesome/css/font-awesome.min.css">
        <link rel="stylesheet" href="../css/style.css">
    </head>

    <body class="hold-transition">

        <div id="app">

            <div class="content-header">
                <h1>圖書管理</h1>
            </div>

            <div class="app-container">
                <div class="box">
                    <div class="filter-container">
                        <el-input placeholder="圖書名稱" style="width: 200px;" class="filter-item"></el-input>
                        <el-button class="dalfBut">查詢</el-button>
                        <el-button type="primary" class="butT" @click="openSave()">建立</el-button>
                    </div>

                    <el-table size="small" current-row-key="id" :data="dataList" stripe highlight-current-row>
                        <el-table-column type="index" align="center" label="序号"></el-table-column>
                        <el-table-column prop="type" label="圖書類别" align="center"></el-table-column>
                        <el-table-column prop="name" label="圖書名稱" align="center"></el-table-column>
                        <el-table-column prop="description" label="描述" align="center"></el-table-column>
                        <el-table-column label="操作" align="center">
                            <template slot-scope="scope">
                                <el-button type="primary" size="mini">編輯</el-button>
                                <el-button size="mini" type="danger">删除</el-button>
                            </template>
                        </el-table-column>
                    </el-table>

                    <div class="pagination-container">
                        <el-pagination
                            class="pagiantion"
                            @current-change="handleCurrentChange"
                            :current-page="pagination.currentPage"
                            :page-size="pagination.pageSize"
                            layout="total, prev, pager, next, jumper"
                            :total="pagination.total">
                        </el-pagination>
                    </div>

                    <!-- 新增标簽彈層 -->
                    <div class="add-form">
                        <el-dialog title="新增圖書" :visible.sync="dialogFormVisible">
                            <el-form ref="dataAddForm" :model="formData" :rules="rules" label-position="right" label-width="100px">
                                <el-row>
                                    <el-col :span="12">
                                        <el-form-item label="圖書類别" prop="type">
                                            <el-input v-model="formData.type"/>
                                        </el-form-item>
                                    </el-col>
                                    <el-col :span="12">
                                        <el-form-item label="圖書名稱" prop="name">
                                            <el-input v-model="formData.name"/>
                                        </el-form-item>
                                    </el-col>
                                </el-row>
                                <el-row>
                                    <el-col :span="24">
                                        <el-form-item label="描述">
                                            <el-input v-model="formData.description" type="textarea"></el-input>
                                        </el-form-item>
                                    </el-col>
                                </el-row>
                            </el-form>
                            <div slot="footer" class="dialog-footer">
                                <el-button @click="dialogFormVisible = false">取消</el-button>
                                <el-button type="primary" @click="saveBook()">确定</el-button>
                            </div>
                        </el-dialog>
                    </div>

                </div>
            </div>
        </div>
    </body>

    <!-- 引入元件庫 -->
    <script src="../js/vue.js"></script>
    <script src="../plugins/elementui/index.js"></script>
    <script type="text/javascript" src="../js/jquery.min.js"></script>
    <script src="../js/axios-0.18.0.js"></script>

    <script>
        var vue = new Vue({

            el: '#app',

            data:{
				dataList: [],//目前頁要展示的分頁清單資料
                formData: {},//表單資料
                dialogFormVisible: false,//增加表單是否可見
                dialogFormVisible4Edit:false,//編輯表單是否可見
                pagination: {},//分頁模型資料,暫時棄用
            },

            //鈎子函數,VUE對象初始化完成後自動執行
            created() {
                this.getAll();
            },

            methods: {
                // 重置表單
                resetForm() {
                    //清空輸入框
                    this.formData = {};
                },

                // 彈出添加視窗
                openSave() {
                    this.dialogFormVisible = true;
                    this.resetForm();
                },

                //添加
                saveBook () {
                    axios.post("/books",this.formData).then((res)=>{

                    });
                },

                //首頁清單查詢
                getAll() {
                    axios.get("/books").then((res)=>{
                        this.dataList = res.data;
                    });
                },

            }
        })
    </script>
</html>
           

繼續閱讀