play framework:在使用数据模型时如何在验证失败时填充表单?

时间:2011-07-21 20:01:59

标签: model-view-controller playframework

我正在构建一些类似CMS的粗略功能(以获得Play Framework的功能)。对于这个测试用例,我构建了2个页面,1个用于列出标签,1个用于创建/编辑/保存标签。

流程如下(routes-file):

#list tags
GET /tags  Application.listTags 

#view/edit existing tag
GET /tag/{<(?!new$)(.+)>name} Application.showTag  

#new tag
GET /tag/new  Application.showTag   

创建/查看/编辑页面显示一个表单,该表单从tagDTO获取它的值。 正常流程没有问题,但是当表单给出验证错误(例如:标签名称必须存在)时,我想再次显示页面,使用编辑的值重新填充表单。

为此(遵循Play框架约定)我可以使用包含这些最后值的'flash'对象,但是表单已经绑定到tagDTO(重定向时为null)而不是'flash'-宾语。

首先是代码: Application.java

.....

public static void showTag(String name) {
    TagDTO tagDTO = TagDTO.buildDTOFromModelOrNew(name);
    render(tagDTO); 
}


/**
 * Save tag and redirect to Show
 * 
 * @param name
 * @param displayname
 * @param isnew
 */
public static void saveTag(
        @Required(message="Name is required") String name,
        String displayname,
        boolean isnew) 
{
    checkAuthenticity();
    if(validation.hasErrors()) {
        params.flash(); 
        validation.keep(); 
        showTag(null);
    }

    //fetch tagDTO based on backend or create new if not exist
    TagDTO tag = TagDTO.buildDTOFromModelOrNew(name);

    // Append / Overwrite values
    tag.displayname = displayname;
    tag.name = name;

    //save result to model
    TagDTO.buildAndSaveModelFromDTO(tag);

    flash.success("Thanks for " + (isnew?"creating":"updating") + " tag " + tag.name);

    //redirect to show
    showTag(tag.name);
} 

和ShowTag.html

    #{extends 'main.html' /}
    #{if flash.success}
        <p class="success">${flash.success}</p>
    #{/if}

    #{ifErrors}
        <p class="errors">Oops...</p>
    #{/ifErrors}

    #{form @Application.saveTag()}
        #{authenticityToken /}
        <p>
            <label for="name">Name: </label>
            <input type="text" name="name" id="name" value="${tagDTO.name}" />
            <span class="error">#{error 'name' /}</span>
        </p>
        <p>
            <label for="displayname">Displayname: </label>
            <input type="text" name="displayname" id="displayname" value="${tagDTO.displayname}" />
            <span class="error">#{error 'displayname' /}</span> 
        </p>
        <p>
            <input type="hidden" name="isnew" value="${tagDTO.isnew}" />
            <input type="submit" value="Submit your comment" />
        </p>
    #{/form}

现在我可以想办法让它发挥作用,但没有一个真正优雅:

  1. 将表单绑定到flash对象(或params-object)并从tagDTO填充flas / params对象

  2. 验证失败时
  3. ,重新获取tagDTO(不再需要DB调用),并使用flash-object中可用的值覆盖tagDTO中的值,将表单绑定到tagDTO。

  4. 喜欢2,但使用某种缓存来快速获取tagDTO(因此不需要db-call)

  5. (/)将tagDTO序列化到会话中的一些通用机制。

  6. 总之,我真的不喜欢他们中的任何一个。 在这种情况下,您认为什么是最佳做法?或者Play Framework中是否有任何我缺少的功能?

2 个答案:

答案 0 :(得分:2)

这是显式渲染调用的便利之处。保留先前提交的表单值并将其返回(如果验证失败),如下所示,

checkAuthenticity();
if(validation.hasErrors()) {
    render("@showTag", name, displayname, isnew);
}

如果您调用了“来自其他操作的操作”,这将避免额外的重定向(如果是播放,则为307!)。

答案 1 :(得分:0)

再次渲染表单并避免重定向是一种解决方案。我认为如果用户按F5就可以了,他会再次收到错误。但我认为您应该创建一个重新加载/取消按钮,这样用户就可以忽略所有信息。

要始终使用正确的URL,您可以在routes.conf中执行以下操作:

GET  /tag/create     TagController.create
POST /tag/create     TagController.insert

闪存解决方案的缺点是您的cookie可能会变得非常大。