Spring & Thymeleaf form - spring

adding in form is trivial when I have only one object like here:
<form th:action="|#{group/save}/${id}|" th:object="${groupForm}" method="post" class="col m8 s8 offset-m2">
<div class="row">
<div class="input-field">
<input th:field="${groupForm.name}" id="name" type="text" required="required"/>
<label for="name">Nazwa:</label>
</div>
</div>
<div class="row">
<button class="btn-success" type="submit" name="save">Wyƛlij<i class="mdi-content-send right"></i></button>
</div>
</form>
but let's assume that groupForm have list of customer
public class Customer{
private long id;
private String firstName;
private String lastName;
private String nick;
}
How can I add 5 Customers into list in class Group? I want to achive in one request.

Assuming that your Group class looks something like this:
public class Group {
private List<Customer> customers;
}
Try this:
<input th:field="*{customers[0].name}" type="text" required="required"/>
<input th:field="*{customers[1].name}" type="text" required="required"/>
<input th:field="*{customers[2].name}" type="text" required="required"/>
<input th:field="*{customers[3].name}" type="text" required="required"/>
<input th:field="*{customers[4].name}" type="text" required="required"/>

Related

The server cannot process the request because of Spring MVC <form:select>

I am creating a formular in order to populate some entities. I run into problems when I am trying to POST a form which contains a Spring MVC <form:select> field.
In Eclipse I do not receive any error or warning message, while in the browser I get a http status 400 - Bad Request.
Type Status Report
Description The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).
Extra explanations:
I have a StudentDetails entity which contains 2 fields that I am interested in at the moment, Classroom classroom and ParentsDetails parentsDetails.
The Classroom objects are already created and all of them will be stored in a LinkedHashMap<Classroom, String> as a model attribute (i am doing this in the saveAccountDetails method from the Controller).
The ParentsDetails object will be created after the StudentDetails entity will be saved with the selected classroom.
When I submit the form as I mentioned above I run into an error but without any(or relevant) error message.
I spent some time debugging and trying different approaches of handling that map of Classrooms, but none of them worked.
What is actually happening, the controller method saveStudentDetails is not called anymore.
The issue must come from that form:select because if I get rid of this input, the controller method will be called and will let me advance in creating the ParentsDetails entity.
I have no clue what is wrong.
I used previously this form:select but the LinkedHashMap contained just Strings, without any objects and it worked. I think thats my issue.
StudentDetails.java
#Entity
#Table(name="student_details")
public class StudentDetails {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id")
private int id;
#Column(name="current_year_of_study")
private Integer currentYearOfStudy;
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name="parents_details_id")
private ParentsDetails parentsDetails;
#ManyToOne(cascade={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH})
#JoinColumn(name="class_id")
private Classroom classroom;
#OneToOne(mappedBy="studentDetails", cascade={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH})
private User user;
#ManyToMany
#JoinTable(name="course_studentdetails",
joinColumns=#JoinColumn(name="student_details_id"),
inverseJoinColumns=#JoinColumn(name="course_id")
)
private List<Course> courses;
... (Constructors, getters setters)
Controller.java
#PostMapping("/save-account-details")
public String saveAccountDetails(#ModelAttribute("theAccountDetails") AccountDetails theAccountDetails, #RequestParam("userUsername") String username, Model theModel) {
User theUser = userService.getUser(username);
theUser.setAccountDetails(theAccountDetails);
accountDetailsService.saveAccountDetails(theAccountDetails);
userService.saveUser(theUser);
theModel.addAttribute("theUser", theUser);
theModel.addAttribute("theStudentDetails", new StudentDetails());
theModel.addAttribute("classroomsList", classroomService.getSchoolClassrooms(theUser.getAccountDetails().getCity()));
theModel.addAttribute("entity", "StudentDetails");
return "create-user";
}
#PostMapping("/save-student-details")
public String saveStudentDetails(#ModelAttribute("theStudentDetails") StudentDetails theStudentDetails, #RequestParam("userUsername") String username, Model theModel) {
User theUser = userService.getUser(username);
theUser.setStudentDetails(theStudentDetails);
studentDetailsService.saveStudentDetails(theStudentDetails);
userService.saveUser(theUser);
theModel.addAttribute("theUser", theUser);
theModel.addAttribute("theParentsDetails", new ParentsDetails());
theModel.addAttribute("entity", "ParentsDetails");
return "create-user";
}
#PostMapping("/save-parents-details")
public String saveParentsDetails(#ModelAttribute("theParentsDetails") ParentsDetails theParentsDetails, #RequestParam("userUsername") String username, Model theModel) {
User theUser = userService.getUser(username);
theUser.getStudentDetails().setParentsDetails(theParentsDetails);
parentsDetailsService.saveParentsDetails(theParentsDetails);
userService.saveUser(theUser);
theModel.addAttribute("theUser", theUser);
theModel.addAttribute("theParentsDetails", new ParentsDetails());
theModel.addAttribute("entity", "ParentsDetails");
return "create-user";
}
create-user.jsp
<c:if test="${entity == 'StudentDetails'}">
<c:url var="saveStudentDetails" value="save-student-details">
<c:param name="userUsername" value="${theUser.username}" />
</c:url>
<form:form action="${saveStudentDetails}" modelAttribute="theStudentDetails" method="POST">
<form:hidden path="id" />
<div class="form-area">
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="inputGroup-sizing-default">Current Year of Study</span>
</div>
<form:input type="text" class="form-control" path="currentYearOfStudy" aria-label="Default" aria-describedby="inputGroup-sizing-default" />
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<label class="input-group-text" for="inputGroupSelect01">Classroom</label>
</div>
<form:select path="classroom" class="custom-select" id="inputGroupSelect01">
<form:option value="" label="Select classroom..." />
<form:options items="${classroomsList}" />
</form:select>
</div>
<button type="submit" class="btn btn-outline-secondary btn-block">Submit</button>
</div>
</form:form>
</c:if>
<c:if test="${entity == 'ParentsDetails'}">
<c:url var="saveParentsDetails" value="save-parents-details">
<c:param name="userUsername" value="${theUser.username}" />
</c:url>
<form:form action="${saveParentsDetails}" modelAttribute="theParentsDetails" method="POST">
<form:hidden path="id" />
<div class="form-area">
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="inputGroup-sizing-default">Father First Name</span>
</div>
<form:input type="text" class="form-control" path="fatherFirstName" aria-label="Default" aria-describedby="inputGroup-sizing-default" />
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="inputGroup-sizing-default">Father Last Name</span>
</div>
<form:input type="text" class="form-control" path="fatherLastName" aria-label="Default" aria-describedby="inputGroup-sizing-default" />
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="inputGroup-sizing-default">Father Telephone</span>
</div>
<form:input type="text" class="form-control" path="fatherTelephone" aria-label="Default" aria-describedby="inputGroup-sizing-default" />
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="inputGroup-sizing-default">Mother First Name</span>
</div>
<form:input type="text" class="form-control" path="motherFirstName" aria-label="Default" aria-describedby="inputGroup-sizing-default" />
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="inputGroup-sizing-default">Mother Last Name</span>
</div>
<form:input type="text" class="form-control" path="motherLastName" aria-label="Default" aria-describedby="inputGroup-sizing-default" />
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="inputGroup-sizing-default">Mother Telephone</span>
</div>
<form:input type="text" class="form-control" path="motherTelephone" aria-label="Default" aria-describedby="inputGroup-sizing-default" />
</div>
<button type="submit" class="btn btn-outline-secondary btn-block">Submit</button>
</div>
</form:form>
</c:if>
If any more code snippets are needed, I will add them as soon as possible. Thank you in advance!
This is the network tab. The object looks like it was submitted with the form...
I will add shortly a video with the application.
Edit: demo link: https://youtu.be/neJOLHL9REo
Try adding multipart form-data to enctype in the form tag, it may works.
FROM:
<form:form action="${saveStudentDetails}"
modelAttribute="theStudentDetails" method="POST">
TO:
<form:form action="${saveStudentDetails}" enctype="multipart/form-data"
modelAttribute="theStudentDetails" method="POST">

