使用 Spring 3 MVC HttpMessageConverter 功能構建 RESTful web 服務
簡介
隨附文章,“使用 Spring 3 構建 RESTful web 服務”(參見 參考資料),介紹了使用
Spring 構建 RESTful web 服務的方式。還解釋瞭如何使用 ContentNegotiatingViewResolver
生成多個具象,這是
RESTful web 服務的一個重要功能。本文還闡述了使用 HttpMessageConverter
生成多個具象的另一種方式,並且本文中的示例展示瞭如何使用 RestTemplate
和 HttpMessageConverter
與服務進行通訊。
Spring MVC 中的 REST 支援
本部分提供了支援 RESTful web 服務的主要 Spring 功能(或註釋)的概述。
-
@Controller
-
使用
@Controller
註釋對將成為 MVC 中控制器的類進行註釋並處理 HTTP 請求。 -
@RequestMapping
-
使用
@RequestMapping
註釋對函式進行註釋,該函式處理某些 HTTP 方法、URI 或 HTTP 頭。此註釋是 Spring REST 支援的關鍵。可以更改method
引數以處理其他 HTTP 方法。例如:
@RequestMapping(method=RequestMethod.GET, value="/emps", headers="Accept=application/xml, application/json")
-
@PathVariable
-
使用
@PathVariable
註釋可將 URI 中的路徑變數作為引數插入。例如:
@RequestMapping(method=RequestMethod.GET, value="/emp/{id}") public ModelAndView getEmployee(@PathVariable String id) { … }
-
其他有用的註釋
-
使用
@RequestParam
將 URL 引數插入方法中。使用
@RequestHeader
將某一 HTTP 頭插入方法中。使用
@RequestBody
將 HTTP 請求正文插入方法中。使用
@ResponseBody
將內容或物件作為 HTTP 響應正文返回。使用
HttpEntity<T>
將它自動插入方法中,如果將它作為引數提供。使用
ResponseEntity<T>
返回具有自定義狀態或頭的 HTTP 響應。例如:
public @ResponseBody Employee getEmployeeBy(@RequestParam("name") String name, @RequestHeader("Accept") String accept, @RequestBody String body) {…} public ResponseEntity<String> method(HttpEntity<String> entity) {…}
參見 Spring 文件(參見 參考資料) 獲得可插入方法中的支援註釋或物件的完整列表。
多具象支援
使用不同 MIME 型別表示同一資源是
RESTful web 服務的一個重要方面。通常,可以使用具有不同 "accept" HTTP 頭的同一 URI 提取具有不同表示的資源。還可以使用不同的 URI 或具有不同請求引數的 URI。
“使用 Spring 3 構建
RESTful web 服務”(參見 參考資料)介紹了
ContentNegotiatingViewResolver
,可以挑選不同的檢視解析器處理同一
URI(具有不同的 accept 頭)。因此,ContentNegotiatingViewResolver
可用於生成多個具象。
還有另一種方式可生成多具象 —
將
HttpMessageConverter
和 c@ResponseBody
註釋結合起來使用。使用這種方法無需使用檢視技術。
HttpMessageConverter
HTTP 請求和響應是基於文字的,意味著瀏覽器和伺服器通過交換原始文字進行通訊。但是,使用
Spring,controller 類中的方法返回純 'String' 型別和域模型(或其他 Java 內建物件)。如何將物件序列化/反序列化為原始文字?這由
HttpMessageConverter
處理。Spring
具有捆綁實現,可滿足常見需求。表 1 顯示了一些示例。
表 1. HttpMessageConverter 示例
使用...... | 您可以...... |
---|---|
StringHttpMessageConverter | 從請求和響應讀取/編寫字串。預設情況下,它支援媒體型別 text/* 並使用文字/無格式內容型別編寫。 |
FormHttpMessageConverter | 從請求和響應讀取/編寫表單資料。預設情況下,它讀取媒體型別 application/x-www-form-urlencoded 並將資料寫入 MultiValueMap<String,String>。 |
MarshallingHttpMessageConverter | 使用 Spring 的 marshaller/un-marshaller 讀取/編寫 XML 資料。它轉換媒體型別為 application/xml 的資料。 |
MappingJacksonHttpMessageConverter |
使用 Jackson 的 ObjectMapper 讀取/編寫
JSON 資料。它轉換媒體型別為 application/json 的資料。 |
AtomFeedHttpMessageConverter | 使用 ROME 的 Feed API 讀取/編寫 ATOM 源。它轉換媒體型別為 application/atom+xml 的資料。 |
RssChannelHttpMessageConverter | 使用 ROME 的 feed API 讀取/編寫 RSS 源。它轉換媒體型別為 application/rss+xml 的資料。 |
構建 RESTful web 服務
在此部分中,學習構建可生成多個具象的簡單
RESTful web 服務。示例應用程式中使用的一些資源在 “使用 Spring 3 構建 RESTful web 服務”(參見 參考資料)中構建。還可以 下載 示例程式碼。
首先,您必須配置
HttpMessageConverter
。要生成多個具象,自定義幾個 HttpMessageConverter
例項,以將物件轉換為不同的媒體型別。此部分包括
JSON、ATOM 和 XML 媒體型別。
JSON
從最簡單的示例開始。JSON 是一個輕量型的資料交換格式,人們可輕鬆地進行讀取和編寫。清單
1 顯示了配置 JSON converter 的程式碼。
清單 1. 配置 rest-servlet.xml 中的 HttpMessageConverter
<bean class="org.springframework.web.servlet.mvc.annotation
.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonConverter" />
<ref bean="marshallingConverter" />
<ref bean="atomConverter" />
</list>
</property>
</bean>
<bean id="jsonConverter"
class="org.springframework.http.converter.json
.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes" value="application/json" />
</bean>
在配置中,註冊了 3 個轉換程式。
MappingJacksonHttpMessageConverter
用於將物件轉換為
JSON,反之亦然。此內建轉換程式使用 Jackson 的 ObjectMapper
將
JSON 對映到 JavaBean,因此您必須將下列 Jackson JAR 檔案新增到類路徑。
-
org.codehaus.jackson.jar
-
org.codehaus.jackson.mapper.jar
下一步是編寫一個方法,處理請求
JSON 具象的請求。清單 2 顯示了詳細資訊。
清單 2. 處理在 EmployeeController 中定義的 JSON 請求
@RequestMapping(method=RequestMethod.GET, value="/emp/{id}",
headers="Accept=application/json")
public @ResponseBody Employee getEmp(@PathVariable String id) {
Employee e = employeeDS.get(Long.parseLong(id));
return e;
}
@RequestMapping(method=RequestMethod.GET, value="/emps",
headers="Accept=application/json")
public @ResponseBody EmployeeListinggetAllEmp() {
List<Employee> employees = employeeDS.getAll();
EmployeeListinglist = new EmployeeList(employees);
return list;
}
@ResponseBody
註釋用於將返回物件(Employee
或 EmployeeList
)變為響應的正文內容,將使用 MappingJacksonHttpMessageConverter
將其對映到
JSON。
使用
HttpMessageConverter
和 @ResponseBody
,您可以實現多個具象,而無需包含
Spring 的檢視技術 — 這是使用ContentNegotiatingViewResolver
所不具有的一個優勢。
現在您可以使用 CURL 或 REST
Client Firefox 外掛呼叫請求。記住新增一個 HTTP 頭:
Accept=application/json
。清單
3 以 JSON 格式顯示了所需的響應。
清單 3. getEmp() 和 getAllEmp() 的 JSON 結果
Response for /rest/service/emp/1
{"id":1,"name":"Huang Yi Ming","email":"huangyim@cn.ibm.com"}
Response for /rest/service/emps
{"count":2,
"employees":[
{"id":1,"name":"Huang Yi Ming","email":"huangyim@cn.ibm.com"},
{"id":2,"name":"Wu Dong Fei","email":"wudongf@cn.ibm.com"}
]}
XML
Spring 的內建轉換程式
MarshallingHttpMessageConverter
用於在物件和
XML (OXM) 之間進行對映。本示例使用 JAXB 2 作為轉換程式的 marshaller/un-marshaller。清單 4 顯示了配置。
清單 4. 配置 MarshallingHttpMessageConverter
<bean id="marshallingConverter"
class="org.springframework.http.converter.xml
.MarshallingHttpMessageConverter">
<constructor-arg ref="jaxbMarshaller" />
<property name="supportedMediaTypes" value="application/xml"/>
</bean>
<bean id="jaxbMarshaller"
class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>dw.spring3.rest.bean.Employee</value>
<value>dw.spring3.rest.bean.EmployeeList</value>
</list>
</property>
</bean>
瞭解 JAXB 2 不能很好地支援
java.util.List<T> 到 XML 的對映很重要。常用實踐是為物件集新增一個包裝類。參見 “使用 Spring 3 構建 RESTful web 服務”(參見 參考資料)或 下載 原始碼,瞭解此
JAXB 註釋類的詳細資訊。
在處理請求的控制器中的方法如何?回顧一下 清單
2 中的程式碼。發現在此處不需要新增任何程式碼一點也不奇怪。您只需要在
Accept
頭中新增另一個支援的媒體型別,如下所示。
headers=”Accept=application/json, application/xml”
轉換程式將物件正確地對映到請求的型別(JSON
或 XML)。清單 5 顯示了請求 application/xml 具象的理想結果。
清單 5. getEmp() 和 getAllEmp() 的 XML 結果
Response for /rest/service/emp/1
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee>
<email>huangyim@cn.ibm.com</email>
<id>1</id>
<name>Huang Yi Ming</name>
</employee>
Response for /rest/service/emps
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employees>
<count>2</count>
<employee>
<email>huangyim@cn.ibm.com</email>
<id>1</id>
<name>Huang Yi Ming</name>
</employee>
<employee>
<email>wudongf@cn.ibm.com</email>
<id>2</id><name>Wu Dong Fei</name>
</employee>
</employees>
ATOM 源
ATOM 源是另一種在 RESTful
web 服務中交換資料的常見格式。Atom 源文件是 Atom 源(包括有關源及與其相關的所有或部分項的後設資料)的具象。其根是
atom:feed
元素。還有一個
ATOM Publish Protocol (APP) 定義交換格式和行為。(定義 ATOM 和 APP 格式不在本文的討論範圍內。參見 參考資料 瞭解更多資訊。)
本示例使用
AtomFeedHttpMessageConverter
轉換
ATOM 源,利用 ROME ATOM API。因此,您必須在類路徑中包含 JAR 檔案 sun.syndication.jar。清單 6 顯示了此轉換程式的配置。
清單 6. 配置 AtomFeedHttpMessageConverter
<bean id="atomConverter"
class="org.springframework.http.converter.feed
.AtomFeedHttpMessageConverter">
<property name="supportedMediaTypes" value="application/atom+xml" />
</bean>
清單 7 顯示了處理 ATOM
請求和源生成的程式碼。
清單 7. EmployeeController & AtomUtil 類中的 getEmpFeed()
@RequestMapping(method=RequestMethod.GET, value="/emps",
headers="Accept=application/atom+xml")
public @ResponseBody Feed getEmpFeed() {
List<Employee> employees = employeeDS.getAll();
return AtomUtil.employeeFeed(employees, jaxb2Mashaller);
}
public static Feed employeeFeed(
List<Employee> employees, Jaxb2Marshaller marshaller) {
Feed feed = new Feed();
feed.setFeedType("atom_1.0");
feed.setTitle("Employee Atom Feed");
List<Entry> entries = new ArrayList<Entry>();
for(Employee e : employees) {
StreamResult result = new StreamResult(
new ByteArrayOutputStream());
marshaller.marshal(e, result);
String xml = result.getOutputStream().toString();
Entry entry = new Entry();
entry.setId(Long.valueOf(e.getId()).toString());
entry.setTitle(e.getName());
Content content = new Content();
content.setType(Content.XML);
content.setValue(xml);
List<Content> contents = new ArrayList<Content>();
contents.add(content);
entry.setContents(contents);
entries.add(entry);
}
feed.setEntries(entries);
return feed;
}
在上述程式碼中,注意:
-
getEmpFeed()
方法將同一 URI 處理為getAllEmp()
,但具有不同的Accept
頭。 -
使用
employeeFeed()
方法,您可以將Employee
物件解析為 XML,然後將其新增到源項的<content>
元素。
清單 8 顯示了請求 URI /rest/service/emps
的 application/atom+xml 具象時的輸出。
清單 8. 請求 application/atom+xml 時的 /rest/service/emps
輸出
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Employee Atom Feed</title>
<entry>
<title>Huang Yi Ming</title>
<id>1</id>
<content type="xml">
<employee>
<email>huangyim@cn.ibm.com</email>
<id>1</id>
<name>Huang Yi Ming</name>
</employee>
</content>
</entry>
<entry>
<title>Wu Dong Fei</title>
<id>2</id>
<content type="xml">
<employee>
<email>wudongf@cn.ibm.com</email>
<id>2</id>
<name>Wu Dong Fei</name>
</employee>
</content>
</entry>
</feed>
實現 POST、PUT 和 DELETE
目前為止,示例已實現了幾個處理
HTTP
GET
方法的方法。清單 9 顯示了 POST
、PUT
和 DELETE
方法的實現。
清單 9. EmployeeController 中的 POST、PUT 和 DELETE
方法
@RequestMapping(method=RequestMethod.POST, value="/emp")
public @ResponseBody Employee addEmp(@RequestBody Employee e) {
employeeDS.add(e);
return e;
}
@RequestMapping(method=RequestMethod.PUT, value="/emp/{id}")
public @ResponseBody Employee updateEmp(
@RequestBody Employee e, @PathVariable String id) {
employeeDS.update(e);
return e;
}
@RequestMapping(method=RequestMethod.DELETE, value="/emp/{id}")
public @ResponseBody void removeEmp(@PathVariable String id) {
employeeDS.remove(Long.parseLong(id));
}
@RequestBody
註釋在 addEmp()
和 updateEmp()
方法中使用。它接收
HTTP 請求正文並試圖使用註冊的 HttpMessageConverter
將其轉換為物件類。在下一部分中,您將使用 RestTemplate
與這些服務進行通訊。
使用 RestTemplate 與 REST 服務進行通訊
“使用 Spring 3 構建
RESTful web 服務”(參見 參考資料)介紹瞭如何使用
CURL 和 REST 客戶端測試 REST 服務。從程式設計水平上講,Jakarta Commons HttpClient 通常用於完成此測試(但這不在本文的討論範圍中)。您還可以使用名為
RestTemplate
的
Spring REST 客戶端。從概念上講,它與 Spring 中的其他模板類相似,比如 JdbcTemplate
和 JmsTemplate
。
RestTemplate
還使用 HttpMessageConverter
。您可以將物件類傳入請求並使轉換程式處理對映。
配置 RestTemplate
清單 10 顯示了
RestTemplate
的配置。它還使用之前介紹的
3 個轉換程式。
清單 10. 配置 RestTemplate
<bean id="restTemplate"
class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<ref bean="marshallingConverter" />
<ref bean="atomConverter" />
<ref bean="jsonConverter" />
</list>
</property>
</bean>
本文中的示例僅使用了一些可簡化伺服器之間通訊的方法。
RestTemplate
支援其他方法,包括:
-
exchange
:使用請求正文執行一些 HTTP 方法並獲得響應。 -
getForObject
:執行 HTTPGET
方法並將響應作為物件獲得。 -
postForObject
:使用特定請求正文執行 HTTPPOST
方法。 -
put
:使用特定請求正文執行 HTTPPUT
方法。 -
delete
:執行 HTTPDELETE
方法以獲得特定 URI。
程式碼示例
下列程式碼示例幫助闡述如何使用
RestTemplate
。參見
RestTemplate API(參見 參考資料)獲得使用的
API 的詳細說明。
清單 11 顯示如何將頭新增到請求中,然後呼叫請求。使用
MarshallingHttpMessageConverter
您可以獲得響應並將其轉換為型別類。可以使用不同的媒體型別測試其他具象。
清單 11. XML 具象請求
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
HttpEntity<String> entity = new HttpEntity<String>(headers);
ResponseEntity<EmployeeList> response = restTemplate.exchange(
"http://localhost:8080/rest/service/emps",
HttpMethod.GET, entity, EmployeeList.class);
EmployeeListingemployees = response.getBody();
// handle the employees
清單 12 顯示瞭如何將新員工釋出到伺服器。伺服器端服務
addEmp()
可接受媒體型別為
application/xml 和 application/json 的資料。
清單 12. 釋出新員工
Employee newEmp = new Employee(99, "guest", "guest@ibm.com");
HttpEntity<Employee> entity = new HttpEntity<Employee>(newEmp);
ResponseEntity<Employee> response = restTemplate.postForEntity(
"http://localhost:8080/rest/service/emp", entity, Employee.class);
Employee e = response.getBody();
// handle the employee
清單 13 顯示瞭如何 PUT
修改的員工以更新舊員工。它還顯示了可用作請求 URI 佔位符(
{id}
)的功能。
清單 13. PUT 以更新員工
Employee newEmp = new Employee(99, "guest99", "guest99@ibm.com");
HttpEntity<Employee> entity = new HttpEntity<Employee>(newEmp);
restTemplate.put(
"http://localhost:8080/rest/service/emp/{id}", entity, "99");
清單 14 顯示瞭如何 DELETE
現有員工。
清單 14. DELETE 現有員工
restTemplate.delete(
"http://localhost:8080/rest/service/emp/{id}", "99");
結束語
在本篇文章中,您學習了 Spring
3 中引入的
HttpMessageConverter
。它提供了對多具象的客戶端和伺服器端支援。使用提供的 原始碼,您可以探索本文中的 HttpMessageConverter
實現和使用
“使用 Spring 3 構建 RESTful web 服務” 中的ContentNegotiatingViewResolver
實現之間的差異。
轉載:http://www.ibm.com/developerworks/cn/web/wa-restful/
相關文章
- spring boot構建restful服務Spring BootREST
- 使用Java和Spring MVC構建Web應用JavaSpringMVCWeb
- Yii2.0 RESTful Web服務(3)RESTWeb
- 使用Docker實現Spring Boot Restful Web服務案例原始碼DockerSpring BootRESTWeb原始碼
- Spring MVC 中 HttpMessageConverter 轉換器SpringMVCHTTP
- Spring系列(六) Spring Web MVC 應用構建分析SpringWebMVC
- 搭建 Restful Web 服務RESTWeb
- 使用Spring Boot 2.0快速構建服務元件Spring Boot元件
- 使用 .NET Core 3.x 構建 RESTFUL ApiRESTAPI
- Spring MVC 中使用 RESTFul 程式設計風格SpringMVCREST程式設計
- 第19章 建立RESTful Web服務RESTWeb
- yii2 restful web服務路由RESTWeb路由
- Yii2.0 RESTful Web服務(4)RESTWeb
- 使用 .NET Core 3.x 構建 RESTFUL Api (續)RESTAPI
- Spring Cloud構建微服務架構-spring cloud服務監控中心SpringCloud微服務架構
- 用 GIN 構建一個 WEB 服務Web
- 使用Spring Boot和GraphQL構建靈活的API服務Spring BootAPI
- 精盡Spring MVC原始碼分析 - HandlerAdapter 元件(五)之 HttpMessageConverterSpringMVC原始碼APT元件HTTP
- Spring Boot中使用Swagger2構建RESTful APIs介紹Spring BootSwaggerRESTAPI
- 使用 Go-Spring 構建最小 Web APIGoSpringWebAPI
- RESTful API開發實戰 使用REST JSON XML和JAX-RS構建微服務 大資料和Web服務應用RESTAPIJSONXML微服務大資料Web
- Spring Cloud構建微服務架構-服務閘道器SpringCloud微服務架構
- Spring Cloud構建微服務架構-Hystrix服務降級SpringCloud微服務架構
- 教你 10 分鐘構建一套 RESTful API 服務 ( 上 )RESTAPI
- 使用Spring Boot RESTful Web流式資料 | TechshardSpring BootRESTWeb
- yii2 restful web服務[格式響應]RESTWeb
- yii2 restful web服務快速入門RESTWeb
- Spring MVC之基於java config無xml配置的web應用構建SpringMVCJavaXMLWeb
- 使用 Cloudflare 構建 Web3 應用CloudWeb
- 使用Swashbuckle構建RESTful風格文件REST
- 使用Golang和MongoDB構建 RESTful APIGolangMongoDBRESTAPI
- Spring Security專案Spring MVC開發RESTful API(二)SpringMVCRESTAPI
- 深入淺出Spring Web MVC:從零開始構建你的第一個Web應用SpringWebMVC
- 如何使用RestTemplate訪問restful服務REST
- 基於 Spring Boot 2.0 構建一個 RESTful WebServiceSpring BootRESTWeb
- 使用SpringBoot構建REST服務-什麼是REST服務Spring BootREST
- Spring Cloud構建微服務架構—服務閘道器過濾器SpringCloud微服務架構過濾器
- Spring Cloud雲服務架構 - 雲架構程式碼結構構建SpringCloud架構
- Spring Cloud雲服務架構 - 企業分散式微服務雲架構構建SpringCloud架構分散式微服務