HTTP Status 500 - Request processing failed;nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement - spring

I am trying to add/update students but while updating student I am getting an error. But while adding student it works fine. I am getting this error while updating: -
HTTP Status 500 - Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
add-students.jsp
<form:form action="addStudent" enctype="multipart/form-data" modelAttribute="addstd" method="POST" >
<form:hidden path="id" />
${message}
<form:errors path="firstName" cssClass="error" />
<form:input path="firstName" placeholder="Fistname" />
<form:errors path="lastName" cssClass="error" />
<form:input path="lastName" placeholder="Lastname" />
<form:input path="contact_No" placeholder="Contact Number" />
<form:input path="address" placeholder="Address" />
<form:errors path="email" cssClass="error" />
<form:input path="email" placeholder="Email" />
<p class="msg">
Year:
<form:select path="year">
<c:forEach var="temp" items="${studentyear}">
<form:option value="${temp.yearId}">${temp.year}</form:option>
</c:forEach>
</form:select>
Faculty:
<form:select path="faculty">
<c:forEach var="temp" items="${studentfaculty}">
<form:option value="${temp.faculty_id}" >${temp.faculty}</form:option>
</c:forEach>
</form:select>
Profile: <input type="file" name="image" accept="image/*" />
</p>
<input type="submit" value="Add/Update Record" class="button" />
</form:form>
#Controller class
#RequestMapping(value="/addStudent",method=RequestMethod.POST)
public String saveStudent(#RequestParam("image") MultipartFile file,#RequestParam("id") int theId,#ModelAttribute("addstd") #Valid StudentInfo theStudent,BindingResult result,Model model){
String fileName=null;
if(!file.isEmpty()){
try {
String path= session.getServletContext().getRealPath("/resources/images");
String newName=String.valueOf(new java.util.Date().getTime());
fileName=file.getOriginalFilename();
String ext=FilenameUtils.getExtension(fileName);
if(ext.equalsIgnoreCase("jpg") || ext.equalsIgnoreCase("jpeg") || ext.equalsIgnoreCase("png")){
File imageFile=new File(path,newName+"."+ext);
file.transferTo(imageFile);
theStudent.setImages(newName+"."+ext);
if(theId!=0){
StudentInfo std=studentService.getStudent(theId);
String images= std.getImages();
File oldImage=new File(path,images);
Files.delete(oldImage.toPath());
}
}
} catch (Exception e) {
}
}
if(result.hasErrors()){
List <Year> theYear = studentService.getYear();
model.addAttribute("studentyear",theYear);
List<Faculty> theFaculty=studentService.getFaculty();
model.addAttribute("studentfaculty",theFaculty);
return "add-students";
}else{
studentService.saveStudent(theStudent);
return "redirect:/login";
}
}
#RequestMapping("/showFormForUpdate")
public String showUpdateStudent(#RequestParam("studentId") int theId, Model model){
StudentInfo theStudent=studentService.getStudent(theId);
model.addAttribute("addstd",theStudent);
List <Year> theYear = studentService.getYear();
model.addAttribute("studentyear",theYear);
List<Faculty> theFaculty=studentService.getFaculty();
model.addAttribute("studentfaculty",theFaculty);
return "add-students";
}
StudentDAOImpl.class
public void saveStudent(StudentInfo theStudent) {
Session currentSession=sessionFactory.getCurrentSession();
currentSession.saveOrUpdate(theStudent);
}
StudentInfo.class
#Entity
#Table (name="studentinfo")
public class StudentInfo implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id")
private int id;
#Column(name="year_id")
private int year;
#Column(name="faculty_id")
private int faculty;
#NotEmpty(message="First Name cannot be empty")
#Column(name="firstname")
private String firstName;
#NotEmpty(message="Last Name cannot be empty")
#Column(name="lastname")
private String lastName;
#Column(name="contact_no")
private String contact_No;
#Column(name="address")
private String address;
#Email(message="Enter a valid email address")
#Column(name="email")
private String email;
#Column(name="images")
private String images;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name="ID")
private User user;
//getter and setter here
User.class
#Entity
#Table(name="user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="user_id")
private int user_id;
#Column(name="username")
private String username;
#Column(name="password")
private String password;
#OneToOne(mappedBy = "user",fetch = FetchType.LAZY)
private StudentInfo info;
//getter and setter here

