บทนำ
JSTL <c:xxx>
แท็กทั้งหมดtaghandlersและพวกเขาจะดำเนินการในช่วงมุมมองสร้างเวลาในขณะ JSF <h:xxx>
แท็กทั้งหมดUI ส่วนประกอบและพวกเขาจะดำเนินการในช่วงมุมมองการแสดงผลเวลามุมมองการแสดงผลเวลา
โปรดทราบว่าจาก JSF ของตัวเอง<f:xxx>
และ<ui:xxx>
แท็กเฉพาะผู้ที่ไม่ได้ขยายจากUIComponent
นี้ยังมี taghandlers เช่น<f:validator>
, <ui:include>
, <ui:define>
ฯลฯ คนซึ่งเพิ่มขึ้นจากUIComponent
นี้ยังมีส่วนประกอบ JSF UI เช่น<f:param>
, <ui:fragment>
, <ui:repeat>
ฯลฯ จากส่วนประกอบ JSF UI เท่านั้นid
และbinding
แอตทริบิวต์ ยังประเมินระหว่างเวลาสร้างมุมมอง ดังนั้นคำตอบด้านล่างเกี่ยวกับวงจรชีวิตของ JSTL ก็ใช้กับid
และbinding
คุณสมบัติของส่วนประกอบ JSF
มุมมองเวลาในการสร้างเป็นช่วงเวลาที่ว่าเมื่อไฟล์ XHTML / JSP การที่จะถูกแยกและแปลงเป็นต้นไม้องค์ประกอบ JSF ที่ถูกเก็บไว้แล้วเป็นของUIViewRoot
FacesContext
เวลาในการเรนเดอร์มุมมองนั้นเป็นช่วงเวลาที่โครงสร้างของ JSF กำลังจะสร้าง HTML ขึ้นต้นด้วยUIViewRoot#encodeAll()
เริ่มต้นด้วย ดังนั้น: องค์ประกอบ JSF UI และแท็ก JSTL จะไม่ทำงานในการซิงค์อย่างที่คุณคาดหวังจากการเข้ารหัส คุณสามารถเห็นภาพได้ดังนี้: JSTL รันจากบนลงล่างก่อนสร้างแผนผังองค์ประกอบ JSF จากนั้นก็ถึงคราวที่จะเรียกใช้ JSF จากบนลงล่างอีกครั้งสร้างเอาต์พุต HTML
<c:forEach>
VS <ui:repeat>
ตัวอย่างเช่นมาร์กอัป Facelets นี้ทำการวนซ้ำมากกว่า 3 รายการโดยใช้<c:forEach>
:
<c:forEach items="#{bean.items}" var="item">
<h:outputText id="item_#{item.id}" value="#{item.value}" />
</c:forEach>
... สร้างในช่วงเวลาสร้างมุมมองสาม<h:outputText>
องค์ประกอบที่แยกจากกันในโครงสร้างองค์ประกอบ JSF ซึ่งแสดงโดยประมาณดังนี้:
<h:outputText id="item_1" value="#{bean.items[0].value}" />
<h:outputText id="item_2" value="#{bean.items[1].value}" />
<h:outputText id="item_3" value="#{bean.items[2].value}" />
... ซึ่งในทางกลับกันสร้างเอาต์พุต HTML ของพวกเขาระหว่างการแสดงผลเวลาดู:
<span id="item_1">value1</span>
<span id="item_2">value2</span>
<span id="item_3">value3</span>
โปรดทราบว่าคุณจำเป็นต้องตรวจสอบความไม่ซ้ำของ ID ส่วนประกอบด้วยตนเองและตรวจสอบว่ามีการประเมินในระหว่างการสร้างมุมมอง
ในขณะนี้ Facelets ทำเครื่องหมายซ้ำมากกว่า 3 รายการโดยใช้<ui:repeat>
ซึ่งเป็นองค์ประกอบของ JSF UI:
<ui:repeat id="items" value="#{bean.items}" var="item">
<h:outputText id="item" value="#{item.value}" />
</ui:repeat>
... สิ้นสุดลงตามที่เป็นอยู่ในโครงสร้างองค์ประกอบ JSF โดยที่<h:outputText>
ส่วนประกอบเดียวกันนั้นอยู่ในช่วงเวลาที่แสดงภาพถูกนำมาใช้ซ้ำเพื่อสร้างเอาต์พุต HTML ตามรอบการวนรอบปัจจุบัน:
<span id="items:0:item">value1</span>
<span id="items:1:item">value2</span>
<span id="items:2:item">value3</span>
โปรดทราบว่าใน<ui:repeat>
ฐานะที่เป็นNamingContainer
องค์ประกอบทำให้มั่นใจได้แล้วว่าเอกลักษณ์ของรหัสลูกค้าตามดัชนีการวนซ้ำ มันเป็นไปไม่ได้ที่จะใช้ EL ในแอid
ททริบิวต์ขององค์ประกอบลูกด้วยวิธีนี้เพราะมันจะถูกประเมินในช่วงเวลาที่สร้างภาพในขณะที่#{item}
ใช้ได้เฉพาะในช่วงเวลาที่แสดงภาพเท่านั้น Same เป็นจริงสำหรับh:dataTable
ส่วนประกอบที่คล้ายคลึงกัน
<c:if>
/ <c:choose>
vsrendered
เป็นอีกตัวอย่างหนึ่งมาร์คอัพ Facelets นี้เพิ่มแท็กที่แตกต่างกันโดยใช้<c:if>
(คุณสามารถใช้<c:choose><c:when><c:otherwise>
สำหรับสิ่งนี้):
<c:if test="#{field.type eq 'TEXT'}">
<h:inputText ... />
</c:if>
<c:if test="#{field.type eq 'PASSWORD'}">
<h:inputSecret ... />
</c:if>
<c:if test="#{field.type eq 'SELECTONE'}">
<h:selectOneMenu ... />
</c:if>
... ในกรณีที่type = TEXT
จะเพิ่มเพียง<h:inputText>
องค์ประกอบในโครงสร้างองค์ประกอบ JSF:
<h:inputText ... />
ในขณะที่มาร์คอัป Facelets นี้:
<h:inputText ... rendered="#{field.type eq 'TEXT'}" />
<h:inputSecret ... rendered="#{field.type eq 'PASSWORD'}" />
<h:selectOneMenu ... rendered="#{field.type eq 'SELECTONE'}" />
... จะจบลงอย่างที่กล่าวไว้ข้างต้นในแผนผังองค์ประกอบ JSF โดยไม่คำนึงถึงเงื่อนไข นี่อาจจบลงในทรีคอมโพเนนต์ "bloated" เมื่อคุณมีหลายองค์ประกอบและจริง ๆ แล้วอิงตามโมเดล "สแตติก" (เช่นที่field
ไม่เปลี่ยนแปลงตลอดเวลาอย่างน้อยขอบเขตการดู) นอกจากนี้คุณอาจพบปัญหา EL เมื่อคุณจัดการกับคลาสย่อยที่มีคุณสมบัติเพิ่มเติมในเวอร์ชัน Mojarra ก่อน 2.2.7
<c:set>
VS <ui:param>
พวกเขาไม่สามารถใช้แทนกันได้ การ<c:set>
ตั้งค่าตัวแปรในขอบเขต EL ซึ่งสามารถเข้าถึงได้หลังจากตำแหน่งแท็กระหว่างเวลาสร้างมุมมอง แต่ที่ใดก็ได้ในมุมมองระหว่างเวลาแสดงผลมุมมอง <ui:param>
ผ่านตัวแปร EL กับแม่แบบ Facelet รวมผ่านทาง<ui:include>
, หรือ<ui:decorate template>
<ui:composition template>
เวอร์ชัน JSF ที่เก่ากว่านั้นมีข้อบกพร่องโดยที่<ui:param>
ตัวแปรยังมีอยู่นอกเทมเพลต Facelet ที่เป็นปัญหาสิ่งนี้ไม่ควรเชื่อถือ
<c:set>
โดยไม่ต้องมีscope
คุณลักษณะที่จะทำตัวเหมือนนามแฝง มันไม่ได้แคชผลลัพธ์ของนิพจน์ EL ในขอบเขตใด ๆ มันสามารถปรับใช้ได้อย่างสมบูรณ์แบบภายในตัวอย่างเช่นวนองค์ประกอบ JSF ดังนั้นเช่นด้านล่างจะทำงานได้ดี:
<ui:repeat value="#{bean.products}" var="product">
<c:set var="price" value="#{product.price}" />
<h:outputText value="#{price}" />
</ui:repeat>
มันไม่เหมาะสำหรับเช่นการคำนวณผลรวมในวง สำหรับสิ่งนั้นใช้สตรีม EL 3.0แทน:
<ui:repeat value="#{bean.products}" var="product">
...
</ui:repeat>
<p>Total price: #{bean.products.stream().map(product->product.price).sum()}</p>
เฉพาะเมื่อคุณตั้งค่าscope
แอตทริบิวต์ที่มีค่าใดค่าหนึ่งที่อนุญาตrequest
, view
, session
หรือapplication
แล้วมันจะได้รับการประเมินทันทีในช่วงเวลาในการสร้างมุมมองและเก็บไว้ในขอบเขตที่กำหนด
<c:set var="dev" value="#{facesContext.application.projectStage eq 'Development'}" scope="application" />
สิ่งนี้จะถูกประเมินเพียงครั้งเดียวและใช้ได้#{dev}
ตลอดทั้งแอปพลิเคชันทั้งหมด
ใช้ JSTL เพื่อควบคุมการสร้างแผนผังองค์ประกอบ JSF
ใช้ JSTL อาจนำไปสู่ผลลัพธ์ที่ไม่คาดคิดเมื่อมีการใช้ภายใน JSF ส่วนประกอบ iterating เช่น<h:dataTable>
, <ui:repeat>
ฯลฯ หรือเมื่อคุณลักษณะแท็ก JSTL ขึ้นอยู่กับผลของเหตุการณ์ JSF เช่นpreRenderView
หรือส่งค่ารูปแบบในรูปแบบที่ไม่สามารถใช้ได้ในช่วงเวลาในการสร้างมุมมอง . ดังนั้นให้ใช้แท็ก JSTL เพื่อควบคุมการไหลของการสร้างแผนผังองค์ประกอบ JSF เท่านั้น ใช้คอมโพเนนต์ JSF UI เพื่อควบคุมโฟลว์ของการสร้างเอาต์พุต HTML อย่าผูกvar
คอมโพเนนต์การวนซ้ำ JSF กับแอ็ตทริบิวต์แท็ก JSTL อย่าพึ่งพาเหตุการณ์ JSF ในแอตทริบิวต์แท็ก JSTL
เมื่อใดก็ตามที่คุณคิดว่าคุณต้องผูกส่วนประกอบเข้ากับแบ็คเอนด์บีนbinding
หรือคว้าผ่านfindComponent()
และสร้าง / จัดการกับลูกโดยใช้โค้ด Java ในแบ็คสเปคด้วยnew SomeComponent()
และไม่ควรทำเช่นนั้นคุณควรหยุดและพิจารณาใช้ JSTL แทนทันที เนื่องจาก JSTL ยังใช้ XML รหัสที่จำเป็นในการสร้างส่วนประกอบ JSF แบบไดนามิกจะสามารถอ่านและบำรุงรักษาได้ดีขึ้นมาก
สิ่งสำคัญที่ควรทราบคือ Mojarra เวอร์ชันเก่ากว่า 2.1.18 มีข้อผิดพลาดในการบันทึกสถานะบางส่วนเมื่ออ้างอิงถั่วมุมมองที่กำหนดในแอตทริบิวต์แท็ก JSTL มุมมองทั้งขอบเขตถั่วจะเพิ่งสร้างขึ้นแทนการดึงออกมาจากต้นไม้มุมมอง (เพียงเพราะต้นไม้มุมมองที่สมบูรณ์คือยังไม่พร้อมที่จุด JSTL วิ่ง) หากคุณคาดหวังหรือเก็บสถานะไว้ในถั่วที่กำหนดมุมมองด้วยแอตทริบิวต์แท็ก JSTL มันจะไม่ส่งคืนค่าที่คุณคาดหวังหรือจะ "หายไป" ในมุมมองที่ถูกกำหนดขอบเขตจริงซึ่งเรียกคืนหลังจากดู ต้นไม้ถูกสร้างขึ้น ในกรณีที่คุณไม่สามารถอัปเกรดเป็น Mojarra 2.1.18 หรือใหม่กว่าการแก้ไขคือการปิดสถานะการประหยัดบางส่วนweb.xml
ดังนี้:
<context-param>
<param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
<param-value>false</param-value>
</context-param>
ดูสิ่งนี้ด้วย:
หากต้องการดูตัวอย่างโลกแห่งความจริงที่มีแท็ก JSTL ที่เป็นประโยชน์ (เช่นเมื่อใช้อย่างถูกต้องระหว่างการสร้างมุมมอง) ให้ดูคำถาม / คำตอบต่อไปนี้:
โดยสังเขป
ในฐานะที่เป็นความต้องการของคุณทำงานคอนกรีตถ้าคุณต้องการที่จะทำให้ส่วนประกอบ JSF เงื่อนไขใช้rendered
แอตทริบิวต์ในองค์ประกอบ JSF HTML แทนโดยเฉพาะอย่างยิ่งถ้า#{lpc}
หมายถึงรายการที่ซ้ำปัจจุบันของ JSF วนองค์ประกอบเช่นหรือ<h:dataTable>
<ui:repeat>
<h:someComponent rendered="#{lpc.verbose}">
...
</h:someComponent>
หรือถ้าคุณต้องการสร้าง (สร้าง / เพิ่ม) ส่วนประกอบ JSF ตามเงื่อนไขให้ใช้ JSTL ต่อไป เป็นวิธีที่ดีกว่าการใช้ verbosely new SomeComponent()
ใน java
<c:if test="#{lpc.verbose}">
<h:someComponent>
...
</h:someComponent>
</c:if>
ดูสิ่งนี้ด้วย: