当前位置: 首页 > 知识库问答 >
问题:

react中的Spring Boot分页实现

有宏峻
2023-03-14

大家好!我希望你一切安好?

我目前正在开发一个简单的应用程序,以了解有关Spring Boot、Spring Security性、jpa和服务器端分页的更多信息。

我成功地构建了我的API,并且我有一个使用分页的控制器。为了使用这个API,我开发了一个反应应用程序,一切都可以按照我想要的方式工作(2FA,帐户创建,登录,忘记密码,更改密码,...)。

但现在,我想开发一个管理界面,在其中我希望能够管理用户帐户。

所以,我创建了一个控制器,它需要管理员角色和连接。为了返回用户列表,我使用了一个扩展分页和排序存储库的DAO,它工作得很好!

现在我想在react应用程序中实现这种分页,这就是我遇到的问题。

我为react尝试了许多分页库。但它们都需要恢复单个列表中的所有数据,这是我不想要的。所以,我开始开发自己的分页组件。我可以轻松地进行正面分页,但只能访问第一页、最后一页、上一页和下一页,但我无法添加这样的页面选择按钮:13[…][n-2][n-1][n]。

这是我的代码:

使用者JAVA

@Entity
@Table(
    name = "USER",
    uniqueConstraints = {
            @UniqueConstraint(columnNames = "username"),
            @UniqueConstraint(columnNames = "email")
    }
)
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NotBlank
    @Size(min = 3, max = 16)
    private String username;

    @NaturalId
    @NotBlank
    @Email
    private String email;

    @NotBlank
    @Size(max = 100)
    private String password;

    private boolean isUsingTwoFA;

    private String twoFASecret;

    @Column(columnDefinition = "DATE NOT NULL")
    private LocalDate accountCreationDate;

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(
        name = "USER_ROLE",
        joinColumns = @JoinColumn(name = "user_id"),
        inverseJoinColumns = @JoinColumn(name = "role_id")
    )
    private Set<Role> roles = new HashSet<>();
}

UserDto。JAVA

public class UserDto {

    private String username;
    private String email;
    private String accountCreationDate;
    private boolean isUsingTwoFA;
    List<String> roles;
}

PagedUserRepository.java

public interface PagedUserRepository extends PagingAndSortingRepository<User, Long> {

    Page<User> findAll(Pageable pageable);
}

仪表板用户服务。JAVA

@Service
public class DashboardUsersService {

    private UserRepository userRepository;
    private PagedUserRepository pagedUserRepository;

    @Autowired
    public DashboardUsersService(UserRepository userRepository, PagedUserRepository pagedUserRepository) {
        this.userRepository = userRepository;
        this.pagedUserRepository = pagedUserRepository;
    }

    public ResponseEntity<?> getUsers(int page, int size) {

        Pageable pageable = PageRequest.of(page, size);
        Page<User> usersPage = pagedUserRepository.findAll(pageable);

        if (usersPage.getContent().isEmpty()) {
            return new ResponseEntity<>(new ApiResponseDto(false, "Unable to retrieve any user"), HttpStatus.INTERNAL_SERVER_ERROR);
        }

        final List<UserDto> users = usersPage.getContent()
                .stream()
                .map(UserDto::new)
                .collect(Collectors.toList());

        return new ResponseEntity<>(new PagedResponseDto(users, usersPage), HttpStatus.OK);
    }
}

仪表板用户控制器。JAVA

@CrossOrigin(maxAge = 36000)
@RestController
@RequestMapping(path = "/api/secure/admin/dashboard/users")
public class DashboardUsersController {

    @Autowired
    private DashboardUsersService dashboardUsersService;

    @Secured("ROLE_ADMIN")
    @GetMapping
    public ResponseEntity<?> getUsers(
            @RequestParam(value = "page", defaultValue = "0") int page,
            @RequestParam(value = "size", defaultValue = "10") int size
    ) {
        return dashboardUsersService.getUsers(page, size);
    }
}

你sers.js

import React, {Component} from 'react';
import {withRouter} from 'react-router-dom';
import {getPageUsers} from "../../../../api/AdminApi";
import UserTableLine from "./component/UserTableLine";
import UserPagination from "./component/UserPagination";

class Users extends Component{

    state = {
        pagedResponse: {},
        users: [],
        showLoading: false
    };

    constructor(props){
        super(props);

        this.getFirstPageUsers = this.getFirstPageUsers.bind(this);
        this.handleChangePage = this.handleChangePage.bind(this);
    }

    componentDidMount(){
        document.title = "Users management";
        this.getFirstPageUsers();
    }