Request method 'POST' not supported

I have a spring-Boot application, and
I am trying to send an object using post method to the below controller:
#PostMapping("/suggestevent")
public String receiveSuggestedEvent(#ModelAttribute SuggestedEvent event) {
return "redirect:/suggestEvent";
}
but it complains with:
There was an unexpected error (type=Method Not Allowed, status=405).
Request method 'POST' not supported
So, what is wrong?
Update:
I have tried this and it also did not work
#RequestMapping(value = "/suggestevent", method = RequestMethod.POST)
The form contains some simple inputes, and a select, which works based on Thyemeleaf. Here is my form:
<form th:action="#{/suggestevent}" method="post">
<div class="form-group">
<label for="title">Title</label>
<input type="text"
class="form-control" id="title" placeholder="Event title"
th:value="${event.title}"
name="title" required="required"/>
</div>
<div class="form-group">
<label for="mainFouce">Main Focus</label>
<input type="text"
class="form-control" id="Focus" placeholder="Focus"
th:value="${event.mainFouce}"
name="Focus" required="required"/>
</div>
Event Type
<div class="form-group">
<select class="form-control" name="type" th:value="${event.type}">
<option value="volvo">Party</option>
<option value="saab">Workshop</option>
<option value="fiat">Friendship</option>
</select>
</div>
<div class="form-group">
<label for="city">Area</label>
<input type="text"
class="form-control" id="area"
th:value="${event.area}"
placeholder="Berlin, Estonia ,or even Asia" name="area"
required="required"/>
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea name="description" class="form-control"
th:value="${event.description}"
required="required" form="usrform"
placeholder="What makes it an special event?"></textarea>
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
The sent object is:
#Entity
#Data
public class SuggestedEvent {
#Id
#GeneratedValue
Long id;
String title;
String mainFouce;
EventType type;
String area;
String description;
}
The postman can successfully reach the controller, but the thyemeleaf complains!!!
What happens when you try to add an empty SuggestedEvent object inside the form and try to populate that object like so:
<form th:action="#{/suggestevent}" th:object="${event}" method="post">
<div class="form-group">
<label for="title">Title</label>
<input type="text"
class="form-control" id="title" placeholder="Event title"
th:value="*{title}"
name="title" required="required"/>
</div>
<div class="form-group">
<label for="mainFouce">Main Focus</label>
<input type="text"
class="form-control" id="Focus" placeholder="Focus"
th:value="*{mainFouce}"
name="Focus" required="required"/>
</div>
Event Type
<div class="form-group">
<select class="form-control" name="type" th:value="*{type}">
<option value="volvo">Party</option>
<option value="saab">Workshop</option>
<option value="fiat">Friendship</option>
</select>
</div>
<div class="form-group">
<label for="city">Area</label>
<input type="text"
class="form-control" id="area"
th:value="*{area}"
placeholder="Berlin, Estonia ,or even Asia" name="area"
required="required"/>
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea name="description" class="form-control"
th:value="*{description}"
required="required" form="usrform"
placeholder="What makes it an special event?"></textarea>
</div>
<button class="btn btn-default">Submit</button>
</form>
And in the #GetMapping("/suggestEvent"):
#GetMapping("/suggestEvent")
public String getSuggestEventPage(Model model) {
model.addAttribute("event", new SuggestEvent());
return "suggestEventPage";
}
Check out the official Thymeleaf doc otherwise. This shouldn't really be a problem, since I am doing the exact same thing in my project.
http://www.thymeleaf.org/doc/articles/standarddialect5minutes.html
http://www.thymeleaf.org/doc/articles/springmvcaccessdata.html
http://www.thymeleaf.org/documentation.html

