Send values from thymeleaf to a spring boot service class - java

I am testing a spring boot application which uses thymeleaf, but I could not find any docs explaining how to send select options values from thymeleaf to a spring boot service class.
Basically, what I am trying to achieve is get values from the select tag so that I can insert them to the database through the method below:
Please note: this method is in the service class => it has both get and post mapping in the controller class.
public void addNewJob(JobPostEntity jobPostEntity, #RequestParam(value="selectCategory") String selectCategory) {
jobPostEntity.setJobcategory("test");
jobPostRepository.save(jobPostEntity);
}
the thymeleaf file is:
<form th:action="#{/newjob}" th:object="${addNewJob}" method="post">
<div class="form-group">
<label for="">Offer Title</label>
<input type="text" th:field="*{jobtitle}" class="form-control" placeholder="Entre Offer Title">
<small class="form-text text-muted">We'll never share your email
with anyone else.</small>
</div>
<div class="form-group">
<label >Company Name</label>
<input type="text" th:field="*{jobcompany}" class="form-control" placeholder="Enter Company Name">
</div>
<div class="form-group dropdown">
<label for="sel1">Choose Category (select one):</label>
<select name="*selectCategory"
class="form-control" id="selectCategory"
onchange="getSelectedValue();" th:field="*{selectCategory}">
<option value="">Select Option</option>
<option value="software_engineer">Software Engineer</option>
<option value="graphic_design ">Graphic Design</option>
<option value="customer_service ">Customer Service</option>
<option value="marketing" >Marketing</option>
<option value="healthcare">Health Care</option>
</select>
</div>
<div class="form-group">
<label for="exampleInputPassword1">Offer</label>
<textarea class="form-control" th:field="*{jobtext}" placeholder="Describe your job offer"></textarea>
</div>
<button type="submit" class="btn btn-primary">Submit Offer</button>
</form>

First, you need to properly configure your controller class. I assume this is where your addNewJob method is located, so I use this in my example.
You need to have a #GetMapping (which is the same as #RequestMapping(method = RequestMethod.GET) that returns the name of the view (this is your thymeleaf file - in the example below I used jobForm.html for this) and maps to a specific path (/test in example).
#GetMapping("/test")
public String getTestView() {
return "jobform";
}
You will also need a method which creates/retrieve the model object you use to fill the form with. This is mapped as th:object=${addNewJob} in the form:
#ModelAttribute(value = "addNewJob")
public JobPostEntity newEntity() {
return new JobPostEntity();
}
Finally, you will need a method with #PostMapping, that's called when you submit your form. In your example, that's mapped to /newjob, so I used this too:
#PostMapping(value = "/newjob")
public void addNewJob(
#ModelAttribute("addNewJob") final JobPostEntity myEntity) {
System.out.println("got dto: " + myEntity);
System.out.println("selectCategory: " + myEntity.getSelectedCategory());
}
To summarize the controller would look something like this:
#Controller
public class TestController {
#GetMapping("/test")
public String getTestView() {
return "jobform";
}
#PostMapping(value = "/newjob")
public void addNewJob(
#ModelAttribute("addNewJob") final JobPostEntity myEntity) {
System.out.println("got dto: " + myEntity);
System.out.println("selectCategory: " + selectCategory);
}
#ModelAttribute(value = "addNewJob")
public JobPostEntity newEntity() {
return new JobPostEntity();
}
}
As for the select option to work, I'd also put that field in the modelAttribute, so you don't have to treat them separately:
public class JobPostEntity {
private String jobtitle;
private String jobcompany;
private String jobtext;
private String selectCategory;
//getters/setters
}
Your pasted html code also contains a few issues:
you don't have the opening tags for form
the select tag doesn't have thymeleaf mapping for it (th:field)
the input tags doesn't have closing elements
The fixed version, which works for me, looks something like this (excluding the body/head/etc wrapper tags):
<form th:action="#{/newjob}" th:object="${addNewJob}" method="post">
<div class="form-group">
<label for="">Offer Title</label>
<input type="text" th:field="*{jobtitle}" class="form-control" placeholder="Entre Offer Title" />
<small class="form-text text-muted">We'll never share your email
with anyone else.</small>
</div>
<div class="form-group">
<label >Company Name</label>
<input type="text" th:field="*{jobcompany}" class="form-control" placeholder="Enter Company Name"/>
</div>
<div class="form-group dropdown">
<label for="sel1">Choose Category (select one):</label>
<select name="*selectCategory"
class="form-control" id="selectCategory"
onchange="getSelectedValue();"
th:field="*{selectCategory}">
<option value="">Select Option</option>
<option value="software_engineer">Software Engineer</option>
<option value="graphic_design ">Graphic Design</option>
<option value="customer_service ">Customer Service</option>
<option value="marketing" >Marketing</option>
<option value="healthcare">Health Care</option>
</select>
</div>
<div class="form-group">
<label for="exampleInputPassword1">Offer</label>
<textarea class="form-control" th:field="*{jobtext}" placeholder="Describe your job offer"></textarea>
</div>
<button type="submit" class="btn btn-primary">Submit Offer</button>
</form>
if you start your application and type http://localhost:8080/test (if you use the default context path / port ) in your browser, the form should appear and work as expected.
also, you can find a pretty good tutorial on here http://www.baeldung.com/thymeleaf-in-spring-mvc

