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 包檔案。
搭建好的專案工程整體目錄比較簡單,具體如下圖所示:
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
//讓 SpringMvc 僅僅掃描載入配置了 @Controller 註解的類
@ComponentScan(value = "com.jobs",
includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION,
classes = {Controller.class}))
//啟用 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