SpringMvc 有關 Restful 接口開發和調用總結


具體什么是 Restful ,可以查詢一下百度百科,簡單的理解就是根據 Http 的請求方式(Get、Post、Put、Delete)來決定處理方式。Restful 的優點主要在於請求地址書寫簡化,隱藏資源的訪問和數據發送細節,對網站有一定的保護作用。

Restful 在實際應用場景中多用於開發接口,大家習慣的約定為: Get 請求用於查詢,Post 請求用於添加,Put 請求用於修改,Delete 請求用於刪除。但是這僅僅是約定而已,並不是必須要遵守的規范,可以隨意打破。比如我個人就是喜歡使用 Post 請求開發所有接口(增刪改查),這也是可以的。

本篇博客主要通過代碼的方式演示 SpringMvc 如何開發 Restful 接口,頁面如何采用 form 表單調用 Restful 接口,頁面如果通過 ajax 請求異步調用 Restful 接口。在本篇博客的最后會提供 Demo 的源代碼下載。


一、搭建工程

新建一個 maven 項目,導入相關 jar 包,我所導入的 jar 包都是最新的,內容如下:

有關具體的 jar 包地址,可以在 https://mvnrepository.com 上進行查詢。

<dependencies>
    <!--導入 servlet 相關的 jar 包-->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.2</version>
        <scope>provided</scope>
    </dependency>

    <!--導入 Spring 核心 jar 包-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.18</version>
    </dependency>
    <!--導入 SpringMvc 的 jar 包-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.18</version>
    </dependency>

    <!--導入 jackson 相關的 jar 包-->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.13.1</version>
    </dependency>
</dependencies>

配置好引用的 jar 包后,打開右側的 Maven 窗口,刷新一下,這樣 Maven 會自動下載所需的 jar 包文件。

搭建好的項目工程整體目錄比較簡單,具體如下圖所示:

image

com.jobs.config 包下存儲的是 SpringMvc 的配置文件和 Servlet 的初始化文件
com.jobs.controller 包下存儲的是用於提供 api 接口的類
com.jobs.domain 包下存儲的是 JavaBean 實體類

web 目錄下放置的是網站文件,只有一個靜態頁面和一些 js 文件


二、SpringMvc 配置相關

com.jobs.config 下的 SpringMvcConfig 類是 SpringMvc 的配置類,具體內容如下:

package com.jobs.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

@Configuration
@ComponentScan("com.jobs")
//啟用 mvc 功能,配置了該注解之后,SpringMvc 攔截器放行相關資源的設置,才會生效
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer {

    //配置 SpringMvc 連接器放行常用資源的格式(圖片,js,css)
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    //配置響應數據格式所對應的數據處理轉換器
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {

        //如果響應的是 application/json ,則使用 jackson 轉換器進行自動處理
        MappingJackson2HttpMessageConverter jsonConverter =
                        new MappingJackson2HttpMessageConverter();
        jsonConverter.setDefaultCharset(Charset.forName("UTF-8"));
        List<MediaType> typelist1 = new ArrayList<>();
        typelist1.add(MediaType.APPLICATION_JSON);
        jsonConverter.setSupportedMediaTypes(typelist1);
        converters.add(jsonConverter);

        //如果響應的是 text/html 和 text/plain ,則使用字符串文本轉換器自動處理
        StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
        stringConverter.setDefaultCharset(Charset.forName("UTF-8"));
        List<MediaType> typelist2 = new ArrayList<>();
        typelist2.add(MediaType.TEXT_HTML);
        typelist2.add(MediaType.TEXT_PLAIN);
        stringConverter.setSupportedMediaTypes(typelist2);
        converters.add(stringConverter);
    }

    //注解配置 SpringMvc 返回配置的字符串所表示的頁面,從哪些去找
    //可以注釋掉下面的方法,這樣需要在 SpringMvc 方法返回時,指定全局路徑的頁面地址
    //這里配置的是:根據 SpringMvc 方法返回的字符串,到 /WEB-INF/pages/ 下找對應名稱的 jsp 頁面
    @Bean
    public InternalResourceViewResolver getViewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/pages/");
        viewResolver.setSuffix(".jsp");
        //如果頁面需要使用JSTL標簽庫的話
        //viewResolver.setViewClass(JstlView.class);
        return viewResolver;
    }
}

ServletInitConfig 類初始化 Servlet 容器,裝載 SpringMvc 的配置,具體如下:

