Spring Data JPA 实现多表关联查询

最近抽出时间来做博客,数据库操作使用的是 JPA,相对比 Mybatis 而言,JPA 单表操作非常方便,增删改查都已经写好了。但是多表操作就不如 Mybatis 那种直接写 sql 语句来得方便,JPA 的多表操作比较麻烦。

 

需求描述

获得文章列表,文章列表里需要显示每篇文章的分类目录列表,因为一个文章可能有多个分类,一个分类当然也可以对应多篇文章的。

 

下面是我用截图软件画的一个图,描述的是三张表和其主要字段。

Spring Data JPA 实现多表关联查询

 

文章表 article 和分类表 category 通过 中间表 article_category 关联

 

我们的需求也很简单,从数据库里查询所有文章,并给每篇文章加一个分类列表的属性。

如图像这样

Spring Data JPA 实现多表关联查询

 

代码实现

Spring Data JPA 需要的依赖和配置文件这里就不给出了,因为不是本文的重点。

 

实体类

1、实体类 Article.java

  1. package com.liuyanzhao.blog.entity;
  2. import javax.persistence.*;
  3. import java.io.Serializable;
  4. import java.util.Date;
  5. import java.util.Set;
  6. /**
  7.  * @author 言曌
  8.  * @date 2017/12/11 下午7:46
  9.  */
  10. @Entity
  11. @Table(name = "article")
  12. public class Article implements Serializable {
  13.     private static final long serialVersionUID = 7419229779731522702L;
  14.     @Id
  15.     @GeneratedValue(strategy = GenerationType.IDENTITY)
  16.     private Integer id;
  17.     @Lob//text
  18.     @Column(columnDefinition="text")
  19.     private String title;
  20.     @Lob //longtext
  21.     @Column(columnDefinition="longtext")
  22.     private String content;
  23.     private Integer userId;
  24.     private Integer likeCount;
  25.     private Date createTime;
  26.     private Date updateTime;
  27.     private Integer status;
  28.     @OneToMany(mappedBy = "article",cascade = CascadeType.ALL, orphanRemoval = true)
  29.     private Set<ArticleCategory> articleCategoryList;
  30.     public Integer getId() {
  31.         return id;
  32.     }
  33.     public void setId(Integer id) {
  34.         this.id = id;
  35.     }
  36.     public String getTitle() {
  37.         return title;
  38.     }
  39.     public void setTitle(String title) {
  40.         this.title = title;
  41.     }
  42.     public String getContent() {
  43.         return content;
  44.     }
  45.     public void setContent(String content) {
  46.         this.content = content;
  47.     }
  48.     public Integer getUserId() {
  49.         return userId;
  50.     }
  51.     public void setUserId(Integer userId) {
  52.         this.userId = userId;
  53.     }
  54.     public Integer getLikeCount() {
  55.         return likeCount;
  56.     }
  57.     public void setLikeCount(Integer likeCount) {
  58.         this.likeCount = likeCount;
  59.     }
  60.     public Date getCreateTime() {
  61.         return createTime;
  62.     }
  63.     public void setCreateTime(Date createTime) {
  64.         this.createTime = createTime;
  65.     }
  66.     public Date getUpdateTime() {
  67.         return updateTime;
  68.     }
  69.     public void setUpdateTime(Date updateTime) {
  70.         this.updateTime = updateTime;
  71.     }
  72.     public Integer getStatus() {
  73.         return status;
  74.     }
  75.     public void setStatus(Integer status) {
  76.         this.status = status;
  77.     }
  78.     public static long getSerialVersionUID() {
  79.         return serialVersionUID;
  80.     }
  81.     public Set<ArticleCategory> getArticleCategoryList() {
  82.         return articleCategoryList;
  83.     }
  84.     public void setArticleCategoryList(Set<ArticleCategory> articleCategoryList) {
  85.         this.articleCategoryList = articleCategoryList;
  86.     }
  87. }

注意 43-44 行

 

