Creating HTML form with Spring+Hibernate - spring

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

Related

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

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>

Neither BindingResult nor plain target object for bean name 'cliente' available as request attribute

I'm facing an issue with spring and thymeleaf, i'm trying to fill a form with data from an entity called cliente, but i'm getting a Whitelabel Error Page message in the browser and this message in the console
Neither BindingResult nor plain target object for bean name 'cliente' available as request attribute
this is the Cliente
package com.bolsadeideasspringboot.app.models.entity;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import org.springframework.format.annotation.DateTimeFormat;
#Entity
#Table(name="clientes")
public class Cliente implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotEmpty
private String nombre;
#NotEmpty
private String apellido;
#NotEmpty
#Email
private String email;
#Column(name="create_at")
#Temporal(TemporalType.DATE)
#DateTimeFormat(pattern="dd/MM/yyyy")
private Date createAt;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public String getApellido() {
return apellido;
}
public void setApellido(String apellido) {
this.apellido = apellido;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Date getCreateAt() {
return createAt;
}
public void setCreateAt(Date createAt) {
this.createAt = createAt;
}
}
this is the controller method
#RequestMapping(value="/form/{id}")
public String editar(#ModelAttribute("form") #PathVariable(value="id")Long id, Map<String, Object>model) {
Cliente cliente = null;
if(id > 0) {
clientedao.findOne(id);
model.put("cliente", cliente);
model.put("titulo", "Editar Cliente");
return "form";
}
else {
return "redirect:/listar";
}
}
this is the ClienteDaoImpl.java method
#Override
public Cliente findOne(Long id) {
// TODO Auto-generated method stub
return em.find(Cliente.class, id);
}
this is the Dao interface method
public Cliente findOne(Long id);
and this is the form
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title th:text="${titulo}">Insert title here</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-4 col-md-offset-3">
<h1 class="text-success" th:text="${titulo}"></h1>
<form th:action="#{/form}" th:object="${cliente}" method="post">
<div class="form-group">
<label>Nombre</label>
<input class="form-control" type="text" th:field="*{nombre}" placeholder="Nombre"/>
<small class="form-text text-danger" th:if="${#fields.hasErrors('nombre')}" th:errors="*{nombre}"></small>
</div>
<div class="form-group">
<label>Apellido</label>
<input class="form-control" type="text" th:field="*{apellido}" placeholder="Apellido"/>
<small class="form-text text-danger" th:if="${#fields.hasErrors('apellido')}" th:errors="*{apellido}"></small>
</div>
<div class="form-group">
<label>Email</label>
<input class="form-control" type="text" th:field="*{email}" placeholder="correo#ejemplo.com"/>
<small class="form-text text-danger" th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></small>
</div>
<div class="form-group">
<label>Fecha</label>
<input class="form-control" type="text" th:field="*{createAt}" placeholder="DD/MM/YYYY"/>
<small class="form-text text-danger" th:if="${#fields.hasErrors('createAt')}" th:errors="*{createAt}"></small>
</div>
<div class="form-group">
<input class="btn btn-primary" type="submit" value="Crear Cliente" />
</div>
<input type="hidden" th:field="*{id}" />
</form>
</div>
</div>
</div>
</body>
</html>
i'm setting the cliente in the controller method and i'm using th:object in the form, so i don't know what i'm doing wrong, any help would be helpul, thanks in advice
Instead of put(), try using the recommended approach to adding an object to your model with
model.addAttribute("cliente", clientedao.findOne(id));
You typically want to use #GetMapping as well for your requests to populate the form. And use #PostMapping for submissions.
Aside: also take a look at Project Lombok to make your beans less error-prone and more readable. You could remove all those getters and setters and just annotate the class with #Data.
While not deprecated, you'll also want to move away from using java.util.Date and use the newer date/time classes.

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>();

i can't send modelAttribute that contains a mapped object from another class

