You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何按嵌套的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&amp;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>&nbsp;</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处理排序:

  1. 先修改HTML的Last Meeting列,添加排序链接:
<th><span><a th:href="@{'/ines/employeePage/' + ${currentPage} + '?sortField=latestMeeting&amp;sortDir=' + ${reverseSortDir}}">
    Last Meeting</a></span>
</th>
  1. 修改控制器中的排序逻辑:
@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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 04:21:48