在 spring 引导中添加与客户的多对多关系中的帐户详细信息时出错

error while adding Account details in manytomany relationship with Customer in spring boot

我在 AccountCustomer[=49] 之间的 spring 引导中使用 @manytomany 关系=] class。 帐户 class

@Entity
@Table(name = "Account")
public class Account {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public int accountNumber;
    public String accountType;
    public int balance;

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JsonManagedReference
    @JsonIgnore
    private List<Customer> customers;
}
//skipped constructors, getters and setters and tostring method

客户class

@Entity
@Table(name = "Customer")
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public int customerId;
    public String firstName;
    public String lastName;
    public String email;

    @ManyToMany(mappedBy = "customers", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JsonBackReference
    private List<Account> accounts;
}
//skipped constructors, getters and setters and tostring method

我正在尝试发送如下所示的 post 请求,该请求使用给定的 ID 获取 Customer table 中存在的客户,并为其创建新帐户,如 [=56] 中给出的=] 正文在 post 请求中。

下面是处理 post 请求的处理程序方法,如上面的屏幕截图所示。

@PostMapping("/customers/{id}/accounts")
    public ResponseEntity<String> createAccountForCustomer(@RequestBody Account account, @PathVariable("id") int id) {
        account.setAccountNumber(0);
        System.out.println(account);
        // fetching customer object based on given customer id
        Customer fetchCustomerByID = this.customerServices.fetchAccountByID(id);

        if (fetchCustomerByID == null) {
            System.out.println("Customer doesn't exist");
            return new ResponseEntity<String>("Customer doesn't exit", HttpStatus.NOT_FOUND);
        } else {
            System.out.println(fetchCustomerByID);
            System.out.println("Customer exists. Creating account!!");

            List<Account> listOfAccounts = fetchCustomerByID.getAccounts();
            listOfAccounts.add(account);
            fetchCustomerByID.setAccounts(listOfAccounts);// adding given account to fetched customer
            System.out.println("newly created customer" + fetchCustomerByID);
            Customer ac = this.customerServices.addAccount(fetchCustomerByID);
            
            // saving fetched customer back to database with updated customer details

            // adding fetched customer to newly created account from given json
            List<Customer> listOfCustomers = new ArrayList<Customer>();
            listOfCustomers.add(fetchCustomerByID);
            account.setCustomers(listOfCustomers);// creating customer list for given account
            System.out.println("newly created account" + account);
            Account addAccount = this.accountServices.addAccount(account);// saving new account to database
            

            return new ResponseEntity<String>("account created for customer", HttpStatus.OK);
        }

    }

CustomerServices addAccount 方法-

 // add an account
    public Customer addAccount(Customer account) {
        Customer acc = this.customerRepository.save(account);
        return acc;
    }

AccountServices addAccount 方法-

  // add an account
    public Account addAccount(Account account) {
        Account acc = this.accountRepository.save(account);
        return acc;
    }

AccountRepository 和 CustomerRepository 是扩展 CrudRepository 接口以进行数据库相关操作的接口。

问题 - 当我 运行 显示的 post 请求时,一切正常。详细信息也添加到数据库中,如下所示 -

