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

Spring Data JPA如何编写按分类查询书籍的Query?原有查询无数据如何解决

问题核心错误点
  • 原生SQL关联条件错误:你写的JOIN条件为b.name = c.id,把书籍名称和分类ID做关联,逻辑完全不成立。Book表关联Category的外键是categoryid字段,需要用该字段关联Category表的id
  • 变量命名逻辑混乱:Controller里把查到的书籍列表存到了名为category的Model属性里,Thymeleaf遍历的时候又把每个Book对象当成Category使用,展示逻辑完全错位
  • 路径映射不匹配:Controller的GetMapping路径是/{category},但Thymeleaf里跳转的路径是/category/{id},路径不匹配会触发404错误
修复方案

1. 修正BookRepo的查询语句

提供三种可选方案,优先推荐JPA自动生成查询的写法:

方案1:方法名自动生成查询(无需手动写SQL)

// Spring Data JPA会自动根据方法名生成符合规则的查询语句
List<Book> findByCategory_Id(Integer categoryId);

方案2:JPQL查询

@Query("SELECT b FROM Book b WHERE b.category.id = :categoryId")
List<Book> findBookByCategory(@Param("categoryId") Integer categoryId);

方案3:修正后的原生SQL查询

@Query(value = "SELECT b.* FROM book b INNER JOIN category c on b.categoryid = c.id WHERE c.id = ?1", nativeQuery = true)
List<Book> findBookByCategory(Integer categoryId);

2. 修正Controller代码

// 路径改为和Thymeleaf跳转匹配的/category前缀
@GetMapping("/category/{categoryId}")
public String getBookByCategory(@PathVariable("categoryId") Integer categoryId, Model model, HttpSession session) {
    List<Book> bookList = bookService.findBookByCategory(categoryId);
    
    if(bookList == null || bookList.isEmpty()) {
        session.setAttribute("message", new MessageResponse("Không có Sách","danger"));
    }
    // 分别存储分类下的书籍列表,以及全部分类列表(渲染分类菜单需要查询所有分类)
    model.addAttribute("bookList", bookList);
    // 补充查询所有分类的逻辑,用于渲染左侧分类菜单
    List<Category> categoryList = categoryService.findAll();
    model.addAttribute("categoryList", categoryList);
    return "home/category";
}

3. 修正Thymeleaf视图代码

<!-- 渲染分类菜单部分 -->
<h4 class="text-uppercase font-weight-bold mb-3">Thể Loại</h4>
<div class="mt-2 mb-2 pl-2 ">
  <div class="custom-control" th:each="category : ${categoryList}" th:value="${category.id}">
      <h5>
          <a class="btn btn-info popovers" th:href="@{/category/{id}(id=${category.id})}"  >[[${category.name}]]</a>
      </h5>
  </div>
</div>

<!-- 渲染当前分类下的书籍列表 -->
<div th:if="${!bookList.isEmpty()}">
  <div th:each="book : ${bookList}">
    <p>书籍名称:[[${book.name}]]</p>
    <p>书籍描述:[[${book.description}]]</p>
  </div>
</div>
<p th:if="${bookList.isEmpty()}" class="text-danger">暂无该分类下的书籍</p>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 05:45:03