package com.jobs.config;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.filter.HiddenHttpMethodFilter;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;

import javax.servlet.*;
import java.util.EnumSet;

public class ServletInitConfig extends AbstractDispatcherServletInitializer {

    //初始化 Servlet 容器,加載 SpringMvc 配置類
    //創建 web 專用的 Spring 容器對象:WebApplicationContext
    @Override
    protected WebApplicationContext createServletApplicationContext() {
        AnnotationConfigWebApplicationContext cwa = new AnnotationConfigWebApplicationContext();
        cwa.register(SpringMvcConfig.class);
        return cwa;
    }

    //注解配置 SpringMvc 的 DispatcherServlet 攔截地址,攔截所有請求
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    @Override
    protected WebApplicationContext createRootApplicationContext() {
        return null;
    }

    //添加過濾器
    @Override
    protected Filter[] getServletFilters() {
        //采用 utf-8 作為統一請求的編碼
        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
        characterEncodingFilter.setEncoding("UTF-8");

        //該過濾器,能夠讓 web 頁面通過 _method 參數將 Post 請求轉換為 Put、Delete 等請求
        HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
        return new Filter[]{characterEncodingFilter, hiddenHttpMethodFilter};
    }
}

需要注意的是:這里換了一種添加過濾器的方式(重寫了 getServletFilters 方法),在該方法中添加了兩個過濾器(統一請求編碼設置過濾器,以及允許將 Post 請求轉化為 Put、Delete 等請求的過濾器),其中這個過濾器:【允許將 Post 請求轉化為 Put、Delete 等請求】很重要,它是頁面發起 Restful 請求調用接口的基礎條件。


三、接口開發介紹

還是首選介紹一下 domian 下的 Employee 實體類,具體內容如下:

package com.jobs.domain;

import java.io.Serializable;
import java.util.List;

public class Employee implements Serializable {

    //姓名
    private String name;
    //年齡
    private Integer age;

    public Employee() {
    }

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

    //這里省略了相關字段的 get 和 set 方法...

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

下面列出 Restful 接口的開發細節,RestfulController1 和 RestfulController2 開發的 Restful 接口的功能是相同的,只不過采用的注解不一樣。

RestfulController1 采用的是普通的注解,RestfulController2 采用的是簡化注解,具體內容如下:

package com.jobs.controller;

import com.jobs.domain.Employee;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/rest1")
public class RestfulController1 {

    //restful風格的接口,在路徑上可以包含請求參數
    //如果沒有注明接收的請求方式,則表示所有請求方式(Get,Post,Put,Delete)都支持
    //使用 @PathVariable 注解獲取路徑上配置的同名變量
    //produces 表示返回的數據類型
    @RequestMapping(value = "/{test}", produces = "text/plain")
    public String restfulTest1(@PathVariable String test) {
        System.out.println("獲取到參數值為:" + test);
        return "獲取到參數值為:" + test;
    }

    //僅僅支持 Get 請求,模擬通過 id 查詢員工
    //增加上 method = RequestMethod.GET 表示僅僅支持 Get 請求
    @RequestMapping(value = "/emp/{id}", method = RequestMethod.GET)
    public Employee restfulTest2(@PathVariable Integer id) {
        System.out.println("接收到 Get 提交的數據,id為:" + id);
        Employee emp = new Employee("任肥肥", 40);
        return emp;
    }

    //僅僅支持 Post 請求,模擬添加一條員工信息(通過路徑參數獲取數據)
    //增加上 method = RequestMethod.POST 表示僅僅支持 Post 請求
    @RequestMapping(value = "/emp/{name}/{age}", method = RequestMethod.POST)
    public Employee restfulTest3(
            @PathVariable String name,
            @PathVariable Integer age) {
        Employee emp = new Employee(name, age);
        System.out.println("接收到 Post 提交的數據,封裝成對象:" + emp);
        return emp;
    }

    //僅僅支持 Post 請求,模擬添加一條員工信息(通過請求的 body 獲取數據)
    //這次直接 Post 提交過來 json 數據,Json 的字段名稱與 Employee 的字段名稱一致
    @RequestMapping(value = "/emp", method = RequestMethod.POST, produces = "text/plain")
    public String restfulTest4(Employee emp) {
        System.out.println("接收到 Post 提交的數據,封裝成對象:" + emp);
        return "獲取 Json 數據,並封裝成功對象成功";
    }

