如何使用hibernate在spring boot中实现分页

     2023-02-26     51

关键词:

【中文标题】如何使用hibernate在spring boot中实现分页【英文标题】:How to implement pagination in spring boot with hibernate 【发布时间】:2015-12-02 17:41:44 【问题描述】:

我正在使用带有休眠功能的 Spring Boot,并且我想在我的项目中使用分页。我在谷歌上搜索并看到了很多例子,但我无法在我的项目中实现它。

我希望如果我在我的 url 中传递 1,那么应该有 10 个结果,如果我传递 2,那么接下来应该有 10 个结果,依此类推。

这是我的

@Transactional
public interface PostDao extends CrudRepository<Post, Long>

@Query(getAllPostsByRank)
List<Post> getAllPostsByRank();

final String getAllPostsByRank= "from Post order by value DESC";

这是我的控制器

@RequestMapping("/top")
    @ResponseBody 
     public List<Post> getAllPosts(HttpServletRequest req, HttpServletResponse res) throws ServletException 

List<Post> postobj = postDao.getAllPostsByRank();
return postobj;

这是我的网址:

http://localhost:8888/v1.0/post/top/1

请提出建议。

【问题讨论】:

你试过 PagingAndSortingRepository 吗? (docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/…) 没有没有尝试.. 因为我是新来的 Spring Boot,所以无法理解 你能编辑我的代码吗? Custom Query in Spring JPA Repository with Pagination的可能重复 【参考方案1】:

我会考虑在您的控制器中直接使用org.springframework.data.domain.Pageable。然后可以将此对象传递给您的 JPA 层,在那里它将处理返回结果的数量和大小。

使用Pageable 的好处在于它返回一个Page 对象,可以在前端使用该对象来形成上一页/下一页逻辑。

默认这个类使用url参数'page'和'size';因此 page=0&size=10 将返回前 10 个项目。

因此,在您的情况下,代码可能类似于:

@ResponseBody
@RequestMapping("/top/pages/")
public List<Post> getAllPosts(@PageableDefault(value=10, page=0) Pageable pageable) throws ServletException 
    Page page = postDao.findAll(pageable);
    return page.getContent();

注意注释@PageableDefault 只是设置默认值,不是必需的。

在前端下一页调用可以是&lt;a href="/top/pages?page=1"&gt;Next&lt;/a&gt;;这将返回从 11 到 20 的帖子列表。

【讨论】:

这应该是默认答案!在 Spring Boot 中执行此操作的正确方法。 如果我使用 DTO 作为返回,我应该如何将它映射到实体,以便在存储库中查询,使用这个“Pageable”接口? 我不确定你到底是什么意思;但是 org.springframework.data.domain.Page 包装了 DTO 的内容,因此您可以使用 page.getContent()。在我的示例中,您可以将 Post 视为 DTO,并通过 Page&lt;Post&gt; page = new PageImpl&lt;&gt;(typedQuery.getResultList(), pageable, totalRows); 完成创建 不起作用:org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.domain.Pageable]: Specified class is an interface @mpr 你确定这是因为在你的方法中添加了Pageable 参数。这很奇怪,因为它不应该引起BeanInstantiationException【参考方案2】:

在 Spring Boot 中实现分页非常简单,只需遵循基本步骤 -

1 - 在存储库接口中扩展 PagingAndSortingRepository

public interface UserRepository extends PagingAndSortingRepository <User, Long> 

2 - 方法声明应该像下面的例子

Page<User> userList(Pageable pageable);

3 - Service 类中的方法实现应如下例所示

@Override
public Page<User> userList(Pageable pageable) 
        return userRepository.findAll(pageable);

4 - 控制器类代码应如下所示

@GetMapping("/list")
public String userList(Model model, Pageable pageable) 
        Page<User> pages = userService.userList(pageable);
        model.addAttribute("number", pages.getNumber());
        model.addAttribute("totalPages", pages.getTotalPages());
        model.addAttribute("totalElements",       
                                      pages.getTotalElements());
        model.addAttribute("size", pages.getSize());
        model.addAttribute("users", pages.getContent());
        return "/user/list";

来自前端的调用应该如下所示

http://localhost:8080/application/user/list?page=0&size=5
http://localhost:8080/application/user/list?page=1&size=5
http://localhost:8080/application/user/list?page=2&size=5

更多详情请观看以下视频

Spring Boot : Pagination Basic

Spring Boot : Pagination Advanced

感谢阅读

【讨论】:

谢谢,这是真正实用的解决方案。它对我有用【参考方案3】:

检查一下。你的控制器

@RequestMapping("/top/pages/pageno")
    @ResponseBody 
     public List<Post> getAllPosts(@PathVariable("pageno") int pageno, HttpServletRequest req, HttpServletResponse res) throws ServletException 

