Sort list of objects in Velocity template - Liferay

寵の児 提交于 2019-12-13 16:06:46

问题


I've created a structure in Liferay as below

<root>
      <dynamic-element name='header' type='text' index-type='' repeatable='true'>
        <dynamic-element name='headerlink' type='text' index-type='' repeatable='false'>       </dynamic-element>
        <dynamic-element name='location' type='text' index-type='' repeatable='false'>  </dynamic-element>
        <dynamic-element name='description' type='text_box' index-type='' repeatable='false'>  </dynamic-element>
        <dynamic-element name='date' type='text' index-type='' repeatable='false'></dynamic-element>
      </dynamic-element>
</root>

Now header repeatable block, I have 4-5 element blocks as same. Each one of have different "date" value inside it. "date" is simple text type. date format is (dd/mm/yyyy)

Now I want to display all the element in sorting order based on the date entered.

My template is as below.

<ul>
                #set($count = 0)
                #foreach( $nm in $header.getSiblings())
                    #set($content="content"+$count)
                    <li id="$content">
                        <div class="event">
                        #set($monthnameid="month"+$count)
                        #set($dayid="day"+$count)
                        <p class="date-section">
                            <span class="month" id="$monthnameid">$nm.date.data</span>
                            <span class="date" id="$dayid"></span>
                        </p>
                        <p class="event-detail-section">
                            #if($nm.headerlink.data !="")
                                <span class="event-title"><a class="event-link" href="$nm.headerlink.data">$nm.data</a></span>
                            #else
                                <span class="event-header">$nm.data</span>
                            #end

                            #if($nm.description.data.toString().length() >100)
                                <span class="event-description">$nm.description.data.toString().substring(0,100)</span>
                            #else
                                <span class="event-description">$nm.description.data.toString()</span>
                            #end
                            <span class="event-location">Location: $nm.location.data</span>
                        </p>
                    </div>
                </li>
                #set($count = $count +1)
            #end
            </ul>

I am not aware regarding how can we sort object inside velocity.

Any help on this would be much appreciated.


回答1:


You can create utility jar and put it in servers lib folder so that it it is available to all applications.

You need to create java project, put code from below in it (modify to your needs).
Export it to jar and copy it to the server. Restart your server if it is running.

package com.tejas.liferay.util.cms;

import java.text.SimpleDateFormat;
import java.util.Comparator;
import java.util.Date;
import java.util.Map;

public final class DateComparator implements Comparator<Object> {

    private String m_node = null;
    private String m_sort = null;
    private String m_format = null;

    public DateComparator(final String p_node, final String p_sort, final String p_format) {
        m_node = p_node;
        m_sort = p_sort;
        m_format = p_format;
    }

    public static DateComparator newInstance(final String p_node, final String p_sort, final String p_format) {
        return new DateComparator(p_node, p_sort, p_format);
    }

    public int compare(Object p_object1, Object p_object2) {
        final Date date1 = getDate((Map) p_object1, m_node);
        final Date date2 = getDate((Map) p_object2, m_node);

        if ("asc".equalsIgnoreCase(m_sort)) {
            return compareAsc(date1, date2);
        } else if ("desc".equalsIgnoreCase(m_sort)) {
            return compareDesc(date1, date2);
        }

        return 0;
    }

    public int compareDesc(Date p_date1, Date p_date2) {

        if (p_date1 == null) {
            return -1;
        }

        if (p_date2 == null) {
            return 1;
        }

        return (p_date1.compareTo(p_date2) * -1);
    }

    public int compareAsc(Date p_date1, Date p_date2) {

        if (p_date1 == null) {
            return -1;
        }

        if (p_date2 == null) {
            return 1;
        }

        return (p_date1.compareTo(p_date2));
    }

    private Date getDate(final Map p_map, final String p_node) {
        final Map map = (Map) p_map.get(p_node);
        if (map == null) {
            return null;
        }
        final String dateStr = (String) map.get("data");

        final Date date1 = parseDate(dateStr, m_format);
        return date1;
    }

