学习 play! 框架(Part One)

Creating a new application

1
2
3
$ activator new my-first-app play-java
or
$ activator new # prompt

The standard application layout

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
app -> Application sources
└ assets -> Compiled asset sources
└ stylesheets -> Typically LESS CSS sources
└ javascripts -> Typically CoffeeScript sources
└ controllers -> Application controllers
└ Application.java
└ models -> Application business layer
└ views -> Templates
└ index.scala.html
└ main.scala.html
└ utils -> add your own packages here
build.sbt -> Application build script
conf -> Configurations files and other non-compiled resources (on classpath)
└ application.conf -> Main configuration file
└ routes -> Routes definition
public -> Public assets
└ stylesheets -> CSS files
└ javascripts -> Javascript files
└ images -> Image files
project -> sbt configuration files
└ build.properties -> Marker for sbt project
└ plugins.sbt -> sbt plugins including the declaration for Play itself
lib -> Unmanaged libraries dependencies
logs -> Standard logs folder
└ application.log -> Default log file
target -> Generated stuff
└ scala-2.10.0
└ cache
└ classes -> Compiled class files
└ classes_managed -> Managed class files (templates, ...)
└ resource_managed -> Managed resources (less, ...)
└ src_managed -> Generated sources (templates, ...)
test -> source folder for unit or functional tests
ApplicationTest.java
IntegrationTest.java

app/controllers/Application.java

1
2
3
4
5
public class Application extends Controller {
public static Result index() {
return ok(index.render("Your new application is ready."));
}
}

conf/routes

Home page
GET / controllers.Application.index()
Map static resources from the /public folder to the /assets URL path
GET /assets/*file controllers.Assets.at(path=”/public”, file)

another

1
2
3
public static Result hello(String name) {
return ok(views.html.hello.render(name));
}
1
2
$ console
scala> views.html.hello.render("Play!")

A basic CRUD application example

conf/routes

GET / controllers.Products.index()
GET /products/ controllers.Products.list()
GET /products/new controllers.Products.newProduct()
GET /products/:ean controllers.Products.details(ean: String)
GET /product/$ean<[0-9]{13}> controllers.Products.details(ean: Long)
POST /products/ controllers.Products.save()


GET /products/:page controllers.Products.list(page:Int) http://localhost/products/2
GET /products/ controllers.Products.list(page:Int) http://localhost/products/?page=2


Route with default value
GET /products controllers.Products.list(page:Int ?= 0)
Fixed value as parameter
GET / controllers.Products.list(page: Int = 0)

app/controllers/Products.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Products extends Controller {
public static Result index() {
return redirect(routes.Products.list(0));
}
public static Result list(Integer page) { ... }
public static Result list() { // List all products
List<Product> products = Product.findAll();
return ok(list.render(products));
}
public static Result newProduct() { // Show a blank product form
return ok(details.render(productForm));
}
public static Result delete(String ean) { ... }
public static Result details(String ean) { // Show a product edit form
return TODO; // return badRequest("Incorrect EAN: " + ean); return notFound("No product with EAN " + ean);
}
public static Result save() { // Save a product
...
}
}

/app/models/Product.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package models;
public class Product {
private static List<Product> products;
static {
products = new ArrayList<Product>();
products.add(new Product("1111111111111", "Paperclips 1",
"Paperclips description 1"));
...
}
public String ean;
public String name;
public String description;
public Product() {}
public Product(String ean, String name, String description) {
this.ean = ean;
...
}
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);
}
}

/app/views/products/list.scala.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@(products: List[Product])
@main("Products catalogue") {
<h2>All products</h2>
<script>
function del(urlToDelete) {
$.ajax({
url: urlToDelete,
type: 'DELETE',
success: function(results) { // Refresh the page
location.reload();
}
});
}
</script>
<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.name</a></td>
</tr>
} </tbody>
</table>
<a href="@routes.Products.newProduct()" class="btn">
<i class="icon-plus"></i> New product</a>
}

/app/views/products/details.scala.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@(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.Products.index()">Cancel</a>
}
}