Thymeleaf with SpringBoot - how to loop model and delete? - java

I am using SpringBoot with Thymeleaf to build a trivial example to help me learn the two technologies.
I am basing my example on THIS GUIDE
The entity is a Greeting which has an Id and a Content.
I create the Greeting just fine, and I can list all the Greetings I've created.
I then wanted to add a delete option against each Greeting in the list page. When clicking delete, I want the object to be deleted and the list page served up again.
Alas, when I load the list page I get this error:
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'greeting' available as request attribute
Controller and respository objects
#Controller
public class GreetingController {
#Autowired
GreetingRepo gr;
#RequestMapping(value="/greeting/list", method=RequestMethod.GET)
public String greetingsForm(Model model) {
model.addAttribute("greetings", gr.findAll());
return "greeting/list";
}
#RequestMapping(value="/greeting/delete", method=RequestMethod.POST)
public String deleteGreeting(#ModelAttribute("greeting") Greeting greeting) {
gr.delete(greeting);
return "redirect:/greeting/list";
}
}
#RepositoryRestResource
interface GreetingRepo extends JpaRepository<Greeting, Long> {
}
List.html page:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Handling Form Submission</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h1>Result</h1>
<div th:each="greeting : ${greetings}">
<p th:text="'id: ' + ${greeting.id}" />
<p th:text="'content: ' + ${greeting.content}" />
<form action="#" th:action="#{/greeting/delete}" th:object="${greeting}" method="post">
<input type="hidden" th:field="*{id}"/>
<input type="hidden" th:field="*{content}"/>
<input type="Submit" value="Delete"/>
</form>
</div>
Add another
Show All
</body>
</html>
Would appreciate a push in the right direction here :-)

I think you miss this line .
model.addAttribute("greeting", new Greeting());
#RequestMapping(value="/greeting/list", method=RequestMethod.GET)
public String greetingsForm(Model model) {
model.addAttribute("greeting", new Greeting());
model.addAttribute("greetings", gr.findAll());
return "greeting/list";
}

you dont have to use a form to delete the greeting you can do it very easily with this approach. hide the id of the greeting within the url. so you dont need to use a form and hidden tags. and annotate the controller method with following approach, to accept incoming id of the greeting.
replace the current form with given html code and replace the delete method in the controller as well.
<a th:href="#{/greeting/{id}/delete(id=${greeting.id})}" th:text="delete"></a>
#RequestMapping(value="/greeting/{id}/delete",method=RequestMethod.GET)
public String deleteGreeting(#PathVariable int id) {
gr.delete(id);
return "redirect:/greeting/list";
}
edit:- since you need the object to be present within the controller
you can use findOne method to fetch the object from the given id.check out the following example.
<a th:href="#{/greeting/{id}/edit(id=${greeting.id})}" th:text="edit"></a>
#RequestMapping(value="/greeting/{id}/edit",method=RequestMethod.GET)
public String Edit(#PathVariable int id){
greeting greetingob = gr.findOne(id);
return "edit";
}

Related

Spring Boot Thymeleaf SpelEvaluationException EL1007E when submitting a form

I'm trying to handle a form submission with thymeleaf in my spring-boot application, i integrated
this example which worked fine on my app. I'm trying to change it a little bit, but this is what i'm getting as an exception:
org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field 'recruiter' cannot be found on null
at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:213) ~[spring-expression-5.2.3.RELEASE.jar:5.2.3.RELEASE]
...
This is the object i'm trying to handle with thymeleaf
public class FormRec {
private String recruiter;
public String getRecruiter() {
return recruiter;
}
public void setRecruiter(String recruiter) {
this.recruiter = recruiter;
}
}
This is my Controller
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import com.service.minimicroservice.objects.FormRec;
#Controller
public class MyController {
#GetMapping("/form")
public String greetingForm(Model model) {
model.addAttribute("recForm", new FormRec());
return "form";
}
#PostMapping("/form")
public String greetingSubmit(#ModelAttribute FormRec rec) {
return "result";
}
}
result.html
<!DOCTYPE HTML>
<html xmlns:th="https://www.thymeleaf.org">
<head>
<title>Getting Started: Handling Form Submission</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h1>Result</h1>
<p th:text="'Recruiter: ' + ${rec.recruiter}" />
Submit another message
</body>
</html>
part of the form.html
<body>
<form action="#" th:action="#{/form}" th:object="${recForm}" method="post">
<div class="form-row m-b-55">
<div class="name">Recruiter<br> Name</div>
<div class="value">
<div class="row row-space">
<div class="col-2">
<div class="input-group-desc">
<input class="input--style-5" type="text" name="first_name" th:field="*{recruiter}">
<label class="label--desc">Full Name</label>
</div>
</div>
...
In order to refer to a FormRec Object i use recForm as th:object in the form.html and rec to refer to it in the result.html.
Note: I pass a value to the th:field="*{recruiter}" input text when i submit the form (is not null)
You have to name the ModelAttribute rec that the data gets bound to. So in your controller method do this (notice the name = "rec"):
public String greetingSubmit(#ModelAttribute(name = "rec") FormRec rec) {
...
}
It should work.
Additional explanation:
I've had a closer look at why that happens and it's because Spring's ModelAttribute annotation by default infers from the name of the type and not the name of the parameter (the example link you provided says it's method parameter name, but it seems to be wrong).
So in this case Spring sends formRec (notice the camelCase, which it expects when the class name is called FormRec) to the result.html and not rec as you would expect.
If my explanation doesn't really make sense, then this is the Spring documentation on ModelAttribute:
The default model attribute name is inferred from the declared attribute type (i.e. the method parameter type or method return type), based on the non-qualified class name: e.g. "orderAddress" for class "mypackage.OrderAddress", or "orderAddressList" for "List".