    getFirstPageUsers(){
        const defaultPageable = {
            pageNumber: 0
        };
        this.setState({showLoading: true});
        getPageUsers(defaultPageable).then(res => {
            this.setState({
                pagedResponse: res,
                users: res.content,
                showLoading: false
            });
        }).catch(error => {
            if(error.message && error.success === false){
                this.props.showAlert(error.message, "error");
            } else {
                this.props.showAlert("Sorry! Something went wrong. Please try again!", "error");
            }
            this.setState({showLoading: false});
            console.log(error);
        });
    }

    handleChangePage(pageable){
        this.setState({showLoading: true});
        getPageUsers(pageable).then(res => {
            this.setState({
                pagedResponse: res,
                users: res.content,
                showLoading: false
            });
        }).catch(error => {
            if(error.message && error.success === false){
                this.props.showAlert(error.message, "error");
            } else {
                this.props.showAlert("Sorry! Something went wrong. Please try again!", "error");
            }
            this.setState({showLoading: false});
            console.log(error);
        });
    }

    render(){

        let tableLines = [];

        if(this.state.pagedResponse && this.state.users.length > 0){
            tableLines = Object.keys(this.state.users)
                .map(key => <UserTableLine key={key} user={this.state.users[key]}/>);
        }

        return(
            <div>
                <h1>Users <span className="text-muted" style={{fontSize: 11}}>management</span></h1>
                <hr/>
                {
                    this.state.showLoading
                    ?
                        <div className="align-content-center text-center">
                            <h4 className="text-muted">Loading. Please Wait...</h4>
                            <i className="material-icons w3-xxxlarge w3-spin align-content-center">refresh</i>
                        </div>
                    :
                        <div>
                            <table className="table table-hover">
                                <thead>
                                    <tr>
                                        <th scope="col">Avatar</th>
                                        <th scope="col">Username</th>
                                        <th scope="col">email</th>
                                        <th scope="col">Action</th>
                                    </tr>
                                </thead>
                                <tbody>
                                {tableLines}
                                </tbody>
                            </table>
                            <UserPagination
                                showAlert={this.props.showAlert}
                                page={this.state.pagedResponse}
                                handleChangePage={this.handleChangePage}
                            />
                        </div>
                }
            </div>
        );
    }
}

export default withRouter(Users);

用户表格行。js

import React, {Component} from 'react';
import {withRouter} from 'react-router-dom';

import {Modal, ModalBody, ModalHeader} from 'reactstrap';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'
import {faSearch} from '@fortawesome/free-solid-svg-icons';

class UserTableLine extends Component {

    state = {
        showModalUserInfo: false,
        user: {}
    };

    constructor(props) {
        super(props);

        this.toggle = this.toggle.bind(this);
    }

    componentDidMount() {
        this.setState({
            user: this.props.user
        });
    }

    toggle() {
        this.setState({
            showModalUserInfo: !this.state.showModalUserInfo
        });
    }

    render() {

        let roles;

        if (this.state.user && this.state.user.roles) {
            roles = Object.keys(this.state.user.roles).map(
                key => " " + this.state.user.roles[key]
            );
        }

        return (
            <tr>
                <th scope="row">
                    <img src={"http://cravatar.eu/helmavatar/" + this.state.user.username + "/32.png"}
                     alt={this.state.user.username} className="img-fluid"/>
                </th>
                <th>
                    {this.state.user.username}
                </th>
                <th>
                    {this.state.user.email}
                </th>
                <th>
                    <button className="btn btn-dark" onClick={this.toggle}><FontAwesomeIcon icon={faSearch}/></button>
                </th>

                <Modal isOpen={this.state.showModalUserInfo} toggle={this.toggle} className={this.props.className}>
                    <ModalHeader toggle={this.toggle}>
                        <div className="align-content-center align-items-center align-self-center text-center">
                            <img src={"http://cravatar.eu/helmavatar/" + this.state.user.username + "/50.png"}
                             alt={this.state.user.username} className="img-fluid rounded align-self-center"/>
                        {" " + this.state.user.username + ' { ' + roles + ' }'}
                        </div>
                    </ModalHeader>
                    <ModalBody>
                        <p>
                            <b>Email adresse:</b> {this.state.user.email}
                        </p>
                        <p>
                            <b>Account creation date:</b> {this.state.user.accountCreationDate}
                        </p>
                        <p>
                            <b>2FA status:</b>
                            {
                                this.state.user.usingTwoFA
                                ?
                                    <span className="badge badge-success">enabled</span>
                                :
                                    <span className="badge badge-danger">disabled</span>
                            }
                        </p>
                    </ModalBody>
                </Modal>
            </tr>
        );
    }
}

export default withRouter(UserTableLine);

最后是用户分页。js

import React, {Component} from 'react';
import {withRouter} from 'react-router-dom';

class UserPagination extends Component {

    state = {
        pagination: {}
    };

