编辑失败后重新显示表单并显示错误消息(PUT)

时间:2012-08-27 22:27:16

标签: html forms rest spring-mvc

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

但我无法让它发挥作用。如果出现错误,我可以让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
 }

我在PersonModel上有JSR-303验证注释,如果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的响应有一个视图名称。

2 个答案:

答案 0 :(得分:0)

您需要在HiddenHttpMethodFilter中添加web.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 Documentation:

  

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

完整参考here

修改

尝试使用<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>

答案 1 :(得分:0)

因此,我的问题的原因是坚持使用HTTP PUT来改变玩家实体(资源)。我坚持这样做是因为我认为这是纯粹的RESTful做事方式:POST用于创建,PUT用于更改。但似乎我和其他人都错了:it's OK to use POST for alteration

我改变了我的控制器:

 @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表单创建和更改来查看,创建和更改播放器实体(资源),并尝试无效创建或更改,从而导致在表单中向用户显示错误消息。

我可以给我的回答标题如何我学会停止担心并热爱POST。