Sending dto with html file in Spring mvc

My current controller is returning to an HTML page. I want to send some data (a DTO) which can be received at front end, like an ajax response (like it happens in ajax + RestController). But this is not a RestController, it is a normal #controller returning HTML. I don't know even if it is possible to send DTO with html. There isn't much code to look at. I am just looking for feasibility. Do let me know if additional info is required. Thanks
Edit
Here is some code for reference. login.html is the page I am returning to. I want to send some additional info with this return ( in the form of a DTO ).
#Controller
public class LoginUserController {
#RequestMapping(value = {"/loginuser", "/loginuser?error"})
public String login() {
return "/login";
}
}
If you want to return view only i.e jsp in your case . You could put DTO object in modelMap and used inside jsp . Or simply if you want to return JSON only you could use #ResponseBody .
#RequestMapping(value = {"/loginuser", "/loginuser?error"})
public String login(ModelMap model) {
YourDTO dtoObject = // get DTO;
model.put("dtoObject",dtoObject)
return "/login";
}
class YourDTO {
private int id;
private String name;
// getters setters
}
Inside login JSP you can usedtoObject .
Name <c:out value="${dtoObject.name}" ></c:out> // Using JSTL
Or In Html file
<input type="text" id="name" value='${dtoObject.name}'/>
Seems like you're trying to build a spring boot web app, here is the bare minimum what you need to do:
Make sure your maven dependencies have spring-boot-starter-thymeleaf along with spring-boot-starter-webapp in the pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Configure/write your controller like this :
#Controller
public class LoginUserController {
#GetMapping(value = {"/loginuser", "/loginuser?error"})
public String login( Model model) {
model.addAttribute("message", "Aww snaps! something went wrong...");
return "login";
}
}
Ensure you have src/main/resources/templates/login.html which may look like this:
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Login Page</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:text="${message}" />
</body>
</html>
You can use any other viewing technology of your choice instead of Thymeleaf. Basically the viewing technology parses the HTML template, looks for expressions like
th:text
to reslove the value of
${message}
with the data that you've put in the model in Controller.
Hope this helps!
you can use following code
#Controller
public class LoginUserController {
#GetMapping(value = {"/loginuser", "/loginuser?error"})
public String login( Model model) {
organizationDTO = organizationService.getOrganizationDTO(id);
model.addAttribute("organizationDTO", organizationDTO);
return "/login";
}
}
and use below code in HTML page using JSTL
<div class="row">
<p class="col-md-4">${organizationDTO."your value"}</p>
</div>
eg below
<div class="row">
<label class="col-md-2">Id</label>
<p class="col-md-4">${organizationDTO.id}</p>
<label class="col-md-2">Name</label>
<p class="col-md-4">${organizationDTO.name}</p>
</div>

Should l make Spring Model class with one field?

I don't know should i make class with only one field which l will use as #ModelAttribute to get data from jsp? for example:
public class Age {
private int number;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}}
And then using spring mvc form tag to fill this ModuleAttribute
<form:form action="processForm" modelAttribute="age">
<form:input path="number"/>
</form:form>
First of all, you need to create a controller :
#Controller
public class AgeController {
// this is to create an instance of Age and set in the model.
#RequestMapping("showForm")
public String showForm(Model model) {
model.addAttribute("age", new Age());
return "form"; // return form page.
}
// this is to print the age in the display page.
#RequestMapping("processForm")
public String processForm(#ModelAttribute("age") Age age) {
return "display"; // return display page where you will display the data populated in the form page.
}
}
Now, form page should look like :
<%#taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<!DOCTYPE html>
<html>
<!-- When you enter the data here, Spring will set the data in the Age bean by calling respective setter of the data members -->
<body>
<form:form action="processForm" modelAttribute="age">
Enter an age : <form:input path="number" />
<input type="submit" value="Submit" />
</form:form>
</body>
</html>
Now, display page should look like :
<%#taglib prefix="core" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<body>
The age is : ${age.number} <!-- Here getter is called internally -->
</body>
</html>
On clicking the submit, the display page will show the data.

