《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) 数据模型

扫描二维码关注公众号,回复: 6664831 查看本文章
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>

 

说明: 整个案例代码

转载于:https://www.cnblogs.com/JoannaQ/p/3572754.html

猜你喜欢

转载自blog.csdn.net/weixin_34216107/article/details/93057164