Hibernate Many To Many не заполняется - PullRequest
0 голосов
/ 04 августа 2020

Итак, у меня есть служба бронирования, где люди заполняют форму, после того как форма отправлена, она сохраняется в базе данных. У меня две модели, чтобы добиться того же.

SpaService. java

@Entity
package com.springsec.model;

import lombok.Getter;
import lombok.Setter;
import org.springframework.format.annotation.DateTimeFormat;

import javax.persistence.*;
import java.util.Date;
import java.util.List;
import java.util.Set;

@Entity
public class Reservation {
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    long orderId;
    @Column(nullable = false)
    String username;
    @Column
    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinTable(joinColumns = @JoinColumn(name = "orderId", referencedColumnName = "orderId"),
            inverseJoinColumns = @JoinColumn(name = "serviceId", referencedColumnName = "serviceId"))
    private List<SpaService> type;
    @Column(nullable = false)
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    Date date;
    @Column(nullable = false)
    String time;
    @Column
    String msg;
    @Column(nullable = false)
    int status;


    public Reservation() {
    }

    public Reservation(String username, Date date, String time, String msg, int status, Set<SpaService> type) {
        this.username = username;
        this.date = date;
        this.time = time;
        this.msg = msg;
        this.status = status;
    }

    @Override
    public String toString() {
        return "Reservation{" +
                "bookedBy='" + username + '\'' +
                ", date=" + date +
                ", time='" + time + '\'' +
                ", msg='" + msg + '\'' +
                ", status=" + status +
                '}';
    }

    public List<SpaService> getType() {
        return type;
    }

    public void setType(List<SpaService> reservation_type) {
        this.type = reservation_type;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String bookedBy) {
        this.username = bookedBy;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time = time;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }
}

Бронирование. java

package com.springsec.model;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
@Getter
@Setter
public class SpaService {
    @Id
    long serviceId;
    @Column(nullable = false)
    String title;
    @Column(nullable = false)
    String description;

    public SpaService() {
    }

    public SpaService(String title, String description) {
        this.title = title;
        this.description = description;
    }

    public long getServiceId() {
        return serviceId;
    }

    public void setServiceId(long serviceId) {
        this.serviceId = serviceId;
    }

    public String getTitle() {
        return title;
    }

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

    public String getDescription() {
        return description;
    }

    public void setDescription(String desc) {
        this.description = desc;
    }
}

Итак, в основном, что происходит, таблица SpaService в базе данных заполняется различными услугами, которые предлагает Spa. Как только пользователь выбирает то, что он хочет, модель типа Reservation формируется и сохраняется в базе данных.

Но по какой-то причине java получает тип Sting из внешнего интерфейса. Кроме того, когда я вручную пытался вставить в первую таблицу, объединенный столбец не заполняется.

РУЧНАЯ ПРОВЕРКА

    @GetMapping("test")
    public String testAppointment(){
        List<SpaService> serviceList = new ArrayList<SpaService>();
        serviceList.add(new SpaService("1", "1"));
        Reservation rs = new Reservation("1",new Date(), "18:00","Hello", 0, serviceList);
        reservationService.setupReservation(rs);
        return "index";
    }

Вот мой обработчик формы отправить

    @PostMapping("book")
    public String bookAppointment(@Valid Reservation reservation, Model model, BindingResult bindingResult){
        model.addAttribute("reservation", reservation);
        reservationService.setupReservation(reservation);
        reservation.getType().forEach(spaService -> {
            System.out.println(spaService.getTitle());
        });
        return "book";
    }

HTML

<!DOCTYPE html>
<html lang="en"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/extras/spring-security">

<head>
    <!-- Font Awesome -->
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.2/css/all.css">
    <!-- Google Fonts -->
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap">
    <!-- Bootstrap core CSS -->
    <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.min.css" rel="stylesheet">
    <!-- Material Design Bootstrap -->
    <link href="https://cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.19.1/css/mdb.min.css" rel="stylesheet">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link href="css/master.css" rel="stylesheet" type="text/css">
    <link href="css/index.css" rel="stylesheet" type="text/css">
    <link href="css/book.css" rel="stylesheet" type="text/css">
    <title>S P A</title>
