如何使用react和formik处理列表子对象

时间:2020-09-01 14:37:40

标签: java reactjs formik

场景

Java后端三个实体,作者,出版者和书籍。作者与书有@ManyToMany关系,出版商与书有@OneToMany关系

每个对象都有一个休息服务,已使用talend和MockMvc对它进行了测试。到目前为止一切都很好。

我可以列出,更新和删除作者和书本对象(在有限制的情况下)。我可以列出Book对象,但是当我尝试添加或更新时,该对象的作者和发行者部分出现了问题。

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

@Entity
public class Author implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="author_gen")
    @SequenceGenerator(name="author_gen", sequenceName="AUTHOR_SEQ", allocationSize=1)
    private long id;
    
    @Column(nullable=false, length=50)
    @NotEmpty(message = "this field is compulsory")
    @Size(max=50, message="no more than 50 characters")
    private String firstname;
    
    @Column(nullable=false, length=50)
    @NotEmpty(message = "this field is compulsory")
    @Size(max=50, message="no more than 50 characters")
    private String lastname;
    
    @Column(length=1000)
    private String biography;

    @Column(nullable=false, length=100)
    @NotEmpty(message = "this field is compulsory")
    @Size(max=100, message="no more than 100 characters")
    private String email;

    public Author(){
        super();
    }
    
    public Author(String firstname, String lastname, String biography, String email) {
        super();
        this.firstname = firstname;
        this.lastname = lastname;
        this.biography = biography;
        this.email = email;
    }

    public Author(long id, String firstname, String lastname, String biography, String email) {
        super();
        this.id = id;
        this.firstname = firstname;
        this.lastname = lastname;
        this.biography = biography;
        this.email = email;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getFirstname() {
        return firstname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    public String getLastname() {
        return lastname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    public String getBiography() {
        return biography;
    }

    public void setBiography(String biography) {
        this.biography = biography;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "Author [id=" + id + ", firstname=" + firstname + ", lastname=" + lastname + ", biography=" + biography
                + ", email=" + email + "]";
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + (int) (id ^ (id >>> 32));
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Author other = (Author) obj;
        if (id != other.id)
            return false;
        return true;
    }
}


import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;

@Entity
public class Publisher {
    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="publisher_gen")
    @SequenceGenerator(name="publisher_gen", sequenceName="PUBLISHER_SEQ", allocationSize=1)
    private long id;
    
    @Column(nullable=false, length=100)
    private String name;

    @Column(nullable=false, length=200)
    private String address;

    public Publisher(){
        super();
    }
    
    public Publisher(String name, String address) {
        super();
        this.name = name;
        this.address = address;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Publisher [id=" + id + ", name=" + name + ", address=" + address + "]";
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + (int) (id ^ (id >>> 32));
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Publisher other = (Publisher) obj;
        if (id != other.id)
            return false;
        return true;
    }
}

import java.time.LocalDate;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;

import org.springframework.format.annotation.DateTimeFormat;

@Entity
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "book_gen")
    @SequenceGenerator(name = "book_gen", sequenceName = "BOOK_SEQ", allocationSize = 1)
    private long id;

    @Column(nullable = false, length = 100)
    private String title;

    @Column(nullable = false, length = 16)
    private String isbn;

    @Column(nullable = false)
    private long pages;

    @Column(nullable = false)
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate publishedDate;

    @ManyToMany
    @JoinColumn(name = "id")
    private List<Author> authors;

    @ManyToOne(cascade = { CascadeType.MERGE })
    @JoinColumn(name = "publisherId")
    private Publisher publisher;

    public Book() {
    }

    public Book(String title, String isbn, long pages, LocalDate publishedDate, List<Author> authors,
            Publisher publisher) {
        super();
        this.title = title;
        this.isbn = isbn;
        this.pages = pages;
        this.publishedDate = publishedDate;
        this.authors = authors;
        this.publisher = publisher;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getIsbn() {
        return isbn;
    }

    public void setIsbn(String isbn) {
        this.isbn = isbn;
    }

    public long getPages() {
        return pages;
    }

    public void setPages(long pages) {
        this.pages = pages;
    }

    public LocalDate getPublishedDate() {
        return publishedDate;
    }

    public void setPublishedDate(LocalDate publishedDate) {
        this.publishedDate = publishedDate;
    }

    public List<Author> getAuthors() {
        return authors;
    }

    public void setAuthors(List<Author> authors) {
        this.authors = authors;
    }

    public Publisher getPublisher() {
        return publisher;
    }

    public void setPublisher(Publisher publisher) {
        this.publisher = publisher;
    }

    @Override
    public String toString() {
        return "Book [id=" + id + ", title=" + title + ", isbn=" + isbn + ", pages=" + pages + ", authors=" + authors
                + ", publisher=" + publisher + "]";
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + (int) (id ^ (id >>> 32));
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Book other = (Book) obj;
        if (id != other.id)
            return false;
        return true;
    }
}

