Итак, у меня есть служба бронирования, где люди заполняют форму, после того как форма отправлена, она сохраняется в базе данных. У меня две модели, чтобы добиться того же.
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>
<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]