    constructor(props) {
        super(props);

        this.onPageChange = this.onPageChange.bind(this);
        this.goToFirstPage = this.goToFirstPage.bind(this);
        this.goToLastPage = this.goToLastPage.bind(this);
        this.goToPreviousPage = this.goToPreviousPage.bind(this);
        this.goToNextPage = this.goToNextPage.bind(this);
        this.setStatePromise = this.setStatePromise.bind(this);
    }

    componentDidMount() {
        const pagination = {
            firstPage: this.props.page.firstPage,
            lastPage: this.props.page.lastPage,
            currentPageable: {
                sort: {
                    sorted: false,
                    unsorted: true
                },
                offset: this.props.page.offset,
                pageSize: this.props.page.pageSize,
                pageNumber: this.props.page.number
            },
            previousPageable: this.props.page.previousPageable,
            nextPageable: this.props.page.nextPageable,
            totalPages: this.props.page.totalPages,
            totalElement: this.props.page.totalElement
        };
        this.setState({pagination});
    }

    setStatePromise(newState) {
        return new Promise((resolve) => {
            this.setState(newState, () => {
                resolve();
            });
        });
    }

    onPageChange = (pageable) => {
        this.props.handleChangePage(pageable);
    };

    goToFirstPage() {
        const firstPage = {
            sort: {
                sorted: false,
                unsorted: true
            },
            offset: 0,
            pageSize: 10,
            pageNumber: 0
        };
        this.onPageChange(firstPage);
    }

    goToLastPage() {
        const lastPage = {
            sort: {
                sorted: false,
                unsorted: true
            },
            pageSize: 10,
            pageNumber: this.state.pagination.totalPages - 1
        };
        this.onPageChange(lastPage);
    }

    goToPreviousPage() {
        const previousPage = this.state.pagination.previousPageable;
        if (previousPage !== "INSTANCE") {
            this.onPageChange(previousPage);
        }
    }

    goToNextPage() {
        const nextPage = this.state.pagination.nextPageable;
        if (nextPage !== "INSTANCE") {
            this.onPageChange(nextPage);
        }
    }

    getPagesNumberButtons(){
        let pages = [];
        if (this.state.pagination) {
            pages.push(
                <li key={1} className="page-item active">
                    <p className="page-link">{this.state.pagination.currentPageable.pageNumber}</p>
                </li>
            );
        }
        return pages;
    }

    render() {

        return (
            <div>
                <ul className="pagination">
                    <li className="page-item" onClick={this.goToFirstPage}>
                        <p className="page-link">&laquo;</p>
                    </li>
                    <li className="page-item" onClick={this.goToPreviousPage}>
                        <p className="page-link">Prev</p>
                    </li>
                    {this.getPagesNumberButtons}
                    <li id="nextPage" className="page-item" onClick={this.goToNextPage}>
                        <p className="page-link">Next</p>
                    </li>
                    <li id="lastPage" className="page-item" onClick={this.goToLastPage}>
                        <p className="page-link">&raquo;</p>
                    </li>
                </ul>
            </div>
        );
    }

}

export default withRouter(UserPagination);

但是如果你想拥有完整的代码:Github

如果你有办法解决我的问题,或者你知道一个处理服务器端分页的库,我很感兴趣:)

提前感谢你花时间阅读这一切,更感谢你的帮助。

亚历克西斯

编辑1:以下是我从控制器得到的响应:

{
    "content": [
        {
            "username": "test1",
            "email": "test1@gmail.com",
            "accountCreationDate": "2018-08-22",
            "roles": [
                "USER"
            ],
            "usingTwoFA": false
        },
        {
            "username": "test2",
            "email": "test2@gmail.com",
            "accountCreationDate": "2018-08-22",
            "roles": [
                "USER"
            ],
            "usingTwoFA": false
        },
        {
            "username": "test3",
            "email": "test3@gmail.com",
            "accountCreationDate": "2018-08-22",
            "roles": [
                "USER"
            ],
            "usingTwoFA": false
        },
        {
            "username": "test4",
            "email": "test4@gmail.com",
            "accountCreationDate": "2018-08-22",
            "roles": [
                "USER"
            ],
            "usingTwoFA": false
        },
        {
            "username": "test5",
            "email": "test5@gmail.com",
            "accountCreationDate": "2018-08-22",
            "roles": [
                "USER"
            ],
            "usingTwoFA": false
        },
        {
            "username": "test6",
            "email": "test6@gmail.com",
            "accountCreationDate": "2018-08-22",
            "roles": [
                "USER"
            ],
            "usingTwoFA": false
        },
        {
            "username": "test7",
            "email": "test7@gmail.com",
            "accountCreationDate": "2018-08-22",
            "roles": [
                "USER"
            ],
            "usingTwoFA": false
        },
        {
            "username": "test8",
            "email": "test8@gmail.com",
            "accountCreationDate": "2018-08-22",
            "roles": [
                "USER"
            ],
            "usingTwoFA": false
        },
        {
            "username": "test9",
            "email": "test9@gmail.com",
            "accountCreationDate": "2018-08-22",
            "roles": [
                "USER"
            ],
            "usingTwoFA": false
        },
        {
            "username": "test10",
            "email": "test10@gmail.com",
            "accountCreationDate": "2018-08-22",
            "roles": [
                "USER"
            ],
            "usingTwoFA": false
        }
    ],
    "offset": 0,
    "pageNumber": 0,
    "pageSize": 10,
    "lastPage": false,
    "totalElement": 24,
    "totalPages": 3,
    "size": 10,
    "number": 0,
    "numberOfElements": 10,
    "firstPage": true,
    "previousPageable": "INSTANCE",
    "nextPageable": {
        "sort": {
            "sorted": false,
            "unsorted": true
        },
        "offset": 10,
        "pageSize": 10,
        "pageNumber": 1,
        "paged": true,
        "unpaged": false
    }
}

