[翻译]Play框架1.2.7版本教程(9) - 自定义编辑区域

自定义编辑区域

在前一章,我们给yabe创建了一个关于面板,并准备了“我的文章”的部分。每个作者可以在这个部分看到他们发布过的文章,以及进行编辑或者创建新的文章。

我们可以重用CRUD模块来实现这部分。但是这里我们打算从头开始,因为我们需要许多自定义的设置。

从文章列表开始

我们仅需要查询用户相关的文章并显示出来。这很简单。从改进Admin.index action开始吧:

public static void index() {
    String user = Security.connected();
    List<Post> posts = Post.find("author.email", user).fetch();
    render(posts);
}

并完成yabe/app/views/Admin/index.html:

#{extends 'admin.html' /}

<h3>Welcome ${user}, <span>you have written ${posts.size() ?: 'no'} 
${posts.pluralize('post', 'posts')} so far</span></h3>

#{list items:posts, as:'post'}
    <p class="post ${post_parity}">
        <a href="#">${post.title}</a>
    </p>
#{/list}

<p id="newPost" >
    <a href="#"><span>+</span> write a new post</a>
</p>

看看第一步的成果:

first

发布文章界面

我们将创建一个用于发布文章的界面。一般对于一个表单,你可以做两件事:显示它,处理它提交的结果。让我们创建Admin.form'和Admin.save`来帮助显示和处理提交结果。

添加新的路由到yabe/conf/routes:

GET     /admin/new                          Admin.form
POST    /admin/new                          Admin.save

接着给Admin.java控制器添加form()save()

public static void form() {
    render();
}

public static void save() {
    // Not implemented yet
}

然后是创建yabe/app/views/Admin/form.html模板:

#{extends 'admin.html' /}

<h3>Write, <span>a new post</span></h3>

#{form @save()}

    #{ifErrors}
        <p class="error">
            Please correct these errors.
        </p>
    #{/ifErrors}

    <p>
        #{field 'title'}
        <label>Post title:</label>
        <input type="text" name="${field.name}" 
            value="${post?.title}" />
        <span class="error">#{error 'post.title' /}</span>
        #{/field}
    </p>

    <p>
        #{field 'content'}
        <label>Write here:</label>
        <textarea name="${field.name}">${post?.content}</textarea>
        <span class="error">#{error 'post.content' /}</span>
        #{/field}
    </p>

    <p>
        #{field 'tags'}
        <label>Enter some tags:</label>
        <input type="text" size="50" 
            name="${field.name}" value="${post?.tags?.join(' ')}" />
        #{/field}
    </p>

    <p>
        <input type="submit" value="Publish this post to the blog" />
    </p>

#{/form}

最后修改yabe/app/views/Admin/index.html,给表单添加Write a new post的链接:

...
<p id="newPost" >
    <a href="@{form()}"><span>+</span> write a new post</a>
</p>
...

检查成果:

result

现在我们来完成处理提交结果的。它将创建一个新的Post对象,转换标签列表成真正的Tag列表,并验证所有成员,进行保存。如果发生错误,它会刷新表单,显示错误信息。

public static void save(String title, String content, String tags) {
    // Create post
    User author = User.find("byEmail", Security.connected()).first();
    Post post = new Post(author, title, content);
    // Set tags list
    for(String tag : tags.split("\\s+")) {
        if(tag.trim().length() > 0) {
            post.tags.add(Tag.findOrCreateByName(tag));
        }
    }
    // Validate
    validation.valid(post);
    if(validation.hasErrors()) {
        render("@form", post);
    }
    // Save
    post.save();
    index();
}

这里我们使用render("@form")作为render("Admin/form.html")的缩写。它表示使用form action的默认模板。

测试一下!

重用发布文章的代码

在发布文章的地方,我们已经写了不少的HTML表单和Java action代码。但我们还需要实现编辑现有文章的修改功能。只需改动一下,我们可以重用原来的代码。

首先我们需要Admin.form可以查询到一个现有的Post

public static void form(Long id) {
    if(id != null) {
        Post post = Post.findById(id);
        render(post);
    }
    render();
}

如你所见,我们把查询功能变成可选的,仅当id参数不为空,才会去查询一个现有文章。所以你可以链接主页面的文章列表到编辑表单。修改yabe/app/views/Admin/index.html

#{extends 'admin.html' /}

<h3>Welcome ${user}, <span>you have written ${posts.size() ?: 'no'} ${posts.pluralize('post', 'posts')} so far</span></h3>

#{list items:posts, as:'post'}
    <p class="post ${post_parity}">
        <a href="@{Admin.form(post.id)}">${post.title}</a>
    </p>
#{/list}

<p id="newPost" >
    <a href="@{form()}"><span>+</span> write a new post</a>
</p>