Related

Exception sending id field to #PostMapping

I'm getting this exceptions when trying to update an object with a PostMapping:
Caused by: org.thymeleaf.exceptions.TemplateProcessingException:
Exception evaluating SpringEL expression: "libro.id" (template:
"formulario-modificar-libros-p" - line 18, col 15)
Caused by:
org.springframework.expression.spel.SpelEvaluationException: EL1007E:
Property or field 'id' cannot be found on null
Form:
<form th:action="#{/libros/modificar-libro-d/__${libro.id}__}" method="post">
<input hidden th:value="${libro.id}" name="id">
<div class="form-group">
<label>ISBN del libro</label> <input th:value="${libro.isbn}" type="number" class="form-control" name="isbnLibro" required>
</div>
<div class="form-group">
<label>Título del libro</label> <input th:value="${libro.titulo}" type="text" class="form-control" name="tituloLibro" required>
</div>
<div class="form-group">
<label>Año del libro</label> <input th:value="${libro.anio}" type="number" class="form-control" name="anioLibro">
</div>
<div class="form-group">
<label>Ejemplares del libro</label> <input th:value="${libro.ejemplares}" type="number" class="form-control" name="ejemplaresLibro" required>
</div>
<div>
<label>Autor</label>
<select class="form-select" aria-label="Default select example" name="nombreAutor">
<option th:each="autor:${autores}"
th:text="${autor.nombre}"
th:value="${autor.nombre}"
>
</option>
</select>
</div>
<div>
<label>Editorial</label>
<select class="form-select" aria-label="Default select example" name="nombreEditorial">
<option th:each="editorial:${editoriales}"
th:text="${editorial.nombre}"
th:value="${editorial.nombre}"
>
</option>
</select>
</div>
<button type="submit" class="btn btn-primary">Aceptar</button>
</form>
Controller
#PostMapping("/modificar-libro-d/{id}")
public String modificarLibroM(#PathVariable String id, #RequestParam Long isbnLibro, #RequestParam String tituloLibro, #RequestParam Integer anioLibro,
#RequestParam Integer ejemplaresLibro, #RequestParam String nombreAutor, #RequestParam String nombreEditorial){
try {
libroServicio.modificarLibro(id, isbnLibro, tituloLibro, anioLibro, ejemplaresLibro, nombreAutor, nombreEditorial);
return "redirect:/libros/lista-libros-d";
} catch (Exception e) {
return "formulario-modificar-libros-p";
}
}
#GetMapping("/modificar-libro-d/{id}")
public String formularioModificarLibrosM(#PathVariable String id, ModelMap modelo) {
modelo.addAttribute("libro", libroServicio.buscarLibroPorId(id));
modelo.addAttribute("autores", autorServicio.listarAutoresAlta());
modelo.addAttribute("editoriales", editorialServicio.listarEditorialesAlta());
return "formulario-modificar-libros-p";
}
In the entity, all fields have their getters and setters correctly.
It looks like your code is okay but the find by id method on your book service returns null for the given id. Put a breakpoint on it and run it in debug. If a libro object must always be present, consider defining your libroServicio.buscarLibroPorId(id) method such that an exception is thrown for a missing id and/or set up error handling in your thymeleaf template.

Problem with PostMapping - GetMapping method - loop in link. SpringBoot