    //僅僅支持 Put 請求,模擬修改一條員工信息
    @RequestMapping(value = "/emp", method = RequestMethod.PUT)
    public Employee restfulTest5(Employee emp) {
        System.out.println("接收到 Put 提交的數據,封裝成對象:" + emp);
        //修改員工信息並返回
        emp.setName(emp.getName() + "111");
        emp.setAge(emp.getAge() + 10);
        return emp;
    }

    //僅僅支持 Delete 請求,模擬通過 id 刪除一條員工信息
    @RequestMapping(value = "/emp/{id}", method = RequestMethod.DELETE, produces = "text/plain")
    public String restfulTest6(@PathVariable Integer id) {
        System.out.println("接收到 Delete 提交的數據,id為:" + id);
        return "接收到 Delete 提交的數據,id為:" + id;
    }
}
package com.jobs.controller;

import com.jobs.domain.Employee;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/rest2")
public class RestfulController2 {

    //如果沒有注明接收的請求方式,則表示所有請求方式(Get,Post,Put,Delete)都支持
    //Restful 只是一種接口編寫的風格,並不是規范
    //大家習慣於 Get 請求用於查詢,Post 請求用於添加,Put 請求用於修改,Delete 請求用於刪除
    //實際上,你也可以不遵循這樣的規則,比如你可以使用 Post 請求執行查詢功能。
    @RequestMapping(value = "/{test}")
    public String restfulTest1(@PathVariable String test) {
        System.out.println("獲取到參數值為:" + test);
        return "獲取到參數值為:" + test;
    }

    //僅僅支持 Get 請求,模擬通過 id 查詢員工
    //可以使用 @GetMapping 注解,簡化 Get 請求編寫方式
    @GetMapping(value = "/emp/{id}")
    public Employee restfulTest2(@PathVariable Integer id) {
        System.out.println("接收到 Get 提交的數據,id為:" + id);
        Employee emp = new Employee("任肥肥", 40);
        return emp;
    }

    //僅僅支持 Post 請求,模擬添加一條員工信息(通過路徑參數獲取數據)
    //可以使用 @PostMapping 注解,簡化 Post 請求編寫方式
    @PostMapping(value = "/emp/{name}/{age}")
    public Employee restfulTest3(
            @PathVariable String name,
            @PathVariable Integer age) {
        Employee emp = new Employee(name, age);
        System.out.println("接收到 Post 提交的數據,封裝成對象:" + emp);
        return emp;
    }

    //僅僅支持 Post 請求,模擬添加一條員工信息(通過請求的 body 獲取數據)
    //這次直接 Post 提交過來 json 數據,Json 的字段名稱與 Employee 的字段名稱一致
    @PostMapping(value = "/emp")
    public String restfulTest4(Employee emp) {
        System.out.println("接收到 Post 提交的數據,封裝成對象:" + emp);
        return "獲取 Json 數據,並封裝成功對象成功";
    }

    //僅僅支持 Put 請求,模擬修改一條員工信息
    //可以使用 @PutMapping 注解,簡化 Put 請求編寫方式
    @PutMapping(value = "/emp")
    public Employee restfulTest5(Employee emp) {
        System.out.println("接收到 Put 提交的數據,封裝成對象:" + emp);
        //修改員工信息並返回
        emp.setName(emp.getName() + "111");
        emp.setAge(emp.getAge() + 10);
        return emp;
    }

    //僅僅支持 Delete 請求,模擬通過 id 刪除一條員工信息
    //可以使用 @DeleteMapping 注解,簡化 Delete 請求編寫方式
    @DeleteMapping(value = "/emp/{id}")
    public String restfulTest6(@PathVariable Integer id) {
        System.out.println("接收到 Delete 提交的數據,id為:" + id);
        return "接收到 Delete 提交的數據,id為:" + id;
    }
}

編寫靜態 html 頁面,其中 form 表單調用的是 RestfulController1 的接口,超鏈接采用 ajax 請求異步調用 RestfulController2 的接口,具體內容如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Restful接口測試</title>
</head>
<body>
    <h1>這里是 SpringMvc 的 Restful 接口開發測試</h1>
    <fieldset>
        <legend>采用 Form 表單提交發起 Get 請求</legend>
        <form action="/rest1/emp/1" method="get">
            <input type="submit" value="發起 Get 請求"/>
        </form>
    </fieldset>
    <hr/>
    <fieldset>
        <legend>采用 Form 表單提交發起 Post 請求</legend>
        <form action="/rest1/emp/喬豆豆/30" method="post">
            <input type="submit" value="發起 Post 請求"/>
        </form>
    </fieldset>
    <hr/>
    <fieldset>
        <legend>采用 Form 表單提交發起 Post 請求</legend>
        <form action="/rest1/emp" method="post">
            name值:<input type="text" name="name" value="任肥肥"><br/>
            age值:<input type="text" name="age" value="40"><br/>
            <input type="submit" value="發起 Post 請求"/>
        </form>
    </fieldset>
    <hr/>
    <fieldset>
        <legend>采用 Form 表單提交發起 Put 請求</legend>
        <form action="/rest1/emp" method="Post">
            <input type="hidden" name="_method" value="put"/>
            name值:<input type="text" name="name" value="候胖胖"><br/>
            age值:<input type="text" name="age" value="42"><br/>
            <input type="submit" value="發起 Put 請求"/>
        </form>
    </fieldset>
    <hr/>
    <fieldset>
        <legend>采用 Form 表單提交發起 Delete 請求</legend>
        <form action="/rest1/emp/100" method="Post">
            <input type="hidden" name="_method" value="delete"/>
            <input type="submit" value="發起 Delete 請求"/>
        </form>
    </fieldset>
    <hr/>
    <fieldset>
        <legend>使用 Ajax 發送 Restful 請求</legend>
        <a href="javascript:void(0);" id="test1">發送Get請求查詢數據</a><br/>
        <a href="javascript:void(0);" id="test2">發送Post請求添加數據(從路徑上獲取數據)</a><br/>
        <a href="javascript:void(0);" id="test3">發送Post請求添加數據(發送 json 數據)</a><br/>
        <fieldset>
            <legend>Ajax 發送 Put 請求</legend>
            提交數據時,需要參加參數:_method:put
            <a href="javascript:void(0);" id="test4">發送Put請求修改數據(發送 json 數據)</a><br/>
        </fieldset>
        <fieldset>
            <legend>Ajax 發送 Delete 請求</legend>
            提交數據時,需要參加參數:_method:delete
            <a href="javascript:void(0);" id="test5">發送Delete請求刪除數據</a><br/>
        </fieldset>
    </fieldset>
    <script src="./js/jquery-3.6.0.min.js"></script>
    <script src="./js/apitest.js"></script>
</body>
</html>

在該靜態頁面中,引用了 js 目錄中編寫的 apitest.js 文件,具體內容如下:

$(function () {
    $('#test1').click(function () {
        $.ajax({
            type: "get",
            url: "/rest2/emp/100",
            dataType: "json",
            success: function (data) {
                alert("返回的數據:" + data.name + "," + data.age);
            }
        });
    });

    $('#test2').click(function () {
        $.ajax({
            type: "post",
            url: "/rest2/emp/喬豆豆/30",
            //如果沒有指定 dataType ,
            //則服務器會自動根據接口返回的 mime 類型,推斷返回的數據類型
            success: function (data) {
                alert("返回的數據:" + data.name + "," + data.age);
            }
        });
    });

    $('#test3').click(function () {
        $.ajax({
            type: "post",
            url: "/rest2/emp",
            data: {name: "任肥肥", age: 40},
            dataType: "text", //服務器接口返回的是 text 類型的數據
            success: function (data) {
                alert(data);
            }
        });
    });

    $('#test4').click(function () {
        $.ajax({
            type: "post",
            url: "/rest2/emp",
            data: {name: "任肥肥", age: 40, _method: "put"},
            dataType: "json", //服務器接口返回的是 json 類型的數據
            success: function (data) {
                alert("返回的數據:" + data.name + "," + data.age);
            }
        });
    });

    $('#test5').click(function () {
        $.ajax({
            type: "post",
            url: "/rest2/emp/88",
            data: {_method: "delete"},
            dataType: "text", //服務器接口返回的是 text 類型的數據
            success: function (data) {
                alert(data);
            }
        });
    });

})

然后運行網站,在首頁 index.html 靜態頁面中,即可進行接口的測試。也可以采用 Postman 工具進行測試。



到此為止,有關從 SpringMvc 開發和調用 Restful 接口,已經介紹完畢。希望對大家有所幫助。

本篇博客的 Demo 源代碼下載地址為:https://files.cnblogs.com/files/blogs/699532/SpringMvc_Restful.zip




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM