2011-10-20 149 views
1

---------------- UPDATE ----------------春季控制器獲得405錯誤

我我已經完全重寫了我的問題,試圖澄清顯然寫得不好的問題。我還包含了更多的代碼,希望有人能夠提供一些幫助。我很抱歉前面提供的令人困惑的東西。

基本上我的問題似乎是我並沒有完全理解Spring和REST。所以我希望有人可以爲我澄清一些事情,也許看看我的代碼,並特別告訴我爲什麼它不起作用。雖然我有一些關於原因的想法,但我不明白爲什麼它是這樣。

我有一個非常基本的Spring應用程序。用戶顯示一個頁面,該頁面列出(從數據庫)一個表格,該表格由填充了usernams的兩列以及是否已啓用的布爾值組成。

@RequestMapping(value="/admin/modifyUser", method=RequestMethod.GET) 
public void showModifyUser() {} 

單擊已啓用列中的鏈接只需切換其狀態。該鏈接是通過將用戶發送到/ admin/access並附加用戶名和訪問變量來創建的。所以,一個例子是http://localhost:8080/myApp/admin/access?username=test&access=true(或者任何確切的語法)。該代碼是:

@RequestMapping(value="/admin/access",method=RequestMethod.GET) 
public String submitModifyAccess(@RequestParam("username")String username, 
           @RequestParam("access")String access) { 
    .... 
    return "redirect:/admin/modifyUser"; 
} 

工作正常。它將更新用戶的訪問權限,並返回包含表格和用戶數據的頁面。 (也許不是實現它的最佳方式?)稍後,我想在Dojo網格中填充數據,因此需要將數據放入JSON格式。因此,我在我的關於REST等的Spring書中讀到過。所以,從容易開始,我決定讓上面的Handler RESTful。所以,我把它改爲:

@RequestMapping(value="/admin/access/{username}/{access}",method=RequestMethod.GET) 
public String submitModifyAccess(@PathVariable String username, 
           @PathVariable String access) { 
    .... 
    return "redirect:/admin/modifyUser"; 
} 

我也更新了JSP,使鏈接到/管理/訪問/用戶名/訪問,因此,例如:http://localhost:8080/myApp/admin/access/test/true。瞧,事情仍然有效。我認爲我已經使它成爲RESTful。雖然有幾件事讓我覺得很奇怪。

首先,當點擊鏈接時,它確實正確地更新了狀態,但是當返回到/ admin/modifyUser頁面(這是它發送給你的頁面)時,這兩個變量將被追加到URL中。所以不是顯示http://localhost:8080/myApp/admin/modifyUser,而是顯示http://localhost:8080/myApp/admin/modifyUser?username=test&access=true。很確定這不應該發生。

其次,我意識到submitModifyAccess的RequestMethod應該是POST(或者也許是PUT)。

但正如我所說,它仍然有效,所以我並不擔心它太多。

接下來我試圖修改其他鏈接,即用戶名鏈接。當點擊該鏈接時,用戶將被帶到填有該人數據的表單中。最初只是通過GET請求將用戶名附加到URL來顯示錶單。所以代碼是:

@RequestMapping(value="/admin/editUser", method=RequestMethod.GET) 
public void showEditUser(Model model, @RequestParam("username") String username) { 
    NFIUser user = userService.getUser(username); 
    UserDetails userDetails = userDetailsManager.loadUserByUsername(username); 

    .... 
    model.addAttribute("user", user); 
} 

工作正常。所以,我更新了JSP這樣的用戶名鏈接調用正確的URL,然後我試圖將其更改爲到的RESTify這個方法:

@RequestMapping(value="/admin/editUser/{username}", method=RequestMethod.GET) 
public String showEditUser(Model model, @PathVariable String username) { 
    NFIUser user = userService.getUser(username); 
    UserDetails userDetails = userDetailsManager.loadUserByUsername(username); 

    .... 
    model.addAttribute("user", user); 
    return "redirect:/admin/editUser"; 
} 

一旦這樣做,我開始看到405錯誤,我現在意識到我清楚不理解的東西。首先,我相信爲了做一個REST PUT或POST,你必須有一個完全相同的URL。那是對的嗎?人們認爲我應該在這種情況下做什麼?

哦,萬一有人需要它,形式我是派人到如下(雖然它不是有朝一日能加載時的鏈接用戶點擊他們得到405錯誤):

<div align="center"> 
<b>If you change the Username you MUST change the password as well.</b> 
<s:url value="/admin/editUser" var="edit_url" /> 
<sf:form method="POST" modelAttribute="user" dojoType="dijit.form.Form" action="${edit_url}"> 
<script type="dojo/method" event="onSubmit"> 
    if (!this.validate()) { 
     return false; 
    } 
    return true; 