但是当我尝试获取由上述 post 请求添加的帐户(使用带有 id 的 get 请求)时,它显示错误。(对于未由 [=57 添加的帐户详细信息) =] 上面的请求被获取而没有任何错误) 错误是-

 at java.base/java.lang.String.valueOf(String.java:3367) ~[na:na]
        at java.base/java.lang.StringBuilder.append(StringBuilder.java:167) ~[na:na]
        at java.base/java.util.AbstractCollection.toString(AbstractCollection.java:457) ~[na:na]
        at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:622) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]   
        at java.base/java.lang.String.valueOf(String.java:3367) ~[na:na]
        at java.base/java.lang.StringBuilder.append(StringBuilder.java:167) ~[na:na]
        at ma20099449.foundation.bank.ma20099449_bank.Entities.Account.toString(Account.java:69) ~[classes/:na]
        at java.base/java.lang.String.valueOf(String.java:3367) ~[na:na]
        at java.base/java.lang.StringBuilder.append(StringBuilder.java:167) ~[na:na]
        at java.base/java.util.AbstractCollection.toString(AbstractCollection.java:457) ~[na:na]
        at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:622) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]   
        at java.base/java.lang.String.valueOf(String.java:3367) ~[na:na]
        at java.base/java.lang.StringBuilder.append(StringBuilder.java:167) ~[na:na]
        at ma20099449.foundation.bank.ma20099449_bank.Entities.Customer.toString(Customer.java:80) ~[classes/:na]
        at java.base/java.lang.String.valueOf(String.java:3367) ~[na:na]
        at java.base/java.lang.StringBuilder.append(StringBuilder.java:167) ~[na:na]
        at java.base/java.util.AbstractCollection.toString(AbstractCollection.java:457) ~[na:na]
        at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:622) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]   
        at java.base/java.lang.String.valueOf(String.java:3367) ~[na:na]
        at java.base/java.lang.StringBuilder.append(StringBuilder.java:167) ~[na:na]
        at ma20099449.foundation.bank.ma20099449_bank.Entities.Account.toString(Account.java:69) ~[classes/:na]
        at java.base/java.lang.String.valueOf(String.java:3367) ~[na:na]
        at java.base/java.lang.StringBuilder.append(StringBuilder.java:167) ~[na:na]
        at java.base/java.util.AbstractCollection.toString(AbstractCollection.java:457) ~[na:na]
        at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:622) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]   
        at java.base/java.lang.String.valueOf(String.java:3367) ~[na:na]
        at java.base/java.lang.StringBuilder.append(StringBuilder.java:167) ~[na:na]
        at ma20099449.foundation.bank.ma20099449_bank.Entities.Customer.toString(Customer.java:80) ~[classes/:na]
        at java.base/java.lang.String.valueOf(String.java:3367) ~[na:na]
        at java.base/java.lang.StringBuilder.append(StringBuilder.java:167) ~[na:na]
        at java.base/java.util.AbstractCollection.toString(AbstractCollection.java:457) ~[na:na]
        at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:622) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]   
        at java.base/java.lang.String.valueOf(String.java:3367) ~[na:na]
        at java.base/java.lang.StringBuilder.append(StringBuilder.java:167) ~[na:na]
        at ma20099449.foundation.bank.ma20099449_bank.Entities.Account.toString(Account.java:69) ~[classes/:na]
        at java.base/java.lang.String.valueOf(String.java:3367) ~[na:na]
        at java.base/java.lang.StringBuilder.append(StringBuilder.java:167) ~[na:na]
        at java.base/java.util.AbstractCollection.toString(AbstractCollection.java:457) ~[na:na]
        at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:622) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]   
        at java.base/java.lang.String.valueOf(String.java:3367) ~[na:na]
        at java.base/java.lang.StringBuilder.append(StringBuilder.java:167) ~[na:na]
        at ma20099449.foundation.bank.ma20099449_bank.Entities.Customer.toString(Customer.java:80) ~[classes/:na]
        at java.base/java.lang.String.valueOf(String.java:3367) ~[na:na]
        at java.base/java.lang.StringBuilder.append(StringBuilder.java:167) ~[na:na]
        at java.base/java.util.AbstractCollection.toString(AbstractCollection.java:457) ~[na:na]
        at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:622) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]   
        at java.base/java.lang.String.valueOf(String.java:3367) ~[na:na]
        at java.base/java.lang.StringBuilder.append(StringBuilder.java:167) ~[na:na]
        at ma20099449.foundation.bank.ma20099449_bank.Entities.Account.toString(Account.java:69) ~[classes/:na]
        at java.base/java.lang.String.valueOf(String.java:3367) ~[na:na]
        at java.base/java.lang.StringBuilder.append(StringBuilder.java:167) ~[na:na]
        at java.base/java.util.AbstractCollection.toString(AbstractCollection.java:457) ~[na:na]
        at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:622) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]   
        at java.base/java.lang.String.valueOf(String.java:3367) ~[na:na]
        at java.base/java.lang.StringBuilder.append(StringBuilder.java:167) ~[na:na]
        at ma20099449.foundation.bank.ma20099449_bank.Entities.Customer.toString(Customer.java:80) ~[classes/:na]
        at java.base/java.lang.String.valueOf(String.java:3367) ~[na:na]
        at java.base/java.lang.StringBuilder.append(StringBuilder.java:167) ~[na:na]
        at java.base/java.util.AbstractCollection.toString(AbstractCollection.java:457) ~[na:na]
        at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:622) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]   
        at java.base/java.lang.String.valueOf(String.java:3367) ~[na:na]

添加 HTTP 响应中显示的堆栈跟踪错误 -

java.lang.WhosebugError\r\n\tat java.base/java.lang.AbstractStringBuilder.<init>(AbstractStringBuilder.java:112)\r\n\tat java.base/java.lang.StringBuilder.<init>(StringBuilder.java:125)\r\n\tat ma20099449.foundation.bank.ma20099449_bank.Entities.Account.toString(Account.java:68)\r\n\tat java.base/java.lang.String.valueOf(String.java:3367)\r\n\tat java.base/java.lang.StringBuilder.append(StringBuilder.java:167)\r\n\tat java.base/java.util.AbstractCollection.toString(AbstractCollection.java:457)\r\n\tat org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:622)\r\n\tat java.base/java.lang.String.valueOf(String.java:3367)\r\n\tat java.base/java.lang.StringBuilder.append(StringBuilder.java:167)\r\n\tat ma20099449.foundation.bank.ma20099449_bank.Entities.Customer.toString(Customer.java:80)\r\n\tat java.base/java.lang.String.valueOf(String.java:3367)\r\n\tat java.base/java.lang.StringBuilder.append(StringBuilder.java:167)\r\n\tat java.base/java.util.AbstractCollection.toString(AbstractCollection.java:457)\r\n\tat org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:622)\r\n\tat java.base/java.lang.String.valueOf(String.java:3367)\r\n\tat java.base/java.lang.StringBuilder.append(StringBuilder.java:167)\r\n\tat ma20099449.foundation.bank.ma20099449_bank.Entities.Account.toStrin

添加获取方法以获取 id 的帐户详细信息

  // get method to fetch single record based on id given in request
    @GetMapping("/accounts/{id}")
    public ResponseEntity<Account> getAccountById(@PathVariable("id") int id) {
        Account fetchAccountByID = this.accountServices.fetchAccountByID(id);
        if (fetchAccountByID == null) {
            return new ResponseEntity<>(fetchAccountByID, HttpStatus.NOT_FOUND);
        } else {
            // System.out.println(fetchAccountByID);
            System.out.println(fetchAccountByID != null ? fetchAccountByID : "null");
            return new ResponseEntity<>(fetchAccountByID, HttpStatus.OK);
        }
    }

我正在添加帐户的 toString 方法 Class

 @Override
    public String toString() {
        return "{" + " accountNumber='" + getAccountNumber() + "'" + ", accountType='" + getAccountType() + "'"
                + ", balance='" + getBalance() + "'" + ", customers='" + getCustomers() + "'" + "}";
    }

尝试从控制器 class 中的 getAccountById() 方法中删除 System.out.println(fetchAccountByID!= null ? fetchAccountByID : "null");。在 System.out.println 中,您尝试打印帐户详细信息,当时调用帐户 class 中的 toString() 方法。所以你最好删除 System.out.println 或在帐户 class.

中添加适当的 toString 方法

根据要求请在帐户和客户 Classes 中找到自定义的 toString() 方法。

  • 帐号ClasstoString()方法
@Override 
public String toString()
{
    return "Account{" +
        "accountNumber=" + accountNumber +
        ", accountType='" + accountType + '\'' +
        ", balance=" + balance +
        ", customers=" + customers +
        '}';
}
  • 客户ClasstoString()方法
@Override 
public String toString()
{
    return "Customer{" +
        "customerId=" + customerId +
        ", firstName='" + firstName + '\'' +
        ", lastName='" + lastName + '\'' +
        ", email='" + email + '\'' +
        '}';
}

我认为这不是问题的根本原因,但您的 Account.toString() 方法导致无限循环:Account.toString() 调用 Customer.toString()Customer.toString() 调用 Account.toString() 对于同一个帐户。

你需要停止那个循环!我建议在调用 Account.toString 时不要“打印”完整的客户。相反,我只会“打印”一些识别细节。

public class Customer {
   public String toStringShort() {
       return "{id=" + id 
              + ", firstName='"+ firstName 
              + "', lastName='"+ lastName + "'}"
   }
}
public class Account {
   ...
   public String toString() {
       final String shortCustomersToString;
       if(this.customers != null) 
          shortCustomersToString = this.customers.stream()
             .map(Customer::toStringShort)
             .collect(Collectors.joining(", ", "[", "]"));
       else
          shortCustomersToString = null;

       return "{" + " accountNumber='" + getAccountNumber() + "'" 
                  + ", accountType='" + getAccountType() + "'" 
                  + ", balance='" + getBalance() + "'" 
                  + ", customers=" + shortCustomersToString + "}";
   }
}