最近在寫JavaEE系列的文章,在寫SpringMVC的REST風格URL的時候出現了一些問題,下面是部分代碼。html
index.jsp頁面代碼:java
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<form action="springmvc/testRest/1" method="post">
<input type="hidden" name="_method" value="PUT">
<input type="submit" value="TestRest PUT">
</form>
<br>
<form action="springmvc/testRest/1" method="post">
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="TestRest DELETE">
</form>
<br>
<form action="springmvc/testRest" method="post">
<input type="submit" value="TestRest POST">
</form>
<br>
<form action="springmvc/testRest/1" method="get">
<input type="submit" value="TestRest GET">
</form>
<br>
</body>
</html>
控制器代碼:web
@RequestMapping("/springmvc")
@Controller
public class RequestMappingTest {
@RequestMapping(value = "/testRest/{id}",method = RequestMethod.PUT)
public String testRestPut(@PathVariable("id") Integer id) {
System.out.println("testRest PUT:" + id);
return "success";
}
@RequestMapping(value = "/testRest/{id}",method = RequestMethod.DELETE)
public String testRestDelete(@PathVariable("id") Integer id) {
System.out.println("testRest DELETE:" + id);
return "success";
}
@RequestMapping(value = "/testRest",method = RequestMethod.POST)
public String testRestPost() {
System.out.println("testRest POST");
return "success";
}
@RequestMapping(value = "/testRest/{id}",method = RequestMethod.GET)
public String testRestGet(@PathVariable("id") Integer id) {
System.out.println("testRest GET:" + id);
return "success";
}
}
項目運行起來:
spring

點GET、POST都沒有問題,但你點DELETE和PUT的時候程序就報錯了,報錯信息以下:

報錯信息提示:jsp只容許GET POST或HEAD。
這個報錯其實很早以前我就遇到了,當時查了一下,總共有四種方式解決:tomcat
tomcat換到7.0以及如下版本微信
在方法上標註@ResponseBodymvc
請求先轉給一個Controller,再返回jsp頁面app
在你的success頁面頭部設置isErrorPage屬性爲truejsp
當時也確實就解決問題了,也沒有深究究竟是爲何,這幾天大概地查了一下,網上寫這個錯誤的人不少,但也只是給出瞭解決方案,並無說到底爲何這樣解決。post
tomcat換到7.0以及如下版本
查閱了不少資料後,我得出一些結論,報錯的信息其實很明顯了,說的是jsp只容許GET、POST或HEAD,而咱們使用了REST風格中的DELETE和PUT,顯然就會報錯了。
那麼爲何把tomcat版本切換到7.0或者7.0如下的版本就不會出現這樣的問題呢?
Tomcat按照JCP規範(JSP2.3版本)的規定,從Tomcat8.x版本開始,再也不支持以HTTP PUT方式訪問JSP頁面,僅支持GET、POST和HEAD方式。
而你在控制器方法中編寫的返回值是一個字符串,SpringMVC會認爲這是一個jsp頁面,因此報錯了。
這就完美地解釋了第一種解決辦法爲何可以起做用,可是切換tomcat版本顯然並很差。
在方法上標註@ResponseBody
剛剛說到SpringMVC會將控制器方法的返回值認爲是一個jsp頁面致使出錯,那麼你就能夠在處理方法上標註@ResponseBody註解,再運行項目試一試:

運行成功,可是返回值顯示到了頁面上。
這就要來了解一下@ResponseBody的做用了:
@ResponseBody註解的做用是將控制器方法的返回值經過適當的轉換器轉換爲指定的格式以後,寫入到Response對象的body區,一般用來返回JSON數據或者是XML數據。
注意:在使用此註解以後不會再走視圖處理器,而是直接將數據寫入到輸入流中,他的效果等同於經過Response對象輸出指定格式的數據。
看到這,你是否是就明白了,你加上這個註解,它就不走視圖處理器,固然也就不會跳轉到jsp頁面了,不跳轉到jsp頁面,固然就不報錯了。
不過這個註解一般是用來返回數據的,若是你確實是要返回數據,這樣寫固然沒有問題,這也是比較規範的一種寫法。
請求先轉給一個Controller,再返回jsp頁面
而若是你僅僅就是想跳轉一個jsp頁面,就能夠用第三種解決方法。
既然不能直接跳轉到jsp頁面,你就能夠將請求先轉給一個控制方法,再經過該控制方法跳轉到jsp頁面。
修改一下控制類的代碼:
@RequestMapping("/springmvc")
@Controller
public class RequestMappingTest {
@RequestMapping("/toSuccess")
public String toSuccess() {
System.out.println("toSuccess");
return "success";
}
@RequestMapping(value = "/testRest/{id}",method = RequestMethod.PUT)
public String testRestPut(@PathVariable("id") Integer id) {
System.out.println("testRest PUT:" + id);
return "redirect:/springmvc/toSuccess";
}
@RequestMapping(value = "/testRest/{id}",method = RequestMethod.DELETE)
public String testRestDelete(@PathVariable("id") Integer id) {
System.out.println("testRest DELETE:" + id);
return "redirect:/springmvc/toSuccess";
}
@RequestMapping(value = "/testRest",method = RequestMethod.POST)
public String testRestPost() {
System.out.println("testRest POST");
return "success";
}
}
......
經過這樣的方式,咱們的DELETE和PUT請求就不會直接地去跳轉jsp頁面,而是先交給了toSuccess控制方法,並由該方法跳轉到jsp頁面。
在你的success頁面頭部設置isErrorPage屬性爲true
至於這種解決方法爲何可以成功,相信大家應該能本身知道了吧?
就是由於DELETE和PUT請求直接跳轉jsp頁面會出錯,當你在待跳轉的jsp頁面中設置isErrorPage屬性爲true後,在跳轉jsp頁面時出錯,而設置了isErrorPage屬性的頁面即爲錯誤頁面,它就這樣顯示出來了。
總結
綜上所述,這四種解決方法其實都是在解決同一個問題,就是jsp不支持DELETE和PUT,咱們要想辦法在這兩種請求的方式下不直接去訪問jsp就好了。
但這些方法總歸是有些違背本身的主觀意願,因此只有當你須要使用DELETE和PUT請求時纔去使用它們,好比經過它們返回一些數據,不然就不要去用它們了,這是畫蛇添足。
老師經常教導咱們,要知其然,還要知其因此然。
本文分享自微信公衆號 - 碼視界(otc_18679428729)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。