How can i open JSP page from another JSP page in java Spring MVC?

I want create 2 JSP pages. I have Controller:
#Controller
#RequestMapping(value = "/api/web/users")
public class ServletWebController {
#RequestMapping(method = RequestMethod.GET)
public String printWelcome(ModelMap model) {
model.addAttribute("message", "message");
return "hello";
}
}
It open first JSP page with form:
<html>
<body>
<form action="main.jsp" method="post">
First Name: <input type="text" name="first_name">
<br />
Last Name: <input type="text" name="last_name" />
<input type="submit" value="Submit" />
</form>
</body>
</html>
When I input data to the form and press submit button, I want to open second JSP page and print data from form:
<html>
<head>
<title>Using GET and POST Method to Read Form Data</title>
</head>
<body>
<center>
<h1>Using GET Method to Read Form Data</h1>
<ul>
<li><p><b>First Name:</b>
<%= request.getParameter("first_name")%>
</p></li>
<li><p><b>Last Name:</b>
<%= request.getParameter("last_name")%>
</p></li>
</ul>
</body>
</html>
But the second JSP page not opened. So I input http://localhost:4000/api/web/users And i have form. Then I input data and press "Submit". Then I have this link http://localhost:4000/api/web/main.jsp and error:
HTTP Status 404 - /api/web/main.jsp
type Status report
message /api/web/main.jsp
description The requested resource is not available.
Apache Tomcat/8.0.26
I am new in Spring and JSP, how can I open JSP from another JSP?
in your Controller you can do something like this:
#RequestMapping(value="/successpage", method =RequestMethod.POST)
public void successpage(ModelMap model, Users user)
{
model.addAttribute("name", user.getFirstName());
}
#RequestMapping(value="/signupform", method=RequestMethod.GET)
public ModelAndView signupForm()
{
return new ModelAndView("user", "command", new Users()); //Object that contains your getter and setters
}
On your form you can modify your open Form tag to look like this:
<form action="/successpage" method="POST">
In your WEB-INF/jsp folder you will need the 2 pages: signupform.jsp and successpage.jsp
After all is said and done, you can pass the ${name} variable on your successpage.jsp to see the value from the form.

#RequestMapping with #PathVariable URI is different

hi i have a problem i am learnig how to pass values with PathVariable, i have a form with a input text and a button when you press the buttom it takes you to other page and show the value but it dont work when i press the buttom it takes me to this URL:
http://localhost:8080/appThyme/shoForm1.html?firstname=MyName&submit=
and i get this error HTTP 404 - /appThyme/showForm1.html
but if i put this URL: http://localhost:8080/appThyme/respuesta/Myname it works it shows me my page with my name, how can i make that work with only pressing the buttom, why when i press the buttom it add question marks and equals symbols to my URI
#Controller
public class HomeController {
#RequestMapping(value = "/form1", method = RequestMethod.GET)
public String showFormulario2(Model model) {
logger.info("***PAG formulario***");
return "form1.html";
}
#RequestMapping(value = "/showForm1/{id}", method = RequestMethod.GET)
public String showForm(Model model, #PathVariable("id") String id)
{
String theId= id;
model.addAttribute("TheID", theId);
return "showForm1.html";
}
my form1.html page
<form id="guestForm" th:action="#{/showForm1.html}" method="get">
<div>
<input type="text" name="firstname" id="firstname"></input>
</div>
<div>
<button type="submit" name="submit">Submit</button>
</div>
</form>
my showForm1.html page
enter code here
<html>
<head>
<title>Home</title>
</head>
<body>
<h1>
Hello world!
</h1>
<P> The value is ${nombre} </P>
</body>
</html>
Form submissions are not intended to work with the #PathVariable construct you are using here. #PathVariable is intended for use with REST-style URI's, and that is not what is generated on a form submit.
If you change your controller signature to look like this:
#RequestMapping("/showForm1.html", method = RequestMethod.GET)
public String showForm(Model model, #RequestParam("firstname") String id)
{
String theId= id;
model.addAttribute("TheID", theId);
return "showForm1.html";
}
then the method should be called correctly on form submission.

Categories