Freemarker ทำซ้ำบนคีย์แฮชแมป


87

Freemarker มีประเภทข้อมูลคอลเลกชันสองรายการรายการและแฮชแมปมีวิธีทำซ้ำคีย์แฮชแมปเหมือนกับที่เราทำกับรายการหรือไม่

ดังนั้นถ้าฉันมีตัวแปรที่มีข้อมูลให้พูดว่า:

user : {
  name : "user"
  email : "looser@everything.com"
  homepage : "http://nosuchpage.org"
}

ฉันต้องการพิมพ์คุณสมบัติของผู้ใช้ทั้งหมดพร้อมค่าของพวกเขา สิ่งนี้ไม่ถูกต้อง แต่เป้าหมายชัดเจน:

<#list user.props() as prop>
  ${prop} = ${user.get(prop)}
</#list>

คำตอบ:


106

แก้ไข:อย่าใช้วิธีนี้กับ FreeMarker 2.3.25 .get(prop)ขึ้นไปโดยเฉพาะอย่างยิ่งไม่ได้ ดูคำตอบอื่น ๆ

คุณใช้ฟังก์ชันปุ่มในตัวเช่นควรใช้งานได้:

<#list user?keys as prop>
    ${prop} = ${user.get(prop)}
</#list>  

4
ไวยากรณ์แตกต่างกันในเวอร์ชันล่าสุดดังที่แสดงในลิงก์ที่ฉันโพสต์ไว้ในคำตอบของฉัน ฉันรู้ว่านี่เป็นคำถามเก่า แต่มันก็ติดอันดับสูงใน Google
Nick Spacek

26
เพียงบันทึก - คุณสามารถใช้${user[prop]}เป็นชวเลขได้
Bozho

นี่คือการรั่วไหลของประสิทธิภาพ: สำหรับทุกคีย์จำเป็นต้องดึงค่า การทำซ้ำทับชุดรายการ () ไม่มีปัญหานั้น
Geoffrey De Smet

4
ควรเป็น $ {user [prop]}
dns

ด้วยค่าเริ่มต้นของการกำหนดค่าจะuser[prop]ทำงานได้เท่ากับpropa String(ไม่เช่นนั้นคุณต้องใช้user?api.get(prop)ในขณะนี้) แต่โปรดระวังกรอบงานบางอย่าง (เช่น Struts ฉันเชื่อว่า) ใช้การตั้งค่าที่เลิกใช้แล้วในขณะนี้ซึ่งชื่อวิธีการผสมกับMapคีย์ดังนั้นหากค่าpropsเกิดขึ้นกับ เป็นชื่อวิธีการในuserวัตถุ Java คุณจะได้รับวิธีการแทนสิ่งที่คุณหมายถึง user.get(prop)นั่นเป็นเหตุผลว่าทำไมในช่วงที่การตั้งค่าแบบเดิมพวกเขามักจะใช้
ddekany

52

FYI ดูเหมือนว่าไวยากรณ์สำหรับการดึงค่าจะเปลี่ยนไปตาม:

http://freemarker.sourceforge.net/docs/ref_builtins_hash.html

<#assign h = {"name":"mouse", "price":50}>
<#assign keys = h?keys>
<#list keys as key>${key} = ${h[key]}; </#list>

2
ไวยากรณ์นี้แตกต่างกันอย่างไร?
Parker

1
คำตอบที่ดี ;-) โปรดทราบว่าคุณอาจต้องทำการตรวจสอบค่าว่างเมื่อพิมพ์ค่าของคุณ <#if h [key] ??> $ {key} = $ {h [key]}; </ # if>
Brad Parks

1
ไวยากรณ์ไม่เปลี่ยนแปลง ทั้งสองอย่าง[key]และ.get(key)มีมาตั้งแต่สมัยโบราณ .get(key)ไม่ได้มีอะไรพิเศษสำหรับ FTL แต่เพียงแค่เรียกวิธีการ Java สาธารณะ แต่คุณจะใช้ได้ก็ต่อเมื่อ FreeMarker ถูกกำหนดค่าให้แสดงMapวิธีการเท่านั้น
ddekany