2、实体类 Category.java

  1. package com.liuyanzhao.blog.entity;
  2. import javax.persistence.*;
  3. import java.io.Serializable;
  4. import java.util.Set;
  5. /**
  6.  * @author 言曌
  7.  * @date 2017/12/11 下午8:16
  8.  */
  9. @Entity
  10. @Table(name = "category")
  11. public class Category implements Serializable {
  12.     private static final long serialVersionUID = 7419229779731522702L;
  13.     @Id
  14.     @GeneratedValue(strategy = GenerationType.IDENTITY)
  15.     private Integer id;
  16.     private String name;
  17.     private String key;
  18.     private Integer status;
  19.     @OneToMany(mappedBy = "category")
  20.     private Set<ArticleCategory> articleCategoryList;
  21.     public Integer getId() {
  22.         return id;
  23.     }
  24.     public void setId(Integer id) {
  25.         this.id = id;
  26.     }
  27.     public String getName() {
  28.         return name;
  29.     }
  30.     public void setName(String name) {
  31.         this.name = name;
  32.     }
  33.     public Integer getStatus() {
  34.         return status;
  35.     }
  36.     public void setStatus(Integer status) {
  37.         this.status = status;
  38.     }
  39.     public String getKey() {
  40.         return key;
  41.     }
  42.     public void setKey(String key) {
  43.         this.key = key;
  44.     }
  45.     public static long getSerialVersionUID() {
  46.         return serialVersionUID;
  47.     }
  48.     public Set<ArticleCategory> getArticleCategoryList() {
  49.         return articleCategoryList;
  50.     }
  51.     public void setArticleCategoryList(Set<ArticleCategory> articleCategoryList) {
  52.         this.articleCategoryList = articleCategoryList;
  53.     }
  54. }

注意 28-29 行

 

 

3、实体类 ArticleCategory.java

  1. package com.liuyanzhao.blog.entity;
  2. import javax.persistence.*;
  3. import java.io.Serializable;
  4. /**
  5.  * @author 言曌
  6.  * @date 2017/12/12 下午4:08
  7.  */
  8. @Entity
  9. @Table(name = "article_category")
  10. public class ArticleCategory implements Serializable {
  11.     private static final long serialVersionUID = 7419229779731522702L;
  12.     @Id
  13.     @ManyToOne
  14.     @JoinColumn(name = "article_id")
  15.     private Article article;
  16.     @Id
  17.     @ManyToOne
  18.     @JoinColumn(name = "category_id")
  19.     private Category category;
  20.     public static long getSerialVersionUID() {
  21.         return serialVersionUID;
  22.     }
  23.     public Article getArticle() {
  24.         return article;
  25.     }
  26.     public void setArticle(Article article) {
  27.         this.article = article;
  28.     }
  29.     public Category getCategory() {
  30.         return category;
  31.     }
  32.     public void setCategory(Category category) {
  33.         this.category = category;
  34.     }
  35. }

注意 17-25 行

 

Dao 层

1、ArticleDao.java

  1. package com.liuyanzhao.blog.dao;
  2. import com.liuyanzhao.blog.entity.Article;
  3. import com.liuyanzhao.blog.vo.ArticleVO;
  4. import org.springframework.data.domain.Page;
  5. import org.springframework.data.domain.Pageable;
  6. import org.springframework.data.jpa.repository.JpaRepository;
  7. /**
  8.  * @author 言曌
  9.  * @date 2017/11/28 下午3:31
  10.  */
  11. public interface ArticleDao extends JpaRepository<Article, Integer> {
  12.     //获取文章列表,按status和id降序
  13.     Page<ArticleVO> findAllByOrderByStatusDescIdDesc(Pageable pageable);
  14. }

 

2、CategoryDao.java

  1. package com.liuyanzhao.blog.dao;
  2. import com.liuyanzhao.blog.entity.Category;
  3. import org.springframework.data.jpa.repository.JpaRepository;
  4. /**
  5.  * @author 言曌
  6.  * @date 2017/12/12 上午11:16
  7.  */
  8. public interface CategoryDao  extends JpaRepository<Category, Integer> {
  9. }

 

Service 层

1、ArticleService.java

  1. package com.liuyanzhao.blog.service;
  2. import com.liuyanzhao.blog.vo.ArticleVO;
  3. import org.springframework.data.domain.Page;
  4. import org.springframework.data.domain.Pageable;
  5. /**
  6.  * @author 言曌
  7.  * @date 2017/12/9 下午4:10
  8.  */
  9. public interface ArticleService {
  10.     //获得文章列表
  11.     Page<ArticleVO> findAll(Pageable pageable);
  12. }

 

