JSTL<c:forEach>中如何修改自定义EL排序函数实现多字段切换排序
现有方案可行性评估
- 新增排序标志位传递给Servlet:可行,但不建议将排序逻辑和Servlet耦合,也不要写重复的渲染代码
- JSP添加
<% %>脚本:完全不推荐,脚本代码和页面逻辑耦合,不符合代码规范,后期维护难度极高 - JSTL
<c:if>判断写多套遍历逻辑:可行但冗余,多套完全相同的渲染代码仅排序方法不同,后续迭代需要修改展示字段时要同步修改多处,复用性极差
最优实现方案
第一步:改造ListEntitySort工具类,新增通用排序方法
不用单独编写sortById、sortByTitle等独立方法,新增一个接收排序类型参数的通用方法即可,同时保留原有方法兼容旧逻辑:
public final class ListEntitySort { private static final Comparator<Entity> COMPARE_BY_TIME = Comparator.comparing(Entity::getTime); private static final Comparator<Entity> COMPARE_BY_ID = Comparator.comparingLong(Entity::getId); private static final Comparator<Entity> COMPARE_BY_TITLE = Comparator.comparing(Entity::getTitle, String.CASE_INSENSITIVE_ORDER); // 原有方法保留,兼容旧代码 public static List<Entity> sortByTime(List<Entity> events) { events.sort(COMPARE_BY_TIME); return events; } // 新增通用排序方法 public static List<Entity> sort(List<Entity> events, String sortType) { if (events == null || sortType == null) { return events; } switch (sortType) { case "id": events.sort(COMPARE_BY_ID); break; case "title": events.sort(COMPARE_BY_TITLE); break; case "time": default: events.sort(COMPARE_BY_TIME); } return events; } }
第二步:在function.tld中新增通用排序函数的注册配置
<function> <name>sort</name> <function-class>ua.com.example.web.command.functions.ListEntitySort</function-class> <function-signature>java.util.List sort(java.util.List, java.lang.String)</function-signature> </function>
第三步:Servlet接收排序参数并透传到JSP
前端排序切换按钮发起请求时带上sort参数,比如请求地址?sort=id、请求地址?sort=title,Servlet中直接将参数存入request域即可:
List<Entity> entities = someService.getListEntities(); request.setAttribute("entities", entities); // 无参数时默认按时间排序 String sortType = request.getParameter("sort") == null ? "time" : request.getParameter("sort"); request.setAttribute("sortType", sortType);
第四步:修改JSP遍历逻辑,无需重复编写渲染代码
仅修改c:forEach的items属性即可,不用调整其他渲染逻辑:
<c:forEach var="entity" items="${p:sort(entities, sortType)}"> <tr> <td>${entity.id}</td> <td>${entity.title}</td> <td>${entity.description}</td> <td>${entity.location}</td> <td>${p:formatLocalDateTime(entity.time, 'dd-MM-yyyy HH:mm')}</td> </tr> </c:forEach>
后续如果需要支持正序/倒序切换,仅需参照上面的逻辑,给通用排序方法新增第三个参数控制排序方向即可,不需要改动其他业务代码。
内容的提问来源于stack exchange,提问作者Semkov Stanislav
相关产品推荐
相关产品推荐

