ในความคิดของฉันความจริงที่ว่าเทมเพลตถูกพิมพ์แบบคงที่นั้นเป็นสิ่งที่ดีจริงๆคุณรับประกันได้ว่าการเรียกใช้เทมเพลตของคุณจะไม่ล้มเหลวหากรวบรวม
อย่างไรก็ตามมันเพิ่มต้นแบบบางอย่างในไซต์การโทร แต่คุณสามารถลดได้ (โดยไม่สูญเสียข้อดีของการพิมพ์แบบคงที่)
ใน Scala ฉันเห็นสองวิธีในการบรรลุเป้าหมาย: ผ่านองค์ประกอบการกระทำหรือโดยใช้พารามิเตอร์นัย ใน Java ฉันขอแนะนำให้ใช้Http.Context.args
แผนที่เพื่อเก็บค่าที่เป็นประโยชน์และเรียกคืนจากเทมเพลตโดยไม่ต้องส่งผ่านเป็นพารามิเตอร์เทมเพลตอย่างชัดเจน
การใช้พารามิเตอร์โดยนัย
วางmenus
พารามิเตอร์ไว้ที่ส่วนท้ายของmain.scala.html
พารามิเตอร์เทมเพลตของคุณและทำเครื่องหมายเป็น "นัย":
@(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>
ตอนนี้หากคุณมีเทมเพลตที่เรียกใช้เทมเพลตหลักนี้คุณสามารถส่งmenus
พารามิเตอร์โดยปริยายให้คุณไปยังmain
เทมเพลตโดยคอมไพลเลอร์ Scala ได้หากมีการประกาศเป็นพารามิเตอร์โดยนัยในเทมเพลตเหล่านี้ด้วย:
@()(implicit menus: Seq[Menu])
@main("SubPage") {
...
}
แต่ถ้าคุณต้องการส่งผ่านตัวควบคุมของคุณโดยปริยายคุณจะต้องระบุเป็นค่าโดยปริยายซึ่งมีอยู่ในขอบเขตที่คุณเรียกใช้เทมเพลต ตัวอย่างเช่นคุณสามารถประกาศวิธีการต่อไปนี้ในคอนโทรลเลอร์ของคุณ:
implicit val menu: Seq[Menu] = Menu.findAll
จากนั้นในการกระทำของคุณคุณจะสามารถเขียนสิ่งต่อไปนี้:
def index = Action {
Ok(views.html.index())
}
def index2 = Action {
Ok(views.html.index2())
}
คุณสามารถค้นหาข้อมูลเพิ่มเติมเกี่ยวกับแนวทางนี้ได้ในโพสต์บล็อกนี้และในตัวอย่างโค้ดนี้
ปรับปรุง : โพสต์บล็อกที่ดีแสดงให้เห็นถึงรูปแบบนี้ยังได้รับการเขียนที่นี่
การใช้องค์ประกอบการกระทำ
ที่จริงแล้วการส่งผ่านRequestHeader
ค่าไปยังเทมเพลตมักจะมีประโยชน์(ดูตัวอย่างเช่นนี้ ) สิ่งนี้ไม่ได้เพิ่มต้นแบบลงในโค้ดคอนโทรลเลอร์ของคุณมากนักเนื่องจากคุณสามารถเขียนการดำเนินการที่ได้รับค่าคำขอโดยปริยาย:
def index = Action { implicit request =>
Ok(views.html.index()) // The `request` value is implicitly passed by the compiler
}
ดังนั้นเนื่องจากเทมเพลตมักจะได้รับพารามิเตอร์โดยนัยนี้เป็นอย่างน้อยคุณจึงสามารถแทนที่ด้วยค่าที่มากขึ้นซึ่งมีเช่นเมนูของคุณ คุณสามารถทำได้โดยใช้กลไกองค์ประกอบการกระทำของ Play 2
ในการทำเช่นนั้นคุณต้องกำหนดContext
ชั้นเรียนของคุณโดยสรุปคำขอพื้นฐาน:
case class Context(menus: Seq[Menu], request: Request[AnyContent])
extends WrappedRequest(request)
จากนั้นคุณสามารถกำหนดActionWithMenu
วิธีการต่อไปนี้:
def ActionWithMenu(f: Context => Result) = {
Action { request =>
f(Context(Menu.findAll, request))
}
}
ซึ่งสามารถใช้ได้ดังนี้:
def index = ActionWithMenu { implicit context =>
Ok(views.html.index())
}
และคุณสามารถใช้บริบทเป็นพารามิเตอร์โดยนัยในเทมเพลตของคุณ เช่นสำหรับ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>
การใช้องค์ประกอบการดำเนินการช่วยให้คุณสามารถรวมค่าโดยนัยทั้งหมดที่แม่แบบของคุณต้องการให้เป็นค่าเดียว แต่ในทางกลับกันคุณอาจสูญเสียความยืดหยุ่นไปบ้าง ...
การใช้ Http.Context (Java)
เนื่องจาก Java ไม่มีกลไกโดยนัยของ Scala หรือสิ่งที่คล้ายกันหากคุณต้องการหลีกเลี่ยงการส่งผ่านพารามิเตอร์เทมเพลตอย่างชัดเจนวิธีที่เป็นไปได้คือการจัดเก็บไว้ในHttp.Context
วัตถุที่มีชีวิตอยู่ในช่วงเวลาของคำขอเท่านั้น วัตถุนี้มีค่าของชนิดargs
Map<String, Object>
ดังนั้นคุณสามารถเริ่มต้นด้วยการเขียนตัวสกัดกั้นตามที่อธิบายไว้ในเอกสารประกอบ :
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");
}
}
วิธีการคงที่เป็นเพียงการชวเลขเพื่อดึงเมนูจากบริบทปัจจุบัน จากนั้นใส่คำอธิบายประกอบตัวควบคุมของคุณเพื่อผสมกับตัวMenus
ดักจับการกระทำ:
@With(Menus.class)
public class Application extends Controller {
// …
}
สุดท้ายดึงmenus
ค่าจากเทมเพลตของคุณดังนี้:
@(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>