我用来尝试添加一本书的反应代码

import React, { Component } from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';
import BookService from '../services/BookService'
import PublisherService from '../services/PublisherService'
import AuthorService from '../services/AuthorService';

class AddBookComponent extends Component {

    constructor(props) {
        super(props)
        this.state = {
           // id: this.props.match.params.id,
            title: '',
            isbn: '',
            pages: '',
            publishedDate: '',
            authors: [],
            publisher: '',
        
           
            
            publishers: [
                {
                    
                },
            ],
        }
        
        this.onSubmit = this.onSubmit.bind(this)
        this.retrieveAllAuthors = this.retrieveAllAuthors.bind(this)
        this.retrieveAllPublishers = this.retrieveAllPublishers.bind(this)
       
    }

    componentDidMount() {
        this.retrieveAllAuthors();
       
        this.retrieveAllPublishers();
    }
    onSubmit(values) {
        let book = {
            //id: this.state.id,
            title: values.title,
            isbn: values.isbn,
            pages: values.pages,
            publishedDate: values.publishedDate,
            authors: values.authors,
            publisher: values.publisher
        }
        BookService.addBook(book)
        .then(() => this.props.history.push('/books') )
    }

    
    retrieveAllAuthors() {
        AuthorService.retrieveAllAuthors()
            .then(
                response => {
                    console.log(response)
                    this.setState({
                        authors: response.data
                    })
                }
            )
    }
    
    retrieveAllPublishers() {
        PublisherService.retrieveAllPublishers()
        .then(
            response => {
                this.setState({
                    publishers: response.data
                })
            }
        )
    }




    render() {
        let { title, isbn, pages, publishedDate, authors, publisher, publishers } = this.state;
        return (

            <div>
                <h1>Add A Book</h1>
                <div className="container">
                    <Formik
                        initialValues={{ title, isbn, pages, publishedDate, authors, publisher, publishers }}
                        onSubmit={this.onSubmit}
                        validateOnChange={false}
                        validate={this.validate}
                        enableReinitialize={true}
                    >
                        {(props) => (
                            <Form>
                                <ErrorMessage name="title" component="div" className="alert alert-warning" />
                                <fieldset className="form-group">
                                    <label>Title: </label>
                                    <Field className="form-control" type="text" name="title"></Field>
                                </fieldset>
                                <ErrorMessage name="isbn" component="div" className="alert alert-warning" />
                                <fieldset className="form-group">
                                    <label>isbn: </label>
                                    <Field className="form-control" type="text" name="isbn"></Field>
                                </fieldset>
                                <ErrorMessage name="pages" component="div" className="alert alert-warning" />
                                <fieldset className="form-group">
                                    <label>pages: </label>
                                    <Field className="form-control" type="number" name="pages"></Field>
                                </fieldset>
                                <fieldset className="form-group">
                                    <label>publishedDate: </label>
                                    <Field className="form-control" type="date" name="publishedDate"></Field>
                                </fieldset>
                                <fieldset className="form-group">
                                <select multiple name="authors">
                                    {authors.map((author, id) => (
                                        <option key={author.id}>
                                            {author.firstname}  {author.lastname}
                                        </option>
                                    ))}
                                   </select>
                                   </fieldset>
                                   <fieldset className="form-group" name="publisher">
                                   <select  name="publisher">
                                    {publishers.map((publisher, id) => (
                                        <option key={publisher.id} name="publisher" >
                                            {publisher.name} {publisher.address} 
                                        </option>
                                    ))}
                                   </select>
                                </fieldset>
                                <button className="btn btn-success" type="submit">
                                    Submit
                                </button>
                            </Form>
                        )}
                    </Formik>
                </div>
            </div>

        );
    }

}

