Problem populating a modal dynamically with ThymeLeaf and Spring MVC - java

This is my HOME page.
When the user selects a Datacenter the page redirects and shows the list of FisicHost's available for that Datacenter.
Datacenter class
#Entity
#Transactional
public class Datacenter {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
#OneToMany(mappedBy = "datacenter")
#LazyCollection(LazyCollectionOption.FALSE)
private List<FisicHost> fisicHostList;
// I've cut the constructor and get/set to make it shorter
}
This is the view where the user is redirected when it chooses a Datacenter:
each row in the view represents a FiscHost object that is available for the chosen datacenter.
FisicHost class
#Entity
#Transactional
public class FisicHost {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch=FetchType.EAGER)
private Datacenter datacenter;
#OneToMany(mappedBy = "fisicHost")
#LazyCollection(LazyCollectionOption.FALSE)
private List<Credential> credentials;
private String name;
private String ip;
private String operatingSystem;
private String notes;
}
This is the controller method handling the second view (the one that shows the list of available FisicHost's for that datacenter):
#RequestMapping(value = "/chosenDatacenter", method = RequestMethod.POST)
public String datacenterPostHandler(#RequestParam("datacenterList") String name, ModelMap modelMap){
List<Datacenter> allDatacenters = datacenterDao.getAllDatacenters();
for (Datacenter dc : allDatacenters) {
if (dc.getName().equals(name)) {
modelMap.put("datacenter", dc);
if(dc.getFisicHostList().size() != 0) {
List<FisicHost> datacenterFisicHosts = dc.getFisicHostList();
modelMap.put("datacenterFisicHosts", datacenterFisicHosts);
for(FisicHost fh : datacenterFisicHosts){
if(fh.getCredentials().size() != 0){
modelMap.put("fisicHostCredentialsList", credentialDao.getAllCredentialsByFisicHost(fh));
}
}
}
return "chosenDatacenter";
}
}
return null;
}
If the user clicks on the "CREDENCIALES" button a modal pops up and show all the credentials available for that FisicHost.
Credential class:
#Entity
public class Credential {
#Id
private int id;
#ManyToOne(fetch= FetchType.EAGER)
private FisicHost fisicHost;
private String user;
private String password;
private String notes;
private String role;
}
All this is working fine, BUT here comes the problem ...
Whatever button is clicked, the modal is opened showing ALL the credentials for ALL the FisicHosts inside THAT Datacenter and I ONLY want to show the Credentials for the specific FisicHost that was clicked in the corresponding datacenter!
I know this logic in the controller:
for(FisicHost fh : datacenterFisicHosts){
if(fh.getCredentials().size() != 0){
modelMap.put("fisicHostCredentialsList", credentialDao.getAllCredentialsByFisicHost(fh));
}
is only bringing back the last iteration of the loop, so it will always bring the credentials for that FisicHost no matter what ! And that's what happening, but I can't find a different way of doing it ...
Just in case, here is the getAllCredentialsByFisicHost() method from the CredentialDaoImpl class:
#Override
public List<Credential> getAllCredentialsByFisicHost(FisicHost fisicHost) {
// Open a session
Session session = sessionFactory.openSession();
Criteria c = session.createCriteria(Credential.class).add(Restrictions.eq("fisicHost.id", fisicHost.getId()));
List<Credential> allCredentials = c.list();
// Close the session
session.close();
return allCredentials;
}
Please help cause I'm going crazy with this !!!
Thanks a lot to all :)
PS: This is the chosenDatacenter template that is being rendered with ThymeLeaf:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title>Generic View</title>
<link rel="stylesheet" th:href="#{/css/bootstrap/bootstrap.min.css}" />
<link rel="stylesheet" th:href="#{/css/choosenDatacenter.css}" />
</head>
<body>
<form id="form" action="/getJson" th:object="${datacenterFisicHosts}" method="post">
<table>
<tr class="row">
<th class="tableHeader">Nombre</th>
<th class="tableHeader">IP</th>
<th class="tableHeaders">Sistema Operativo</th>
<th class="tableHeaders">Notas</th>
</tr>
<th:block th:each="fh : ${datacenterFisicHosts}">
<div id="fila">
<tr class="row">
<td id="fisicHostName" th:text="${fh.name}"></td>
<td id="fisicHostIp" th:text="${fh.ip}"></td>
<td id="fisicHostOS" th:text="${fh.operatingSystem}"></td>
<td id="fisicHostNotes" th:text="${fh.notes}"></td>
<td><button type="button" th:onclick="'javascript:openCredentialModal()'">CREDENCIALES</button></td>
</tr>
</div>
</th:block>
</table>
</form>
<!-- Modal -->
<div class="modal fade" id="modalCredenciales" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modal-title">Credenciales</h5>
</div>
<div class="modal-body">
<table>
<tr class="row">
<th class="tableHeader">Usuario</th>
<th class="tableHeader">Clave</th>
<th class="tableHeaders">Notas</th>
</tr>
<th:block th:each="credential : ${fisicHostCredentialsList}">
<tr class="row">
<td id="credentialUser" th:text="${credential.user}"></td>
<td id="credentialPassword" th:text="${credential.password}"></td>
<td id="credentialRole" th:text="${credential.notes}"></td>
</tr>
</th:block>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cerrar</button>
</div>
</div>
</div>
</div>
<script th:src="#{js/jquery-1.11.3.js}"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<script th:src="#{js/chosenDatacenter.js}"></script>
</body>
</html>

You can use Ajax to pass the id to your controller and have it return only the relevant cerdentials, as explained here.
In your controller you add a method that returns the correct list of credentials taking the id of the fisicHost as a parameter:
#RequestMapping("/fisicHost/{id}")
public String fisicHost credentials(#PathVariable("id") String id, ModelMap model)
{
//find credentials by fisicHost using your DAO and add them to model
return "modal/credentials :: modalContents";
}
You'll need a 'modalContents' Thymeleaf fragment to display the credentials as added to model.
Then on the onClick event, you can use Ajax to call the url with the correct id and display the data. In your template, you'd have:
th:onclick="'javascript:openCredentialModal(\'' + ${fh.id} + '\');'"
The Ajax function just calls the url of your controller by passing th id along, and is returned the html code from the thymeleaf fragment. It then packs the html content in the modal.

Related

I am trying to display a product Image that I have saved to the database in a SpringBoot application. When displaying in my front end Image is blank

The image is saving to the database no problem but when trying to display in my front end I am getting blank Images. I also am struggling to understand the logic in how the Image is saving. I have it saved in /user-photos, you will see in my code that the path is this: /user-photos/" + "0" + "/" + image; at first the zero was id as I thought that's how it would save but I noticed they were all saving to /user-photos/0 but either way the image is not displaying - here is my code.
#Entity
#Table(name = "msItem")
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long itemId;
#Column(nullable = false, length = 45)
private String itemName;
#Column(nullable = false)
private int itemPrice;
#Column(nullable = false, length = 100)
private String itemDesc;
#Column(nullable = false, length = 100)
private String category;
#Column(nullable = false, length = 100)
private String image;
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "id")
private User user;
#Transient
public String getPhotosImagePath() {
return "/user-photos/" + "0" + "/" + image;
}
#PostMapping("/products/save")
public String itemAdd(Item item, #RequestParam("file") MultipartFile multipartFile, Principal principal, RedirectAttributes redirectAttributes) throws IOException {
User user = userRepository.findByEmail(principal.getName());
item.setUser(user);
String fileName = StringUtils.cleanPath(multipartFile.getOriginalFilename());
item.setImage(fileName);
String uploadDir = "user-photos/" + item.getItemId();
FileUploadUtil.saveFile(uploadDir, fileName, multipartFile);
itemRepository.save(item);
redirectAttributes.addFlashAttribute("message", "Product Listed for sale");
return "home_page";
}
#Configuration
public class MvcConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
exposeDirectory("user-photos", registry);
}
private void exposeDirectory(String dirName, ResourceHandlerRegistry registry) {
Path uploadDir = Paths.get(dirName);
String uploadPath = uploadDir.toFile().getAbsolutePath();
if (dirName.startsWith("../")) dirName = dirName.replace("../", "");
registry.addResourceHandler("/" + dirName + "/**").addResourceLocations("file:/"+ uploadPath + "/");
}
}
In the html page:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>List products</title>
<link rel="stylesheet" type="text/css" href="/webjars/bootstrap/css/bootstrap.min.css" />
<script type="text/javascript" src="/webjars/jquery/jquery.min.js"></script>
<script type="text/javascript" src="/webjars/bootstrap/js/bootstrap.min.js"></script>
<style>
body {
background-image: url('MarketSwipe.png');
background-size: cover;
}
</style>
</head>
<body>
<div class="container text-center">
<div th:if="${message}" class ="alert alert-success text-center">
[[${message}]]
</div>
<div>
<h2>Manage My Products</h2>
</div>
<div>
<table class="table table-striped table-bordered">
<thead class="thead-dark">
<tr>
<th>Image</th>
<th>Name</th>
<th>Description</th>
<th>$ Price</th>
<th>Manage Product</th>
</tr>
</thead>
<tbody>
<tr th:each="item: ${listItems}">
<td> <img th:scr="${item.photosImagePath}" style="width: 100px; height: 100px;"></td>
<td th:text="${item.itemName}">Name</td>
<td th:text="${item.itemDesc}">Description</td>
<td th:text="${item.itemPrice}">Price</td>
<td>
<a class="btn btn-primary mt 4" th:href="#{'/products/update/' + ${item.itemId}}">Update</a>
<a class="btn btn-danger" th:href="#{'/products/delete/' + ${item.itemId}}">Delete</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>
you have mentoned this as scr, instead of src
th:src="${item.photosImagePath}"

