2013-08-28 83 views
10

我正在开发一个使用Spring + Thymeleaf的简单应用程序。在其中一页上,我有一份需要分页的项目清单。Spring + Thymeleaf - 如何实现列表分页

理想情况下,我只想向视图发送currPageNo(当前页面的编号)和numOfPages(总页数)变量,剩下的工作将在那里完成(这是一个演示文稿问题并且与业务逻辑无关)。但是,如果最干净的解决方案首先要求我在控制器中进行一些计算,那么我会认为它是一个小小的邪恶。

我想以下面的形式获取页面列表。

<Prev | 1 | ... | 3 | 4 | 5 | 6 | 7 | ... | 15 | Next> 

我只能用以下解决方案来。它的工作原理,但我相信你会同意这是非常混乱,真的很难阅读。

此外,除了currPageNonumOfPages我不得不再发送两个变量到视图。理想的解决方案不会要求我这样做。

firstPageNo = Math.max(2, currPageNo - 2) 
lastPageNo = Math.min(numOfPages - 1, currPageNo + 2) 

我的代码的当前版本如下。

<ul> 
    <li th:if="${currPageNo &gt; 1}"> 
     <a th:href="@{/items.html(pageNo = ${currPageNo - 1})}" href="">&lt; Prev</a> 
    </li> 
    <li th:class="${currPageNo == 1} ? 'selected'"> 
     <a th:href="@{/items.html(pageNo = 1)}" th:if="${currPageNo &gt; 1}" href="">1</a> 
     <span th:if="${currPageNo == 1}">1</span> 
    </li> 
    <li th:if="${currPageNo &gt;= 5}"> 
     ... 
    </li> 
    <li th:each="pageNo : ${#numbers.sequence(firstPageNo, lastPageNo)}" th:class="${currPageNo == pageNo} ? 'selected'"> 
     <a th:href="@{/items.html(pageNo = ${pageNo})}" th:if="${pageNo != currPageNo}" th:text="${pageNo}" href="">2</a> 
     <span th:if="${pageNo == currPageNo}" th:text="${pageNo}">2</span> 
    </li> 
    <li th:if="${currPageNo &lt;= (numOfPages - 4)}"> 
     ... 
    </li> 
    <li th:class="${currPageNo == numOfPages} ? 'selected'"> 
     <a th:href="@{/items.html(pageNo = ${numOfPages})}" th:if="${currPageNo &lt; numOfPages}" th:text="${numOfPages}" href="">10</a> 
     <span th:if="${currPageNo == numOfPages}" th:text="${numOfPages}">1</span> 
    </li> 
    <li th:if="${currPageNo &lt; numOfPages}"> 
     <a th:href="@{/items.html(pageNo = ${currPageNo + 1})}" href=""> Next &gt;</a> 
    </li> 
</ul> 

以下列表详细列出了我想摆脱最多的问题。我明白其中一些是平台所固有的,但仍然是,这个列表似乎很长,代码很杂乱。

  • 必须将预先计算的值firstPageNolastPageNo发送到控制器的视图。
  • 必须在表达式中使用&lt;而不是<
  • 必须使用具有互斥条件的锚点和跨度,以便浏览器不要为当前页面使用链接。

我也欢迎任何其他有关如何提高代码质量的建议。


我明白,也许这个问题将是一个更适合的代码审查现场,但作为Thymeleaf似乎是一个很小的用户群的技术还没有,我期待一个合理的答案,而在这里堆栈溢出,它有更大的用户群(我相信)。

但是,如果真的不欢迎这样的问题,请考虑将它移到正确的网站而不是关闭它,以便我得到我需要的建议。

回答

2

另一种选择是Ben Thurley的解决方案。我们已经实现了它,它运行平稳:http://bthurley.wordpress.com/2012/07/18/spring-mvc-with-restful-datatables/

它缺少项目的筛选器参数,但您可以通过PagingCriteria对象轻松添加项目,并确保将其添加到TableParamArgumentResolver中。

public class TableParamArgumentResolver implements WebArgumentResolver { 

    private static final String S_ECHO   = "sEcho"; 
    private static final String I_DISPLAY_START = "iDisplayStart"; 
    private static final String I_DISPLAY_LENGTH = "iDisplayLength"; 
    private static final String I_SORTING_COLS = "iSortingCols"; 

    private static final String I_SORT_COLS  = "iSortCol_"; 
    private static final String S_SORT_DIR  = "sSortDir_"; 
    private static final String S_DATA_PROP  = "mDataProp_"; 
    private static final String I_DATA_SEARCH = "sSearch"; 