Occasional null pointer exception on jsp form (java Spring Boot)

I saw some NullPointerExceptions in the log. All the exceptions are from two users. The spring controller is supposed to received the form object that the user uploaded. However it is null.
This is the jsp code of the form:
<form method="POST" action="/events/${id}/tickets/checkout" id="checkout-info-form">
<label> Recipient Name <input id="recipient" type="text" name="recipient"></label>
<label class="address-row checkout-hidable"> Address Line 1 <input id="address1" type="text" name="addressLine1"> </label>
<label class="checkout-hidable"> Address Line 2 (optional) <input id="address2" type="text" name="addressLine2"> </label>
<label class="city-row checkout-hidable"> City <input type="text" id="city" name="city" placeholder="e.g. New York"> </label>
<label class="state-row checkout-hidable"> State <input type="text" id="state" name="state" placeholder="e.g. NY"> </label>
<label class="zip-row checkout-hidable"> Zip Code <input type="text" id="zip" name="zip" placeholder="e.g. 12345"> </label>
<label class="shipping-row">Shipping Method:</label>
<label class="shipping-method">
<input type="radio" name="shipping" value="usps_5days" id="shipping1">
<span>USPS 3-5 days shipping</span> $5.99
</label>
<label class="shipping-method">
<input type="radio" name="shipping" value="usps_1days" id="shipping2">
<span>USPS overnight shipping</span> $19.99
</label>
<c:set var="index" value="${0}"/>
<c:forEach items="${tickets}" var="ticket">
<input type="hidden" name="tickets[${index}]" value="${ticket.id}">
<c:set var="index" value="${index + 1}"/>
</c:forEach>
<c:remove var="index"/>
<input id="checkout-info-form-submit-button" class="btn-blue-large" type="submit" name="submitbutton" value="Next step">
</form>
This is the model object that I use to receive the form:
public class CheckoutInfo implements Serializable {
private static final long serialVersionUID = 2585075011792338943L;
private String recipient;
private String addressLine1;
private String addressLine2;
private String city;
private String state;
private String zip;
private String shipping;
private String[] tickets;
public CheckoutInfo() {
}
}
The controller:
#RequestMapping(value="/events/{eventId}/tickets/checkout", method=RequestMethod.POST)
public ModelAndView purchaseTickets(
#PathVariable("eventId") long id,
CheckoutInfo checkoutInfo,
RedirectAttributes redir,
#AuthenticationPrincipal User user) {
......
}
The null pointer exception occurs because checkoutInfo is null. I don't know why this could happen. I never seen this happen. And this only come from a few of our users. I am using spring boot v1.2.3.RELEASE
I appreciate it if anyone could help.

