Java 如何使用 Hibernate 在 Spring Boot 中实现分页

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32434058/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 12:32:06  来源:igfitidea点击:

How to implement pagination in spring boot with hibernate

javahibernatepaginationspring-boothql

提问by Nadeem Ahmed

I am using spring boot with hibernate and I want to use pagination in my project. I have searched on google and saw many examples but I am unable to implement it in my project.

我正在将 Spring Boot 与 Hibernate 一起使用,并且我想在我的项目中使用分页。我在谷歌上搜索并看到了很多例子,但我无法在我的项目中实现它。

I want like if I pass 1 in my url then 10 results should come and if I pass 2 then next 10 results should come and so on.

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

Here is my my Dao

这是我的我的

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

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

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

Here is my Controller

这是我的控制器

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

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

And here is my url:

这是我的网址:

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

Please suggest.

请建议。

采纳答案by artle

Check it. Your controller

核实。您的控制器

@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;
}

Your dao

你的道

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

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

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

回答by Ithar

I would consider using org.springframework.data.domain.Pageabledirectly into your controller. This object can then be passed to your JPA layer where it will handle the number of returned results and the size.

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

The great thing about using Pageableis that it returns a Pageobject which can be used on the front-end to form previous/next page logic.

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

By default this class uses url parameters 'page' and 'size'; hence page=0&size=10 will return the first 10 items.

默认情况下,此类使用 url 参数“页面”和“大小”;因此 page=0&size=10 将返回前 10 个项目。

Hence in your case the code could look something like:

因此,在您的情况下,代码可能如下所示:

@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();
}

Notice the annotation @PageableDefaultis just to set up the defaults & it's not required.

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

In the front-end the next page call can be <a href="/top/pages?page=1">Next</a>; this will return a list of Posts from 11 to 20.

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

回答by jeet singh parmar

Implement pagination in Spring Boot is quite easy only you need to follow basic steps -

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

1 - Extends PagingAndSortingRepository in repository interface

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

public interface UserRepository extends PagingAndSortingRepository <User, Long> 

2 - Method declaration should be like below example

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

Page<User> userList(Pageable pageable);

3 - Method implementation in Service class should be like below example

3 - Service 类中的方法实现应该像下面的例子

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

4 - Controller class code should be like below

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";
}

From front-end call should be like below

从前端调用应该如下所示

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

For more details watch below video

有关更多详细信息,请观看下面的视频

Spring Boot : Pagination Basic

Spring Boot:分页基础

Spring Boot : Pagination Advanced

Spring Boot:分页高级

Thanks for reading

谢谢阅读

回答by Manas Ranjan Mahapatra

How to Implement Dynamic Pagination Using a Native Query

如何使用本机查询实现动态分页

Here, you can find the repository and service layers and your data transfer object (DTO), which will be used for mapping our result and sending it to the controller layer.

在这里,您可以找到存储库和服务层以及您的数据传输对象 (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 translates your query as follows:

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;
    }
}

Pros and ConsPros: Fewer SQL queries will be generated, compared to using Spring Data. These complex queries cannot be written in Spring Data, and we have to specify our query as a native one, which can still be paged by using this methodology.

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

Cons: The "object" array must map to a Java object. It is painful and hard to maintain.

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

How to Implement OffsetLimit Pagination With Spring Data As far as I know, there is no "out-of-the-box" support for what you need in default Spring Data repositories. But you can create a custom implementation of Pageable objects that will take limit/offset parameters.

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

Make a pageable object and pass it to PaginationAndSortingRepository:

创建一个可分页对象并将其传递给 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;
    }
    ....
}

It means there is no need to change the repository layer. The only change you would need is to make is to the service layer, as follows:

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

@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();
    }
}

Note that you don't need to map the result manually, and it will take off a good amount of time from development.

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

回答by Senthuran

I have implemented pagination in spring boot. Below is my Repository.

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

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

Below is my Controller.

下面是我的控制器。

@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";
    }
}

Below is the view,for that I have used thymeleaf.

下面是视图,为此我使用了百里香叶。

<!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>