Hashmap tuşları üzerinde yinelenen Freemarker


87

Freemarker'ın iki koleksiyon veri türü, listeleri ve hashmap'leri vardır. Listelerde yaptığımız gibi, hashmap anahtarlarını yinelemenin bir yolu var mı?

Yani veri içeren bir varım varsa şunu söyleyelim:

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

Tüm kullanıcı özelliklerini değerleri ile yazdırmak istiyorum. Bu geçersiz, ancak amaç net:

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

Yanıtlar:


106

Düzenleme: Bu çözümü FreeMarker 2.3.25 ve üstü ile kullanmayın, özellikle de kullanmayın .get(prop). Diğer cevaplara bakın.

Yerleşik tuşlar işlevini kullanırsınız, örneğin bu çalışmalıdır:

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

4
cevabımda yayınladığım bağlantıda gösterildiği gibi son sürümde sözdizimi farklı. Bunun eski bir soru olduğunun farkındayım, ancak Google'da üst sıralarda yer alıyor.
Nick Spacek

26
sadece bir not - ${user[prop]}kısaltma olarak kullanabilirsiniz
Bozho

Bu bir performans sızıntısıdır: Her anahtar için değeri geri alması gerekir. EntrySet () üzerinde yinelemenin bu sorunu yoktur.
Geoffrey De Smet

4
$ {user [prop]} olmalıdır
dns

Yapılandırma varsayılan ile user[prop]eserleri uzak olduğu kadar propbir olan String(aksi takdirde gerekmez user?api.get(prop), şu anda), ama dikkat bazı çerçeveler (Struts gibi, inanıyorum) yöntemi isimleri ile karışmış olan ve şimdi artık yok kurulumunu kullanmak Maptuşları ve değer eğer öyleyse propsolur userJava nesnesinde bir yöntem adı olursa, kastettiğiniz şey yerine yöntemi alırsınız. Bu aynı zamanda eski kurulumlarda her zaman kullandıkları da budur user.get(prop).
ddekany

52

Bilginize, değerleri almak için sözdizimi şuna göre değişmiş gibi görünüyor:

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
Bu sözdizimi nasıl farklıdır?
Parker

1
iyi cevap ;-) Değerinizi yazdırırken bir boş değeri kontrol etmeniz gerekebileceğini unutmayın, <#if h [anahtar] ??> $ {anahtar} = $ {h [anahtar]}; </ # if>
Brad Parks

1
Sözdizimi değiştirilmedi. Hem [key]ve .get(key)eski çağlardan beri vardır. .get(key)FTL için herhangi bir özel değil, sadece o genel Java yöntemini çağırıyor. Ancak, yalnızca FreeMarker, Mapyöntemleri ortaya çıkarmak için yapılandırıldıysa kullanabilirsiniz .
ddekany

Yinelediğimde yöntemler (getClass, hashCode, equals, get, toString, class) alıyorum ... ancak, bir listesini almak istediğim 'id' gibi özelliklerden hiçbirini görmüyorum. Bu karmaşadan yöntem dışı özelliklerin listesini nasıl alacağınıza dair herhangi bir öneriniz var mı? Bu mülk adlarını bilmem gerekiyor. : |
MaxRocket

49

2.3.25'ten beri, şöyle yapın:

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

Bunun dize olmayan anahtarlarla da çalıştığını unutmayın ( o zamanki map[key]gibi yazılması gerekenlerin aksine map?api.get(key)).

2.3.25'ten önce standart çözüm şöyleydi:

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

Bununla birlikte, bazı gerçekten eski FreeMarker entegrasyonları, genel Mapyöntemlerin (gibi getClass) anahtar olarak göründüğü garip bir yapılandırma kullanır . Bu , mülkiyeti açık bırakılan bir saf BeansWrapper(yerine DefaultObjectWrapper) kullandıkları için olur . Yöntemleri gerçek girdilerle karıştırdığı için böyle bir kurulumdan kaçınmalısınız . Böyle talihsiz kurulum haline çalıştırırsanız Fakat durum kaçmak için bir yol gibi, maruz Java yöntemleri kullanıyor , gibi şablon dil yapılarını kullanmayın, vb değil ya .simpleMapWrapperfalseMapuser.entrySet()user.get(key)?keysuser[key]


