how to pass value in thymleaf, checking entity for betting service - spring

creating simple match betting service. I have a problem in thymeleaf with passing the value of the match on which the user is currently betting. I want to pass the ID of the match I am betting on to the bet table. I'm not entirely sure about the entities I have whether they are designed correctly. Currently to the bet table passes me the team that the user is betting on by entering the name on input, I want to pass the match ID as well but without entering.
Bet entity
#Entity
#AllArgsConstructor
#NoArgsConstructor
#Setter
#Getter
#Builder
public class Bet {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#ManyToOne
#JoinColumn(name = "employee_id")
private Employee employee;
#ManyToOne(cascade = CascadeType.REMOVE)
#JoinColumn(name = "match_id")
private Match match;
#Column(name = "team_bet")
private String teamBet;
private String result;
}
Match entity
#Entity
#AllArgsConstructor
#NoArgsConstructor
#Setter
#Getter
#Builder
public class Match {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name = "first_team_name")
private String firstTeamName;
#Column(name = "second_team_name")
private String secondTeamName;
#DateTimeFormat(pattern ="yyyy-MM-dd")
private Date dateOut;
#OneToMany(mappedBy = "match", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Bet> bet = new HashSet<>();
private String timeOut;
}
Controllers
#GetMapping("/matches/bet/{id}")
public String createBet(Model model, #PathVariable(name = "id") int matchId) throws MatchNotFoundExceptions {
Match match = matchService.getMatch(matchId);
Bet bet = new Bet();
model.addAttribute("match", match);
model.addAttribute("bet", bet);
return "bet_form";
}
#PostMapping("/bet/save")
public String saveBet(Bet bet, RedirectAttributes redirectAttributes) {
betService.createBet(bet);
redirectAttributes.addFlashAttribute("message", "The bet has been created successfully!");
return "redirect:/bets";
}
bet_form.html
<form th:action="#{/bet/save}" method="post"
style="max-width: 700px; margin: 0 auto" th:object="${bet}">
<input type="hidden" th:field="*{id}"/>
<input type="hidden">
<form th:object="${match}">
<!--send to bet entity-->
<td th:text="${id}"></td>
</form>
<div style="text-align: center" class="m-3">
<b>Match Start: </b>
<td th:text="${#dates.format(match.dateOut, 'yyyy-MM-dd')}"></td>
<td th:text="${match.timeOut}"></td>
<div style="text-align: center" class="m-3">
<a th:text="${match.firstTeamName}"></a>
<b>VS</b>
<a th:text="${match.secondTeamName}"></a>
<div class="m-4">
<b>Team Name:</b>
<input type="text" class="form-control"
th:field="*{teamBet}" required minlength="3" maxlength="24"/>
</div>
</div>
</div>
<div class="text-center">
<div class="m-3">
<input type="submit" value="accept" class="btn btn-primary"/>
<input type="submit" value="cancel" class="btn btn-warning"
onclick="location.href='/matches';"/>
</div>
</div>
</form>

Related

Select thymeleaf doesn't create a value in my db