I have problems with sending data to one of my tables.
Below you can see my methods: one that shows the template with form, and the second that shoud add this action.
#GetMapping("/addaction/{id}")
public String addAction(Model model, #PathVariable("id") int id ) {
Optional<PlantEntity> plantEntity = plantService.getPlantById(id);
if (plantEntity.isPresent()) {
model.addAttribute("plant", plantEntity.get());
}
return "addaction";
}
#PostMapping("/addaction/{id}")
public String addAction(#ModelAttribute ActionForm actionForm,
#PathVariable("id") int plantId) {
if(!userService.isLogin()) {
return "redirect:/";
}
actionService.addAction(actionForm, plantId);
return "redirect:/plant/"+plantId;
}
Here is my method in Service:
public void addAction (ActionForm actionForm, int plantId) {
PlantEntity plantEntity = new PlantEntity();
plantEntity.setId(plantId);
ActionEntity act = new ActionEntity();
act.setName(actionForm.getName());
act.setDescription(actionForm.getDescription());
act.setPlant(plantEntity);
act.setUser(userService.getUserData());
act.setMonth(actionForm.getMonth());
actionRepository.save(act);
}
and my template: addaction.html
<form method="post" action="'/addaction/'+${plant.getId()}"
th:object="${actionForm}">
<div class="form-group">
<label for="exampleInputEmail1">Name of activity</label> <input
type="text" th:field="*{name}" class="form-control"
id="exampleFormControlInput1" aria-describedby="emailHelp"
placeholder="Name your work">
</div>
<div class="form-group">
<label for="exampleFormControlTextarea1">What you gonna
do?</label>
<textarea class="form-control" th:field="*{description}"
id="exampleFormControlTextarea1" rows="4"></textarea>
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<label class="input-group-text" for="inputGroupSelect01">Month of activity</label>
</div>
<select class="custom-select" th:field="*{month}"
id="inputGroupSelect01">
<option value="1">January</option>
<option value="2">February</option>
<option value="3">March</option>
<option value="4">April</option>
<option value="5">May</option>
<option value="6">June</option>
<option value="7">July</option>
<option value="8">August</option>
<option value="9">September</option>
<option value="10">October</option>
<option value="11">November</option>
<option value="12">December</option>
</select>
</div>
<button type="submit" class="btn btn-dark">Action!</button>
</form>
The main problem is: when I try to addAction the result is:
http://localhost:8080/addaction/'/addaction/'+$%7Bplant.getId()%7D
There is some kind of loop. What am I doing wrong? Thank you for your time!
You don't have to pass '. spring expression language will take without ' also.
Try removing like below.
action="/addaction/${plant.getId()}"
Refer thymeleaf-construct-url-with-variable

Spring and hibernate persist() not working

Hello I am developing a CMS using Spring and Hibernate. I have a page displaying existing products and a form which should add a new product to the database. However when I fill out the form and submit it nothing gets saved to the database. Additionally System.out.println does not print anything to the console so I have no idea where is the problem.
jsp page
<form:form class="form-horizontal" method="post" modelAttribute="productForm">
<div class="form-group">
<label class="col-sm-2 control-label"> Product Name:</label>
<div class="col-sm-10">
<form:input class="form-control" type="text" id="productName" name="product name" path="name" />
<br></div></div>
<div class="form-group">
<label class="col-sm-2 control-label"> Serial number:</label>
<div class="col-sm-10">
<form:input class="form-control" type="text" id="productSerial" name="serial number" path="serial" value=" " /></div></div>
<input type="submit" value="Submit">
</form:form>
controller
#RequestMapping(value = "/saveNewContact", method = RequestMethod.POST)
public ModelAndView saveContact(#ModelAttribute("userForm") Product product,
BindingResult result, Model model) {
System.out.println(product);
productService.saveOrUpdate(product);
return new ModelAndView("redirect:/");
}
Service
#Override
public void saveProduct(Product product) {
productDao.saveProduct(product);
}
DAO
the interface implementation has #Transactional(readOnly = false)
public void saveNewProduct(Product product) {
persist(product);
}
The problem was in the form just adding action="saveNewContact" fixed the issue.

print an arraylist while passing it from a controller to a jsp

hi i am trying to print the contents of an arraylist in a jsp
here is the controller code
#RequestMapping(value = "/deleteFilter", method = RequestMethod.GET)
public String deleteFilter(FilterValues filterData,ModelMap modalMap) {
logger.info("delete a filter");
ArrayList<String> filtername= mongoService.getTargetFiltersName();
modalMap.addAttribute("filterslist", filtername);
return "delete";
}
and here is the part of the jsp where i have to print it
<div class="col-xs-4">
<label for="pwd">Filter Name:</label>
<select type="Filter Name" class="form-control" id="pwd" placeholder="Enter Filter Name">
<c:forEach items="${filterslist}" var="filtername">
<option value="${filtername.value}">${filtername.value}</option>
</c:forEach>
</select>
</div>
its giving me errors
thanks in advance
i think you should use the following code as you are iterating on an ArrayList of String
<div class="col-xs-4">
<label for="pwd">Filter Name:</label>
<select type="Filter Name" class="form-control" id="pwd" placeholder="Enter Filter Name">
<c:forEach items="${filterslist}" var="filtername">
<option value="${filtername}">${filtername}</option>
</c:forEach>
</select>
</div>

Spring MVC Form Submit - Dynamically change the form catching Object

