首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >react中的Spring引导分页实现

react中的Spring引导分页实现
EN

Stack Overflow用户
提问于 2018-08-23 20:46:47
回答 1查看 4.2K关注 0票数 1

大家好!我希望你没事?

我目前正在开发一个简单的应用程序,以了解更多关于spring、security、jpa和服务器端分页的知识。

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

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

因此,我创建了一个控制器,它需要管理角色并进行连接。为了返回用户列表,我使用了扩展PagingAndSortingRepository的DAO,它工作得很好!

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

我尝试过许多分页库来响应。但它们都需要在一个列表中恢复所有数据,而我不希望这样做。因此,我开始开发自己的分页组件。我可以轻松地进行前端分页,但只访问第一页、最后一页、前一页和下一页,但我不能添加这样的页面选择按钮:13..n-1。

当前,我的分页组件如下所示:

我想要这样的东西:

这是我的密码:

User.java

代码语言:javascript
复制
@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

代码语言:javascript
复制
public class UserDto {

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

PagedUserRepository.java

代码语言:javascript
复制
public interface PagedUserRepository extends PagingAndSortingRepository<User, Long> {

    Page<User> findAll(Pageable pageable);
}

DashboardUserService.java

代码语言:javascript
复制
@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);
    }
}

DashboardUserController.java

代码语言:javascript
复制
@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);
    }
}

Users.js

代码语言:javascript
复制
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);

UserTableLine.js

代码语言:javascript
复制
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);

最后,UserPagination.js

代码语言:javascript
复制
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:下面是从控制器获得的响应:

代码语言:javascript
复制
{
    "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
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-08-25 15:17:52

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

以下是上述组件的代码:

代码语言:javascript
复制
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

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51994030

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档