0

我正在尝试创建一个 Spring MVC 控制器,该控制器可以Player使用 HTML 表单创建和编辑简单的域对象 (a)。最好以 RESTful 方式。当提交的表单中有错误时,我遇到了编辑问题。我希望客户端(浏览器)显示错误消息和原始表单,以便用户可以更正并重新提交。

但我无法让它发挥作用。出现错误时,我可以让 Web 应用程序重新显示原始表单,但没有错误消息。我认为是因为在这种情况下我的代码会重定向到表单页面。我尝试删除重定向,但随后 Web 服务器抱怨PUT该资源不允许。我需要做什么?

这是我的控制器的相关代码:

 @Controller
 @RequestMapping({
    "/player"
 })
 public class PlayerController {

    @RequestMapping(value = "/{id}/edit", method = RequestMethod.PUT)
    public String editPlayer(@PathVariable("id")
    final long id, @Valid
    @ModelAttribute(Model.PLAYER)
    final PlayerModel player, final BindingResult result) {
       if (!result.hasErrors()) {
          final Player playerEntity = playerService.find(id);
          playerEntity.setName(player.getName());
          playerService.update(playerEntity);
          return "redirect:/player/" + id;
       } else {
          return "redirect:/player/" + id + "/edit";
       }
    }

    @RequestMapping(value = "/{id}/edit", method = RequestMethod.GET)
    public String showEditPlayerPage(@PathVariable("id")
    final long id, final org.springframework.ui.Model model) {
       createModel(id, model);
       return View.EDIT_PLAYER;// the player editing page
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public String showPlayerPage(@PathVariable("id")
    final long id, final org.springframework.ui.Model model) {
       // ...
       return View.PLAYER;// the read-only view of a player
    }

    // Other code
 }

我在 上有 JSR-303 验证注释,如果太短或太长PersonModel会触发验证失败。name编辑表单的 HTML 是这样的:

 <form:form commandName="player" method="PUT">
    <fieldset>
       <table>
          <tr>
             <th><label for="player_name">Player Name:</label></th>
             <td><form:input path="name" size="64" maxlength="64"
                   id="player_name" /> <br /> <small
                id="player_name_msg">Not empty, but no more
                   than 64 characters.</small> <form:errors path="name"
                   class="error" /></td>
          </tr>
       </table>
       <input type="submit" value="Submit"></input>
    </fieldset>
 </form:form>

编辑:

需要明确的是,对于表格有效的情况,一切正常。我有用于将 PUT 转换为 POST 的 servlet 过滤器,它似乎工作正常。


编辑2:

实验和修补表明我的控制器正在执行;PUT 的拒绝发生我的控制器执行后。似乎 Spring 不喜欢对 PUT 的响应使用视图名称。

4

2 回答 2

0

所以,我的问题的一个原因是坚持使用 HTTP PUT 来改变玩家实体(资源)。我坚持这样做是因为我相信这是纯粹的 RESTful 做事方式:POST 用于创建,PUT 用于更改。但似乎我和其他人错了:使用 POST 进行更改是可以的

我因此改变了我的控制器:

 @Controller
 @RequestMapping({
    "/player"
 })
 public class PlayerController {

    @RequestMapping(value = "/{id}", method = RequestMethod.PUT)
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void editPlayer(
       @PathVariable("id") final long id,
       @Valid @ModelAttribute(Model.PLAYER) final PlayerModel player,
       final BindingResult result) {
       // ...
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.CREATED)
    public String editPlayerWithView(
       @PathVariable("id") final long id,
       @Valid @ModelAttribute(Model.PLAYER) final PlayerModel player,
       final BindingResult result) {
       // ...
       if (result.hasErrors()) {
          return View.EDIT_PLAYER;
       } else {
          // ...
          return View.PLAYER;
       }
    }

    @RequestMapping(value = "/{id}/edit", method = RequestMethod.GET)
    public String showEditPlayerPage(
       @PathVariable("id") final long id,
       final org.springframework.ui.Model model) {
       // ...
       return View.EDIT_PLAYER;
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public String showPlayerPage(
       @PathVariable("id") final long id,
       final org.springframework.ui.Model model) {
       // ...
       return View.PLAYER;
    }

我对我的表格做了一个简单的改变:

 <form:form commandName="player" action="/player/${player.id}">
    <!-- ... -->
 </form:form>

现在,我可以查看、创建和更改播放器实体(资源),使用 HTML 表单进行创建和更改,并尝试进行无效创建或更改,从而在表单中向用户显示错误消息。

我可以给我的答案加上副标题,我是如何学会停止担心并喜欢这篇文章的。

于 2012-08-28T21:28:32.900 回答
0

您需要添加HiddenHttpMethodFilterweb.xml的才能进行PUT/DELETE 工作:

<filter>
    <filter-name>httpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>httpMethodFilter</filter-name>
    <servlet-name>your-servlet</servlet-name>
</filter-mapping>

来自 Spring 文档:

... 虽然 HTTP 定义了这四种方法,但 HTML 只支持两种:GET 和 POST。幸运的是,有两种可能的解决方法:您可以使用 JavaScript 执行 PUT 或 DELETE,或者简单地使用 'real' 方法作为附加参数执行 POST(建模为 HTML 表单中的隐藏输入字段)。后一个技巧就是 Spring 的 HiddenHttpMethodFilter 所做的。这个过滤器是一个普通的 Servlet 过滤器,因此它可以与任何 Web 框架(不仅仅是 Spring MVC)结合使用。只需将此过滤器添加到您的 web.xml 中,带有隐藏 _method 参数的 POST 就会转换为相应的 HTTP 方法请求。

完整的参考在这里

编辑:

尝试使用<url-mapping/>标签而不是<servlet-name/>

<filter>
    <filter-name>httpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>httpMethodFilter</filter-name>
    <url-mapping>/*</url-mapping>
</filter-mapping>
于 2012-08-28T06:45:35.090 回答