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

Spring Boot自定义CRUD查询问题:家务追踪应用适配Thymeleaf

解决Completion实体与ID参数的CRUD适配问题

1. 先确认实体类的关联配置是否正确

首先确保你的Completion实体类中,Person和Chore字段的关联注解配置正确,明确指定数据库对应的外键列:

@Entity
@Table(name = "completion")
public class Completion {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "person_id", nullable = false) // 对应数据库person_id外键
    private Person person;

    @ManyToOne
    @JoinColumn(name = "chore_id", nullable = false) // 对应数据库chore_id外键
    private Chore chore;

    // 其他业务字段(如完成时间)、getter/setter、构造方法
}

2. 修正CompletionRepository的查询方法

针对传入的long类型ID参数,有两种简单可行的实现方式:

方式一:利用Spring Data JPA方法命名规则

直接定义符合规则的方法,JPA会自动生成对应的SQL逻辑:

public interface CompletionRepository extends JpaRepository<Completion, Long> {
    // 根据person_id和chore_id查询单条完成记录
    Optional<Completion> findByPersonIdAndChoreId(Long personId, Long choreId);

    // 根据person_id查询该用户的所有完成记录
    List<Completion> findByPersonId(Long personId);

    // 根据chore_id查询该家务的所有完成记录
    List<Completion> findByChoreId(Long choreId);
}

方式二:使用@Query注解自定义JPQL

如果需要更复杂的查询逻辑,可通过JPQL直接关联实体ID字段:

public interface CompletionRepository extends JpaRepository<Completion, Long> {
    @Query("SELECT c FROM Completion c WHERE c.person.id = :personId AND c.chore.id = :choreId")
    Optional<Completion> findByPersonIdAndChoreId(@Param("personId") Long personId, @Param("choreId") Long choreId);
}

3. 完善Service层逻辑

在CompletionService实现类中,直接调用Repository方法即可,无需手动转换实体对象:

@Service
public class CompletionServiceImpl implements CompletionService {
    private final CompletionRepository completionRepository;
    private final PersonRepository personRepository;
    private final ChoreRepository choreRepository;

    // 构造注入依赖
    public CompletionServiceImpl(CompletionRepository completionRepository,
                                 PersonRepository personRepository,
                                 ChoreRepository choreRepository) {
        this.completionRepository = completionRepository;
        this.personRepository = personRepository;
        this.choreRepository = choreRepository;
    }

    @Override
    public Optional<Completion> getCompletionByPersonAndChoreIds(Long personId, Long choreId) {
        return completionRepository.findByPersonIdAndChoreId(personId, choreId);
    }

    @Override
    public List<Completion> getCompletionsByPersonId(Long personId) {
        return completionRepository.findByPersonId(personId);
    }

    // 新增完成记录示例
    @Override
    public Completion saveCompletion(Long personId, Long choreId, LocalDateTime completedAt) {
        // 先校验并获取关联实体
        Person person = personRepository.findById(personId)
                .orElseThrow(() -> new IllegalArgumentException("不存在该ID的用户"));
        Chore chore = choreRepository.findById(choreId)
                .orElseThrow(() -> new IllegalArgumentException("不存在该ID的家务"));
        
        Completion completion = new Completion();
        completion.setPerson(person);
        completion.setChore(chore);
        completion.setCompletedAt(completedAt);
        return completionRepository.save(completion);
    }
}

4. Controller层传递数据到Thymeleaf

在Controller中接收前端传入的ID参数,调用Service获取数据后渲染到页面:

@Controller
@RequestMapping("/completions")
public class CompletionController {
    private final CompletionService completionService;

    public CompletionController(CompletionService completionService) {
        this.completionService = completionService;
    }

    @GetMapping("/person/{personId}")
    public String getCompletionsByPerson(@PathVariable Long personId, Model model) {
        List<Completion> completions = completionService.getCompletionsByPersonId(personId);
        model.addAttribute("completions", completions);
        return "completion-list"; // 对应Thymeleaf模板文件名
    }

    // 新增完成记录的提交接口
    @PostMapping("/add")
    public String addCompletion(@RequestParam Long personId, @RequestParam Long choreId) {
        completionService.saveCompletion(personId, choreId, LocalDateTime.now());
        return "redirect:/completions/person/" + personId;
    }
}

5. Thymeleaf页面渲染示例

在completion-list.html中遍历数据展示:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>用户家务完成记录</title>
</head>
<body>
    <h1>用户家务完成记录</h1>
    <table>
        <tr>
            <th>用户名</th>
            <th>家务名称</th>
            <th>完成时间</th>
        </tr>
        <tr th:each="completion : ${completions}">
            <td th:text="${completion.person.name}"></td>
            <td th:text="${completion.chore.name}"></td>
            <td th:text="${#temporals.format(completion.completedAt, 'yyyy-MM-dd HH:mm')}"></td>
        </tr>
    </table>
</body>
</html>

内容的提问来源于stack exchange,提问作者dave_m

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 15:01:24