场景
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来说还算是新事物,所以任何输入都值得赞赏