2、ArticleServiceImpl.java

  1. package com.liuyanzhao.blog.service.Impl;
  2. import com.liuyanzhao.blog.dao.ArticleDao;
  3. import com.liuyanzhao.blog.service.ArticleService;
  4. import com.liuyanzhao.blog.vo.ArticleVO;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.data.domain.Page;
  7. import org.springframework.data.domain.Pageable;
  8. import org.springframework.stereotype.Service;
  9. import javax.transaction.Transactional;
  10. /**
  11.  * @author 言曌
  12.  * @date 2017/12/9 下午4:10
  13.  */
  14. @Service("articleService")
  15. @Transactional
  16. public class ArticleServiceImpl implements ArticleService {
  17.     @Autowired
  18.     private ArticleDao articleDao;
  19.     @Override
  20.     public Page<ArticleVO> findAll(Pageable pageable) {
  21.         Page<ArticleVO> articleVOPage = articleDao.findAllByOrderByStatusDescIdDesc(pageable);
  22.         return articleVOPage;
  23.     }
  24. }

 

 

Controller 层

ArticleController.java

  1. package com.liuyanzhao.blog.controller;
  2. import com.liuyanzhao.blog.service.ArticleService;
  3. import com.liuyanzhao.blog.vo.ArticleVO;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.data.domain.Page;
  6. import org.springframework.data.domain.PageRequest;
  7. import org.springframework.stereotype.Controller;
  8. import org.springframework.web.bind.annotation.*;
  9. import org.springframework.web.servlet.ModelAndView;
  10. /**
  11.  * @author 言曌
  12.  * @date 2017/11/28 下午3:33
  13.  */
  14. @Controller
  15. public class ArticleController {
  16.     @Autowired
  17.     private ArticleService articleService;
  18.     @RequestMapping(value = "/admin/article")
  19.     public ModelAndView listUser(@RequestParam(value = "page",defaultValue = "1") Integer page,
  20.                                  @RequestParam(value = "size",defaultValue = "10") Integer size) {
  21.         ModelAndView modelAndView = new ModelAndView();
  22.         PageRequest request = new PageRequest(page-1,size);
  23.         Page<ArticleVO> articleVOPage = articleService.findAll(request);
  24.         modelAndView.addObject("articleVOPage",articleVOPage);
  25.         modelAndView.setViewName("/admin/article/list");
  26.         return modelAndView;
  27.     }
  28. }

 

视图层

视图层主要看表格的打印吧,分页部分和其他内容就不贴出来了

  1. <table class="table table-bordered">
  2.           <tr>
  3.               <th><input type="checkbox" id="allSelect" onclick="DoCheck()"></th>
  4.               <th>ID</th>
  5.               <th>作者</th>
  6.               <th>标题</th>
  7.               <th>分类</th>
  8.               <th>更新时间</th>
  9.               <th>操作</th>
  10.           </tr>
  11.           <c:forEach var="article" items="${articleVOPage.content}">
  12.               <tr>
  13.                   <td><input type="checkbox" name="ids" value="${article.id}"></td>
  14.                   <td>${article.id}</td>
  15.                   <td>${article.userId}</td>
  16.                   <td><a href="">${article.title}</a></td>
  17.                   <td>
  18.                       <c:forEach var="c" items="${article.articleCategoryList}">
  19.                           <a href="">${c.category.name}</a> &nbsp;
  20.                       </c:forEach>
  21.                   </td>
  22.                   <td>${article.updateTime}</td>
  23.                   <td>
  24.                       <a href="${pageContext.request.contextPath}/admin/user/profile/${article.id}">
  25.                           <button type="button" class="btn btn-success btn-xs">查看</button>
  26.                       </a>
  27.                       <button type="button" class="btn btn-danger btn-xs"
  28.                               onclick="deleteUser(${article.id})">删除
  29.                       </button>
  30.                       <a href="${pageContext.request.contextPath}/admin/user/edit/${article.id}">
  31.                           <button type="button" class="btn btn-primary btn-xs">编辑</button>
  32.                       </a>
  33.                   </td>
  34.               </tr>
  35.           </c:forEach>
  36.       </table>

 

最终效果图就是上面的

Spring Data JPA 实现多表关联查询

 

 

本文地址:https://liuyanzhao.com/6978.html

  • 微信
  • 交流学习,有偿服务
  • weinxin
  • 博客/Java交流群
  • 资源分享,问题解决,技术交流。群号:590480292
  • weinxin
言曌

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

目前评论:3   其中:访客  3   博主  0

    • avatar 阿雄

      是我的那个版本不对把,我的springboot是2.0的,博主这个打字的效果,真的好看,IDEA的插件Power Model2没你这个好看

      • avatar 阿雄

        博主,为什么我这样,启动的时候,会报错啊,category表没有建出来,报关联外键id,category_id失败,我在yml配置表引擎是InnoDB,能给我解惑吗?

        • avatar Ediaos

          测试一下