I have a project of library in spring with thymeleaf and MySQL. I have a form of book in which I have select option with author and other with editorial. I receive a list of all of them from my ddbb, but when I submit in the button the data doesn't create a registry in my ddbb, But when I use input its work fine.
here is the code
HTML
<div class="form-group">
<label class="col-sm-2 col-form-label">Autor</label>
<div class="col-sm-6">
<select th:field="*{autor}" id="provincia">
<option th:each="autor:${autores}" th:text="${autor.nombre}"
th:value="${autor.id}" />
</select>
<!-- <input type="text" th:field="*{autor.id}" class="form-control" th:errorclass="'form-control alert-danger'" />-->
<!-- <small class="form-text text-danger" th:if="${#fields.hasErrors('autor.id')}" th:errors="*{autor.id}"></small> -->
</div>
</div>
<div class="form-group">
<label class="col-sm-2 col-form-label">Editorial</label>
<div class="col-sm-6">
<select th:field="*{editorial}">
<option th:each="editorial:${editoriales}"
th:text="${editorial.nombre}" th:value="${editorial.id}" />
</select>
<!-- <input type="text" th:field="*{editorial.id}" class="form-control" th:errorclass="'form-control alert-danger'" />-->
<!-- <small class="form-text text-danger" th:if="${#fields.hasErrors('editorial.id')}" th:errors="*{editorial.id}"></small> -->
</div>
</div>
Here is the controller
#RequestMapping(value = "/form_lib")
public String crearLibro(Model model) {
Libro libro = new Libro();
model.addAttribute("libro", libro);
model.addAttribute("titulo", "Formulario crear Libro");
model.addAttribute("autores", autorDao.listaAutores());
model.addAttribute("editoriales", editorialDao.listaEditoriales());
return "form_lib";
}
#RequestMapping(value = "/form_lib", method = RequestMethod.POST)
public String guardarLibro(#Valid #ModelAttribute Libro libro, BindingResult result, Model model,
#RequestParam("file") MultipartFile imagen, RedirectAttributes attributes) {
if (result.hasErrors()) {
model.addAttribute("titulo", "Formulario de Libro");
model.addAttribute("libro", libro);
System.out.println("errrorrrr");
return "listar_libro";
}
if (!imagen.isEmpty()) {
=Paths.get("src//main//resources//static/images");
String rutaAbsoluta = "//home//marce//Documentos//imagen";
try {
byte[] bytesImg = imagen.getBytes();
Path rutaCompleta = Paths.get(rutaAbsoluta + "//" + imagen.getOriginalFilename());
Files.write(rutaCompleta, bytesImg);
libro.setImagen(imagen.getOriginalFilename());
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println(libro.toString());
libroDao.guardarLibro(libro);
return "redirect:/form_lib";
}
Here is the entity
#Entity
#Table(name = "libros")
public class Libro implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id_libro")
private int id;
#Column(name = "isbn")
private long isbn;
#Column(name = "titulo")
private String titulo;
#Column(name = "anio")
private int anio;
#Column(name = "ejemplares")
private int ejemplares;
#Column(name = "ejemplaresp")
private int ejemplaresPrestados;
#Column(name = "ejemplaresr")
private int ejemplaresRestantes;
#Column(name = "alta")
private boolean alta;
#Column(name = "imagen")
private String imagen;
#OneToOne
#JoinColumn(name="id_autor")
private Autor autor;
#OneToOne
#JoinColumn(name="id_editorial")
private Editorial editorial;

I am getting an error 500, while i am trying to show all the products that exist in my database using SpringBoot

when i create a product and fill out the details in the create_product.html page when i click on add button, it should direct me to the Products.html page which I will show all the products but I am getting an error when I transferred me to the Products.html page. However, when i check my database table I found that the product had been added.
ProductController Class
#Controller
public class ProductsController {
//adding the service layer of the product
#Autowired
private ProductService productService;
#Autowired
private CategoriesRepository categoriesRepository;
public ProductsController(ProductService productService,CategoriesRepository categoriesRepository )
{
super();
this.productService = productService;
this.categoriesRepository = categoriesRepository;
}
// models
#ModelAttribute("category")
public List<Categories> initializeCategories(){
List<Categories> categories = categoriesRepository.findAll();
return categories ;
}
#ModelAttribute("product")
public Products products()
{
return new Products();
}
/////////////////////////////////// handllers
//request to list all the products
#RequestMapping("/products/all_products")
public String listProducts(Model model)
{
model.addAttribute("product",productService.getAllProducts());
return "Products/products";
}
//request to show the form to create a product // when u are accessing the http request u will access that one coz it will show the form and then the Save method will do the action
#GetMapping("/products/new/product")
public String createProductForm(Model model)
{
//Create product object
Products product = new Products();
model.addAttribute("product",product); // product is the object from products Entityclass
return "Products/create_product";
}
//request to create/save a product
#RequestMapping(value = "/products/create_product",method = RequestMethod.POST)
public String saveProduct(#ModelAttribute("product") Products product) // Products is the name of the Entity class and creating a productObjcet from it
{
productService.saveProduct(product);
return "redirect:/products/all_products";
}
#GetMapping("/products/edit/{id}")
public String editProductForm(#PathVariable long id, Model model)
{
model.addAttribute("product",productService.getProductById(id));
return "Products/edit_product";
}
//request to update product
#RequestMapping(value = "/products/update_product/{id}",method=RequestMethod.POST)
public String updateProduct(#PathVariable Long id, #ModelAttribute("product") Products product, Model model) // model Attribute is the data taken from the html file by the user
{
//get product from the db by id
Products existingProduct = productService.getProductById(id);
existingProduct.setProduct_id(id);
existingProduct.setProduct_name(product.getProduct_name());
existingProduct.setProduct_price(product.getProduct_price());
existingProduct.setProduct_category(product.getProduct_category());
existingProduct.setProduct_quantity(product.getProduct_quantity());
existingProduct.setProduct_Section(product.getProduct_Section());
existingProduct.setProduct_ExpDate(product.getProduct_ExpDate());
//updating the product
productService.updateProduct(existingProduct);
return "redirect:/products/all_products";
}
//request to Delete product
#GetMapping("/products/delete_product/{id}")
public String deleteProduct(#PathVariable long id)
{
productService.deleteProduct(id);
return "redirect:/products/all_products";
}
}
Categories Entity Class:
#Entity
#Data
public class Categories {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long categories_id;
private String categoryName;
#OneToMany(mappedBy = "product_category",fetch = FetchType.LAZY) //the name of the variable in the other class
private Set<Products> product_category = new HashSet<>();
public Categories(String categoryName, Set<Products> product_category) {
this.categoryName = categoryName;
this.product_category = product_category;
}
public Categories() {
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
}
Product Entity class :
#Entity
#Table(name = "Products")
#Data
public class Products {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long product_id;
private String product_name;
private BigDecimal product_price;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "categories_id") //the name of the column in the other class and that name will be a column in the class
private Categories product_category;
private String product_quantity;
private String product_Section;
private String product_ExpDate;
public Products()
{
super();
}
public Products(String product_name, BigDecimal product_price,String product_quantity,Categories product_category ,String product_Section,String product_ExpDate) {
this.product_name = product_name;
this.product_category = product_category;
this.product_price = product_price;
this.product_quantity = product_quantity;
this.product_Section = product_Section;
this.product_ExpDate = product_ExpDate;
}
ProductService Class:
#Service
public class ProductServiceImp implements ProductService {
//productRepository class
private ProductRepository productRepository;
public ProductServiceImp(ProductRepository productRepository) {
this.productRepository = productRepository;
}
#Override
public List<Products> getAllProducts() {
return this.productRepository.findAll();
}
#Override
public Products saveProduct(Products product) {
return this.productRepository.save(product);
}
#Override
public Products updateProduct(Products product) {
return this.productRepository.save(product);
}
#Override
public void deleteProduct(long id) {
this.productRepository.deleteById(id);
}
public Products getProductById(long id)
{
return productRepository.findById(id).get();
}
}
CreateProduct.html page:
<form th:action="#{/products/create_product}" method="post" th:object="${product}">
<div class="form-group">
<label class="control-label" for="product_name"> Product Name </label> <input
id="product_name" class="form-control" th:field="*{product_name}"
required autofocus="autofocus" />
</div>
<div class="form-group">
<label class="control-label" for="product_price"> Price </label> <input
id="product_price" class="form-control" th:field="*{product_price}" required
autofocus="autofocus" />
</div>
<div class="col-1.5">
<label th:for="category"> Category </label>
<select class="form-control form-control-sm" id="category" name="product_category">
<option value=""> Select Category </option>
<option th:each = "category: ${category}"
th:value="${category.categories_id}"
th:text="${category.categoryName}"
> <!--th:field="*{product_category}"-->
</option>
</select>
</div>
<br>
<div class="form-group">
<label class="control-label" for="product_quantity"> Quantity </label> <input
id="product_quantity" class="form-control" type="text"
th:field="*{product_quantity}" required autofocus="autofocus" />
</div>
<div class="form-group">
<label class="control-label" for="product_Section"> Section </label> <input
id="product_Section" class="form-control" type="text"
th:field="*{product_Section}" required autofocus="autofocus" />
</div>
<div class="form-group">
<label class="control-label" for="product_ExpDate"> Expire Date </label> <input
id="product_ExpDate" class="form-control" type="text"
th:field="*{product_ExpDate}" required autofocus="autofocus" />
</div>
<div class="form-group">
<button type="submit" class="btn btn-success">Save</button>
</div>
</form>
products.html page
<table class = "table table-striped table-bordered">
<thead class = "table-dark">
<tr>
<th> Category </th>
<th> Product Name </th>
<th> Product Price </th>
<th> Product Quantity </th>
<th> Product Section </th>
<th> Product Expiry Date </th>
<th> Edit </th>
<th> Delete </th>
</tr>
</thead>
<tbody>
<tr th:each = "product: ${product}"> <!-- this attribute to list up products -->
<td th:text="${product.product_category}" ></td>
<td th:text="${product.product_name}"></td>
<td th:text="${product.product_price}"></td>
<td th:text="${product.product_quantity}" ></td>
<td th:text="${product.product_Section}" ></td>
<td th:text="${product.product_ExpDate}" ></td>
<td> <center> <a th:href="#{/products/edit/{id}(id=${product.product_id})}" style="color: green"> Edit </a> </center> </td>
<td> <center> <a th:href="#{/products/delete_product/{id}(id=${product.product_id}) }" style="color: red"> Delete </a> </center> </td>
</tr>
</tbody>
</table>
FullTrace Error:
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Wed Oct 20 03:45:45 EDT 2021
There was an unexpected error (type=Internal Server Error, status=500).
No message available
java.lang.StackOverflowError
at com.mysql.cj.NativeSession.execSQL(NativeSession.java:696)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:930)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeQuery(ClientPreparedStatement.java:1003)
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeQuery(ProxyPreparedStatement.java:52)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeQuery(HikariProxyPreparedStatement.java)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:57)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.getResultSet(AbstractLoadPlanBasedLoader.java:390)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeQueryStatement(AbstractLoadPlanBasedLoader.java:163)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:104)
at org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer.initialize(AbstractLoadPlanBasedCollectionInitializer.java:87)
at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:710)
at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:76)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:99)
at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:2163)
at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.java:589)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:264)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:585)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149)
at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:458)
at com.example.warehouseManagementSystem.Entities.Categories.hashCode(Categories.java:10)
at com.example.warehouseManagementSystem.Entities.Products.hashCode(Products.java:10)
at java.base/java.util.HashMap.hash(HashMap.java:340)
at java.base/java.util.HashMap.put(HashMap.java:612)
at java.base/java.util.HashSet.add(HashSet.java:221)
The problem is that you are using #Data from Lombok on your entity. Remove this and manually implement equals() and hashCode in a way that does not lead to a StackOverflowError. In most cases, you only want to check the primary key.
See https://www.wimdeblauwe.com/blog/2021/04/26/equals-and-hashcode-implementation-considerations/ for more info on how to correctly implement equals and hashcode.
See also https://thorben-janssen.com/lombok-hibernate-how-to-avoid-common-pitfalls/#Avoid_Data for more info on why you should be careful with Lombok and JPA/Hibernate.