Cannot submit a form on SpringMVC

I am fairly new to SpringMVC and have a form that can not submit to the back-end. I created the form as following and when I submit it error 404 will be returned. I changed action to /MyProject/contact but did not work.
<form class="form-horizontal" role="form" method="post"
action="/contact">
<div class="form-group">
<div class="col-md-12">
<label class="sr-only" for="exampleInputName2">Name
</label> <input type="text" class="form-control" id="name"
name="name" placeholder="Your name" value="">
</div>
</div>
<div class="form-group">
<div class="col-md-12">
<label class="sr-only" for="exampleInputName2">Email
Address</label> <input type="email" class="form-control" id="email"
name="email" placeholder="Your email" value="">
</div>
</div>
<div class="form-group">
<div class="col-md-12">
<label class="sr-only" for="exampleInputName2">Phone
Number</label> <input type="number" class="form-control" id="phone"
name="phone" placeholder="Phone number" value="">
</div>
</div>
<div class="form-group">
<div class="col-md-12">
<label class="sr-only" for="exampleInputName2">Enquiry</label>
<textarea class="form-control" rows="4" name="message"
placeholder="Please enter your enquiry"></textarea>
</div>
</div>
<div class="form-group">
<div class="col-md-2 " style="float: right;">
<input id="submit" name="submit" type="submit" value="Send"
class="btn btn-primary">
</div>
</div>
<div class="form-group">
<div class="col-sm-10 col-sm-offset-2">
<! Will be used to display an alert to the user>
</div>
</div>
</form>
Controller
#Controller
public class ContactController {
#RequestMapping(value="/contact", method=RequestMethod.POST)
public String processForm(Contact contact, Model model){
System.err.println("Contact Name is:" + contact.getName());
return null;
}
}
Error
HTTP Status 404 - /contact
type Status report
message /contact
description The requested resource is not available.
Its beacuse spring does not know how to pass the param Contact contact to your controller method. You need to do couple of things to make it work. Change your form to like below.
<form class="form-horizontal" role="form" method="post" modelAttribute="contact" action="/contact">
Your controller to take contact as model attribute.
#Controller
public class ContactController {
#RequestMapping(value="/contact", method=RequestMethod.POST)
public String processForm(#ModelAttribute Contact contact, Model model){
System.err.println("Contact Name is:" + contact.getName());
return null;
}
}
For a better understanding of what a model attribute does, there are plenty of samples and explanation online. Hope this helps.
I could solve the problem by help of minion's answer, following this tutorial and adding following link
#RequestMapping(value = "/contact", method = RequestMethod.GET)
public ModelAndView contactForm() {
System.err.println("here in GET");
return new ModelAndView("contact", "command", new Contact());
}