Spring MVC new row in database is created while want to update

I write my first form using Spring MVC pattern and Hibernate.
I have a problem when I want to update existing row in table.
After click "Edit" Buttno in a table, correct row is found in db. Then I can update "name" field and click SAVE button. Than in database i created new row with new ID.
I have wrote two System.out to check current values of object.
My Controller class:
#Controller
//#RequestMapping("/")
public class InterventionController {
#Autowired
private InterventionService interventionService;
#GetMapping("/")
public String viewHomePage(Model model){
List<InterventionModel> interventionList = interventionService.listAll();
model.addAttribute("interventionList", interventionList);
return "index";
}
#GetMapping("/new")
public String addInterventionForm(Model model){
InterventionModel interventionModel = new InterventionModel();
model.addAttribute("interventionModel", interventionModel);
System.out.println(model.toString());
return "new_intervention";
}
#RequestMapping(value="/save", method = RequestMethod.POST)
public String saveIntervention(#ModelAttribute("interventionModel")InterventionModel interventionModel){
System.out.println("Object retreived from editing view "+interventionModel); // <- just to check in console object attributes
interventionService.save(interventionModel);
return "redirect:/";
}
#RequestMapping("/edit/{id}")
public ModelAndView showEditInterventionForm(#PathVariable(name="id") Long id){
ModelAndView mav = new ModelAndView("edit_intervention");
InterventionModel interventionModel = interventionService.get(id).get(); // <-- Optional received from service layer
mav.addObject("interventionModel", interventionModel);
System.out.println("Object retrieved from database : "+interventionModel); // <- just to check in console object attributes
return mav;
}
#GetMapping("/delete/{id}")
public String deleteIntervention(#PathVariable(name="id") Long id){
interventionService.delete(id);
return "redirect:/";
}
My InterventionModel class doesn't contain any annotation. I don't know if that is a mistake, but that object is DTO between controller and service layer. In the service layer, it is mapped to the entity which is annotated #Entity.
public class InterventionModel {
private Long id;
private String name;
public InterventionModel() {
}
public InterventionModel(Long id, String name) {
this.id = id;
this.name = name;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "InterventionModel{" +
"id=" + id +
", name='" + name + '\'' +
'}';
} }
index.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Interventions</title>
</head>
<body>
<div align="center">
<h1>Interventions</h1>
Create new Intervention
<br><br>
<table border="2" cellpadding="10">
<thead>
<tr>
<th>Intervention Id</th>
<th>Name</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr th:each="intervention :${interventionList}">
<td th:text="${intervention.id}">Intervention Id</td>
<td th:text="${intervention.name}">Name</td>
<td>
<a th:href="#{'/edit/' + ${intervention.id}}">Edit</a>
<a th:href="#{'/delete/' + ${intervention.id}}">Delete</a>
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
and edit_intervention.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Edit Intervention</title>
</head>
<body>
<div align="center">
<h1>Edit Intervention</h1>
<br/>
<form action="#" th:action="#{/save}" th:object="${interventionModel}" method="post">
<table border="0" cellpadding="10">
<tr>
<td>Intervention ID</td>
<!-- <td><input type="text" th:field="*{id}" readonly="readonly"/></td>-->
<td><input type="text" th:field="*{id}" readonly="readonly"/></td>
</tr>
<tr>
<td>Intervention name</td>
<td><input type="text" th:field="*{name}"/></td>
</tr>
<tr>
<td colspan="2"><button type="submit">Save</button> </td>
</tr>
</table>
</form>
</div>
</body>
</html>
What is curious for me. Object when is retrieved from DB has proper attributes (id, name) than Model is created and sent to edit_intervention.html form. After changing name, it goes back to save method but there ID number is "null", instead of name which contains changed new value.
For me (as a beginner) it looks like no all attributes are transferred from the view to the save method in controller. When we have ID set to "null" it's a sign for hibernate to create new row.
I guess there is a minor failure which I cannot find.
Logs from terminal when I call update form:
and view how table after modification looks like:
Thank you in advance for help.
As you see your id field is null. Because probably the Long value wasn't set.
In entity class you should mark id property as #Id, also you can always add the #GeneratedValue annotation above.

Thymeleaf view doesn't pass entity ID to a Spring #Controller, but does it with other properties

When I go to /add endpoint my Controller creates a Contact object and generates an ID for it. This ID is then properly passed to a Thymeleaf view and showed on the webpage. When the form from the view is submitted (with POST) to another endpoint in my Controller all of the properties are passed except the ID field. I use Spring Model and #ModelAttribute annotation to pass the object to and from the view. Getters and setters for the entity are generated with Lombok.
Controller class:
#Controller
public class PhonebookController {
private final PhonebookService phonebookService;
#Autowired
public PhonebookController(PhonebookService phonebookService) {
this.phonebookService = phonebookService;
}
#GetMapping("/add")
public String addContact(Model model) {
model.addAttribute("contact", new Contact(EntityUtils.generateId()));
return "contact";
}
#PostMapping("/save")
public String validateAndSaveContact(#ModelAttribute("contact") #Valid Contact contact, BindingResult bindingResult) { // contact.getId() returns null
if (bindingResult.hasErrors()) {
return "contact";
}
phonebookService.getContactRepository().save(contact);
return "redirect:/contacts";
}
}
Entity class:
#Data
#NoArgsConstructor
#AllArgsConstructor
#Document(indexName = "contact")
public class Contact implements Comparable<Contact> {
#Id
private String id;
#NotEmpty(message = "Name can not be empty.")
private String name;
#NotEmpty(message = "Number can not be empty.")
#Pattern(regexp = "[0-9]+", message = "Number can contains only numbers.")
private String number;
public Contact(String id) {
this.id = id;
}
#Override
public int compareTo(Contact o) {
return this.getName().compareTo(o.name);
}
}
Thymeleaf view:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" href="/webjars/bootstrap/css/bootstrap.min.css"/>
<script type="text/javascript" src="/webjars/jquery/jquery.min.js"></script>
<script type="text/javascript" src="/webjars/bootstrap/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="/webjars/font-awesome/css/font-awesome.min.css"/>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-12">
<h1>Add new contact</h1>
<form th:action="#{/save}" method="post" th:object="${contact}">
<div class="form-group">
<label for="idText">Identifier (automaticaly generated):</label>
<strong id="idText" th:text="${contact.getId()}"></strong>
</div>
<div class="form-group">
<label for="nameInput">Contact name:</label>
<input type="text" th:field="*{name}" th:value="*{name}" class="form-control" id="nameInput"/>
<div class="alert alert-warning" role="alert" th:if="${#fields.hasErrors()}" th:errors="*{name}"></div>
</div>
<div class="form-group">
<label for="numberInput">Phone number:</label>
<input type="text" th:field="*{number}" th:value="*{number}" class="form-control" id="numberInput"/>
<div class="alert alert-warning" role="alert" th:if="${#fields.hasErrors()}" th:errors="*{number}"></div>
</div>
<div class="form-group text-right">
<button type="submit" class="btn btn-success">Confirm</button>
<a class="btn btn-danger" th:href="#{/contacts}" role="button">Cancel</a>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
You need to have a hidden input field which contains the id value.
<div class="form-group">
<label for="idText">Identifier (automaticaly generated):</label>
<strong id="idText" th:text="${contact.getId()}"></strong>
<input id="id" th:field="*{id}" type="hidden"/>
</div>
I would like to help you, but I don´t know if you are using the same object to save the data in your table (your entity) and for return your view model in your controller. Normally you should use a different objects and mapping this in your service. It is posible that you have problems if you are using the same object.

spring form validation BindingResult always returns false

i am using spring form validation to validate my form input fields..I am having problem with BindingResult where result.hasErrors() is always returning false even though my input fields are null/empty..i managed all the imports and everything is looking fine to me.But as I said, my validation is not working and needs help with fixing this...
form:
<%#include file="././Header.jsp"%>
<%# taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<script src="<c:url value="/js/smlibray/emailCommunicate.js"/>"></script>
<link href="<c:url value="/js/jquery-ui.css"/>" rel="stylesheet" />
<script src="<c:url value="/js/jquery-ui.js"/>"></script>
<input type="hidden" name="applicationUrl" id="applicationUrl"
value="${pageContext.request.contextPath}">
<div class="container sec-container middle-sec">
<div class="form-fields row">
<div class="col-md-12 col-sm-12 col-xs-12">
<form:form class="form-horizontal policy-form" id="emailCommu-form" method="POST" action="sendEmailMessage" commandName="emailForm">
<div class="form-group">
<h1 class="email-header">SiteMidner Email Notification</h1>
<c:choose>
<c:when test="${not empty sMsg}">
<div class="email-Commu-SMsg">* ${sMsg}</div>
</c:when>
<c:otherwise>
<c:if test="${not empty eMsg}">
<div class="email-Commu-EMsg">* ${eMsg}</div>
</c:if>
</c:otherwise>
</c:choose>
<div class="form-emailCommu">
<label for="emailSub-txtArea" class="email-ContentHead">Enter
the Subject Line for the Email : </label>
<div class="email-sm-textDiv">
<form:textarea path="emailSubject" name="emailSubject" id="emailSubTxtArea"
placeholder="Email Subject"/>
</div>
<span><form:errors path="emailSubject" cssClass="error" /></span>
</div>
<div class="form-emailCommu">
<label for="emailBod-txtArea" class="email-ContentHead">Enter
the Message Body for the Email : </label>
<div class="email-sm-textDiv">
<form:textarea path="emailMsg" name="emailMsg" id="emailBodyTxtArea"
placeholder="Email Body"/>
</div>
<span><form:errors path="emailMsg" cssClass="error" /></span>
</div>
<div class="email-sendButton">
<input type="submit" class="styled-button" value="Send Email"></input>
</div>
</div>
</form:form>
</div>
<!--form-fields close -->
</div>
</div>
controller code:
#RequestMapping(value="/sendEmailMessage",method=RequestMethod.POST)
public ModelAndView sendEmailCommunication(#Valid #ModelAttribute("emailForm") EmailReqInfo emailInfo,BindingResult result,HttpServletRequest request){
ModelAndView view = null;
StringBuffer sMsg = new StringBuffer();
StringBuffer eMsg = new StringBuffer();
boolean isAdmin = false;
try{
String loggedInUser = request.getHeader("sm_user").trim();
isAdmin = getUserAdminRights(request);
if(result.hasErrors()){
view = new ModelAndView("EmailCommunication");
view.addObject("isAdmin", isAdmin);
return view;
}
else{
String emailSubject = emailInfo.getEmailSubject();
String emailMsg = emailInfo.getEmailMsg().replace("\n", "<br />\n");
boolean status = emailService.sendEmailCommuncation(emailSubject,emailMsg);
if(status){
sMsg.append(" Sending SiteMinder Notification Email was Success.");
}
else{
eMsg.append(" Oops! Something went wrong while sending Email Notification. Pls check logs");
}
}
}
catch(Exception ex){
ex.printStackTrace();
eMsg.append("Oops! Something went wrong while sending Email Notification. Pls check logs");
}
view = new ModelAndView("EmailCommunication");
view.addObject("emailForm", new EmailReqInfo());
view.addObject("isAdmin", isAdmin);
view.addObject("sMsg", sMsg.toString());
view.addObject("eMsg", eMsg.toString());
return view;
}
email Model:
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.NotEmpty;
public class EmailReqInfo
{
#NotNull #NotEmpty
#Size(min=1)
private String emailSubject;
#NotNull #NotEmpty
private String emailMsg;
public String getEmailSubject() {
return emailSubject;
}
public void setEmailSubject(String emailSubject) {
this.emailSubject = emailSubject;
}
public String getEmailMsg() {
return emailMsg;
}
public void setEmailMsg(String emailMsg) {
this.emailMsg = emailMsg;
}
}
i have the necessary annotation in my spring-mvc.xml
<mvc:annotation-driven>
<mvc:message-converters register-defaults="false">
<bean id="jacksonMessageConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
help needed in fixing the validation..thanks
#NotNull: Checks whether the value is not null, disregarding the content.
#NotEmpty: Checks whether the value is not null nor empty. If it has just empty spaces, it will allow it as not empty.
#NotBlank: Checks whether the value is not null nor empty, trimming the value first. It means that, it won’t allow just empty spaces
So, if you want to validate that a field is not null but also that it doesn’t has just empty spaces, but text, you should use #NotBlank.
This example is working, try to do the same:
Entity:
#Entity
#Table(name="EMPLOYEE")
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Size(min=3, max=50)
#Column(name = "NAME", nullable = false)
private String name;
#NotNull
#DateTimeFormat(pattern="dd/MM/yyyy")
#Column(name = "JOINING_DATE", nullable = false)
#Type(type="org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
private LocalDate joiningDate;
#NotNull
#Digits(integer=8, fraction=2)
#Column(name = "SALARY", nullable = false)
private BigDecimal salary;
#NotEmpty
#Column(name = "SSN", unique=true, nullable = false)
private String ssn;
//getter & setter
}
Controller:
#RequestMapping(value = { "/new" }, method = RequestMethod.POST)
public String saveEmployee(#Valid Employee employee, BindingResult result,
ModelMap model) {
if (result.hasErrors()) {
return "registration";
}
service.saveEmployee(employee);
model.addAttribute("success", "Employee " + employee.getName() + " registered successfully");
return "success";
}
registation.jsp
<h2>Registration Form</h2>
<form:form method="POST" modelAttribute="employee">
<form:input type="hidden" path="id" id="id"/>
<table>
<tr>
<td><label for="name">Name: </label> </td>
<td><form:input path="name" id="name"/></td>
<td><form:errors path="name" cssClass="error"/></td>
</tr>
<tr>
<td><label for="joiningDate">Joining Date: </label> </td>
<td><form:input path="joiningDate" id="joiningDate"/></td>
<td><form:errors path="joiningDate" cssClass="error"/></td>
</tr>
<tr>
<td><label for="salary">Salary: </label> </td>
<td><form:input path="salary" id="salary"/></td>
<td><form:errors path="salary" cssClass="error"/></td>
</tr>
<tr>
<td><label for="ssn">SSN: </label> </td>
<td><form:input path="ssn" id="ssn"/></td>
<td><form:errors path="ssn" cssClass="error"/></td>
</tr>
<tr>
<td colspan="3">
<c:choose>
<c:when test="${edit}">
<input type="submit" value="Update"/>
</c:when>
<c:otherwise>
<input type="submit" value="Register"/>
</c:otherwise>
</c:choose>
</td>
</tr>
</table>
</form:form>
I see problem with Hibernate Validators. #NotEmpty is anyway on top of #NotNull.
Try removing #NotEmpty validation constraints from your form and execute once again.