I have a problem in a matter concerning a mapped object.
here are the entities used:
#Entity
#Table(name = "skill")
public class Skill {
.
.
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "collab_id")
private Collaborateur collaborateur;
........................
#Entity
#Table(name = "collaborateur")
public class Collaborateur {
.
.
#OneToOne(fetch = FetchType.LAZY, mappedBy = "collaborateur")
private Skill skill;
My jsp file :
<form:form action="/app/skill" method="post" modelAttribute="skill"
id="myForm">
<div>
<fieldset>
<legend>Recherche de skill par critere :</legend>
.
.
.
<form:select path="collaborateur" id="input" >
<form:option value="" label="--Collaborateur--"></form:option>
<form:options path="collaborateur" items="${collaborateurs}" itemLabel="firstname" itemValue="id"/>
</form:select>
<input type="submit" value="Search" name="Search"
class="searchButton" onclick="pagination('${1}', '${size}')" />
</fieldset>
When i try to search for a "collaborateur" in a "skill" list, using Example from spring data,i get the this error.
org.springframework.dao.InvalidDataAccessApiUsageException: Path
'collaborateur.skill.collaborateur' from root Skill must not span a cyclic
property reference!
[{ com.app.entities.Skill#a648b00 }] -collaborateur-> [{
com.app.entities.Collaborateur#2b }] -skill-> [{
com.app.entities.Skill#33a1c699 }] -collaborateur-> [{
com.app.entities.Collaborateur#2b }]
What causing this error ?

JasperException: java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'user' available as request attribute

I have two Data Model : User and Car, User can have many cars , so this is the User Class :
#Entity
#Table(name="APP_USER")
public class User implements Serializable{
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
......
#OneToMany(mappedBy="user",cascade=CascadeType.ALL)
private Set<Car> cars = new HashSet<Car>();
Car.java :
#Entity
public class Car implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id ;
.....
#ManyToOne(optional=false)
#JoinColumn(name="user_fk")
private User user;
In the carController , I have the method to add a new Car for one user :
#Controller
#RequestMapping("/cars")
public class CarController {
#Autowired
CarService carService;
#Autowired
UserService userService;
#RequestMapping(value={"/list"},method=RequestMethod.GET)
public String listCars(ModelMap model){
List<Car> cars = carService.allCars();
model.addAttribute("cars", cars);
return "car"; }
#ModelAttribute("utilisateurs")
public List<User> allUsers(){
List<User> utilisateurs = userService.findAllUsers();
return utilisateurs;
}
#RequestMapping(value={"/newCar"},method=RequestMethod.GET)
public String newCar(ModelMap model){
Car car = new Car();
model.addAttribute("car",car);
return "carRegistration";
}
#RequestMapping(value={"newCar"},method=RequestMethod.POST)
public String newCar(#Valid Car car, BindingResult result,ModelMap model){
if (result.hasErrors()) {
return "registration";
}
carService.save(car);
model.addAttribute("car",car);
return "redirect:/cars/list";
}
Finally , in the view , the form is :
<form:form method="POST" modelAttribute="car"
class="form-horizontal">
<form:input type="hidden" path="id" id="id" />
<div class="control-group">
<label class="control-label">Libelle</label>
<div class="controls">
<form:input type="text" path="libelle" id="libelle" style="height:4%" />
</div>
</div>
<div class="control-group">
<label class="control-label">Registration</label>
<div class="controls">
<form:input type="text" path="registration" id="email" />
</div>
</div>
<div class="control-group">
<label class="control-label">Utilisateur</label>
<div class="controls">
<form:select path="user" items="${utilisateurs}" itemValue="id" itemLabel="lastName" style="margin-left: 4%;"></form:select>
</div>
</div>
<div class="form-actions">
<input type="submit" value="Validate" class="btn btn-success" />
</div>
</form:form>
I can get the view , but when I click on button submit , I get this error :
Neither BindingResult nor plain target object for bean name 'user' available as request attribute.
I think there is a problem with the select item of users !!
Have you provided any Spring converter or formatter for User ?
applicationContext.xml:
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="my.project.StringToUser"/>
<bean class="my.project.StringToRole"/>
</list>
</property>
</bean>
<mvc:annotation-driven conversion-service="conversionService" />
It will convert User id to User object.
my.project.StringToUser:
import org.springframework.core.convert.converter.Converter;
public class StringToUser implements Converter<String, JUser> {
#Autowired
private UserService userService;
#Override
public JUser convert(String source) {
long id = Long.valueOf(source);
return userService.get(id);
}
}
the error :
WARNING: Failed to bind request element: org.springframework.beans.TypeMismatchException:
Failed to convert value of type [com.websystique.springmvc.model.User] to required type [com.websystique.springmvc.model.User];
nested exception is org.springframework.core.convert.ConversionFailedException:
Failed to convert from type [com.websystique.springmvc.model.User] to
type [#org.springframework.web.bind.annotation.ModelAttribute #javax.validation.Valid com.websystique.springmvc.model.User]
for value 'User [id=null, ssoId=alaa, password=alaa1991, firstName=, lastName=, email=, userProfiles=null, accounts=null, userDocuments=[], cars=[], documents=[]]';
nested exception is java.lang.ClassCastException:
com.websystique.springmvc.model.User cannot be cast to java.lang.String

Resources