List<Post> postobj = postDao.getAllPostsByRank(new PageRequest(pageno,10));
return postobj;

你的道

@Transactional
public interface PostDao extends CrudRepository<Post, Long>

@Query(getAllPostsByRank)
List<Post> getAllPostsByRank(Pageable pageable);

final String getAllPostsByRank= "from Post order by value DESC";

【讨论】:

有趣的是,我刚刚使用from Foo order by id DESC 尝试了这个,它在启动时抛出了异常。 from Foo f order by id DESC 没有。 页面请求现已弃用。【参考方案4】:

我已经在 Spring Boot 中实现了分页。下面是我的存储库。

    @Repository("userRepository")
    public interface UserRepository extends PagingAndSortingRepository<User, Long> 
  

下面是我的控制器。

@Controller
public class SampleController 

    @Autowired
    private UserRepository repository;

    @GetMapping("/userview")
    public String getEmployees(@PageableDefault(size = 1) Pageable pageable,
                               Model model) 
        Page<User> page = repository.findAll(pageable);
        model.addAttribute("page", page);
        return "userdetail";
    

下面是视图,因为我用的是百里香。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<h2>USER DETAILS</h2>

<table class="table table-striped table-responsive-md">
    <thead>
    <tr>
        <th> ID </th>
        <th>Name</th>
        <th>Last Name</th>
        <th>Email</th>
        <th>Role</th>
    </tr>
    </thead>
    <tbody>
    <tr th:each="user : $page.content">
        <td th:text="$user.id"></td>
        <td th:text="$user.email"></td>
        <td th:text="$user.name"></td>
        <td th:text="$user.lastName"></td>
        <td th:text="$user.roles[0].role"></td>

    </tr>
    </tbody>
</table>

<div class="pagination-div">
    <span th:if="$page.hasPrevious()">
        <a th:href="@/userview(page=$page.number-1,size=$page.size)">Previous</a>
    </span>
    <th:block th:each="i: $#numbers.sequence(0, page.totalPages - 1)">
        <span th:if="$page.number == i" class="selected">[[$i+1]]</span>
        <span th:unless="$page.number == i">
             <a th:href="@/userview(page=$i,size=$page.size)">[[$i+1]]</a>
        </span>
    </th:block>
    <span th:if="$page.hasNext()">
        <a th:href="@/userview(page=$page.number+1,size=$page.size)">Next</a>
    </span>
</div>
</body>
</html>

【讨论】:

【参考方案5】:

如何使用原生查询实现动态分页

在这里,您可以找到存储库和服务层以及您的数据传输对象 (DTO),它们将用于映射我们的结果并将其发送到控制器层。

public interface CustomSomethingRepository 
    List<Something> findPagedResultBySomethingElseId(long somethingElseId, int offset, int limit);