My Spring framework version 3.1.4
Question ??? Is there is any way to dynamically change the form catching Object depending on the some criteria.
Its really tough to explain, I will do my best here
JAVA OBJECTS
I have a Java Object PatientDocument.java
public class PatientDocument{
#Id
protected String documentId;
#Indexed
protected String patientId;
#Indexed
protected Integer documentType;
protected Object document;
}
The field document in above class can have any datatype objects depending upon the value in field documentType Eg : If documentType is 1, the Object representing the field 'document' will be MedicalCertificate.Java and I'm storing the PatientDocument into MongoDB collection.
MedicalCertificate.java looks like
public class MedicalCertificate {
protected String complaint;
protected String suggestedRestingDays;
protected Integer treatingDoctor;
protected Integer medicalDirector;
}
CLIENT SIDE
I'm using Thymeleaf for my client side rendering
My patientDocument.html looks like
<form action="#" id="patientDocument" th:action="#{/emr/patient/document/save}" th:object="${patientDocument}" method="post" class="form-horizontal">
<!-- #### HIDDEN FIELDS #### -->
<input type="hidden" th:field="*{documentId}" class="col-xs-12" readonly="readonly"/>
<input type="hidden" th:field="*{documentType}" class="col-xs-12" readonly="readonly"/>
<input type="hidden" th:field="*{patientId}" class="col-xs-12" readonly="readonly"/>
<!-- Medical Certificate -->
<section th:if="${patientDocument.documentType == 1}" layout:include="#{emr/patient/medicalCertificate} :: main"></section>
<!-- Referal Letter -->
<section th:if="${patientDocument.documentType == 2}" layout:include="#{emr/patient/referalLetter} :: main"></section>
<!-- Acknowledgment Form -->
<section th:if="${patientDocument.documentType == 3}" layout:include="#{emr/patient/acknowledgeForm} :: main"></section>
<form>
medicalCertificate.html looks like
<section layout:fragment="main">
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label class="control-label col-xs-2">Complaint</label>
<div class="col-xs-10">
<textarea rows="5" th:field="*{document.complaint}" class="col-xs-12"></textarea>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-xs-4">Rest For</label>
<div class="col-xs-8">
<input type="text" th:field="*{document.suggestedRestingDays}" class="col-xs-12"/>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-xs-4">Treated By</label>
<div class="col-xs-8">
<input type="hidden" th:field="*{document.treatingDoctor}" readonly="readonly"/>
<input type="text" th:field="*{document.treatingDoctorName}" class="form-control"/>
</div>
</div>
</div>
<div class="col-xs-6">
<div class="form-group">
<label class="control-label col-xs-4">Medical Director</label>
<div class="col-xs-8">
<input type="hidden" th:field="*{document.medicalDirector}" readonly="readonly"/>
<input type="text" th:field="*{document.medicalDirectorName}" class="form-control"/>
</div>
</div>
</div>
</div>
</section>
View Controller
#RequestMapping(value="/document/save", method=RequestMethod.POST)
public String savePatientDocument(#ModelAttribute PatientDocument patientDocument, Model model, HttpServletRequest request){
logger.debug("Executing save for Patient Document : {}", patientDocument.toString());
////Logic to the Service Layer
}
Explanation of the Questions : As you can see the patientDocument.html the Client side form content corresponding to field 'document' will be replaced by Thymeleaf Fragments depending on documentType field. So when i submit the form into view controller the Object patientDocument contains the MedicalCertificate fields in place of field 'document'. Thats alright !!!
Now in View Controller, i need to say to the submit handler that "Hey, a PatientDocument.java object is coming as form submit. But the object inside the field 'document' will be 'MedicalCertificate.java'"
Where can i specify that?? Is there is any way to do it in SPRING MVC??
I need to alter the patientDocument.java Object as below before the Catching the client side form submit. But how?
PatientDocument patientDocument = new PatientDocument();
patientDocument.setDocument(new MedicalCertificate());
Thanks in advance
Good Day
Option 1: Change your container class to:
public class PatientDocument{
#Id
protected String documentId;
#Indexed
protected String patientId;
#Indexed
protected Integer documentType;
protected AcknowledgeForm acknowledgeForm;
protected MedicalCertificate medicalCertificate;
protected ReferalLetter referalLetter;
}
Then, form fields in medicalCertificate.html would look like:
<textarea rows="5" th:field="*{medicalCertificate.complaint}" class="col-xs-12"></textarea>
<input type="text" th:field="*{medicalCertificate.suggestedRestingDays}" class="col-xs-12"/>
<input type="hidden" th:field="*{medicalCertificate.treatingDoctor}" readonly="readonly"/>
<input type="text" th:field="*{medicalCertificate.treatingDoctorName}" class="form-control"/>
You will have to make similar changes to the other forms. Then, you can read the required property of PatientDocument based on its documentType.
Option 2: Write a PropertyEditor for PatientDocument to parse the request and set the document based on the request parameters.

Categories