• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
Joanna Qian
Stay Hungry, Stay Foolish!
博客园    首页    新随笔    联系   管理    订阅  订阅
《Play for Java》学习笔记(二)基本的CRUD应用

注解:  CRUD——Create,Retrieve, Update, Delete

文件结构

一、添加控制器(controller和action)——/app/controllers/Products.java

package controllers;
import play.mvc.Controller;
import play.mvc.Result;
public class Products extends Controller {
    public static Result list() {     //列出所有的产品
        return TODO;
    }
    public static Result newProduct() {   //显示一个空的产品Form
        return TODO;
    }
    public static Result details(String ean) {   //显示一个编辑产品的Form
        return TODO;
    }
    public static Result save() {    //保存产品资料
        return TODO;
    }
}

说明:  controllers的action方法必须满足以下三个条件:

  • 必须是public
  • 必须是static
  • 返回类型必须是Result和Result的子类

完整代码为

package controllers;

import models.Product;
import play.data.Form;
import play.mvc.Controller;
import play.mvc.Result;
import java.util.ArrayList;
import java.util.List;

import views.html.*;

public class Products extends Controller {
    //constant for Form
    private static final Form<Product> productForm = Form.form(Product.class);
    
    public static Result list(){
        List<Product> products = Product.findAll();
        return ok(list.render(products));
    }
    
    public static Result newProduct(){
        return ok(details.render(productForm));
    }
    
    public static Result details(String ean){
        final Product product = Product.findByEan(ean);
        if(product == null){
            return notFound(String.format("Product %s does not exist.", ean));            
        }
        
        Form<Product> filledForm = productForm.fill(product);
        return ok(details.render(filledForm));
    }
    
    public static Result save(){
        Form<Product> boundForm = productForm.bindFromRequest();
        if(boundForm.hasErrors()){
            flash("error","Please correct the form below.");
            return badRequest(details.render(boundForm));
        }
        
        Product product = boundForm.get();
        product.save();
        flash("success",String.format("Successfully added product %s", product));
        return redirect(routes.Products.list());
    }    
    
    public static Result delete(String ean){
        final Product product = Product.findByEan(ean);
        if(product == null){
            return notFound(String.format("Product %s does not exist.", ean));
        }
        
        Product.remove(product);
        return redirect(routes.Products.list());
    }
}
Java Code

二. 修改routes文件

GET       /products/       controllers.Products.list()
GET       /products/new    controllers.Products.newProduct()
GET       /products/:ean   controllers.Products.details(ean: String)
POST      /products/       controllers.Products.save()
DELETE  /products/:ean   controllers.Products.delete(ean: String)

action和route对应关系如下图

三 . 添加Model Class——/app/models/Product.java

3.1) 数据模型

public class Product {
    public String ean;
    public String name;
    public String description;
    
    public Product(){}
    
    public Product(String ean, String name, String description){
        this.ean = ean;
        this.name = name;
        this.description = description;
    }
    
    public String toString(){
        return String.format("%s - %s", ean, name, description);
    }
}

说明:    不同于Java,play使用public,不用setter和getter方法

3.2)为了模拟练习,在Product.java中加一些模拟数据

// mocking some data
    private static List<Product> products;    
    static {
        products = new ArrayList<Product>();
        products.add(new Product("111111111","Paperclips 1","Paperclips description 1"));
        products.add(new Product("222222222","Paperclips 2","Paperclips description 2"));
        products.add(new Product("333333333","Paperclips 3","Paperclips description 3"));
        products.add(new Product("444444444","Paperclips 1","Paperclips description 4"));
        products.add(new Product("555555555","Paperclips 1","Paperclips description 5"));
    }

3.3) 数据处理方法——findAll(), findByEan(), findByName(), remove(), save()

    public static List<Product> findAll(){
        return new ArrayList<Product>(products);
    }
    
    public static Product findByEan(String ean){
        for(Product candidate : products){
            if(candidate.ean.equals(ean)){
                return candidate;
            }
        }
        return null;
    }
    
    public static List<Product> findByName(String term){
        final List<Product> results = new ArrayList<Product>();
        for(Product candidate : products){
            if(candidate.name.toLowerCase().contains(term.toLowerCase())){
                results.add(candidate);
            }        
        }
        return results;
    }
    
    public static boolean remove(Product product){
        return products.remove(product);
    }
    
    public void save(){
        products.remove(findByEan(this.ean));
        products.add(this);
    }

完整代码为

Java Code

四、添加和修改模板文件——list.scala.html, details.scala.html

4.1) list.scala.html

@(products:List[Product])    <!--parameter list: define which parameters this template accepts -->

@main("Product catalogue"){   <!-- call main template, the title is "Product catalogue" -->
    <h2>All Product</h2>
    <table class="table table-striped">
      <thead>
          <tr>
            <th>EAN</th>
            <th>Name</th>
            <th>Description</th>
          </tr>      
      </thead>
      <tbody>
          @for(product <- products){
          <tr>
            <td><a href="@routes.Products.details(product.ean)">@product.ean</a></td>
            <td><a href="@routes.Products.details(product.ean)">@product.name</a></td>
            <td><a href="@routes.Products.details(product.ean)">@product.description</a></td>
          </tr>
          }
      </tbody>
    </table>
}

相应的,修改controller用于显示该模板的HTML内容,即修改/app/controllers/Products.java中的list()方法

...
import views.html.*;    //引入模板

public class Products extends Controller {
    public static Result list() {
        List<Product> products = Product.findAll();
        return ok(list.render(products));
    }
...
}

在浏览器地址栏输入: http://localhost:9000/products

4.2) details.scala.html

@(productForm:Form[Product])
@import helper._
@import helper.twitterBootstrap._

