I'm creating a new java entity with html post form,but I don't understand how to convert system id to a class System (that I pass with model.addAttribute("System",id); in controller).
Release
#Table(name = "treleas")
public class Release {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "release_id")
Integer releaseId;
#Column(name = "release_name", nullable = false)
private String releaseName;
#Column(name = "create_date", nullable = false)
private LocalDateTime releaseDate = LocalDateTime.now();
#ManyToOne
#JoinColumn(name = "system_id")
private System system;
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name="release_id")
private List<Req> requirements;
}
System
#Entity
#Table(name = "tsystem")
public class System {
#Id
#Column(name = "system_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
Integer systemId;
#Column(name = "system_name", nullable = false)
private String systemName;
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name="system_id")
private List<Release> releases;
}
Html new release
<!DOCTYPE html>
<html lang="en" xmlns:th="http://thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Новый релиз</title>
</head>
<body>
<form th:method="POST" th:action="#{|/systems/${System}/releases|}"
th:object="${release}">
<label for="releaseName" >Введите название релиза: </label>
<input type="text" th:field="*{releaseName}" id="releaseName"/>
<div style="color:#f80d0d" th:if="${#fields.hasErrors('releaseName')}" th:errors="*{releaseName}"
>Name error</div>
<input type="hidden" th:field="*{system}" th:value="|${System}|"/>
<br/>
<input type="submit" value="Create!"/>
</form>
</body>
</html>
Exception
Caused by: org.postgresql.util.PSQLException: ОШИБКА: значение NULL в столбце "system_id" отношения "treleas" нарушает ограничение NOT NULL
Подробности: Ошибочная строка содержит (5, ReleaseName, 2022-05-15, null).
which means that it cannot insert release with a null system id
Related
i have a spring boot application, and when i load the data in thymeleaf it doesn't load, it's empty. I'm using H2, so every time i launch the app i do some inserts to test, but it never loads the data. I've tried the enpoints with Postman, and they all work. I'm thinking it's something with the method i'm using, but i don't know yet.
Here's my application models:
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#ToString
#Entity
#Table(name = "estudiante")
public class Estudiante {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "estudiante_generator")
private Long id;
#Column(name = "nombre")
private String nombre;
#Column(name = "apellido")
private String apellido;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "profesor_id", nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
#JsonIgnore
private Profesor profesor;
}
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#ToString
#Entity
#Table(name = "profesor")
public class Profesor {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "profesor_generator")
private Long id;
#Column(name = "nombre")
private String nombre;
#Column(name = "apellido")
private String apellido;
#Column(name = "curso")
private String curso;
public Profesor(String nombre, String apellido, String curso){
this.nombre = nombre;
this.apellido = apellido;
this.curso = curso;
}
}
The controller for the index, and the controller for the backend:
#GetMapping("/index")
public String mostrarProfesores(Model model){
List<Profesor> profesor = profesorRepository.findAll();
model.addAttribute("profesores", profesor);
return "index";
}
#GetMapping("/profesores")
public ResponseEntity<List<Profesor>> getProfesores(){
List<Profesor> profesor = new ArrayList<Profesor>();
profesorRepository.findAll().forEach(profesor::add);
if(profesor.isEmpty()){
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<>(profesor, HttpStatus.OK);
}
And the thymeleaf template:
<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<h2>Users</h2>
<table>
<thead>
<th>Nombre</th>
<th>Apellido</th>
</thead>
<tbody>
<th:block th:each="profesor : ${profesores}">
<tr>
<td>[[${profesor.nombre}]]</td>
<td>[[${profesor.apellido}]]</td>
</tr>
</th:block>
</tbody>
</table>
</div>
</body>
</html>
Any help is appreciated, thanks in advance for your help.
You should iterate the collection inside the <tr> label.
<tbody>
<tr th:each="profesor : ${profesores}">
<td th:text="${profesor.nombre}"></td>
<td th:text="${profesor.nombre}"></td>
</tr>
</tbody>
Hi I need a little help with my code. I tried solutions online but I couldn't fix my bug. I working in java and spring with mysql and tymeleaf. My error is short:
Invalid property 'projection' of bean class [com.bakulic.CinemaTicketShop.model.dto.requests.CreateOrUpdateProjectionDTO]: Bean property 'projection' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
And I found that my problem is in the html file createProjectionForm whitch I will put below as well as the entities and all that is needed. My projection entity has a relation to Hall and Movie and I'm not sure how to get attributes of Movie and Hall in my html. For the fiel I tried to put ${projection.hall.name} and ${projection.movie.movieName}. Zou will find it in the code.
Thank you in advance.
#Data
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "projections")
public class Projection {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int projectionId;
#Column(name = "date")
private String date;
#Column(name = "startTime")
private String startTime;
#ManyToOne
#JoinColumn(name = "idHall")
private Hall hall;
#ManyToOne
#JoinColumn(name = "idMovie")
private Movie movie;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "projection", cascade = CascadeType.ALL)
private List<Seat> seatList;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "projection", cascade = CascadeType.ALL)
private List<Ticket> ticketList;
}
#Entity
#Table(name = "halls")
#Data
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class Hall {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int hallId;
#Column(name = "name")
private String name;
#Column(name = "numberofseats")
private Integer numberOfSeats;
#Column(name = "description")
private String description;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "hall", cascade = CascadeType.ALL)
private List<Projection> projectionList;
}
#Entity
#Table(name = "movies")
#Data
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class Movie {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int movieId;
#Column(name = "name")
private String name;
#Column(name = "description")
private String description;
#Column (name = "length")
private String length;
#Column(name = "picture")
private String picture;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "movie", cascade = CascadeType.ALL)
private List<Projection> projectionList;
}
#Data
public class ProjectionDTO implements Serializable {
private int id;
private String date;
private String startTime;
private List<Seat> seatList;
private List<Ticket> ticketList;
private Hall hall;
private Movie movie;
public ProjectionDTO(Projection projection){
if(projection != null){
this.id = projection.getProjectionId();
this.date = projection.getDate();
this.startTime = projection.getStartTime();
this.seatList = projection.getSeatList();
this.ticketList = projection.getTicketList();
this.hall = projection.getHall();
this.movie = projection.getMovie();
}
}
}
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
public class CreateOrUpdateProjectionDTO implements Serializable {
private String date;
private String startTime;
private List<Seat> seatList;
//aditional info
private String name;
private String movieName;
}
/** create projection*/
public Projection createProjection(CreateOrUpdateProjectionDTO createProjectionDTO){
if(createProjectionDTO == null){
throw new InvalidDataException("Projection cannot be null");
}
timeValidator.checkTime(createProjectionDTO.getStartTime());
dateValidator.checkDate(createProjectionDTO.getDate());
Projection proj = new Projection();
proj.setDate(createProjectionDTO.getDate());
proj.setStartTime(createProjectionDTO.getStartTime());
Hall hall = proj.getHall();
if(hall == null){
hall = new Hall();
}
hall.setName(createProjectionDTO.getName());
Integer numOfSeats = hall.getNumberOfSeats();
Movie movie = proj.getMovie();
if(movie == null){
movie = new Movie();
}
movie.setName(createProjectionDTO.getMovieName());
List<Seat> list = createProjectionDTO.getSeatList();
for(int i=1; i<=numOfSeats; i++ ){
Seat seat = new Seat();
seat.setSeatNumber(i);
seat.setStatus("empty");
list.add(seat);
}
Projection projCreated = projectionRepository.save(proj);
log.info(String.format("Projection %s has been created.", proj.getProjectionId()));
return projCreated;
} The function is similar for update.
<
<!DOCTYPE html>
<html lang="en" xmlns:th="http://thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Create theater</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin="anonymous">
</head>
<body style="background-color:lightgrey;">
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<img src="../pictures/cinemalogo.png" th:src="#{pictures/cinemalogo.png}" class = "center"alt="logo" width="120" height="100"/>
<ul class="navbar-nav">
<li class="nav-item">
<h1>Our cinema!</h1>
</li>
</ul>
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="/logout">Logout</a>
</li>
</ul>
</nav>
</nav>
<br>
<br>
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<h1>Add projection</h1><br>
<form th:action="#{/projection}" method="post" th:object="${projection}">
<div class="form-group">
<label class="control-label" for="date"> Date </label>
<input id="date" class="form-control" th:field="*{date}"
required autofocus="autofocus" />
</div>
<div class="form-group">
<label class="control-label" for="startTime"> Start time</label> <input
id="startTime" class="form-control" th:field="*{startTime}" required
autofocus="autofocus" />
</div>
<div class="form-group">
<label class="control-label" for="hallName"> Hall name </label> <input
id="hallName" class="form-control" th:field="*{projection.hall.name}" required
autofocus="autofocus" />
</div>
<div class="form-group">
<label class="control-label" for="movieName"> Movie name </label> <input
id="movieName" class="form-control" th:field="*{projection.movie.movieName}" required
autofocus="autofocus" />
</div>
<div class="form-group">
<button type="submit" class="btn btn-success">Submit</button>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
Use th:field="*{hall.name}" instead of th:field="*{projection.hall.name}" and th:field="*{movie.movieName}" instead of th:field="*{projection.movie.movieName}"
I'm working on a JPA project in which I have two models: TableDecor and Product Tag, which look like this:
#Entity(name="table_decor")
public class TableDecor {
#Id
#IdConstraint
private String id;
#Positive
#Column(nullable = false)
private int width;
#Positive
#Column(nullable = false)
private int height;
#NotNull
#Enumerated(EnumType.STRING)
#Column(nullable = false)
private Color color;
#NotNull
#Enumerated(EnumType.STRING)
#Column(nullable = false)
private Fabric fabric;
#ManyToMany
#JoinTable(
name = "seller",
joinColumns = #JoinColumn(name = "table_decor_id"),
inverseJoinColumns = #JoinColumn(name = "seller_id"))
private List<Seller> sellers;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="producer_id")
private Producer producer;
#OneToOne(cascade=CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "product_tag_id", referencedColumnName = "id")
private ProductTag productTag;
// getters, setters
#Entity(name="product_tag")
#Table
public class ProductTag {
#Id
#GeneratedValue
private UUID id;
#NotNull
#Enumerated
#Column(nullable = false)
private ProductState productState;
#Column(nullable = false)
#NotNull
private float price;
#OneToOne(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "table_decor_id", referencedColumnName = "id")
private TableDecor tableDecor;
// getters, setters
As you can see they're connected with each other with bidirectional one to one relationship. Since one can't exist without another, how can I create a Thymeleaf add form that could create both objects at the same time? The controller function currently looks like this:
#GetMapping("/table-decor/add")
public String showAddForm(TableDecor decorToAdd, ProductTag productTag) {
return "table-decor-add";
}
#PostMapping("/table-decor/add-new")
public String addTableDecor(#Valid TableDecor decorToAdd, #Valid ProductTag productTag, BindingResult bindingResult, Model model){
if (bindingResult.hasErrors()) {
System.out.println("Error");
return "table-decor-add";
}
decorToAdd.setProductTag(productTag);
tableDecorService.addTableDecor(decorToAdd);
model.addAttribute("allTableDecor", tableDecorService.getAllTableDecor());
return "redirect:/table-decor";
and the form:
<form action="#" method="post" th:action="#{/table-decor/add-new}">
<div><input name="id" type="text" th:value="${tableDecor.id}"></div>
<span th:if="${#fields.hasErrors('tableDecor.id')}" th:errors="*{tableDecor.id}"></span>
<div><input name="width" type="text" th:value="${tableDecor.width}"></div>
<span th:if="${#fields.hasErrors('tableDecor.width')}" th:errors="*{tableDecor.width}"></span>
<div><input name="height" type="text" th:value="${tableDecor.height}"></div>
<span th:if="${#fields.hasErrors('tableDecor.height')}" th:errors="*{tableDecor.height}"></span>
<select name="color">
<option th:each="color : ${T(jee.labs.lab05.domain.Color).values()}"
th:text="${color}"
th:value="${tableDecor.color}">
</option>
</select>
<select name="fabric">
<option th:each="fabric : ${T(jee.labs.lab05.domain.Fabric).values()}"
th:text="${fabric}"
th:value="${tableDecor.fabric}">
</option>
</select>
<select name="productState">
<option th:each="productState : ${T(jee.labs.lab05.domain.ProductState).values()}"
th:text="${productState}"
th:value="${productTag.productState}">
</option>
</select>
<div><input name="price" type="text" th:value="${productTag.price}"></div>
<span th:if="${#fields.hasErrors('productTag.price')}" th:errors="*{productTag.price}"></span>
<div><input type="submit" th:value="Submit"></div>
</form>
I created a jsp that will include two seletcts and one depends on the other.
In the first are city names:
<div class="container p-5">
<form action="/addFlat" method="post">
<div class="form-group">
<label for="exampleInputEmail1">City</label>
<select class="custom-select mr-sm-2" id="inlineFormCustomSelect">
<c:forEach items="${cities}" var="cities">
<option value="${cities.id}">${cities.name}</option>
</c:forEach>
</select>
</div>
I want the second to display street names that depend on the first.
I used hibernate to create tables.
City:
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#Column(name = "name")
private String name;
Street:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#Column(name = "name")
private String name;
#ManyToOne
#JoinColumn(name = "city_id")
private City city;
when I try to open from url the create form I'm having an error. I have 2 models that are mapped as one to many and using autopopulatinglist:
ContractHeader.java
#Entity
#Table(name = "CONTRACT_HEADER")
public class ContractHeader {
#Id
#Column(name = "id", unique = true, nullable = false)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "contractHeader")
private List<ContractEntitlement> contractEntitlements;
#Column(name = "customer_name")
private String customerName;
getter and setter ....
}
ContractEntitlement.java
#Entity
#Table(name = "CONTRACT_ENTITLEMENT")
public class ContractEntitlement {
#Id
#Column(name = "id", unique = true, nullable = false)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id", nullable = false, insertable = false, updatable = false)
private ContractHeader contractHeader;
getter and setter ....
}
Controller
#RequestMapping(value = "/create", method = RequestMethod.GET)
public String createForm(Model model) {
ContractHeader ch = new ContractHeader();
ch.setContractEntitlements(new AutoPopulatingList<ContractEntitlement>(ContractEntitlement.class));
model.addAttribute("createForm", ch);
return "create";
}
Create.jsp
<form:form method="post" commandName="createForm" action="${addAction}">
<table>
<tr>
<td>
<form:input path="customerName" size="40" />
</td>
</tr>
</table>
</form:form>
The error:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'contractEntitlement' available as request attribute
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'contractEntitlement' available as request attribute
What I don't understand is why is saying contractEntitlement when my input path object is from the ContractHeader class.
My hibernate config
<mapping class="com.at.ccts.model.ContractHeader" />
<mapping class="com.at.ccts.model.ContractEntitlement" />
Any help is appreciated.
Reason for this is in my jsp i commented out:
<!-- <td>
<form:input name="category" type="text" path="contractEntitlement.category"/>
</td> -->
But for some reason spring still checks it and throws an error. Deleting the pirece of code fixed it. I wonder why since it's out. Anyway this fixed my issue and the page is now loading properly.