In your StudentInfo class there is one field:
private User user;
You have not mapped user with any field in your form controller.
You can map your user like this:
<form:hidden path="user.user_id"/>
If you want to allow this value as null then provide
nullable = true
in your one-to-one annotation and also allow null in db.
If you are doing add student and you have not user nullable then you will have to somehow inject user into your controller.
For example, in your controller method while adding new StudentInfo get user info from database and then inject in studentInfo. I have written sudo code as below:
// User user = session.get(User.class, 1);
// studentInfo.setUser(user);
// saveorUpdate studentInfo

Related

Thymeleaf form returns null values

when I submit the form, the pageBook.id and loggedUser.id values become null (in GetMapping method they have values). Any ideas why?
This is my form:
<div sec:authorize="isAuthenticated()">
<form th:action="#{/} + ${pageBook.id}" th:object="${transaction}" method="post">
<input type="hidden" th:field="${transaction.bookTransaction}" th:value="${pageBook.id}">
<input type="hidden" th:field="${transaction.userTransaction}" th:value="${loggedUser.id}">
<input type="submit" value="Submit!" />
</form>
</div>
My Entity:
#Entity
#Table(name = "transactions")
public class Transaction {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name="book_id", nullable=false)
private Book bookTransaction;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name="user_id", nullable=false)
private User userTransaction;
... consturctors getters and setters
and my controller (pageBook and loggedUser aren't null):
#GetMapping("/{id}")
public String showBookPage(#AuthenticationPrincipal UserDetails userDetails, #PathVariable("id") Long id, Model model, RedirectAttributes redirectAttributes){
try {
Book pageBook = bookService.getBookById(id);
User loggedUser = (User) userService.loadUserByUsername(userDetails.getUsername());
model.addAttribute("transaction", new Transaction());
model.addAttribute("pageBook", pageBook);
model.addAttribute("loggedUser", loggedUser);
} catch (BookNoFoundException e) {
redirectAttributes.addFlashAttribute("message", e);
}
return "users/users_book_page";
}
#PostMapping("/{id}")
public String newTransaction(#PathVariable("id") Long id, #ModelAttribute("transaction") Transaction transaction){
log.info(transaction.getUserTransaction());
log.info(transaction.getBookTransaction());
transactionService.newTransaction(transaction);
return "redirect:/" + id;
}

Send object from th:each loop to controller

I have form and corresponding controller to which list of objects is passed.
entity classes:
#Entity
public class Entity1
#Id
#Column(name="id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#ManyToOne(cascade = CascadeType.PERSIST)
#JoinColumn(name = "entity2_id")
private Entity2 entity2Field;
#Entity
public class Entity2
#Id
#Column(name="id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name="name")
private String name;
controller:
#GetMapping(value="/create")
puplic String show(Model entity1Model, Model entity2Model){
entity1Model.addAttribute("entity1", new Entity1());
List<Entity2> list= entity2Repository.findAll();
entity2Model.addAttribute("entity2list", list);
return "form"
}
#PostMapping(value="/create/new")
public String save(Entity1 entity1, #RequestParam(name="entity2list) String somevalue{
Entity2 entity2= entity2Repository.findByName(somevalue);
entity1.setEntity2Field(entity2)
entity1Repository.save(entity1)
return "redirect:/"
}
form:
<form method="post" th:action="#{create/new}">
<select class="form-control" name="entity2list">
<option th:each="ent2:${entity2list}
th:value="${ent2.name} th:text="${ent2.name}>
</select>
<button type="submit"></button>
</form>
I suppose that thymeleaf th:each loop variable in form can't be th:object=${ent2} (cause if i do this way, select form return null).
Whereas th:value="${ent2.name} return string value. So i had to send #RequestParam(th:value) to "save" method. But in this case i had to do additional request to database, to get Entity2 object and set it to Entity1.
How can i get entity object in some way like:
<form method="post" th:action="#{create/new}">
<select class="form-control">
<option th:each="ent2:${entity2list}
th:object="${ent2} th:text="${ent2.name}>
</select>
<button type="submit"></button>
</form>
and send (#ModelAttribute("ent2")Entity2 ent2 instead of #RequestParam) to the "save" method to avoid redundant request to database?
i have solved the issue th:field="*{entity2Field} works like setter
https://www.thymeleaf.org/doc/tutorials/3.0/thymeleafspring.html#creating-a-form
<form method="post" th:action="#{create/new}" th:object="${entity1}">
<select class="form-control" th:field="*{entity2Field}>
<option th:each="ent2:${entity2list}
th:value="${ent2} th:text="${ent2.name}></option>
</select>
<button type="submit"></button>
</form>

Thymeleaf : error while parsing user credentials inside registration form Springboot

I need to complete the registration form on SpringBoot. To achieve this I created 2 classes : User and Credentials, the 2nd handles unique username and password.
#Getter
#Setter
#Entity
#Table(name = "users")
public class User {
public User() {}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String username;
}
public class Credentials {
public static final String DEFAULT_ROLE = "DEFAULT";
public static final String ADMIN_ROLE = "ADMIN";
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Getter
#Column(nullable = false, unique = true)
private String username;
#Getter
#Column(nullable = false)
private String password;
#Getter
#Setter
#Column(nullable = false)
private String role;
#OneToOne(cascade = CascadeType.ALL)
private User user;
}
This is registrationController (handles "/registration" requests) :
#Controller
public class RegController {
#GetMapping("/register")
public String register(Model model){
model.addAttribute("user", new User());
model.addAttribute("credentials", new Credentials());
return "register";
}
}
Now it should be all set, ready to read data from html form and register new users using thymeleaf.
This is registration form inside registration.html, my goal is to read username and password then create a new user and save him on Postgres :
<body>
<div class="login">
<form id="login" method="POST" th:action="#{/register}">
<label><b>User Name
</b>
</label>
<input type="text" name="Uname" id="Uname" placeholder="Username" required th:field="${credentials.username}">
<br><br>
<label><b>Password
</b>
</label>
<input type="Password" name="Pass" id="Pass" placeholder="Password" required th:field="${credentials.password}">
<br><br>
<label><b>Repeat Password
</b>
</label>
<input type="Password" name="RPass" id="RPass" placeholder="Password">
<br><br>
<button type="submit" class="btn btn-primary" id="log">Registrati</button>
<div style = "background-color:green">
<a id= "link" th:href="#{/login}" >or login</a>
</div>
</form>
</div>
</body>
But when I navigate to registration.html this is the error from TomCat :
Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateInputException:
An error happened during template parsing (template: "class path resource [templates/register.html]")
What I noticed is that if I remove all the th:field (used to get user input) the page is shown without error.
I noticed that your Credentials class has only getters for username and password. If Thymeleaf has to fill them with the user input, shouldn't you provide setters too?
#Getter
#Setter
#Column(nullable = false, unique = true)
private String username;
#Getter
#Setter
#Column(nullable = false)
private String password;

Spring MVC Error: Failed to convert property value of type java.lang.String to required type

I can't let this exception go:
Failed to convert property value of type java.lang.String to required type com.company.springdemo.entity.Product for property productId; nested exception is java.lang.IllegalStateException: Cannot convert value of type java.lang.String to required type com.company.springdemo.entity.Product for property productId: no matching editors or conversion strategy found
Order Model
#Entity
#Table(name = "orders") // naming the table only order, will throw exception
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "order_id")
private Integer orderId;
#OneToOne(cascade = {CascadeType.DETACH,CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH})
#JoinColumn(name = "product_id")
private Product productId;
#ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.DETACH,CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH})
#JoinColumn(name = "client_id")
private Client client;
....
Product Model
#Entity
#Table(name = "product")
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "product_id")
private Integer id;
#Column(name = "product_name")
private String productName;
#Column(name = "product_serial")
private String productSerial;
...
Client Model
#Entity
#Table(name = "clients")
public class Client {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#NotEmpty
#Column(name = "first_name")
private String firstName;
#NotEmpty
#Column(name = "last_name")
private String lastName;
#NotEmpty
#Email
#Column(name = "email")
private String email;
#NotEmpty
#Column(name = "location")
private String location;
#OneToMany(mappedBy = "client",cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<Order> orders;
Controller, where I save the order with related client and product
#PostMapping("add")
public ModelAndView addOrder( #Validated #ModelAttribute("ords") Order order, BindingResult bindingResult ){
if (bindingResult.hasErrors()) {
System.out.println("Having errors: " + bindingResult.getAllErrors());
Iterable<Product> products = productService.listProducts();
Iterable<Client> clients = clientService.listClients();
System.out.println("Error "+ bindingResult.getAllErrors());
ModelAndView mv = new ModelAndView("orders/add-order");
mv.addObject("products",products);
mv.addObject("clients",clients);
return mv;
}
try {
orderService.saveOrder(order);
} catch (Exception e) {
e.printStackTrace();
}
ModelAndView mv = new ModelAndView("redirect:list");
return mv;
}
Finally, my JSP form View page
<form:form action="add" method="post" modelAttribute="ords">
<label for="productId" >Product Id</label>
<form:select path="productId" >
<c:forEach var="product" items="${products}">
<form:option value="${product.id}">${product.productName}</form:option>
</c:forEach>
</form:select>
<form:errors path="productId"/>
<br>
<label for="client" >Client Id</label>
<form:select path="client" >
<c:forEach var="client" items="${clients}">
<form:option value="${client.id}">${client.id} - ${client.lastName}</form:option>
</c:forEach>
</form:select>
<form:errors path="client"/>
<br>
<input type="submit" value="Place Order">
</form:form>
What am I doing wrong?
You most likely need to build a converter class such as this one :
#Component("facilityConverter")
public class FacilityConverter implements Converter<String, Facility>
{
#Autowired
FacilityService facilityService;
#Override
public Facility convert(String id)
{
return facilityService.findById(Integer.parseInt(id));
}
}
Then, you need to register it by implementing the addFormatters method inside of a configuration class implementing WebMvcConfigurer like so :
#Override
public void addFormatters (FormatterRegistry registry)
{
registry.addConverter((FacilityConverter)ctx.getBean("facilityConverter"));
}
Your entities will then correctly be mapped from a dropdown selection. Also, this might not be part of your issue but you can just build your dropdowns like this :
<form:select name="linkedInterface" path="linkedInterface" id="linkedInterface">
<form:options items="${interfaces}" itemLabel="name" itemValue="id"/>
</form:select>
The productId field is actually a Product object, not an ID (String/int). You need your JSP to use path="productId.id" rather than path="productId".
(Although I'd also suggest you also rename the field product rather than productId.)
<form:select path="product.id">
I think you'll hit the same issue on your <form:select path="client"> too.

Pass object in spring form input hidden SpringMVC

i have problem with pass object(CarType) in spring input form.
My Car model:
#Entity
#Table(name="CAR")
public class Car implements Serializable{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "CAR_ID", unique=true, nullable=false)
private long id;
#NotEmpty
#Column(name = "REG_NO", nullable=false)
private String regNo;
#NotEmpty
#Column(name = "YEAR", nullable=false, length = 4)
private String year;
#Column(name = "AVAILABLE", nullable=false)
private boolean available = true;
#Column(name = "START_DATE")
private String startDate;
#Column(name = "RETURN_DATE")
private String returnDate;
#OneToOne
#JoinColumn(name="CAR_TYPE_ID")
private CarType carType;
//getters and setters
Car Type model:
#Entity
#Table(name = "CAR_TYPE")
public class CarType {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "CAR_TYPE_ID", unique=true, nullable=false)
private int id;
#NotEmpty
#Column(name = "MARK", nullable=false)
private String mark;
#NotEmpty
#Column(name = "MODEL", nullable=false)
private String model;
//getters and setters
Controllers:
#RequestMapping(value = { "/rent-car-{regNo}" }, method = RequestMethod.GET)
public String rentCar(#PathVariable String regNo, ModelMap model) {
Car car = carService.findCarByRegNo(regNo);
model.addAttribute("car", car);
return "rentcar";
}
#RequestMapping(value = { "/rent-car-{regNo}" }, method = RequestMethod.POST)
public String saveRentCar(#Valid Car car, BindingResult result, ModelMap model) {
carService.updateCar(car);
model.addAttribute("success", "Car " + car.getRegNo() + " rented successfully");
return "registrationsuccess";
}
JSP file
<form:form method="POST" modelAttribute="car" class="form-horizontal">
<form:input type="hidden" path="id" id="id"/>
<form:input type="hidden" path="year" id="year"/>
<form:input type="hidden" path="regNo" id="regNo"/>
<form:input type="hidden" path="available" id="available"/>
<form:input type="hidden" path="carType" id="carType"/>
<form:input type="text" path="startDate" id="startDate"/>
<form:input type="text" path="returnDate" id="returnDate"/>
I have problem with that code
<form:input type="hidden" path="carType" id="carType"/>
how can i pass object CarType to Car form? I always have that same error: column 'CAR_TYPE_ID' cannot be null. It looks like I'm transferring a null CarType to Car. I dont know why?
Someone can help me? In registercar.jsp i used converter (convert regNo to class CarType) and its works.
You need to know how the Car object gets bound in the Controller handler method from http request from the client. Spring MVC maps the the request parameters to contruct the Car object. Hence the CarType is an associated object. You need to provide a minimal clue to Spring MVC to construct that for you.
<form:form method="POST" action="/rent-car${regNo}" modelAttribute="car">
......
<form:input type="hidden" path="carType.id"/>
<form:input type="hidden" path="carType.model"/>
<form:input type="hidden" path="carType.mark"/>
<input type="submit" value="Submit"/>
</form:form>
you will find a complementary example here is this article Spring MVC - Binding Request Parameters and Path Variables to Java Backing Objects

Resources