เมื่อทำซ้ำฉันจะได้รับเมธอด (getClass, hashCode, เท่ากับ, get, toString, class) ... อย่างไรก็ตามฉันไม่เห็นคุณสมบัติใด ๆ เช่น 'id' ซึ่งเป็นสิ่งที่ฉันต้องการรับรายการ. มีข้อเสนอแนะว่าจะรับรายการคุณสมบัติที่ไม่ใช่วิธีการจากแฮชนั้นได้อย่างไร ฉันต้องการทราบชื่อคุณสมบัติเหล่านั้น : |
MaxRocket

49

ตั้งแต่ 2.3.25 ให้ทำดังนี้:

<#list user as propName, propValue>
  ${propName} = ${propValue}
</#list>

โปรดทราบว่าสิ่งนี้ใช้ได้กับคีย์ที่ไม่ใช่สตริง (ไม่เหมือนกับmap[key]ที่ต้องเขียนตามmap?api.get(key)นั้น)

ก่อน 2.3.25 โซลูชันมาตรฐานคือ:

<#list user?keys as prop>
  ${prop} = ${user[prop]}
</#list>

อย่างไรก็ตามการผสานรวม FreeMarker แบบเก่าจริงๆบางอย่างใช้การกำหนดค่าแปลก ๆ โดยที่Mapวิธีการสาธารณะ(เช่นgetClass) ปรากฏเป็นคีย์ ที่เกิดขึ้นขณะที่พวกเขากำลังใช้บริสุทธิ์BeansWrapper(แทนDefaultObjectWrapper) ที่มีคุณสมบัติถูกทิ้งบนsimpleMapWrapper falseคุณควรหลีกเลี่ยงการตั้งค่าดังกล่าวเนื่องจากเป็นการผสมผสานวิธีการกับMapรายการจริง แต่ถ้าคุณทำงานในการติดตั้งที่โชคร้ายเช่นวิธีที่จะหลบหนีสถานการณ์ที่มีการใช้วิธีการ Java สัมผัสเช่นuser.entrySet(), user.get(key)ฯลฯ และไม่ได้ใช้ภาษาโครงสร้างแม่แบบเหมือนหรือ?keysuser[key]


นี้ทำงานได้อย่างสมบูรณ์ แต่ฉันพบข้อผิดพลาดใน springource IDE มีความคิดอย่างไรที่จะแก้ไข? ขอบคุณ
harshavmb

@harshavmb ผิดพลาดประการใด อาจใช้ปลั๊กอิน FreeMarker ที่ล้าสมัยซึ่งมาพร้อมกับ FreeMarker เวอร์ชันเก่าหรือไม่
ddekany

อย่าคิดอย่างนั้น ดาวน์โหลดล่าสุดจาก jboss tools ฉันจะลองเครื่องอื่นและแจ้งให้คุณทราบ
harshavmb

@harshavmb หากคุณป้อนสิ่งที่ต้องการ${x?nosuchthing}และคุณวางเมาส์เหนือข้อความแสดงข้อผิดพลาดที่แสดงจะบอกเวอร์ชัน FreeMarker ที่ใช้ 2.3.25-incubatingมันควรจะเป็น
ddekany

แปลกฉันเพิ่งลองใน Mac และไม่สามารถจำลองปัญหาได้ ปัญหาน่าจะเป็นเฉพาะกับ vm ของฉัน ฉันจะดูเวอร์ชั่นขวดโหล อย่างไรก็ตามมันเป็นเพียงข้อผิดพลาดในตัวแก้ไข แต่โค้ดถูกดำเนินการอย่างถูกต้อง
harshavmb

12

หากใช้BeansWrapper ที่มีระดับการเปิดรับ Expose.SAFE หรือ Expose.ALL สามารถใช้วิธี Java มาตรฐานในการวนซ้ำชุดรายการได้:

ตัวอย่างเช่นสิ่งต่อไปนี้จะทำงานใน Freemarker (ตั้งแต่อย่างน้อยเวอร์ชัน 2.3.19):

<#list map.entrySet() as entry>  
  <input type="hidden" name="${entry.key}" value="${entry.value}" />
</#list>

ตัวอย่างเช่นใน Struts2 ส่วนขยายของ BeanWrapperจะใช้กับระดับแสงที่เป็นค่าเริ่มต้นเพื่อให้สามารถทำซ้ำได้ในลักษณะนี้