Can't print name by foreign key

Spring boot 2.5
Controller:
#org.springframework.stereotype.Controller
public class OrdersController {
#Value("${spring.application.name}")
private String appName;
#Autowired
private OrderRepository orderRepository;
#Autowired
private CategoryRepository categoryRepository;
private static Logger logger = LogManager.getLogger(OrdersController.class);
#GetMapping("/orders")
public String getAllOrders(Model model) {
model.addAttribute("ordersList", orderRepository.findAll());
model.addAttribute("appName", appName);
return "orders";
}
orders.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title th:text="${appName}">Order template title</title>
<link th:href="#{/public/style.css}" rel="stylesheet"/>
<meta charset="UTF-8"/>
</head>
<body>
<div class="container entity_list">
<h2>Orders</h2>
<br/>
<table>
<tr>
<td colspan="3" align="left" th:text="'Total count: ' + ${ordersList.size()}"/>
<td colspan="3" align="right"><a th:href="#{/order/add}">Add</a></td>
</tr>
<tr>
<th width="50">ID</th>
<th width="120">Name</th>
<th width="200">Created At</th>
<th width="200">Updated At</th>
<th width="200">Category</th>
<th width="60"></th>
<th width="60"></th>
</tr>
<th:block th:each="order : ${ordersList}">
<tr>
<td th:text="${{order.id}}"/>
<td><a th:href="#{/order/view/{id}(id=${order.id})}"/><span th:text="${order.name}"/></td>
<td th:text="${{order.created}}"/>
<td th:text="${{order.updated}}"/>
<td th:text="${{order.category}}"/>
<td><a th:href="#{/order/edit/{id}(id=${order.id})}">Edit</a></td>
<td><a th:href="#{/order/delete/{id}(id=${order.id})}">Delete</a></td>
</tr>
</th:block>
</table>
</div>
</body>
</html>
jpa:
import org.springframework.data.repository.CrudRepository;
import java.util.List;
public interface OrderRepository extends CrudRepository<Orders, Integer> {
// Spring Data - use JPQL -> generate SQL query on runtime
public List<Orders> findByName(String name);
public List<Orders> findByNameOrderById(String name);
}
Models:
#Entity
public class Orders {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#NotNull
private String name;
private String description;
#NotNull
#DateTimeFormat(pattern = "dd.MM.yyyy HH:mm:ss")
private Date created;
#DateTimeFormat(pattern = "dd.MM.yyyy HH:mm:ss")
private Date updated;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "category_id")
private Category category;
#Entity
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#NotNull
private String name;
private String description;
#NotNull
#DateTimeFormat(pattern = "dd.MM.yyyy HH:mm:ss")
private Date created;
#DateTimeFormat(pattern = "dd.MM.yyyy HH:mm:ss")
private Date updated;
#OneToOne(fetch = FetchType.LAZY,
cascade = CascadeType.ALL,
mappedBy = "category")
private Orders orders;
And here result:
As you can see print category's id. But I need to print category's name.
Try to change tour orders.html and in order.category edit like below:
<td th:text="${{order.category?.name}}"/>
Hope useful

