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

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

需求描述

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

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

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

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

如图像这样

代码实现

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 实现多表关联查询的更多相关文章

  1. SpringBoot中使用Spring Data Jpa 实现简单的动态查询的两种方法

    软件152 尹以操 首先谢谢大佬的简书文章:http://www.jianshu.com/p/45ad65690e33# 这篇文章中讲的是spring中使用spring data jpa,使用了xml ...

  2. 【hql】spring data jpa中 @Query使用hql查询 问题

    spring data jpa中 @Query使用hql查询 问题 使用hql查询, 1.from后面跟的是实体类 不是数据表名 2.字段应该用实体类中的字段 而不是数据表中的属性 实体如下 hql使 ...

  3. spring data jpa 使用方法命名规则查询

    按照Spring Data JPA 定义的规则,查询方法以findBy开头,涉及条件查询时,条件的属性用条件关键字连接,要注意的是:条件属性首字母需大写.框架在进行方法名解析时,会先把方法名多余的前缀 ...

  4. 使用Spring Data JPA的Specification构建数据库查询

    Spring Data JPA最为优秀的特性就是可以通过自定义方法名称生成查询来轻松创建查询SQL.Spring Data JPA提供了一个Repository编程模型,最简单的方式就是通过扩展Jpa ...

  5. spring data jpa 使用JPQL的方式查询

    用Spring Data JPA提供的查询方法已经可以解决大部分的应用场景,但是对于某些业务来说,我们还需要灵活的构造查询条件,这时就可以使用@Query注解,结合JPQL的语句方式完成查询 @Que ...

  6. Spring Data JPA 复杂/多条件组合查询

    1: 编写DAO类或接口  dao类/接口 需继承 public interface JpaSpecificationExecutor<T> 接口: 如果需要分页,还可继承 public ...

  7. Spring data Jpa 分页从1开始,查询方法兼容 Mybatis,分页参数兼容Jqgrid

    废话少说 有参数可以设置 在org.springframework.boot.autoconfigure.data.web.SpringDataWebProperties 中 /** * Whethe ...

  8. 【spring data jpa】带有条件的查询后分页和不带条件查询后分页实现

    一.不带有动态条件的查询 分页的实现 实例代码: controller:返回的是Page<>对象 @Controller @RequestMapping(value = "/eg ...

  9. spring data jpa之Auditing 表的创建时间,更新时间自动生成策略

    java实际编程中,几乎每一张表都会有createTime和updateTime字段,spring的优秀之处在于只要用几个注解,就帮我们解决该类问题,具体实现: 1,实体类添加注解: @EntityL ...

随机推荐

  1. [USACO16JAN]子共七Subsequences Summing to Sevens

    [USACO16JAN]子共七Subsequences Summing to Sevensa[i]表示前缀和如果a[i]%7==t&&a[j]%7==t那么a[j]-a[i-1]一定是 ...

  2. git初级浅入其常用操作

    1. git init 我们从初始化一个仓库开始,通过此命令可以初始化一个仓库 git init 首先我们在当前目录下创建一个目录pratice和一个文件test.js mkdir pratice c ...

  3. SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30001ms.

    SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after ...

  4. centos7 静默安装oracle

    系统centos7.4 mini 关闭selinux.firewalld 配置主机名: hostnamectl set-hostname  --static oracle 之前说oracle不认cen ...

  5. 解决apache上访问 cgi脚本时总是在网页中显示出脚本的源代码而不是执行结果的问题

    apache是支持cgi脚本的,但是需要保证四个条件: 1.放置cgi脚本的文件夹本身需要对apache服务器这个用户(一般默认用户名是www,linux下的用户机制请自行百度)开放x(即可执行)权限 ...

  6. web实践小项目<一>:简单日程管理系统(涉及html/css,javascript,python,sql,日期处理)

    暑假自学了些html/css,javascript和python,苦于学完无处练手几乎过目即忘...最后在同学的建议下做了个简单日程管理系统.借第一版完成之际,希望能将实践期间犯过的错误和获得的新知进 ...

  7. 1257: [CQOI2007]余数之和

    题目链接 bzoj1257: [CQOI2007]余数之和 题解 数论分块,乘等差数列求和 代码 #include<bits/stdc++.h> using namespace std; ...

  8. ROS知识(20)----SLAM资源集合

    1.各种最新开源的SLAM a.OpenSLAM.这里收集了各种最新的开源SLAM资料,包含了比如: ORB_SLAM, ORB_SLAM2, hector_slam,ethzasl_ptam,g2o ...

  9. linux_远程copy

    1:远程copy [linux对linux 远程拷贝]   scp 文件名 root@远程ip:/路径/   将本地home目录下的test.tar的文件拷贝到远程主机192.168.1.23的/ho ...

  10. 关于java中的锁(转)

    对于锁一直处于比较模糊的状态,最近一天晚上偶然想看看,就翻了几本书,然后弄明白了一些概念,有一些仍然没明白,例如AQS,先把搞明白的记录一下吧. 什么是线程安全? 当多个线程访问一个对象时,如果不用考 ...