public class SomethingRepositoryImpl implements CustomSomethingRepository 
    @Autowired
    private EntityManager em;

    @SuppressWarnings("unchecked")
    @Override
    public List<Something> findPagedResultBySomethingElseId(long somethingElseId, int offset, int limit) 
        String query = "select s.* from Something s "
                + "join somethingelse selse on selse.id = s.fk_somethingelse "
                + "where selse.id = :somethingElseId "
                + "order by selse.date";
        Query nativeQuery = em.createNativeQuery(query);
        nativeQuery.setParameter("somethingElseId", somethingElseId);
        //Paginering
        nativeQuery.setFirstResult(offset);
        nativeQuery.setMaxResults(limit);
        final List<Object[]> resultList = nativeQuery.getResultList();
        List<Something> somethingList = Lists.newArrayList();
        resultList.forEach(object -> somethingList.add(//map obj to something));
        return somethingList;
    

Hibernate 将您的查询翻译如下:

SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( select TOP(?) t as page0_ from Something s join s.somethingelse as selse order by selse.date ) inner_query ) SELECT page0_ FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?


@Service
public class SomethingService 
    private SomethingRepository somethingRepository;
    @Autowired
    public SomethingService(SomethingRepository somethingRepository)
        this.somethingRepository = somethingRepository;
    
    @Transactional(readOnly=true)
    public PageDto getSomething(long somethingElseId, int page, int size)
         List<Something> somethings = somethingRepository.findBySomethingElseId(somethingElseId, offset, limit);
        return new PagedResult<>(somethings
                .stream()
                .map(SomethingDto::createDto)
                .sorted(comparing(SomethingDto::getDatum))
                .collect(toList()), somethings.getTotalElements(), somethings.getTotalPages();
    

@Controller
//....
public class PagedResult<T> 
    public static final long DEFAULT_OFFSET = 0;
    public static final int DEFAULT_MAX_NO_OF_ROWS = 100;
    private int offset;
    private int limit;
    private long totalElements;
    private List<T> elements;
    public PagedResult(List<T> elements, long totalElements, int offset, int limit) 
        this.elements = elements;
        this.totalElements = totalElements;
        this.offset = offset;
        this.limit = limit;
    
    public boolean hasMore() 
        return totalElements > offset + limit;
    
    public boolean hasPrevious() 
        return offset > 0 && totalElements > 0;
    
    public long getTotalElements() 
        return totalElements;
    
    public int  getOffset() 
        return offset;
    
    public int getLimit() 
        return limit;
    
    public List<T> getElements() 
        return elements;
    

优点和缺点 优点:与使用 Spring Data 相比,将生成更少的 SQL 查询。这些复杂的查询不能用 Spring Data 编写,我们必须将我们的查询指定为原生查询,仍然可以使用这种方法进行分页。

缺点:“对象”数组必须映射到 Java 对象。这是痛苦且难以维持的。

如何使用 Spring Data 实现 OffsetLimit 分页 据我所知,默认 Spring Data 存储库中没有“开箱即用”的支持。但是您可以创建一个自定义实现 Pageable 对象,该对象将采用限制/偏移参数。

制作一个可分页对象并将其传递给 PaginationAndSortingRepository:

public class OffsetLimitRequest implements Pageable 
    private int limit;
    private int offset;
    public OffsetLimitRequest(int offset, int limit)
        this.limit = limit;
        this.offset = offset;
    
        @Override
    public int getPageNumber() 
        return 0;
    
    @Override
    public int getPageSize() 
        return limit;
    
    @Override
    public int getOffset() 
        return offset;
    
    ....

这意味着无需更改存储库层。您需要做的唯一更改是服务层,如下所示:

@Service
public class SomethingService 
    private SomethingRepository somethingRepository;
    @Autowired
    public SomethingService(SomethingRepository somethingRepository)
        this.somethingRepository = somethingRepository;
    
    @Transactional(readOnly=true)
    public PageDto getSomething(long somethingElseId, int page, int size)
        Page<Something> somethings = somethingRepository.findBySomethingElseId(somethingElseId, new OffsetLimitRequest(offset, limit));
        return new PageDto(somethings.getContent()
                .stream()
                .map(SomethingDto::createDto)
                .sorted(comparing(SomethingDto::getDatum))
                .collect(toList()), somethings.getTotalElements(), somethings.getTotalPages();
    

请注意,您不需要手动映射结果,这会占用大量开发时间。

【讨论】:

如何使用 Hibernate 在 Spring Boot 中处理数据库迁移?

】如何使用Hibernate在SpringBoot中处理数据库迁移?【英文标题】:HowtohandledatabasemigrationsinSpringBootwithHibernate?【发布时间】:2017-11-0506:40:45【问题描述】:我的数据库背景来自Django框架(python)。在Django中,开始进行数据库迁移很... 查看详情

如何在 Spring Boot 中使用 Hibernate/JPA 返回多级 json

】如何在SpringBoot中使用Hibernate/JPA返回多级json【英文标题】:HowcanIreturnmulti-leveljsonusingHibernate/JPAinSpringBoot【发布时间】:2018-04-0905:34:35【问题描述】:我有一个Postgres数据库,其中包含4个表Parent、Children、Groups和Group_Membership。... 查看详情

如何使用 Spring Boot 2.0 指定 Hibernate 映射?

】如何使用SpringBoot2.0指定Hibernate映射?【英文标题】:HowtospecifiyHibernatemappingswithSpringBoot2.0?【发布时间】:2017-10-1707:31:21【问题描述】:在SpringBoot1.x中,我们可以通过扩展HibernateJpaAutoConfiguration、覆盖LocalContainerEntityManagerFactoryB... 查看详情

如何通过使用 JPA + Hibernate 和 Spring-boot 在一个数据库中使用多个模式?

】如何通过使用JPA+Hibernate和Spring-boot在一个数据库中使用多个模式?【英文标题】:Howtousemultipleschema\'sinonedatabasebyusingJPA+HibernatewithSpring-boot?【发布时间】:2018-11-1812:48:44【问题描述】:我需要它在一个数据库(MySQL)中访问2个... 查看详情

如何在 Spring Boot 应用程序中使用 Hibernate 验证进行 Bean 验证?

】如何在SpringBoot应用程序中使用Hibernate验证进行Bean验证?【英文标题】:HowtodoBeanValidationwithHibernateValidationinSpringBootapp?【发布时间】:2020-09-2511:17:04【问题描述】:我正在学习SpringBoot应用程序中的Hibernate验证,并且我有一个Res... 查看详情

JTAC 在 Spring Boot 中是不是推荐与 Hibernate 一起使用

...。是否建议在此堆栈中使用JTA事务管理器?如果推荐JTA,如何在控制器或服务层以编程方式访 查看详情

如何使用 Hibernate/Spring boot 将 JSON 文件作为 JSON 数据类型存储在 mysql 中?

】如何使用Hibernate/Springboot将JSON文件作为JSON数据类型存储在mysql中?【英文标题】:HowtostoreJSONfileasaJSONdatatypeinmysqlusingHibernate/Springboot?【发布时间】:2020-05-1311:36:21【问题描述】:我尝试了几种将json文件存储在数据库中的方法... 查看详情

Hibernate 不使用 Spring boot 在 PostgreSql 中创建数据库

...据库的代码优先方法。但是,我还不能这样做。请建议我如何解决这个问题。这是我的POM<?xmlversion 查看详情

如何在spring boot和hibernate中计算特定id的记录

】如何在springboot和hibernate中计算特定id的记录【英文标题】:Howtocountrecordsofparticularidinspringbootandhibernate【发布时间】:2015-11-2504:07:17【问题描述】:我正在开发一个使用SpringBoot和Hibernate的项目。我想根据表中的id来计算记录。... 查看详情

如何知道 spring-boot 项目中使用了哪些版本的 hibernate/spring 数据?

】如何知道spring-boot项目中使用了哪些版本的hibernate/spring数据?【英文标题】:howtoknowwhichversionsofhibernate/springdataareusedinspring-bootproject?【发布时间】:2021-02-2809:53:43【问题描述】:我使用的是spring-boot项目,<parent><groupId>... 查看详情

如何使用 Hibernate 和 Spring Boot 配置和监控 HikariCP

】如何使用Hibernate和SpringBoot配置和监控HikariCP【英文标题】:HowtoconfigureandmonitorHikariCPwithHibernateandSpringBoot【发布时间】:2016-05-2115:17:54【问题描述】:我有一个简单的带有Hibernate的SpringBoot项目,我想知道我的HikariCP配置类和appli... 查看详情

grails3(spring-boot)-如何配置hibernate二级缓存

当尝试使用ehcache作为休眠二级缓存时,我得到以下异常:org.hibernate.cache.NoCacheRegionFactoryAvailableException:在应用程序中使用二级缓存,但是没有给出属性hibernate.cache.region.factory_class我试着在application.yml中配置它:spring:jpa:properties:... 查看详情

如何在不依赖数据库的情况下使用 Hibernate 5 (JPA) 启动 Spring Boot Application 2?

】如何在不依赖数据库的情况下使用Hibernate5(JPA)启动SpringBootApplication2?【英文标题】:HowtostartSpringBootApplication2withHibernate5(JPA)withoutdependingonDatabase?【发布时间】:2019-07-2211:40:17【问题描述】:首先:这不是一个重复的问题。4.5... 查看详情

如何在 Spring Boot 中自动装配 Hibernate SessionFactory

】如何在SpringBoot中自动装配HibernateSessionFactory【英文标题】:HowtoautowireHibernateSessionFactoryinSpringboot【发布时间】:2017-10-0906:56:27【问题描述】:我已经创建了一个SpringBoot应用程序,我想处理HibernateSessionFactory,所以在我的服务类... 查看详情

Spring Boot:在单元测试中使用 Hibernate Session

】SpringBoot:在单元测试中使用HibernateSession【英文标题】:SpringBoot:UseHibernateSessioninaunittest【发布时间】:2016-07-2314:09:17【问题描述】:在我的SpringBoot应用程序中,我访问我的Hibernate会话,如以下答案所示:https://***.com/a/33881946/2... 查看详情

无法使用 Hibernate 在 Spring Boot 中将 MongoDB 设置为自动递增

】无法使用Hibernate在SpringBoot中将MongoDB设置为自动递增【英文标题】:UnabletosetMongoDBtoautoincrementinSpringbootusingHibernate【发布时间】:2018-01-1717:27:16【问题描述】:我尝试使用此链接(CustomSequences)在SpringBootWeb应用程序中进行自动... 查看详情

在 Spring Boot 中使用 Hibernate 为 DAO 层配置单元测试

】在SpringBoot中使用Hibernate为DAO层配置单元测试【英文标题】:ConfigureUnittestingforDAOLayerwithHibernateinSpringBoot【发布时间】:2018-02-1109:31:34【问题描述】:我已经使用Springboot和Hibernate创建了一个应用程序,我想为其配置单元测试。... 查看详情

Spring Boot / JPA / Hibernate,如何根据 Spring 配置文件切换数据库供应商?

】SpringBoot/JPA/Hibernate,如何根据Spring配置文件切换数据库供应商?【英文标题】:SpringBoot/JPA/Hibernate,HowtoswitchdatabasevendoraccordingtoSpringprofile?【发布时间】:2017-02-1313:32:54【问题描述】:我正在使用SpringBoot/JPA/Hibernate。我想在localh... 查看详情