Spring 4 and thymeleaf form validatation

Can anyone give sample Java code for validating the HTML form (ex: form attributes not null, minimum and maximum size) using via Spring MVC and with thymeleaf-spring4 libraries?
The simplest, you annotate your dao object (in this case user), with the constraints you need:
#Entity
public class User
{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#NotNull
private String login;
#Size(min=2, max=30)
private String firstName;
#Min(18)
private int age;
}
These annotation are from javax.validation.constraints.
After this you need to modify your controller, you need to clarify your controller that the object must be #Valid:
#RequestMapping(method=RequestMethod.POST)
public String registerUser(#Valid final User user, final BindingResult bindingResult)
{
if (bindingResult.hasErrors()) {
return "form";
}
// Your code
return "redirect:/userList";
}
The errors are stored in the BindingResult.
Finally show the errors:
<span th:if="${#fields.hasErrors('login')}" th:errors="*{login}"></span>
Edit:
Return ModelAndView
#RequestMapping(method=RequestMethod.POST)
public ModelAndView registerUser(#Valid final User user, final BindingResult bindingResult)
{
if (bindingResult.hasErrors()) {
ModelAndView mav = new ModelAndView("form");
mav.addObject(bindingResult);
return mav;
}
}
These are latest maven dependencies for java validation API
1.dependency
groupId javax.validation
artifactId validation-api
version 1.1.0.Final
2.dependency
groupId org.hibernate
artifactId hibernate-validator
version 5.0.1.Final
Take a look at this:
First, comes the Object...
public class PruebaFormCommand {
#NotEmpty
#Size(min = 3, max = 50)
private String textoPrueba;
public String getTextoPrueba() {
return textoPrueba;
}
public void setTextoPrueba(String textoPrueba) {
this.textoPrueba = textoPrueba;
}
}
Then, the Controller:
#Controller
public class PruebaFormController {
#RequestMapping("/pruebaform")
public String pruebaForm(Model model){
model.addAttribute("pruebaFormCommand", new PruebaFormCommand());
return "pruebaform";
}
#RequestMapping(value = "/dopruebaform", method = RequestMethod.POST)
public String doPruebaForm(#Valid PruebaFormCommand pruebaFormCommand, BindingResult bindingResult){
if (bindingResult.hasErrors()) {
return "pruebaform";
}
return "pruebaformcomplete";
}
}
Then, the HTML:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<link href="../static/css/bootstrap-3.3.4-dist/css/bootstrap.min.css" rel="stylesheet" media="screen"
th:href="#{/css/bootstrap-3.3.4-dist/css/bootstrap.min.css}"/>
<script src="../static/js/jquery-2.1.4.min.js"
th:src="#{/js/jquery-2.1.4.min.js}"></script>
<link th:href="#{/css/custom.css}" rel="stylesheet" media="screen"/>
<title>Checkout</title>
</head>
<body>
<div class="container">
<h2>PRUEBA Form</h2>
<form class="form-horizontal" th:object="${pruebaFormCommand}" th:action="#{/dopruebaform}" method="post">
<div th:if="${#fields.hasErrors('*')}" class="alert alert-danger">
<p th:text="#{pruebaFormCommand.hasErrors}">Error Message</p>
</div>
<div class="form-group" th:class="${#fields.hasErrors('textoPrueba')} ? 'form-group has-error' : 'form-group'">
<label class="col-sm-2 control-label">Meteme algo payo:</label>
<div class="col-sm-10">
<input type="text" class="form-control" th:field="*{textoPrueba}" th:errorclass="has-error"/>
<span class="help-block" th:if="${#fields.hasErrors('textoPrueba')}">
<ul>
<li th:each="err : ${#fields.errors('textoPrueba')}" th:text="${err}" />
</ul>
</span>
</div>
</div>
<div class="row">
<button type="submit" class="btn btn-default">Submit</button>
</div>
</form>
</div>
</body>
</html>
Finally, include your message.properties:
pruebaFormCommand.hasErrors=Porfa corrige los errores:
NotEmpty.pruebaFormCommand.textoPrueba={0} caracteres mínimo....
Size.pruebaFormCommand.textoPrueba={0} debe tener entre {2} y {1} caracteres

Categories