    public Object resolveArgument(MethodParameter param, NativeWebRequest request) 
      throws Exception { 
     TableParam tableParamAnnotation = param.getParameterAnnotation(TableParam.class); 

     if (tableParamAnnotation != null) { 
      HttpServletRequest httpRequest = (HttpServletRequest) request.getNativeRequest(); 

      String sEcho = httpRequest.getParameter(S_ECHO); 
      String sDisplayStart = httpRequest.getParameter(I_DISPLAY_START); 
      String sDisplayLength = httpRequest.getParameter(I_DISPLAY_LENGTH); 
      String sSortingCols = httpRequest.getParameter(I_SORTING_COLS); 
      String sSearch = httpRequest.getParameter(I_DATA_SEARCH); 

      Integer iEcho = Integer.parseInt(sEcho); 
      Integer iDisplayStart = Integer.parseInt(sDisplayStart); 
      Integer iDisplayLength = Integer.parseInt(sDisplayLength); 
      Integer iSortingCols = Integer.parseInt(sSortingCols); 

      List<SortField> sortFields = new ArrayList<SortField>(); 
      for (int colCount = 0; colCount < iSortingCols; colCount++) { 
       String sSortCol = httpRequest.getParameter(I_SORT_COLS + colCount); 
       String sSortDir = httpRequest.getParameter(S_SORT_DIR + colCount); 
       String sColName = httpRequest.getParameter(S_DATA_PROP + sSortCol); 
       sortFields.add(new SortField(sColName, sSortDir)); 
      } 

      PagingCriteria pc = new PagingCriteria(iDisplayStart, iDisplayLength, iEcho, sortFields, sSearch); 

      return pc; 
     } 

     return WebArgumentResolver.UNRESOLVED; 
    } 
} 
18

来解决类似的 http://www.javacodegeeks.com/2013/03/implement-bootstrap-pagination-with-spring-data-and-thymeleaf.html

,但没有使用了Spring可分页包装说明

<div class="table-pagination"> 
    <ul class="pagination"> 
     <li th:class="${contactsPage.number eq 0} ? 'disabled' : ''"> 
      <a th:if="${not contactsPage.firstPage}" th:href="@{${'/contacts'}(page=${contactsPage.number-1},size=${contactsPage.size})}">Previous</a> 
      <a th:if="${contactsPage.firstPage}" href="javascript:void(0);">Previous</a> 
     </li> 

     <li th:each="pageNo : ${#numbers.sequence(0, contactsPage.totalPages - 1)}" th:class="${contactsPage.number eq pageNo}? 'active' : ''"> 
      <a th:if="${contactsPage.number eq pageNo}" href="javascript:void(0);"> 
       <span th:text="${pageNo + 1}"></span> 
      </a> 
      <a th:if="${not (contactsPage.number eq pageNo)}" th:href="@{${'/contacts'}(page=${pageNo},size=${contactsPage.size})}"> 
       <span th:text="${pageNo + 1}"></span> 
      </a> 

     </li> 
     <li th:class="${contactsPage.number + 1 ge contactsPage.totalPages} ? 'disabled' : ''"> 
      <a th:if="${not contactsPage.lastPage}" th:href="@{${'/contacts'}(page=${contactsPage.number+1},size=${contactsPage.size})}">Next</a> 
      <a th:if="${contactsPage.lastPage}" href="javascript:void(0);">Next</a> 
     </li> 
    </ul> 
</div> 
+2

请附上一些文字,例如带有代码的解释。 –

+2

不要只是转储代码...并添加一些肉。 – Werner

+1

注意到现在,您必须用'first'和'last'替换'firstPage'和'lastPage'。 – membersound

1

我有这个几乎准备就绪,希望它可以帮助....

<div class="tag-box tag-box-v7 text-justify"> 
    <div class="text-center"> 
     <ul class="pagination" th:with="elementsperpage=2, blocksize=10, pages=${page2th.Number}/${elementsperpage}, wholepages=${format.format(pages)}, 
whole=(${page2th.Number}/${blocksize})+1, wholex=${format.format(whole)}, startnlockpage=${wholepages}*${blocksize+1}, endblockpage=${wholepages}*${blocksize+1}, 
startpage=${wholex-1}*${blocksize}, endpage=(${wholex}*${blocksize})+1"> 

      <li> 
       <a th:if="${startpage gt 0}" th:href="@{${'/viewannouncements?p='}+${startpage}}">&lt;&lt;</a> 
       <a th:if="${startpage eq 0}" href="javascript:void(0);">&lt;&lt;</a> 
      </li> 

      <li th:each="pageNo : ${#numbers.sequence(endpage-11, (endpage lt page2th.TotalPages)? endpage-2 : page2th.TotalPages-1)}" 
      th:class="${page2th.Number eq pageNo}? 'active' : ''"> 
        <a th:if="${page2th.Number eq pageNo}" href="javascript:void(0);"> 
         <span th:text="${pageNo + 1}"></span> 
        </a> 
        <a th:if="${not (page2th.Number eq pageNo)}" th:href="@{${'/viewannouncements?p='}+${pageNo+1}}"> 
         <span th:text="${pageNo + 1}"></span> 
        </a> 
      </li> 

      <li> 
       <a th:if="${(endpage*elementsperpage) le (page2th.TotalElements)}" th:href="@{${'/viewannouncements?p='}+${endpage}}">&gt;&gt;</a> 
       <a th:if="${(endpage*elementsperpage) le (page2th.TotalElements)}" href="javascript:void(0);"></a> 
      </li> 



     </ul> 
    </div> 
</div>