</script> 
<sf:hidden path="username"/> 
<table> 
<tr> 
<td align="right">Username: </td> 
<td> 
    <sf:input path="newUsername" dojoType="dijit.form.ValidationTextBox" trim="true" required="true" value="${user.username}"/> 
</td> 
</tr> 
<tr> 
<td align="right">Password: </td> 
<td> 
    <sf:input path="password" type="password" dojoType="dijit.form.ValidationTextBox" required="true"/> 
</td> 
</tr> 
<tr> 
<td align="right">Enabled: </td> 
<td> 
    Yes<sf:radiobutton path="enabled" value="true" dojoType="dijit.form.RadioButton"/> 
    No<sf:radiobutton path="enabled" value="false" dojoType="dijit.form.RadioButton"/> 
</td> 
</tr> 
<tr> 
<td align="right">Admin: </td> 
<td> 
    Yes<sf:radiobutton path="isAdmin" value="true" dojoType="dijit.form.RadioButton"/> 
    No<sf:radiobutton path="isAdmin" value="false" dojoType="dijit.form.RadioButton"/> 
</td> 
</tr> 
<tr> 
<td align="right" colspan="2"> 
    <button dojoType="dijit.form.Button" type="submit">Submit</button> 
</td> 
</tr> 
</table> 
</sf:form> 
</div> 

所以希望這會讓事情更加清晰。再說一遍,如果你對我做錯了什麼有所瞭解,如果你可以解釋我明顯沒有得到的關於REST的信息,或者任何其他可以改進我的代碼的評論,請通知我。非常感謝你。

+1

您是否更新了您的(JSP/Velocity模板/通用視圖技術)以反映鏈接的新路徑? –

+0

是的,我確保更新所有鏈接以調用/ admin/editUser/username的新路徑。 – cardician

+1

你可以發表你的表格嗎? –

回答

1

首先是主要問題,您的405錯誤。 405表示「方法不支持」,即不支持HTTP方法(GET/PUT/POST /等)。您重定向到/admin/editUser將返回一個302到客戶端(瀏覽器),並帶有指示重定向URL的標頭。瀏覽器然後將針對該URL發出GET(即,它將自己重定向)。從您的映射看來,您可以處理的最接近的匹配請求是GET /admin/editUser/{username} - 但您將重定向到GET /admin/editUser。我的猜測是這個問題 - 你的重定向與你聲明的任何端點不匹配。

注意我假設您的示例中的/admin/editUser/username網址應該確實爲/admin/editUser/{username},因爲您需要使用大括號@PathVariable的大括號。

另請注意,從GET重定向有點不常見。你剛剛得到了一些東西,大概是爲了回到客戶端 - 爲什麼重定向到其他東西?

關於http://localhost:8080/myApp/admin/access/test/true是否是「RESTful」可能是一個意見,但我的意見是,它不是。對我來說資源是用戶的「訪問」。要授予訪問權限,我可能會執行PUT /users/{username}/access。要拒絕訪問,我可能會做一個DELETE /users/{username}/access。注意統一接口:在同一個URL上運行不同的HTTP方法。

如果你在你的網址(如「modifyUser」)動詞或在網址中傳遞數據(例如,在access=truetrue/access/true)你可能不遵守REST原則。

最後,我覺得你可以從一本關於REST的好書中獲益,而不是我猜測你正在使用的是在線發現的博客/文章。我發現Rest in Practice是迄今爲止最好的。

+0

非常感謝您的回覆。當我稍後查看時應該會有所幫助。此外,我的意思是它是{用戶名}(它在代碼中)。最後,我同意其中一些方法不應該是GETS,我自己也很困惑,但擔心改變它們會讓事情變得糟糕。我列出的第二種方法通常是按照我一直在寫東西的方式進行POST,但是我最初錯過了它並使其成爲GET。然後,在RESTifying該方法後,我嘗試將其更改爲PUT,但出現錯誤。看起來可能是因爲我缺少/ admin/editUser句柄 – cardician

+0

另外,你說的對,我可能會從書中受益。感謝您的建議。我一直在使用的這本書實際上是Spring in Action 3,雖然它不錯,但我不得不說它留下了大量可能有用的信息。因此,爲什麼我很清楚地使用REST不當和不恰當。 – cardician

0

modifyUser vs. editUser

你寫的鏈接是: http://localhost:8080/myApp/admin/modifyUser 但你映射到 /admin/editUser/{username}

如果這不是問題,那麼儘量讓你的問題更清楚一點 - 尤其是什麼是當前實現什麼目前不工作。

+0

我認爲'modifyUser'是用戶的表格,'editUser'是編輯用戶的表單。 –

+0

這是正確的。如果可以的話,讓我試着再澄清一點。 – cardician