Spring Controllers, использующие REST, получают 405 ошибок - PullRequest
1 голос
/ 20 октября 2011

---------------- ОБНОВЛЕНИЕ ----------------

I 'Мы полностью переписали мой вопрос, пытаясь уточнить, что было написано плохо.Я также включил еще больше кода в надежде, что кто-то может предложить некоторую помощь.Мои извинения за запутанные вещи, предоставленные ранее.

В основном моя проблема, кажется, в том, что я не совсем понимаю Spring и REST.Поэтому я надеюсь, что кто-то может прояснить для меня вещи и, возможно, просмотреть мой код и сообщить мне, в частности, почему он не работает.Хотя у меня есть некоторое представление о причине, я не понимаю, почему это так.

У меня есть очень простое приложение Spring.Пользователю отображается страница со списком (из БД) таблицы, состоящей из двух столбцов, заполненных именами пользователей, и логическим значением того, включены они или нет.

@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 и тому подобное.Итак, чтобы начать легко, я решил сделать вышеупомянутый обработчик RESTful.Поэтому я изменил его на:

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

Я также обновил JSP, чтобы ссылка шла на / admin / access / username / access, например: 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. Почти наверняка этого не должно было быть.

Во-вторых, я понял, что RequestMethod для submitModifyAccess должен быть POST (или, возможно,PUT).

Но, как я уже сказал, он все еще работал, поэтому я не слишком беспокоился об этом.

Затем я попытался изменить другую ссылку, ссылку на имя пользователя.При нажатии на эту ссылку пользователь попадает в форму, заполненную данными этого человека.Первоначально это было вызвано просто добавлением имени пользователя к URL с запросом GET для отображения формы.Итак, код был:

@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-адресами, а затем попытался переоценить этот метод, изменив его на:

@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, вы должны получить GET с точно таким же 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, или какие-либо другие комментарии, которые могли бы улучшить мой код, обязательно дайте мне знать.Большое спасибо.

Ответы [ 2 ]

1 голос
/ 20 октября 2011

Сначала основная проблема, ваша ошибка 405. 405 означает «метод не поддерживается», то есть метод HTTP (GET / PUT / POST / etc.) Не поддерживается. Перенаправление на /admin/editUser вернет клиенту (браузеру) 302 с заголовком, указывающим URL перенаправления. Браузер тогда выдаст GET против URL (то есть он сам перенаправит). Из ваших сопоставлений выглядит, что ближайший запрос на сопоставление, который вы можете обработать, - GET /admin/editUser/{username} - но вы перенаправляете на GET /admin/editUser. Я думаю, что это проблема - ваш редирект не соответствует ни одной конечной точке, которую вы объявили.

Примечание. Я предполагаю, что ваш /admin/editUser/username URL в вашем примере действительно должен был быть /admin/editUser/{username}, потому что вам нужно использовать фигурные скобки для @PathVariable.

Также обратите внимание, что редкость перенаправления с GET немного. Вы только что получили что-то, предположительно для возврата клиенту - зачем перенаправлять на что-то другое?

Относительно того, является ли что-то вроде http://localhost:8080/myApp/admin/access/test/true "RESTful", может быть мнение, но я считаю, что это не так. Ресурсом для меня является «доступ» пользователя. Для предоставления доступа я бы, вероятно, сделал PUT /users/{username}/access. Чтобы запретить доступ, я бы, вероятно, сделал DELETE /users/{username}/access. Обратите внимание на единый интерфейс: разные методы HTTP работают с одним и тем же URL.

Если в ваших URL-адресах есть глаголы (например, «modifyUser») или в ваших URL-адресах передаются данные (например, true в access=true или /access/true), вы, вероятно, не придерживаетесь принципов REST.

Наконец, я чувствую, что вы могли бы извлечь пользу из хорошей книги по REST, а не из блогов / статей, найденных в Интернете. Я считаю Отдых на практике лучшим на сегодняшний день.

0 голосов
/ 20 октября 2011

modifyUser против editUser?

Вы написали, что ссылка: http://localhost:8080/myApp/admin/modifyUser но вы сопоставлены с /admin/editUser/{username}

Если проблема не в этом, постарайтесь прояснить свой вопрос - особенно, что является текущей реализацией, а что не работает в настоящее время.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...