Theo tôi, thực tế là các mẫu được gõ tĩnh thực sự là một điều tốt : bạn được đảm bảo rằng việc gọi mẫu của bạn sẽ không thất bại nếu nó được biên dịch.
Tuy nhiên, nó thực sự bổ sung một số mẫu soạn sẵn trên các trang web gọi điện. Nhưng bạn có thể giảm nó (mà không mất lợi thế gõ tĩnh).
Trong Scala, tôi thấy hai cách để đạt được nó: thông qua thành phần hành động hoặc bằng cách sử dụng các tham số ngầm. Trong Java, tôi đề nghị sử dụng Http.Context.args
bản đồ để lưu trữ các giá trị hữu ích và truy xuất chúng từ các mẫu mà không cần phải truyền rõ ràng dưới dạng tham số mẫu.
Sử dụng tham số ngầm
Đặt menus
tham số ở cuối main.scala.html
tham số mẫu của bạn và đánh dấu tham số đó là ẩn ngầm ẩn:
@(title: String)(content: Html)(implicit menus: Seq[Menu])
<html>
<head><title>@title</title></head>
<body>
<div>
@for(menu<-menus) {
<a href="#">@menu.name</a>
}
</div>
@content
</body>
</html>
Bây giờ nếu bạn có các mẫu gọi mẫu chính này, bạn có thể có menus
tham số được chuyển hoàn toàn cho bạn tới main
mẫu bằng trình biên dịch Scala nếu nó cũng được khai báo là tham số ẩn trong các mẫu này:
@()(implicit menus: Seq[Menu])
@main("SubPage") {
...
}
Nhưng nếu bạn muốn nó được truyền hoàn toàn từ bộ điều khiển của bạn, bạn cần cung cấp nó dưới dạng một giá trị ngầm định, có sẵn trong phạm vi mà bạn gọi mẫu. Chẳng hạn, bạn có thể khai báo phương thức sau trong bộ điều khiển của mình:
implicit val menu: Seq[Menu] = Menu.findAll
Sau đó, trong hành động của bạn, bạn sẽ có thể chỉ cần viết như sau:
def index = Action {
Ok(views.html.index())
}
def index2 = Action {
Ok(views.html.index2())
}
Bạn có thể tìm thêm thông tin về phương pháp này trong bài đăng trên blog này và trong mẫu mã này .
Cập nhật : Một bài đăng blog tốt đẹp thể hiện mô hình này cũng đã được viết ở đây .
Sử dụng thành phần hành động
Trên thực tế, việc truyền RequestHeader
giá trị cho các mẫu thường rất hữu ích (xem ví dụ mẫu này ). Điều này không thêm quá nhiều mẫu mã vào mã điều khiển của bạn bởi vì bạn có thể dễ dàng viết các hành động nhận giá trị yêu cầu ngầm:
def index = Action { implicit request =>
Ok(views.html.index()) // The `request` value is implicitly passed by the compiler
}
Vì vậy, vì các mẫu thường nhận được ít nhất tham số ngầm định này, bạn có thể thay thế nó bằng một giá trị phong phú hơn có chứa, ví dụ như các menu của bạn. Bạn có thể làm điều đó bằng cách sử dụng cơ chế cấu thành hành động của Play 2.
Để làm điều đó, bạn phải xác định Context
lớp của mình , gói một yêu cầu cơ bản:
case class Context(menus: Seq[Menu], request: Request[AnyContent])
extends WrappedRequest(request)
Sau đó, bạn có thể xác định ActionWithMenu
phương pháp sau :
def ActionWithMenu(f: Context => Result) = {
Action { request =>
f(Context(Menu.findAll, request))
}
}
Mà có thể được sử dụng như thế này:
def index = ActionWithMenu { implicit context =>
Ok(views.html.index())
}
Và bạn có thể lấy bối cảnh làm tham số ẩn trong các mẫu của bạn. Ví dụ main.scala.html
:
@(title: String)(content: Html)(implicit context: Context)
<html><head><title>@title</title></head>
<body>
<div>
@for(menu <- context.menus) {
<a href="#">@menu.name</a>
}
</div>
@content
</body>
</html>
Sử dụng thành phần hành động cho phép bạn tổng hợp tất cả các giá trị ngầm định mà các mẫu của bạn yêu cầu thành một giá trị duy nhất, nhưng mặt khác, bạn có thể mất một số tính linh hoạt.
Sử dụng http.Context (Java)
Do Java không có cơ chế ẩn ý của Scala hoặc tương tự, nếu bạn muốn tránh truyền các tham số mẫu một cách rõ ràng, một cách có thể là lưu trữ chúng trong Http.Context
đối tượng chỉ tồn tại trong thời gian yêu cầu. Đối tượng này chứa một args
giá trị của loại Map<String, Object>
.
Do đó, bạn có thể bắt đầu bằng cách viết một thiết bị chặn, như được giải thích trong tài liệu :
public class Menus extends Action.Simple {
public Result call(Http.Context ctx) throws Throwable {
ctx.args.put("menus", Menu.find.all());
return delegate.call(ctx);
}
public static List<Menu> current() {
return (List<Menu>)Http.Context.current().args.get("menus");
}
}
Phương thức tĩnh chỉ là một tốc ký để lấy các menu từ ngữ cảnh hiện tại. Sau đó chú thích bộ điều khiển của bạn để trộn với bộ Menus
chặn hành động:
@With(Menus.class)
public class Application extends Controller {
// …
}
Cuối cùng, lấy menus
giá trị từ các mẫu của bạn như sau:
@(title: String)(content: Html)
<html>
<head><title>@title</title></head>
<body>
<div>
@for(menu <- Menus.current()) {
<a href="#">@menu.name</a>
}
</div>
@content
</body>
</html>