REST和SpringMVC映射請求資料
7.REST-優雅的url請求風格
7.1REST基本介紹
REST風格詳細介紹
-
REST:即 Representational State Transfer,表述性狀態傳遞,它結構清晰,同時可以隱藏行為,
-
通過一個url來直觀展示傳統風格與REST風格的區別:
-
傳統風格:
當我們在瀏覽器上訪問一些資源時,可以看到有些網頁的url為http://localhost/students/selectById?id=1(該地址表示查找id為1的students物件)http://localhost/students/saveStudent(該地址表示保存students資訊) -
REST風格:
http://localhosts/student/1http://localhosts/student
通過這兩種風格的對比,我們可以看到REST風格的一部分優點:
(1)可以隱藏資源訪問行為(如隱藏了selectById等),這樣就無法通過地址得知對資源進行了哪種操作
(2)可以明顯的看到其書寫簡化了,不僅書寫簡化了,在開發時代碼也可以簡化,
-
-
HTTP 協議里,四個表示操作方式的動詞:GET,POST,PUT,DELETE,它們分別對應四種基本操作:GET用來獲取資源,POST用來新建資源,PUT用來更新資源,DELETE用來洗掉資源,
-
傳統的url通過引數說明 crud的型別,而rest則是通過 get/post/put/delete 來說明 crud的型別
- REST的核心過濾器
- 當前的瀏覽器只支持 post/get 請求,因此為了得到 put/delete 的請求方式,需要使用 Spring 提供的
HiddenHttpMethodFilter過濾器進行轉換, - HiddenHttpMethodFilter :瀏覽器form表單只支持GET 和 POST請求,而DELETE、PUT 等method并不支持,Spring 添加了一個過濾器,可以將這些請求轉換為標準的http方法,使得支持這四種請求方式,
- 需要特別注意:HiddenHttpMethodFilter 只能對 post請求方式進行轉換
- 這個過濾器需要在web.xml中配置
- 當前的瀏覽器只支持 post/get 請求,因此為了得到 put/delete 的請求方式,需要使用 Spring 提供的
7.2Rest風格的url-完成crud操作
7.2.1需求說明
7.2.2代碼實作
-
修改web.xml添加 HiddenHttpMethodFilter過濾器,它的作用是將post請求轉換為指定的delete或put請求
<!--配置HiddenHttpMethodFilter過濾器 1.它的作用是將以post方式提交的delete請求和put請求進行轉換 2.配置url-pattern為/*,表示所有請求都經過hiddenHttpMethodFilter過濾 --> <filter> <filter-name>hiddenHttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>hiddenHttpMethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> -
在SpringDispatcherServlet-servlet.xml添加兩個常規的配置
<!--加入兩個常規的配置--> <!--支持SpringMVC的高級功能,比如:JSR303校驗,映射動態請求--> <mvc:annotation-driven></mvc:annotation-driven> <!--將SpringMVC不能處理的請求,交給tomcat處理,比如css,js--> <mvc:default-servlet-handler/>注意:mvc:annotion添加的是后綴為mvc的命名空間:
-
創建rest.jsp
Idea中匯入jquery無法生效的解決方法
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>rest</title> <script type="text/javascript" src="https://www.cnblogs.com/liyuelian/p/script/jquery-3.6.0.min.js"></script> <script type="text/javascript"> $(function () { $("#deleteBook").click(function () { //將當前的超鏈接的href的值,賦給hiddenForm表單的action屬性 $("#hiddenForm").attr("action", this.href); $(":hidden").val("DELETE");//給hidden的_method引數賦值為delete $("#hiddenForm").submit();//提交表單 return false;//改變超鏈接行為,不再提交 }) //與上同理,不一樣的是這里原本就是表單post請求 $("#updateBook").click(function () { //帶上目標請求格式,HiddenHttpMethodFilter會自動將post請求轉成你指定的格式 $(":hidden").val("PUT");//給hidden的_method引數賦值為put }) }) </script> </head> <body> <h2>Rest風格的crud操作案例</h2> <hr/> <h3>rest風格的url 查詢書籍[get]</h3> <a href="https://www.cnblogs.com/liyuelian/p/user/book/200">點擊查詢書籍</a> <hr/> <h3>rest風格的url 添加書籍[post]</h3> <form action="user/book" method="post"> name:<input name="bookName" type="text"/><br/> <input type="submit" value="https://www.cnblogs.com/liyuelian/p/添加書籍"/> </form> <hr/> <h3>rest風格的url 洗掉書籍[delete]</h3> <%--說明: 1.在默認情況下,超鏈接是get請求 2.要將get請求轉成SpringMVC可以識別的delete,就要考慮HiddenHttpMethodFilter機制: public static final String DEFAULT_METHOD_PARAM = "_method"; ------------------------------------- private static final List<String> ALLOWED_METHODS = Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(), HttpMethod.DELETE.name(), HttpMethod.PATCH.name())); ------------------------------------- //獲取請求的方式,如果是post方式,就進行處理 if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) { String paramValue = https://www.cnblogs.com/liyuelian/p/request.getParameter(this.methodParam); if (StringUtils.hasLength(paramValue)) { String method = paramValue.toUpperCase(Locale.ENGLISH); if (ALLOWED_METHODS.contains(method)) {//若指定method在ALLOWED_METHODS中存在 //進行包裝,轉換為springmvc可以決議的請求 requestToUse = new HttpMethodRequestWrapper(request, method); } } } -------------------------------------- 3.從上述代碼可以看到,HiddenHttpMethodFilter 過濾器可以對以 Post方式提交的delete,put,patch轉換成springmvc識別的RequestMethod.DElETE,RequestMethod.PUT... 4.但是當前的超鏈接為 get請求,怎么將get請求轉換成 post的請求方式呢? 5.我們可以使用jquery來進行處理,讓用戶點擊超鏈接的時候,走一個表單的請求 --%> -
BookHandle.java
- 下面的代碼中可以看到,許多方法的REST風格匹配的url是一樣的,但是由于它們的請求方式不同,所以匹配到的方法不同,這也是rest風格的優點:不僅簡化了url,而且隱藏了行為,
- 所以實際上SpringMVC的Controller層的url是可以相同的,會另外根據請求方式的不同來匹配方法
package com.li.web.rest; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; /** * @author 李 * @version 1.0 * 用于處理rest風格的請求-crud */ @RequestMapping(value = "https://www.cnblogs.com/user") @Controller public class bookHandler { //查詢[get] @RequestMapping(value = "https://www.cnblogs.com/book/{id}", method = RequestMethod.GET) public String getBook(@PathVariable("id") String id) { System.out.println("查詢書籍 id=" + id); return "success"; } //添加[post] @PostMapping(value = "https://www.cnblogs.com/book") public String addBook(String bookName) {//注意引數名字要和表單提交的引數名稱一致 System.out.println("添加書籍 bookName=" + bookName); return "success"; } //洗掉[delete] @DeleteMapping(value = "https://www.cnblogs.com/book/{id}") public String delBook(@PathVariable("id") String id) { System.out.println("洗掉書籍 id=" + id); //return "success";//這樣寫,回傳會報錯:HTTP Status 405 - JSPs only permit GET POST or HEAD //redirect:/user/success 重定向,會被決議成 /web工程路徑/user/success,然后回傳給瀏覽器決議 return "redirect:/user/success";//重定向到一個沒有指定method的 Handler方法 } //如果請求是 /user/success,就轉發到success.jsp @RequestMapping(value = "https://www.cnblogs.com/success") public String successGeneral() { return "success";//該方法轉發到success.jsp頁面 } @PutMapping(value = "https://www.cnblogs.com/book/{id}") public String updateBook(@PathVariable("id") String id) { System.out.println("修改書籍 id=" + id); return "redirect:/user/success";//同理 } } -
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>操作成功</title> </head> <body> <h1>恭喜,操作成功!</h1> </body> </html> -
測驗,redeployTomcat,訪問:
http://localhost:8080/springmvc/rest.jsp,在分別點擊四種提交方式,前端頁面和后臺輸出如下:

7.3注意事項和使用細節
-
HiddenHttpMethodFilter在將 post請求轉成 delete/put請求時,是按照
_method引數名來讀取的
-
如果web專案是運行在 Tomcat8及以上,會發現被過濾成 DELETE和 PUT請求后,到達控制器Controller時能順利執行,但是回傳(forward)會報HTTP 405 提示:HTTP Status 405 - JSPs only permit GET POST or HEAD,意為JSP只允許GET POST 或 HEAD
(1)解決方式1:使用Tomcat7
(2)解決方式2:將請求轉發(forward)改為重定向(redirect),重定向到一個Handler,由Handler轉發到頁面,
-
頁面測驗時,如果出現點擊修改書籍,仍然走的是洗掉url,可能是瀏覽器快取等原因,換成Chrome即可,如果再不行,使用js修改表單的hidden的_method的值
8.SpringMVC映射請求資料
8.1獲取引數值
在開發中,如何獲取到 http://xxx/url?引數名1=引數值1&引數名2=引數值2 中的引數?
之前的案例中我們知道:提交的url的引數名必須和映射的方法中的形參名保持一致,否則方法獲取的是null,
但是如果url的引數名和方法的形參名不一致,又要獲取該引數,應該解決這個問題呢?
答案是使用 @RequestParam 注解,
應用實體
- request_parameter.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>測驗request_parameter</title>
</head>
<body>
<h2>獲取到超鏈接引數值</h2>
<a href="https://www.cnblogs.com/liyuelian/p/vote/vote01?name=jack">獲取超鏈接的引數</a>
</body>
</html>
- VoteHandler.java:
package com.li.web.requestparam;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @author 李
* @version 1.0
*/
@RequestMapping(value = "https://www.cnblogs.com/vote")
@Controller
public class VoteHandler {
/**
* 1.獲取到超鏈接傳遞的資料
* 請求為 http://localhost:8080/springmvc/vote/vote01?name=xxx
* (即提交的引數名和方法形參名不一致)
* 2.@RequestParam 表示會接收提交的引數
* 3.value = "https://www.cnblogs.com/liyuelian/p/name" 表示提交的引數名是name
* 4.required = false 表示該引數可以沒有(默認true,表示必須有該引數)
* 5.當我們使用了 @RequestParam(value = "https://www.cnblogs.com/liyuelian/p/name", required = false) 后,
* 請求的引數名和方法形參名可以不一致
*
* @param username
* @return
*/
@RequestMapping(value = "https://www.cnblogs.com/vote01")
public String test01(@RequestParam(value = "https://www.cnblogs.com/liyuelian/p/name", required = false) String username) {
System.out.println("獲取到的username=" + username);
return "success";
}
}
-
訪問
http://localhost:8080/springmvc/request_parameter.jsp,點擊超鏈接,
-
后臺輸出如下,說明在提交引數和方法形參名不一致的情況下,通過@RequestParam 注解可以獲取到引數
8.2獲取http請求訊息頭
開發中,如何獲取到http請求的訊息頭資訊(使用較少)
在映射的方法的形參前添加@RequestHeader(value="https://www.cnblogs.com/liyuelian/p/要獲取的Header引數"),即可獲取相關資訊,然后將其值賦給方法的形參,
應用實體
- 在VoteHandler.java
package com.li.web.requestparam;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* @author 李
* @version 1.0
*/
@RequestMapping(value = "https://www.cnblogs.com/vote")
@Controller
public class VoteHandler {
//需求:獲取請求頭的Accept-Encoding和 Host
@RequestMapping(value = "https://www.cnblogs.com/vote02")
public String test02(@RequestHeader("Accept-Encoding") String ae,
@RequestHeader(value = "https://www.cnblogs.com/liyuelian/p/Host") String host) {
System.out.println("Accept-Encoding=" + ae);
System.out.println("Host=" + host);
return "success";
}
}
-
瀏覽器地址欄發送請求
http://localhost:8080/springmvc/vote/vote02,后臺輸出:
8.3獲取Javabean形式的資料
- 在開發中,如何獲取到Javabean的資料?即如何按照java物件的形式來接收資料?
使用場景說明:例如,在實際開發中提交一個表單,表單提交后,希望在后端handler接收到表單資料時,自動地將這些資料封裝到某個Javabean中,
應用實體
- Pet.java
package com.li.entity;
/**
* @author 李
* @version 1.0
* entity
*/
public class Pet {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Pet{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
- Master.java
package com.li.entity;
/**
* @author 李
* @version 1.0
* entity
*/
public class Master {
private Integer id;
private String name;
private Pet pet;//物件的屬性級聯
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Pet getPet() {
return pet;
}
public void setPet(Pet pet) {
this.pet = pet;
}
@Override
public String toString() {
return "Master{" +
"id=" + id +
", name='" + name + '\'' +
", pet=" + pet +
'}';
}
}
- VoteHandler.java
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/543052.html
標籤:Java