Bu mükemmel çalışıyor. Ancak, springsource IDE'de hatalar görüyorum. Nasıl düzeltileceğine dair bir fikrin var mı? Teşekkürler
harshavmb

@harshavmb Hangi hatalar? Eski bir FreeMarker sürümüyle birlikte gelen eski bir FreeMarker eklentisi kullanıyor mu?
ddekany

Öyle düşünmeyin. Jboss araçlarından en son sürümünü indirmiş olun. Başka bir makinede deneyeceğim ve size haber vereceğim.
harshavmb

@harshavmb Benzer bir şey ${x?nosuchthing}girerseniz ve üzerine gelirseniz, gösterilen hata mesajı hangi FreeMarker sürümünü kullandığını söyleyecektir. Olmalı 2.3.25-incubating.
ddekany

garip, Mac'te yeni denedim ve sorunu tekrarlayamadım. Sorun yalnızca sanal makinemle ilgili görünüyor. Jar versiyonuna bir göz atacağım. Ancak, bu yalnızca editördeki bir hatadır, ancak kod doğru şekilde çalıştırılmıştır.
harshavmb

12

Expose.SAFE veya Expose.ALL maruz kalma seviyesine sahip bir BeansWrapper kullanıyorsanız , giriş kümesini yinelemenin standart Java yaklaşımı kullanılabilir:

Örneğin, Freemarker'da aşağıdakiler çalışacaktır (en azından sürüm 2.3.19'dan beri):

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

Örneğin, Struts2'de BeanWrapper'ın bir uzantısı, bu tür bir yinelemeye izin vermek için varsayılan poz seviyesi ile kullanılır.


3
Bunu gerçekten denedin mi? Çünkü InvalidReferenceExceptionçalışırken denediğimde bir aldım map?keys.
kdgregory

4
Bu, yalnızca freemarker.ext.beans.BeansWrappernesne sarmalayıcı olarak kullanıldığında işe yarar. Aksi takdirde Maps, otomatik olarak SimpleHashdesteklemeyen bir nesneye sarılır #entrySet(). (bkz. freemarker.sourceforge.net/docs/api/freemarker/template/… )
Koraktor

Haklısınız ve cevabımı yorumunuzu yansıtacak şekilde güncelledim. İyi bak!
rees

1
BeanWrapper ile Spring Freemarker çözücüyü kullanıyorsanız, özellikle FTL içinde oluşturulan karma için yukarıdakiler o kadar iyi çalışmayacaktır. Ftl dosyasında bildirilen hash sarmalanmaz ve hala? Anahtarları kullanılarak yinelenebilir bir hash olacaktır.
09

1
Pure BeansWrapper, en azından varsayılanları olduğu yerde simpleMapWrapperkullanmayın false. Anahtarları yöntem isimleriyle karıştırdığı için çok kafa karıştırıcı oluyor. Çağırmanız gerekirse entrySet(), varsayılan gibi "temiz" bir nesne sarmalayıcı kullanmaya devam edin map?api.entrySet()ve anahtarlar yerine Java API'ye erişmeniz gerekiyorsa yazın.
ddekany

2

Yinelenen Nesneler

Harita anahtarlarınız bir nesne ise ve bir dizge değilse, Freemarker'ı kullanarak onu yineleyebilirsiniz.

1) Haritayı kontrol cihazında bir listeye dönüştürün:

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

2) Anahtardaki nesneye ve Değerdeki Nesneye erişerek Freemarker şablonundaki haritayı yineleyin:

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

1

Tamlık için, yakın zamandan beri Freemarker'da boş koleksiyonların iyi bir şekilde ele alındığından bahsetmeye değer.

Bir haritayı yinelemenin en uygun yolu şudur:

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

Artık <#if ...>sarmalayıcı yok .


En iyi cevap. Teşekkür ederim.
egemen

0

Java programınızda belirlediğiniz anahtara erişmek için tek bir alıntı kullanabilirsiniz.

Java'da bunun gibi bir Harita ayarlarsanız

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);

Daha sonra Freemarker'daki 'hash' üyelerine şöyle erişebilirsiniz -

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

Çıktı :

a
b

bu, tek tek anahtarların nasıl ele alınacağını gösterir, ancak soru nasıl yineleneceğini sorar
Lambart
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.