    public static Date parseDate(final String p_string, final String p_format) {
        if (p_string == null) {
            return null;
        }

        final SimpleDateFormat sdf = new SimpleDateFormat(p_format);

        try {
            return sdf.parse(p_string);
        } catch (Exception e) {
            // do you error handeling
        }

        return null;
    }
}

Than update your velocity template so that on top it has

#set($comparator = $portal.getClass().forName("com.tejas.liferay.util.cms.DateComparator").getMethod("newInstance", $portal.getClass().forName("java.lang.String"), $portal.getClass().forName("java.lang.String"), $portal.getClass().forName("java.lang.String")).invoke(null, "date", "asc", "dd/MM/yyyy"))
#set($void = $portal.getClass().forName("java.util.Collections").getMethod("sort", $portal.getClass().forName("java.util.List"), $portal.getClass().forName("java.util.Comparator")).invoke(null, $header.getSiblings(), $comparator))

than goes original content from you template.

Notice end of first velocity line

invoke(null, "date", "asc", "dd/MM/yyyy"))

"date" is the name of the field that holds your date, "asc" is sort parameter (it can be "desc") and last parameter is date format.

UPDATE:
Second of two velocity lines from above was showing in rendered html, so I've updated to not be shown :)

UPDATE: For additional question in comment

Add additional class to your jar (from above)

package com.tejas.liferay.util.cms;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;

public final class VelocityUtil {

    private VelocityUtil() {
        // utility class
    }

    public static void filterOlderThanTodayFromListAndSort(final List<Map<String, Map<String, ?>>> p_list, final String p_dateFieldName, final String p_dateFormat, final String p_sort) {
        filterOlderThanTodayFromList(p_list, p_dateFieldName, p_dateFormat);
        Collections.sort(p_list, new DateComparator(p_dateFieldName, p_sort, p_dateFormat));
    }

    public static void filterOlderThanTodayFromList(final List<Map<String, Map<String, ?>>> p_list, final String p_dateFieldName, final String p_dateFormat) {
        final Date todayMidnight = getTodayMidnight();

        for (int i = p_list.size() - 1; i >= 0; i--) {
            Map<String, Map<String, ?>> map = p_list.get(i);
            final Date date = getDate(map, p_dateFieldName, p_dateFormat);
            if (todayMidnight.after(date)) {
                p_list.remove(i);
            }
        }
    }

    public static Date getTodayMidnight() {
        final Calendar calendar = Calendar.getInstance(Locale.getDefault());
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.HOUR_OF_DAY, 0);

        final Date todayMidnight = calendar.getTime();
        return todayMidnight;
    }

    public static Date getDate(final Map<String, Map<String, ?>> p_map, final String p_dateFieldName, final String p_dateFormat) {
        final Map<String, ?> map = p_map.get(p_dateFieldName);
        if (map == null) {
            return null;
        }
        final String dateStr = (String) map.get("data");

        final Date date1 = parseDate(dateStr, p_dateFormat);
        return date1;
    }

    public static Date parseDate(final String p_string, final String p_format) {
        if (p_string == null) {
            return null;
        }

        final SimpleDateFormat sdf = new SimpleDateFormat(p_format, Locale.getDefault());

        try {
            return sdf.parse(p_string);
        } catch (Exception e) {
            // do you error handeling
        }

        return null;
    }
}

and in velocity template put

#set($classString = $portal.getClass().forName("java.lang.String"))
#set($classList = $portal.getClass().forName("java.util.List"))
#set($classComparator = $portal.getClass().forName("java.util.Comparator"))

#set($void = $portal.getClass().forName("com.tejas.liferay.util.cms.VelocityUtil").getMethod("filterOlderThanTodayFromList", $classList, $classString, $classString).invoke(null, $header.getSiblings(), "date", "dd/MM/yyyy"))

Assuming $header.getSiblings() is list that you want to filter.




回答2:


I had good results with the Velocity $sortTool. An example can be found here at the bottom of the page http://www.liferay.com/community/forums/-/message_boards/message/11146823 The helparray can not be avoided.

Since your dates don't have the format yyyyMMdd you also need $dateTool.toDate to put the date in the array as a Comparable.



来源:https://stackoverflow.com/questions/7670646/sort-list-of-objects-in-velocity-template-liferay

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!