@main("Product Form"){
    <h1>Product Form</h1>    
    @helper.form(action = routes.Products.save()){
        <fieldset>            
            <legend>Product(@productForm("name").valueOr("New"))</legend>
            @helper.inputText(productForm("ean"),'_label -> "EAN")
            @helper.inputText(productForm("name"),'_label -> "Name")
            @helper.textarea(productForm("description"),'_label -> "description")
        </fieldset>
        <input type="submit" class="btn btn-primary" value="Save" />
        <a class="btn" href="@routes.Application.index()">Cancel</a>
    }
}

说明:  本模板使用了Play表单Form

  • @(productForm:Form[Product]) —>— productForm是play.data.Form.form()的方法,在controller中定义
  • @import helper._ —>— 引入生产HTML,@import helper.twitterBootstrap._ 生产的HTML符合Twitter Bootstrap标准
  • @helper.form(action =routes.Products.save()){ —>— 生产的 HTML的Form代码, 并将数据提交给controller的save()方法处理,@helper.inputText生产的 HTML的input代码,@helper.textarea生产的 HTML的textarea代码
  • Product(@productForm("name").valueOr("New"))  —>— productForm.field("name")的缩写,请求表单中名为name的域(field)值,如何该值不存在,则创建一个"New"为默认值。

最后生产的HTML代码如下

<form action="/products" method="GET" >    
<fieldset>            
<legend>Product(New)</legend>
<div class="clearfix  " id="ean_field">
    <label for="ean">EAN</label>
    <div class="input">        
    <input type="text" id="ean" name="ean" value="" >
        <span class="help-inline"></span>
        <span class="help-block">Required</span> 
    </div>
</div>

<div class="clearfix  " id="name_field">
    <label for="name">Name</label>
    <div class="input">        
    <input type="text" id="name" name="name" value="" >
        <span class="help-inline"></span>
        <span class="help-block">Required</span> 
    </div>
</div>
<div class="clearfix  " id="description_field">
    <label for="description">description</label>
    <div class="input">        
    <textarea id="description" name="description" ></textarea>
        <span class="help-inline"></span>
        <span class="help-block"></span> 
    </div>
</div>
</fieldset>
<input type="submit" class="btn btn-primary" value="Save" />
<a class="btn" href="/products">Cancel</a>
</form>
HTML Code

 相应的,修改controller用于显示该模板的HTML内容,即修改/app/controllers/Products.java中的newProduct()()方法

    public static Result newProduct(){
        return ok(details.render(productForm));
    }

在浏览器地址栏输入: http://localhost:9000/products/new

 

五、处理表单提交和验证——binding values from the request

 play可以从HTTP request获取一个包含name/value对的映射Map,实现这个功能的是类Form的bindFromRequest()方法,该方法会返回一个Form对象,故我们可以在保存的时候获取页面表单的数据。

5.1) 在/app/models/Products.java中加入

public class Products extends Controller {
...
    public static Result save() {
        Form<Product> boundForm = productForm.bindFromRequest();
        Product product = boundForm.get();       
        product.save();
        return ok(String.format("Saved product %s", product));
    }
}

5.2) 在/app/models/Product.java中加入验证

...
import play.data.validation.Constraints;
public class Product {
    ...
    @Constraints.Required
    public String ean;
    @Constraints.Required
    public String name;
    public String description;
    ...
}

5.3) 对/app/models/Products.java中save()的改进

对模型加入验证数据后,希望能在controller中显示相应的成功、失败信息,这里可以使用play的validation表单功能,修改save()方法如下:

public static Result save() {
    Form<Product> boundForm = productForm.bindFromRequest();
    if(boundForm.hasErrors()) {
        flash("error", "Please correct the form below.");
        return badRequest(details.render(boundForm));
    }
    Product product = boundForm.get();
    product.save();
    flash("success",String.format("Successfully added product %s", product));
    return redirect(routes.Products.list());
}    

同时还必须在app/views/main.scala.html的<body>标签的开头中加入实现flash scope的代码:

@if(flash.containsKey("success")){
    <div class="alert alert-success">
    @flash.get("success")
    </div>
}
@if(flash.containsKey("error")){
    <div class="alert alert-error">
    @flash.get("error")
    </div>
}

说明:  flash scope是用于在请求(request)的时候存储变量的一个地方,在下一次请求开始之前存储在flash scope的值一直保持着,所以flash 是flash scope用来显示失败和成功是最理想的!

六、在列表中加入删除功能——app/views/products/list.scala.html

6.1) 在routes中加入DELETE路由

DELETE     /products/:ean      controllers.Products.delete(ean: String)

6.2) 在list.scala.html中加入JS代码,本例用JS处理Ajax请求

<h2>All products</h2>
<script>
function del(urlToDelete) {
    $.ajax({
        url: urlToDelete,
        type: 'DELETE',
        success: function(results) {   
            location.reload();   // Refresh the page
        }
    });
}
</script>
......
<tbody>
     @for(product <- products){
          <tr>
            <td><a href="@routes.Products.details(product.ean)">@product.ean</a></td>
            <td><a href="@routes.Products.details(product.ean)">@product.name</a></td>
            <td><a href="@routes.Products.details(product.ean)">@product.description</a></td>
            <td>
                <a href="@routes.Products.details(product.ean)"><i class="fa fa-pencil"></i></a>&nbsp;&nbsp;
                <a onclick="del('@routes.Products.delete(product.ean)')"><i class="fa fa-trash-o"></i></a>
            </td>
          </tr>
          }
      </tbody>
    </table>    
    <a href="@routes.Products.newProduct()" class="btn btn-primary"><i class="fa fa-plus-circle"></i> New product</a>

 

说明: 整个案例代码

posted on 2014-02-28 04:29  Joanna Qian  阅读(944)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3