export default AddBookComponent

显示该表单,并在列表中填充所有可能的作者和发布者,但是,当我尝试发布该表单时,在控制台的“网络”选项卡中出现以下错误,它表明所有作者均已添加,并且发布者字段留空

请求网址:http:// localhost:8088 / api / v1 / book / create 请求方法:POST 状态码:400 远端地址:[:: 1]:8088 推荐人政策:降级时不推荐人 Access-Control-Allow-Origin:http:// localhost:3000 连接方式:关闭 内容长度:0 日期:星期二,2020年9月1日14:10:06 GMT 变化:起源 变化:访问控制请求方法 变化:访问控制请求头 接受:application / json,text / plain, / 接受编码:gzip,deflate,br 接受语言:en-US,en; q = 0.9 连接:保持活动状态 内容长度:792 内容类型:application / json; charset = UTF-8 主机:localhost:8088 来源:http:// localhost:3000 引荐来源:http:// localhost:3000 / book / 秒提取目标:空 安全提取模式:cors 安全提取站点:同一站点 用户代理:Mozilla / 5.0(Macintosh; Intel Mac OS X 10_13_4)AppleWebKit / 537.36(KHTML,例如Gecko)Chrome / 85.0.4183.83 Safari / 537.36 {title:“”,isbn:“”,页面:“”,发布日期:“”,…} 作者:[{id:1,名字:“ J.K.ewrwerwqr”,姓氏:“ Rowling”,传记:“儿童作家”,…},…] 0:{id:1,名字:“ J.K.ewrwerwqr”,姓氏:“ Rowling”,传记:“ Childrens author”,…} 1:{id:2,名字:“ G.R.R。”,姓氏:“ Martin”,传记:“幻想作者”,电子邮件:“ grr@martin.com”} 2:{id:3,名字:“ Irvine”,姓氏:“ Welsh”,传记:“ Distopian author”,电子邮件:“ I@welsh.com”} 3:{id:4,名字:“ Irvine”,姓氏:“ Welsh”,传记:“ Distopian author”,电子邮件:“ I@welsh.com2”} 4:{id:5,名字:“ Irvine”,姓氏:“ Welsh”,传记:“ Distopian author”,电子邮件:“ I@welsh.com3”} 5:{id:6,名字:“ Irvine”,姓氏:“ Welsh”,传记:“ Distopian author”,电子邮件:“ I@welsh.com4”} 6:{id:8,名字:“ 43r35t35”,姓氏:“ 3453”,传记:“ 4353”,电子邮件:“ 3453”} isbn:“” 页数:“” PublishedDate:“” 发布者:“” 标题:“”

java控制台说: 2020-09-01 15:10:06.364 WARN 19732 --- [nio-8088-exec-1] .mmaExceptionHandlerExceptionResolver:已解决[org.springframework.http.converter.HttpMessageNotReadableException:JSON解析错误:无法构造{{ 1}}(尽管至少存在一个Creator):没有从String值('')反序列化的String-argument构造函数/工厂方法;嵌套异常为com.fasterxml.jackson.databind.exc.MismatchedInputException:无法构造com.bookshop.model.Publisher的实例(尽管存在至少一个Creator):没有用于从字符串值('')反序列化的String-argument构造函数/工厂方法 在[来源:(PushbackInputStream);行:1,列:790](通过参考链:com.bookshop.model.Book [“ publisher”])]

如果我可以解决这个问题,那么我希望以后可以解决这个问题。对React来说还算是新事物,所以任何输入都值得赞赏

0 个答案:

没有答案