SpringMvc 從 Body 中獲取資料的介面開發方式
目前網站開發基本上都是採用前後端分離,所以對於 SpringMvc 來說,大部分情況下可能主要是開發介面,接收靜態 html 頁面傳送來的請求資料,將處理後的資料返回給呼叫者。在前面的部落格中,已經介紹過了許多接收請求資料的方式,其實已經夠用了。但是接收請求資料的方式還有很多,而且技術也在不斷的發展演變,因此有必要學習更多的介面開發方式。
本篇部落格主要介紹從請求 body 中接收資料的介面開發方式,後續會介紹 restful 風格介面的開發方式,掌握了這些介面開發方式後,基本上就可以應對企業中的各種開發場景了。本篇部落格的 Demo 做的很簡單,在部落格的最後會提供 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.servlet.support.AbstractDispatcherServletInitializer;
import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
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;
}
//在servlet容器啟動時進行配置
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
//這行程式碼不能省略
super.onStartup(servletContext);
//設定【獲取到的請求】的統一字元編碼過濾器,
//無論是【請求、轉發、包含】統一使用 UTF-8 編碼
CharacterEncodingFilter cef = new CharacterEncodingFilter();
cef.setEncoding("UTF-8");
//注意:這裡的過濾器名稱必須是 characterEncodingFilter
FilterRegistration.Dynamic registration =
servletContext.addFilter("characterEncodingFilter", cef);
registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST,
DispatcherType.FORWARD, DispatcherType.INCLUDE), false, "/*");
}
}
上面這些 SpringMvc 純註解搭建的細節,沒有任何變化,我直接從之前編寫的部落格中抄了一下,估計看過我之前部落格的小夥伴們,已經看吐了。其實 SpringMvc 純註解搭建,本來就很簡單,但是為了保持部落格文章的完整性,我還是得保留這些內容。
三、介面開發介紹
還是首選介紹一下 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 +
'}';
}
}
然後列出從請求的 body 中獲取資料的介面開發方式,內容如下:
package com.jobs.controller;
import com.jobs.domain.Employee;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
//由於介面開發,都是返回資料,不返回頁面,所以直接使用 @RestController 註解
@RequestMapping("/api")
@RestController
public class ApiController {
//這裡主要演示普通的介面開發,主要通過 ajax 請求呼叫這裡的介面
//請求 body 中發過來文字型別的資料
@RequestMapping(value = "/test1", produces = "text/plain")
public String testApi1(@RequestBody String text) {
System.out.println("接收了發來的文字資料:" + text);
return "成功接收到資料:" + text;
}
//請求的 body 中發來的是 Json 資料,
//並且 Json 資料中的欄位名稱與 Java 實體類中的欄位名稱一致
//此時可以採用 Java 實體類接收 Json 資料,SpringMvc 會自動賦值處理
@RequestMapping(value = "/test2", produces = "application/json")
public Employee testApi2(@RequestBody Employee emp) {
System.out.println("接收了發來的單個 Json 物件資料,自動封裝成物件:");
System.out.println(emp);
System.out.println("我們對 emp 進行修改,然後返回給呼叫者,修改後的結果為:");
emp.setName(emp.getName() + "111");
emp.setAge(emp.getAge() + 10);
System.out.println(emp);
return emp;
}
//請求的 body 中發來的是 Json 陣列資料,
//陣列中每個 Json 物件的欄位名稱與 Java 實體類中的欄位名稱一致
//此時可以採用 Java 實體類集合接收,SpringMvc 會自動賦值處理並轉換為集合
@RequestMapping(value = "/test3", produces = "application/json")
public List testApi3(@RequestBody List<Employee> emplist) {
System.out.println("接收了發來的單個 Json 陣列物件資料,自動封裝成物件集合:");
System.out.println(emplist);
System.out.println("我們在 emplist 中增加一個 Employee 物件,然後返回給呼叫者:");
emplist.add(new Employee("喬豆豆", 38));
System.out.println(emplist);
return emplist;
}
//使用 @CrossOrigin 開啟跨域訪問
//如果 @CrossOrigin 標註在方法上,方表示該方法支援跨域訪問
//如果 @CrossOrigin 標註在 Controller 類上,表示該類中的所有方法均支援跨域訪問
@CrossOrigin
@RequestMapping(value = "/testCross", produces = "text/plain")
public String testApi4(@RequestBody String msg) {
System.out.println("跨域訪問成功..." + msg);
return "恭喜你跨域訪問成功,獲取到的資料為:" + msg;
}
}
本篇部落格決定使用靜態 html 頁面,採用 JQuery 請求這些介面進行測試,首先列出靜態頁面的內容:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>演示普通介面的請求和響應</title>
</head>
<body>
<h1>SpringMvc 採用 Ajax 呼叫普通 Api 介面</h1>
<a href="javascript:void(0);" id="test1">SpringMvc傳送普通文字資料</a><br/>
<a href="javascript:void(0);" id="test2">SpringMvc傳送單個物件的Json資料</a><br/>
<a href="javascript:void(0);" id="test3">SpringMvc傳送多個物件的Json資料(Json陣列)</a><br/>
<br/>
<fieldset>
<legend>SpringMvc跨域訪問</legend>
條件準備:<br/>
1.請在本機的 hosts 檔案中配置 www.jobs.com 對應的 ip 地址為 127.0.0.1<br/>
2.在 SpringMvc 的後端介面上,增加 @CrossOrigin 註解<br/>
<a href="javascript:return false;" id="testCross">SpringMvc測試跨域訪問</a><br/>
</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: "post",
url: "/api/test1",
data: "努力學習,天天向上",
dataType: "text",
contentType: "text/plain",
success: function (data) {
alert(data);
}
});
});
$('#test2').click(function () {
$.ajax({
type: "post",
url: "/api/test2",
data: '{"name":"喬豆豆","age":28}',
dataType: "json",
contentType: "application/json",
success: function (data) {
alert("修改後的結果:" + data.name + "," + data.age);
}
});
});
$('#test3').click(function () {
$.ajax({
type: "post",
url: "/api/test3",
data: '[{"name":"任肥肥","age":40},{"name":"侯胖胖","age":42}]',
dataType: "json",
contentType: "application/json",
success: function (data) {
//採用陣列儲存字串,最後以中文逗號拼接在一起
let arr = new Array();
for (let i = 0; i < data.length; i++) {
arr.push(data[i].name + '---' + data[i].age);
}
let result = arr.join(',');
alert(result);
}
});
});
$('#testCross').click(function () {
$.ajax({
type: "post",
url: "http://www.jobs.com:8080/api/testCross",
data: "祝大家事業有成",
dataType: "text",
contentType: "text/plain",
success: function (data) {
alert(data);
}
});
});
})
然後執行網站,在首頁 index.html 靜態頁面中,即可進行介面的測試。
Ok,有關從 body 中獲取請求資料的介面開發方式,已經介紹完畢。這種開發接收的方式比較常用。
本篇部落格的 Demo 原始碼下載地址為:https://files.cnblogs.com/files/blogs/699532/SpringMvc_DataApi.zip