如何按嵌套的meetingStartDateTime对Employee列表降序排序?
问题:按员工最新会议日期排序员工列表
我是Spring和Thymeleaf新手,现有Employee对象列表,该对象与MeetingInfo存在一对多关联。页面展示的是每位员工仅包含最新会议的列表,现在需要将此列表按meetingStartDateTime从最新到最旧排序,尝试过重写compareTo方法,但不知道如何处理嵌套日期,求最佳实现方案。
补充信息
meetingStartDateTime是Java Date对象,实体字段定义如下:
@JsonDeserialize(using = LocalDateTimeDeserializer.class) @Column(name = "meeting_start_date_time") @DateTimeFormat(pattern = "dd/MM/yyyy h:mm a") private Date meetingStartDateTime;
现有代码
业务逻辑代码
@Override public List<Employee> getAllEmployeesWithLatestMeeting(List<Employee> employees) { List<Employee> newEmployeeList = new ArrayList<>(); for (Employee employee : employees) { Employee newEmployee = new Employee(); List<MeetingInfo> meetingInfo = new ArrayList<>(); Long id = employee.getEmployeeId(); String name = employee.getName(); MeetingInfo lastMeeting = getLatestMeetingById(id); meetingInfo.add(lastMeeting); newEmployee.setEmployeeId(id); newEmployee.setName(name); newEmployee.setMeetingInfo(meetingInfo); newEmployeeList.add(newEmployee); } return newEmployeeList; }
控制器代码(基础分页实现)
@GetMapping("/employeePage/{pageNo}") public String findEmployeePaginated(@PathVariable(value = "pageNo") int pageNo, @RequestParam("sortField") String sortField, @RequestParam("sortDir") String sortDir, Model model) { int pageSize = 5; Page<Employee> page = employeeService.findPaginated(pageNo, pageSize, sortField, sortDir); List<Employee> toSortEmployees = page.getContent(); model.addAttribute("currentPage", pageNo); model.addAttribute("totalPages", page.getTotalPages()); model.addAttribute("totalItems", page.getTotalElements()); model.addAttribute("sortField", sortField); model.addAttribute("sortDir", sortDir); model.addAttribute("reverseSortDir", sortDir.equals("asc") ? "desc" : "asc"); List<Employee> listEmployees = employeeService.getAllEmployeesWithLatestMeeting(toSortEmployees); model.addAttribute("listEmployees", listEmployees); return "meeting/home.html"; }
HTML页面代码
<thead> <tr> <th><span>Status</span></th> <th><span><a th:href="@{'/ines/employeePage/' + ${currentPage} + '?sortField=name&sortDir=' + ${reverseSortDir}}"> Employee</a></span> </th> <th><span>Last Meeting</span></th> <th><span>Message</span></th> <th><span>Add/View All/Delete</span></th> <th> </th> </tr> </thead> <tbody> <tr th:each="employee : ${listEmployees}"> <th:block th:each="latest : ${employee.meetingInfo}"> <td align="center"> <span th:switch="${latest.iconColor}"> <i th:case="Yellow" class="fa-solid fa-triangle-exclamation fa-2x" id="yellowWarning" title="3 months since last meeting"></i> <i th:case="Red" class="fa-solid fa-triangle-exclamation fa-2x" id="redWarning" title="6 months since last meeting"></i> <i th:case="Green" class="fa-solid fa-circle-check fa-2x" id="greenWarning" title="Under 3 months since last meeting"></i> </span> </td> <td th:text="${employee.name}"></td> <td th:text="${#calendars.format(latest.meetingStartDateTime,'EEE, d MMM yyyy HH:mm:ss')}"></td> <td th:text="${#strings.abbreviate(latest.message,60)}"></td> </th:block>
解决方案
方案1:在业务逻辑中直接排序
修改getAllEmployeesWithLatestMeeting方法,在返回列表前通过Stream按最新会议日期倒序排序,同时处理空会议的情况:
@Override public List<Employee> getAllEmployeesWithLatestMeeting(List<Employee> employees) { List<Employee> newEmployeeList = new ArrayList<>(); for (Employee employee : employees) { Employee newEmployee = new Employee(); List<MeetingInfo> meetingInfo = new ArrayList<>(); Long id = employee.getEmployeeId(); String name = employee.getName(); MeetingInfo lastMeeting = getLatestMeetingById(id); if (lastMeeting != null) { meetingInfo.add(lastMeeting); } newEmployee.setEmployeeId(id); newEmployee.setName(name); newEmployee.setMeetingInfo(meetingInfo); newEmployeeList.add(newEmployee); } // 按最新会议日期倒序排序,无会议的排末尾 return newEmployeeList.stream() .sorted((e1, e2) -> { MeetingInfo m1 = e1.getMeetingInfo().isEmpty() ? null : e1.getMeetingInfo().get(0); MeetingInfo m2 = e2.getMeetingInfo().isEmpty() ? null : e2.getMeetingInfo().get(0); if (m1 == null && m2 == null) return 0; if (m1 == null) return 1; if (m2 == null) return -1; Date d1 = m1.getMeetingStartDateTime(); Date d2 = m2.getMeetingStartDateTime(); return d2.compareTo(d1); }) .collect(Collectors.toList()); }
方案2:结合分页参数支持动态排序
如果需要支持前端点击Last Meeting列切换排序方向,修改控制器逻辑,根据传入的sortField和sortDir处理排序:
- 先修改HTML的
Last Meeting列,添加排序链接:
<th><span><a th:href="@{'/ines/employeePage/' + ${currentPage} + '?sortField=latestMeeting&sortDir=' + ${reverseSortDir}}"> Last Meeting</a></span> </th>
- 修改控制器中的排序逻辑:
@GetMapping("/employeePage/{pageNo}") public String findEmployeePaginated(@PathVariable(value = "pageNo") int pageNo, @RequestParam("sortField") String sortField, @RequestParam("sortDir") String sortDir, Model model) { int pageSize = 5; Page<Employee> page = employeeService.findPaginated(pageNo, pageSize, sortField, sortDir); List<Employee> toSortEmployees = page.getContent(); model.addAttribute("currentPage", pageNo); model.addAttribute("totalPages", page.getTotalPages()); model.addAttribute("totalItems", page.getTotalElements()); model.addAttribute("sortField", sortField); model.addAttribute("sortDir", sortDir); model.addAttribute("reverseSortDir", sortDir.equals("asc") ? "desc" : "asc"); List<Employee> listEmployees = employeeService.getAllEmployeesWithLatestMeeting(toSortEmployees); // 根据排序字段处理 if ("latestMeeting".equals(sortField)) { listEmployees.sort((e1, e2) -> { MeetingInfo m1 = e1.getMeetingInfo().isEmpty() ? null : e1.getMeetingInfo().get(0); MeetingInfo m2 = e2.getMeetingInfo().isEmpty() ? null : e2.getMeetingInfo().get(0); if (m1 == null && m2 == null) return 0; if (m1 == null) return sortDir.equals("asc") ? 1 : -1; if (m2 == null) return sortDir.equals("asc") ? -1 : 1; Date d1 = m1.getMeetingStartDateTime(); Date d2 = m2.getMeetingStartDateTime(); return sortDir.equals("asc") ? d1.compareTo(d2) : d2.compareTo(d1); }); } else if ("name".equals(sortField)) { // 保留原有的姓名排序逻辑 listEmployees.sort((e1, e2) -> sortDir.equals("asc") ? e1.getName().compareTo(e2.getName()) : e2.getName().compareTo(e1.getName())); } model.addAttribute("listEmployees", listEmployees); return "meeting/home.html"; }
方案3:重写Employee的compareTo方法
如果要通过Comparable接口实现排序,重写Employee类的compareTo方法,注意只针对最新会议日期:
public class Employee implements Comparable<Employee> { // 其他字段和方法 @Override public int compareTo(Employee other) { MeetingInfo myLatest = this.getMeetingInfo().isEmpty() ? null : this.getMeetingInfo().get(0); MeetingInfo otherLatest = other.getMeetingInfo().isEmpty() ? null : other.getMeetingInfo().get(0); if (myLatest == null && otherLatest == null) return 0; if (myLatest == null) return 1; if (otherLatest == null) return -1; // 倒序排序,最新的在前 return otherLatest.getMeetingStartDateTime().compareTo(myLatest.getMeetingStartDateTime()); } }
之后在需要排序的地方直接调用Collections.sort(listEmployees);即可。
内容的提问来源于stack exchange,提问作者Kayd Anderson
相关产品推荐
相关产品推荐