How to use jsp tag for select?

I have a view model and one of the fields has to be mapped to a dropdown. I manage to populate the dropdown but i don't know how to specify the selected value.
edituser.jsp
<%# include file="/WEB-INF/template/taglibs.jsp"%>
<div class="container">
<%# include file="menu.jsp"%>
<form:form commandName="editForm" method="post" class="form-horizontal form-width">
<fieldset>
<legend>Edit user</legend>
<div class="form-group">
<input class="hidden" type="text" value="${id}" hidden="true" name="id"/>
<label for="firstName" class="col-lg-2 control-label">First
name</label>
<div class="col-lg-10">
<input type="text" class="form-control" id="firstName"
placeholder="First name" name="firstName" value="${fname}">
</div>
</div>
<div class="form-group">
<label for="lastName" class="col-lg-2 control-label">Last
name</label>
<div class="col-lg-10">
<input type="text" class="form-control" id="lastName"
placeholder="Last name" name="lastName" value="${lname}">
</div>
</div>
<div class="form-group">
<label for="select" class="col-lg-2 control-label">Role</label>
<div class="col-lg-10">
<select name="role" class="form-control">
<option value="NONE">Select role</option>
<c:forEach items="${roles}" var="role">
<option value="${role}">${role}</option>
</c:forEach>
</select>
</div>
</div>
<div class="form-group">
<label for="username" class="col-lg-2 control-label">Username</label>
<div class="col-lg-10">
<input type="text" class="form-control" id="username"
placeholder="Username" name="username" value="${username}">
</div>
</div>
<div class="form-group">
<label for="inputPassword" class="col-lg-2 control-label">Password</label>
<div class="col-lg-10">
<input type="password" class="form-control" id="inputPassword"
placeholder="Password" name="password" value="${guid}">
</div>
</div>
<div class="form-group">
<label for="inputPassword" class="col-lg-2 control-label">Confirm password</label>
<div class="col-lg-10">
<input type="password" class="form-control" id="inputPassword"
placeholder="Password" name="confirmedpassword" value="${guid}">
</div>
</div>
<div class="form-group">
<div class="col-lg-10 col-lg-offset-2">
<a class="btn btn-warning" href="http://localhost:8080/Catering/index/users">Cancel</a>
<button type="submit" class="btn btn-warning">Submit</button>
</div>
</div>
</fieldset>
</form:form>
</div>
UsersController
#Controller
public class UsersController {
#RequestMapping(value = "/editUser", method = RequestMethod.GET)
public String getEditUserPage(#RequestParam int id, Model model, Authentication authentication) {
logger.debug("Received request to show edit user page(GET)");
model.addAttribute("username", "You are logged in as " + authentication.getPrincipal());
UserModel user = UserDataAccess.getUserById(id);
model.addAttribute("id", user.getId());
model.addAttribute("fname", user.getFirstName());
model.addAttribute("lname", user.getLastName());
model.addAttribute("role", user.getRole());
model.addAttribute("username", user.getUsername());
model.addAttribute("guid", guid);
model.addAttribute("editForm", new UserViewModel());
return "edituser";
}
}
UserViewModel
public class UserViewModel {
private int id;
private String firstName;
private String lastName;
private String role;
private String username;
private String password;
private String confirmedpassword;
//getters and setters
}
You can do something like (not tested)
<select name="role" class="form-control">
<option value="NONE">Select role</option>
<c:forEach items="${roles}" var="curRole">
<c:choose>
<c:when test="${curRole eq role}">
<option selected="selected">${role}</option>
</c:when>
<c:otherwise>
<option>${role}</option>
</c:otherwise>
</c:choose>
</c:forEach>
</select>
You also must add a Collection in your controller, representing the list of all roles. I cannot see it from your code.
I suggest you to take a look at spring-form.tld facilities, in your particular case: select tags: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/spring-form.tld.html#spring-form.tld.select
Here you can find a simple example on how using spring:form tag: http://www.mkyong.com/spring-mvc/spring-mvc-dropdown-box-example/

Resources