非常简单,但是有一个问题。如果你查看这些链接生成的URL,会看到:

/admin/new?id=3

它能用,但是不是很好。我们可以指定另一个路由。如果指定了id参数,就用新的路由。

GET     /admin/myPosts/{id}                 Admin.form
GET     /admin/new                          Admin.form

如你所见,我们在旧的路由之上定义新路由,所以它的优先级更高。这意味着,如果提交了id参数,Play将选择这条路由。如果不是,它就选择原来那条。

刷新My posts页面,你应该能看到URL的变化。

现在我们需要修改yabe/app/views/Admin/form.html

#{extends 'admin.html' /}

#{ifnot post?.id}
    <h3>Write, <span>a new post</span></h3>
#{/ifnot}
#{else}
    <h3>Edit, <span>this post</span></h3>
#{/else}

#{form @save(post?.id)}

    #{ifErrors}
        <p class="error">
            Please correct these errors.
        </p>
    #{/ifErrors}

    <p>
        #{field 'title'}
        <label>Post title:</label>
        <input type="text" name="${field.name}" 
            value="${post?.title}" />
        <span class="error">#{error 'post.title' /}</span>
        #{/field}
    </p>

    <p>
        #{field 'content'}
        <label>Write here:</label>
        <textarea name="${field.name}">
          ${post?.content}
        </textarea>
        <span class="error">#{error 'post.title' /}</span>
        #{/field}
    </p>

    <p>
        #{field 'tags'}
        <label>Enter some tags:</label>
        <input type="text" size="50" 
            name="${field.name}" value="${post?.tags?.join(' ')}" />
        #{/field}
    </p>

    <p>
        <input type="submit" value="Publish this post to the blog" />
    </p>

#{/form}

如你所见,如果id参数存在,我们将用它作为提交表单的第一个参数。所以假如这个文章具有id的值(意味着它已经存在在系统中),Admin.save就会被调用。

现在我们改变save()方法,让它同时能处理创建和修改文章的情况:

public static void save(Long id, String title, String content, String tags) {
    Post post;
    if(id == null) {
        // Create post
        User author = User.find("byEmail", Security.connected()).first();
        post = new Post(author, title, content);
    } else {
        // Retrieve post
        post = Post.findById(id);
        // Edit
        post.title = title;
        post.content = content;
        post.tags.clear();
    }
    // Set tags list
    for(String tag : tags.split("\\s+")) {
        if(tag.trim().length() > 0) {
            post.tags.add(Tag.findOrCreateByName(tag));
        }
    }
    // Validate
    validation.valid(post);
    if(validation.hasErrors()) {
        render("@form", post);
    }
    // Save
    post.save();
    index();
}

一如之前那样,我们需要定义多一个更合适的路由,还是用之前的方式:

POST    /admin/myPosts/{id}                 Admin.save
POST    /admin/new                          Admin.save

完成了!现在我们可以用同一个方法来创建新的文章,或者修改旧的文章,而且管理面板也完成了!


spacewander
这个专栏什么都有,大部分都是关于Linux或后端开发的

make building blocks that people can understand and use easily, and people will work together to ...

5.5k 声望
1.4k 粉丝
0 条评论
推荐阅读
ebpf 月报 - 2023 年 2 月
本刊物旨在为中文用户提供及时、深入、有态度的 ebpf 资讯。如果你吃了鸡蛋觉得好吃,还想认识下蛋的母鸡,欢迎关注:笔者的 twitter:[链接]bpftrace 发布 0.17.0 版本[链接]时隔数月,bpftrace 发布了新版本 0....

spacewander阅读 1.5k

Java8的新特性
Java语言特性系列Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java...

codecraft32阅读 27.5k评论 1

一文彻底搞懂加密、数字签名和数字证书!
微信搜索🔍「编程指北」,关注这个写干货的程序员,回复「资源」,即可获取后台开发学习路线和书籍来源:个人CS学习网站:[链接]前言这本是 2020 年一个平平无奇的周末,小北在家里刷着 B 站,看着喜欢的 up 主视...

编程指北71阅读 33.7k评论 20

Java11的新特性
Java语言特性系列Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java...

codecraft28阅读 19.4k评论 3

Java5的新特性
Java语言特性系列Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java...

codecraft13阅读 21.8k

Java9的新特性
Java语言特性系列Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java...

codecraft20阅读 15.4k

学会这些 Web API 使你的开发效率翻倍
随着浏览器的日益壮大,浏览器自带的功能也随着增多,在 Web 开发过程中,我们经常会使用一些 Web API 增加我们的开发效率。本篇文章主要选取了一些有趣且有用的 Web API 进行介绍,并且 API 可以在线运行预览。C...

九旬13阅读 1.6k

封面图

make building blocks that people can understand and use easily, and people will work together to ...

5.5k 声望
1.4k 粉丝
宣传栏