3
คุณได้ลองสิ่งนี้จริงหรือไม่? เพราะฉันได้รับInvalidReferenceExceptionเมื่อฉันลองในขณะที่map?keysทำงาน
kdgregory

4
สิ่งนี้ใช้ได้เฉพาะเมื่อใช้freemarker.ext.beans.BeansWrapperเป็นวัตถุห่อหุ้ม มิฉะนั้นMaps จะถูกห่อเป็นSimpleHashวัตถุที่ไม่รองรับ#entrySet()โดยอัตโนมัติ (ดูfreemarker.sourceforge.net/docs/api/freemarker/template/… )
Koraktor

คุณถูกต้องและฉันได้อัปเดตคำตอบเพื่อแสดงความคิดเห็นของคุณ ดูดี!
รี

1
ข้างต้นใช้ไม่ได้ผลกับแฮชที่สร้างขึ้นภายใน FTL โดยเฉพาะหากคุณใช้ตัวแก้ไข Spring Freemarker กับ BeanWrapper แฮชที่ประกาศภายในไฟล์ Ftl จะไม่ถูกรวมและจะยังคงเป็นเพียงแฮชที่สามารถทำซ้ำได้โดยใช้?
ข้าม

1
อย่าใช้บริสุทธิ์BeansWrapperอย่างน้อยไม่ได้อยู่กับค่าเริ่มต้นของมันที่เป็นsimpleMapWrapper falseมันสับสนมากเพราะมันผสมคีย์กับชื่อเมธอด หากคุณต้องการเรียกใช้entrySet()เพียงใช้กระดาษห่ออ็อบเจ็กต์ที่ "สะอาด" ต่อไปเช่นค่าเริ่มต้นและเขียนmap?api.entrySet()ว่าคุณต้องการเข้าถึง Java API แทนคีย์หรือไม่
ddekany

2

การทำซ้ำวัตถุ

หากคีย์แผนที่ของคุณเป็นวัตถุไม่ใช่สตริงคุณสามารถทำซ้ำได้โดยใช้ Freemarker

1) แปลงแผนที่เป็นรายการในตัวควบคุม:

List<Map.Entry<myObjectKey, myObjectValue>> convertedMap  = new ArrayList(originalMap.entrySet());

2) ทำแผนที่ซ้ำในเทมเพลต Freemarker เข้าถึงวัตถุในคีย์และวัตถุในค่า:

<#list convertedMap as item>
    <#assign myObjectKey = item.getKey()/>
    <#assign myObjectValue = item.getValue()/>
    [...]
</#list>

1

เพื่อความสมบูรณ์ควรกล่าวถึงว่ามีการจัดการคอลเลกชันที่ว่างเปล่าใน Freemarker ตั้งแต่เมื่อไม่นานมานี้

ดังนั้นวิธีที่สะดวกที่สุดในการทำแผนที่ซ้ำคือ:

<#list tags>
<ul class="posts">
    <#items as tagName, tagCount>
        <li>{$tagName} (${tagCount})</li>
    </#items>
</ul>
<#else>
    <p>No tags found.</p>
</#list>

ไม่มี<#if ...>เครื่องห่อเพิ่มเติม


คำตอบที่ดีที่สุด ขอขอบคุณ.
egemen

0

คุณสามารถใช้ใบเสนอราคาเดียวเพื่อเข้าถึงคีย์ที่คุณตั้งไว้ในโปรแกรม Java ของคุณ

หากคุณตั้งค่าแผนที่ใน Java เช่นนี้

Map<String,Object> hash = new HashMap<String,Object>();
hash.put("firstname", "a");
hash.put("lastname", "b");

Map<String,Object> map = new HashMap<String,Object>();
map.put("hash", hash);

จากนั้นคุณสามารถเข้าถึงสมาชิกของ 'แฮช' ใน Freemarker ได้เช่นนี้ -

${hash['firstname']}
${hash['lastname']}

เอาท์พุต:

a
b

ที่แสดงวิธีจัดการกับแต่ละคีย์ แต่คำถามถามว่าจะย้ำอย่างไร
Lambart
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.