具體什么是 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 包文件。
搭建好的項目工程整體目錄比較簡單,具體如下圖所示:
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