</head>
<body >
<header>
    <nav class="navbar navbar-expand-lg nav-custom-bg rounded nav-shadow">
        <div class="container">
            <a class="navbar-brand spa display-4" href="#"><strong>SPA</strong></a>
            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
                <span class="" role="button" ><i class="fa fa-bars" aria-hidden="true" style="color:#fc5185"></i></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarSupportedContent">
                <ul class="navbar-nav mr-auto">
                    <li class="nav-item active">
                        <a class="nav-link" href="#">Home<span class="sr-only">(current)</span></a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#">Link</a>
                    </li>
                    <li class="nav-item dropdown">
                        <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                            Dropdown
                        </a>
                        <div class="dropdown-menu" aria-labelledby="navbarDropdown">
                            <a class="dropdown-item" href="#">Action</a>
                            <a class="dropdown-item" href="#">Another action</a>
                            <div class="dropdown-divider"></div>
                            <a class="dropdown-item" href="#">Something else here</a>
                        </div>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
                    </li>
                </ul>
                <ul class="navbar-nav my-2 my-lg-0">
                    <li class="nav-item">
                        <div sec:authorize="isAnonymous()">
                            <ul class="navbar-nav mr-auto">
                                <li class="nav-item">
                                    <a class="btn btn-custom btn-lg form-sign-in-heading" th:href="@{/login}">login</a>
                                </li>&nbsp; &nbsp;
                                <li class="nav-item">
                                    <a class="btn btn-custom btn-lg form-sign-in-heading" th:href="@{/register}">register</a>
                                </li>
                            </ul>
                        </div>
                        <div sec:authorize="isAuthenticated()">
                            <ul class="navbar-nav mr-auto">
                                <li class="nav-item">
                                    <a class="btn btn-danger btn-lg form-sign-in-heading" th:href="@{/logout}">Logout</a>
                                </li>
                            </ul>
                        </div>
                    </li>
                </ul>
            </div>
        </div>
    </nav>
</header>
<!--Main Layout-->
<div sec:authorize="isAuthenticated()">
    <div class="row">
        <div class="col-md-12">
            <div class="jumbotron jumbotron-fluid" style="margin-bottom: 0;">
                <div class="container">
                    <h1 class="display-4">Let's book your appointment!</h1>
                    <p class="lead">Fill the below form so we can process your appointment.</p>
                </div>
            </div>
        </div>
    </div>
    <div class="container-fluid">
        <div class="row center-me-pl0x">
            <div class="col-md-12">
                <form class="text-center border border-light p-5" method="POST" th:action="@{/book}" th:object="${reservation}">
                    <div class="md-form">
                        <label for="username" style="color: #fc5185;" th:value="${#authentication.name}" class="sr-only"></label>
                        <input style="color: #fc5185;" th:field="*{username}" th:value="${#authentication.name}" th:placeholder="${#authentication.name}" readonly type="text" id="username" name="username" class="form-control" required>
                    </div>
                    <div class="md-form">
                        <label for="serviceType" class="sr-only">Service Type</label>
                        <input type="hidden" id="serviceType" readonly name="serviceType" class="form-control" placeholder="Service Type" required>
                    </div>
                    <div class="md-form">
                        <input type="text" class="form-control" placeholder="I want a" style="border-bottom: #fc5185" readonly>
                    </div>
                    <div class="btn-group btn-group-toggle" data-toggle="buttons" th:each="service : ${serviceList}">
                        <label class="btn btn-light">
                            <input type="checkbox" autocomplete="off" th:type="" th:text="${service.getTitle()}" th:field="*{type}" th:value="${service}">
                        </label>
                    </div>
                    <div class="md-form">
                        <label for="date"></label><input th:field="*{date}" placeholder="Date" type="date" id="date" class="form-control" min="9/10/2018" required>
                    </div>
                    <div class="md-form">
                        <label for="time"></label><input placeholder="Time" class="form-control" type="time" id="time" min="10:00" max="21:00" name="time">
                        <small>SPA Timing are from 10AM to 10PM</small>
                    </div>
                    <div class="md-form">
                        <textarea id="msg" th:field="*{msg}" class="md-textarea form-control" rows="3"></textarea>
                        <label for="msg" style="color: #fc5185;">Any message?</label>
                    </div>
                    <button class="btn btn-lg btn-custom btn-block" type="submit">Sign up</button>
                </form>
            </div>
        </div>
    </div>
</div>
<!-- JQuery -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<!-- Bootstrap tooltips -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.4/umd/popper.min.js"></script>
<!-- Bootstrap core JavaScript -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/js/bootstrap.min.js"></script>
<!-- MDB core JavaScript -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.19.1/js/mdb.min.js"></script>
<!-- DateFixer -->
<script type="text/javascript" src="js/book.js"></script>
</body>
</html>

Вот ошибка

Tue Aug 04 20:06:04 IST 2020
There was an unexpected error (type=Bad Request, status=400).
Validation failed for object='reservation'. Error count: 1
org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'reservation' on field 'type': rejected value [com.springsec.model.SpaService@67ef3c1d]; codes [typeMismatch.reservation.type,typeMismatch.type,typeMismatch.java.util.List,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [reservation.type,type]; arguments []; default message [type]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.List' for property 'type'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'com.springsec.model.SpaService' for property 'type[0]': no matching editors or conversion strategy found]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...