Pytanie Freemarker iteruje klucze hashmap


Freemarker ma dwa typy danych kolekcji, listy i hashmapy Czy istnieje sposób na iterację kluczy hashmap, tak jak robimy to z listami?

Więc jeśli mam var z danymi, powiedzmy:

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

Chciałbym wydrukować wszystkie właściwości użytkownika z ich wartością. Jest to nieprawidłowe, ale cel jest jasny:

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

76
2017-09-30 12:22


pochodzenie




Odpowiedzi:


Edytować: Nie używaj tego rozwiązania z FreeMarker 2.3.25 i nowszymi, szczególnie nie .get(prop). Zobacz inne odpowiedzi.

Używasz wbudowanego klawiatura funkcja, np. to powinno działać:

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

94
2017-09-30 12:27



składnia jest inna w najnowszej wersji, co ilustruje link zamieszczony w mojej odpowiedzi. Rozumiem, że to stare pytanie, ale pojawia się wysoko w Google. - Nick Spacek
tylko notatkę - możesz użyć ${user[prop]} jako skrót - Bozho
Jest to wyciek wydajności: dla każdego klucza musi pobrać wartość. Iterowanie przez entrySet () nie ma tego problemu. - Geoffrey De Smet
powinno być $ {user [prop]} - dns
To $ {map [key]}, patrz freemarker.org/docs/ref_builtins_hash.html - david_p


FYI, wygląda na to, że składnia pobierania wartości zmieniła się zgodnie z:

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>

47
2018-03-30 17:24



Czym różni się ta składnia? - Parker
Myślę, że to było .get, które już nie działało. - Nick Spacek
dobra odpowiedź ;-) zauważ, że podczas drukowania wartości może być konieczne sprawdzenie zerowej wartości, <#if h [klucz] ??> $ {klucz} = $ {h [klucz]}; </ # if> - Brad Parks
Składnia nie została zmieniona. Obie [key] i .get(key) istnieje od czasów starożytnych. .get(key) nie jest żadnym specjalnym dla FTL, to po prostu wywołanie tej publicznej metody Javy. Ale możesz go użyć tylko wtedy, gdy FreeMarker został skonfigurowany do wyświetlania Map metody. - ddekany
Podczas iteracji uzyskuję metody (getClass, hashCode, equals, get, toString, class) ... jednak nie widzę żadnej z właściwości takich jak "id", dlatego chcę uzyskać listę. Wszelkie sugestie, jak uzyskać tę listę właściwości innych niż metody z tego skrótu? Muszę znać te nazwy właściwości. : | - MaxRocket


Od wersji 2.3.25 wykonaj to tak:

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

Zauważ, że działa to również z kluczami innymi niż łańcuchowe (w przeciwieństwie do map[key], który musiał być napisany jako map?api.get(key) następnie).

Przed 2.3.25 standardowym rozwiązaniem było:

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

Jednak niektóre naprawdę stare wersje FreeMarker używają dziwnej konfiguracji, w której publiczność Map metody (np getClass) pojawiają się jako klucze. Tak się dzieje, gdy używają czystej BeansWrapper (zamiast DefaultObjectWrapper), którego simpleMapWrapper nieruchomość została pozostawiona false. Powinieneś unikać takiej konfiguracji, ponieważ łączy ona metody z rzeczywistością Map wpisy. Ale jeśli natkniesz się na tak niefortunną konfigurację, sposobem na uniknięcie sytuacji jest wykorzystanie wyeksponowanych metod Java, takich jak user.entrySet(), user.get(key)itp., a nie przy użyciu takich konstrukcji języka szablonów jak ?keys lub user[key].


24
2017-07-08 17:25



To działa idealnie. Ale widzę błędy w źródle IDE. Masz pomysł, jak to naprawić? Dzięki - harshavmb
@harshavmb Jakie błędy? Czy może użyć przestarzałej wtyczki FreeMarker, która pochodzi ze starą wersją FreeMarker? - ddekany
Nie sądzę. Pobrałem najnowszą wersję z narzędzi jboss. Spróbuję na innej maszynie i dam ci znać. - harshavmb
@harshavmb Jeśli wpiszesz coś podobnego ${x?nosuchthing} i najedziesz na niego, wyświetlony komunikat o błędzie pokaże, której wersji FreeMarker używa. Powinno być 2.3.25-incubating. - ddekany
dziwne, po prostu próbowałem na Macu i nie mogłem powtórzyć problemu. Problem wydaje się być tylko z moim vm. Popatrzę na wersję słoika. Jednak jest to po prostu błąd w edytorze, ale kod został wykonany poprawnie. - harshavmb


Jeśli używasz BeansWrapper przy poziomie ekspozycji Expose.SAFE lub Expose.ALL można zastosować standardowe podejście Java do iteracji zestawu wpisów:

Na przykład następujące elementy będą działały w Freemarker (od co najmniej wersji 2.3.19):

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

Na przykład w Struts2 rozszerzenie BeanWrapper jest używany z poziomem ekspozycji domyślnym, aby umożliwić ten sposób iteracji.


12
2018-05-07 14:48



Czy próbowałeś tego? Ponieważ dostałem InvalidReferenceException kiedy próbowałem, podczas gdy map?keys pracował. - kdgregory
Działa to tylko podczas używania freemarker.ext.beans.BeansWrapper jako wrapper obiektu. Inaczej Maps zostanie automatycznie zawinięte w SimpleHash obiekt, który nie obsługuje #entrySet(). (widzieć freemarker.sourceforge.net/docs/api/freemarker/template/...) - Koraktor
Masz rację i zaktualizowałem swoją odpowiedź, aby odzwierciedlić Twój komentarz. Dobrze wyglądać! - rees
Powyższe nie będzie działało tak dobrze dla hasza utworzonego wewnątrz FTL, szczególnie jeśli używasz Spring Freemarker resolver z BeanWrapper. Skrót zadeklarowany w pliku Ftl nie jest zawijany i nadal będzie tylko hashowalnym klawiszem. - skipy
Nie używaj czystego BeansWrapper, przynajmniej nie z ustawieniami domyślnymi, gdzie simpleMapWrapper jest false. To staje się bardzo mylące, ponieważ miesza klucze z nazwami metod. Jeśli chcesz zadzwonić entrySet(), po prostu używaj "czystego" opakowania obiektu, takiego jak domyślny, i pisz map?api.entrySet() jeśli potrzebujesz dostępu do API Java zamiast kluczy. - ddekany


Iterowanie obiektów

Jeśli twoje klucze map są obiektem, a nie ciągiem, możesz go iterować za pomocą Freemarker.

1) Konwertuj mapę na listę w kontrolerze:

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

2) Iteruj mapę w szablonie Freemarker, uzyskując dostęp do obiektu w kluczu i obiektu w wartości:

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

2
2018-06-20 08:42





Można użyć pojedynczego cudzysłowu, aby uzyskać dostęp do klucza ustawionego w programie Java.

Jeśli ustawisz Mapę w Javie w ten sposób

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

Następnie możesz uzyskać dostęp do członków 'hash' w Freemarker w ten sposób -

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

Wyjście:

a
b

1
2018-03-19 18:28



pokazuje, jak adresować poszczególne klucze, ale pytanie pyta, jak wykonać iterację - Lambart


Podsumowując, warto wspomnieć, że od niedawna w Freemarker jest porządna obsługa pustych kolekcji.

Najwygodniejszym sposobem na iterację mapy jest:

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

Już nie <#if ...> opakowania.


0
2017-07-23 16:09