共有1个答案

司徒正信
2023-03-14

在与@SGhaleb进行交互之后,我终于为这种分页开发了自己的组件,并且它可以正常工作。这不是一个最优的解决方案(1k行代码),但对于第一个版本来说已经足够了,我将在以后对其进行优化。

下面是所述组件的代码:

import React, {Component} from 'react';

class UserPagination extends Component {

    constructor(props) {
        super(props);

        this.state = {
            page: props.page,
            pageSize: props.pageSize,
            currentPage: props.currentPage,
            totalNumberOfElements: props.totalNumberOfElements
        };

        this.onPageChange = this.onPageChange.bind(this);
        this.goToFirstPage = this.goToFirstPage.bind(this);
        this.goToLastPage = this.goToLastPage.bind(this);
        this.goToPreviousPage = this.goToPreviousPage.bind(this);
        this.goToNextPage = this.goToNextPage.bind(this);
        this.buildPagination = this.buildPagination.bind(this);
    }

    onPageChange = (pageNumber) => {
        this.props.handleChangePage(pageNumber);
    };

    static getDerivedStateFromProps(props, state) {
        state = props;
        return state;
    }

    goToFirstPage() {
        this.onPageChange(0);
    }

    goToLastPage() {
        this.onPageChange(this.state.page.totalNumberOfPages - 1);
    }

    goToPreviousPage() {
        const previousPage = this.state.page.previousPageable;
        if (previousPage !== "INSTANCE") {
            this.onPageChange(previousPage.pageNumber);
        }
    }

    goToNextPage() {
        const {currentPage, page} = this.state;
        const nextPage = page.nextPageable;
        if (nextPage !== "INSTANCE") {
            this.onPageChange(currentPage + 1);
        }
    }

    buildPagination(page, currentPage) {
        //PAGINATION LOGIC
        //SEE LINK TO PASTEBIN.COM
    }

    render() {

        const {page, currentPage} = this.state;

        let pagination = this.buildPagination(page, currentPage);


        return (
            <ul className="pagination">
                {pagination}
            </ul>
        );
    }
}

export default UserPagination;

https://pastebin.com/x4Fx9pLm

现在分页看起来就像我想要的:

 类似资料:
  • 我正在尝试使用cassandra实现分页,但我在Stackoverflow上没有得到任何成功的解决方案。我遇到的突出错误是“对第一个页面以外的页面进行分页查询需要具有有效分页状态的CassandraPageRequest”。请协助。

  • 本文向大家介绍SpringBoot 使用Mybatis分页插件实现详解,包括了SpringBoot 使用Mybatis分页插件实现详解的使用技巧和注意事项,需要的朋友参考一下 这篇文章主要介绍了SpringBoot 使用Mybatis分页插件实现详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1、导入分页插件包和jpa包 2、增加分页配置 配

  • 我有以下的请求给管理员和管理员 我想用上面Dto中不为空的字段搜索用户存储库。 示例:如果firstName是“john”,lastName是“smith”,其余字段为空,那么我必须在存储库中搜索firstName是“john”,lastName是“smith”的所有记录(不是或) 我还必须为响应执行分页 我是Spring靴新手,有人能建议我怎么做吗?

  • 本文向大家介绍Springboot分页插件使用实例解析,包括了Springboot分页插件使用实例解析的使用技巧和注意事项,需要的朋友参考一下 这篇文章主要介绍了Springboot分页插件使用实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在springboot工程下的pom.xml中添加依赖 在工程的配置Application文件中添

  • 本文向大家介绍SpringBoot整合mybatis结合pageHelper插件实现分页,包括了SpringBoot整合mybatis结合pageHelper插件实现分页的使用技巧和注意事项,需要的朋友参考一下 SpringBoot整合mybatis分页操作 SpringBoot整合Mybatis进行分页操作,这里需要使用Mybatis的分页插件:pageHelper, 关于pageHelper的

  • 我很感激任何帮助如何解决这个问题。