hibernate validation not working while one-to-one mapping in between two entities

During form submission, if there is any validation error then form shows the errors messages under the fields. But the actual problem is in another place. I have two entities User and UserDetails. These entities are mapped with each other by bidirectional one-to-one mapping. Validation is working only with the User entity fields but not with the UserDetails entity.
Spring - 5.0.2`
Hibernate - 5.2.10
User.java
#Entity
#Table(name="users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#NotEmpty(message="{common.error.msg}")
private String first_name;
#NotEmpty(message="{common.error.msg}")
private String last_name;
#NotEmpty(message="{common.error.msg}")
private String status;
#OneToOne(cascade = CascadeType.ALL, mappedBy = "user", fetch = FetchType.LAZY)
private UserDetails userDetails;
//Getter and setter methods
}
UserDetails.java
#Entity
#Table(name="user_details")
public class UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int user_id;
#NotEmpty(message="{common.error.msg}")
private String address;
#NotEmpty(message="{common.error.msg}")
private String mobile;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id")
private User user;
//Getter and setter methods
}
Get and Post methods in the controller class
#GetMapping(value="/create")
public String loadUserForm(Model model) {
model.addAttribute("command", new User());
return "backend/oms/user/form"; //JSP
}
#PostMapping(value="/create")
public String Save(#Valid #ModelAttribute("command") User user, BindingResult br, Model model, HttpSession session, RedirectAttributes ra) {
if(br.hasErrors()) {
return "backend/oms/user/form"; //JSP
} else {
try {
int id = userService.save(user);
if(id > 0) {
ra.addFlashAttribute("flash_msg", "ok|User added!");
return "redirect:/oms/user/edit/"+id;
} else {
return "backend/oms/user/create"; //JSP
}
} catch (ConstraintViolationException ex) {
model.addAttribute("err", "Something wrong! Please try again.");
return "backend/oms/user/form"; //JSP
}
}
}
messages.properties
common.error.msg=This field is required!
form.jsp
<form:form action="/oms/user/create" method="post" modelAttribute="command">
<label>First Name</label>
<form:input path="first_name" class="form-control" placeholder="First Name" value="" />
<form:errors cssClass="error" path="first_name" />
<label>Last Name</label>
<form:input path="last_name" class="form-control" placeholder="Last Name" value="" />
<form:errors cssClass="error" path="last_name" />
<label>Mobile</label>
<form:input path="userDetails.mobile" class="form-control" placeholder="Mobile" value="" />
<form:errors cssClass="error" path="userDetails.mobile" />
<label>Address</label>
<form:textarea path="UserDetails.address" class="form-control" placeholder="Address" value="" />
<form:errors cssClass="error" path="userDetails.address" />
<label>Status</label>
<form:select class="form-control" path="status">
<option value="">Choose...</option>
<option value="E">Enable</option>
<option value="D">Disable</option>
</form:select>
<form:errors path="status" cssClass="error"/>
<input type="submit" class="btn btn-primary" value="Save" />
</form>
Please see the screenshot
As you can see the image only fields from the User entity is validating but fields those are from the UserDetails are not validating. Please help.
It is solved now. #Valid annotation solved my problem. I need to put #Valid annotation before the entity variable declaration like below --
#OneToMany(mappedBy="majorHead", cascade = CascadeType.ALL)
#Valid
private List<MinorHead> minorHead = new ArrayList<MinorHead>();

Creating HTML form with Spring+Hibernate

I have 3 classes:
First class, is an entity, that stores String variable:
#Entity
#Table(name = "mods_langs_texts", catalog = "artfunpw")
#Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
public class ModsLangsTexts implements java.io.Serializable {
#Column(name = "Title", nullable = false, length = 300)
public String getTitle() {
return this.title;
}
Second entity is for relations:
#Entity
#Table(name = "mods_langs_texts_relations", catalog = "artfunpw")
#Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
public class ModsLangsTextsRelations implements java.io.Serializable {
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "textId", nullable = false)
public ModsLangsTexts getModsLangsTexts() {
return this.modLangsTexts;
}
And the third entity is the main class:
#Entity
#Table(name = "mods", catalog = "artfunpw")
#Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
public class Mod implements java.io.Serializable {
#OneToMany(fetch = FetchType.EAGER, mappedBy = "mod")
#Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
public Set<ModsLangsTextsRelations> getModsLangsTextsRelationses() {
return this.modsLangsTextsRelationses;
}
I am trying to create HTML form with the code:
m.addAttribute("formClass", mod);
And HTML code:
<p th:text="${formClass.modsLangsTextsRelationses.toArray()[0].getModsLangsTexts().title}" />
<form action="" th:object='${formClass}' method="POST">
<input type="hidden" th:field='*{id}' />
Title: <input type="text" th:field='${formClass.modsLangsTextsRelationses.toArray()[0].getModsLangsTexts().title}' />
<br />
But it fails with error:
2017-10-13 14:33:56.661 ERROR 4744 --- [nio-8080-exec-9] org.thymeleaf.TemplateEngine : [THYMELEAF][http-nio-8080-exec-9] Exception processing template "mods/editPages/editModPage": Error during execution of processor 'org.thymeleaf.spring4.processor.attr.SpringInputGeneralFieldAttrProcessor' (mods/editPages/editModPage:57)
Where line 57 is the line with code:
Title: <input type="text" th:field='${formClass.modsLangsTextsRelationses.toArray()[0].getModsLangsTexts().title}' />
In the same time, code
<p th:text="${formClass.modsLangsTextsRelationses.toArray()[0].getModsLangsTexts().title}" />
works fine.
How can I access inner objects from HTML form code with Spring+Hibernate+Thymeleaf?
Have a look at the thymeleaf tutorial :
The th:field is a field reference to a command object you declare on the form tag thanks to the th:object attribute
From the tutorial :
<form action="#" th:action="#{/seedstartermng}" th:object="${seedStarter}" method="post">
<input type="text" th:field="*{datePlanted}" />
</form>
Adapted to your case it would be something like :
<form action="#" th:action="#{???}" th:object="${formClass.modsLangsTextsRelationses.toArray()[0].getModsLangsTexts()}" method="post">
<input type="text" th:field="*{title}" />
</form>
I have a doubt it will work this way. Have a look at section 7.6 : dynamic fields

Resources