So here is my Controller. First of all, here I have both request methods GET and POST but for some strange reason the GetMapping("/journeys") is not being recognized.
#Controller
#GetMapping("/journeys")
String journeys(Model model , #Valid JourneyForm form) {
model.addAttribute("journeys", journeys.findAll()) ;
model.addAttribute("form", form);
return "journeys" ;}
#GetMapping("/jounreyCreate")
String createJourney(Model model , JourneyForm form){
model.addAttribute("form", form) ;
return "journeyCreate" ;
}
#PostMapping("/journeyCreate")
String createJourney(Model model ,Errors errors,#Valid #ModelAttribute("form") JourneyForm form ) {
if (errors.hasErrors()) {
return journeys(model , form);
}
journeys.save( form.createJourney() ) ;
return "redirect:/journeys";
}
and here is the JourneyForm Class
public class JourneyForm {
private String name;
public JourneyForm(String name) {
this.name = name ;
}
public String getName() {
return name;
}
public Journey createJourney() {
return new Journey(getName());
}
}
and for the last part the journey.html and journeyCreate.html
<body>
<h2 th:text="#{journeys.title}">Reise</h2>
<a href="/journeyCreate">
<button class="ui button">Journey erstellen</button>
</a>
<a href="/journeyEdit">
<button class="ui button">Reise bearbeiten</button>
</a>
<div th:each="journey : ${journeys}">
<p th:text="'Reise: '+${journey.name}">Reise</p>
</div>
and journeyCreate.html
<a href="/journeys">
<button class="ui button">Zurück zur Reise</button>
</a>
<form role="form" class="ui form" id="form" th:object="${form}" th:method="post" th:action="#{/journeyCreate}">
<div class="field">
<label for="journeyName">Name</label>
<input id="journeyName" name="journeyName" type="text" th:field="*{name}" th:errorclass="is-invalid" required="required"/><br/>
<div th:if="${#fields.hasErrors('name')}" class="invalid-feedback">Please provide a name.</div>
</div>
<input type="submit" value="Submit">
</form>
it is really frustrating and I can't get my hand on the cause
Your help will be appreciated, thank you.
Related
I am trying to make a Book Management project where I have three buttons on the home.jsp page. Each button redirects to a separate page and each of these pages has a form. I have one Controller class that has three methods to handle each form submissions from each of these pages but when I try to use #ModelAttribute in the JSP page for any form, I am unable to get the value that I add to the Model.
Here is the home.jsp:
<body>
<div class="container">
<div>
<h1>Spring Boot Web JSP Example</h1>
<h2>Name: ${book.name}</h2>
<h2>Author: ${book.author}</h2>
<h2>ISBN: ${book.isbn}</h2>
</div>
</div>
<form:form method="POST" action="/get" modelAttribute="newBook">
<div class="form-group">
<label for="authorInput">Author</label>
<form:input path="author" cssClass="form-control" id="authorInput"></form:input>
</div>
<div class="form-group">
<label for="dateInput">Date</label>
<form:input path="date" cssClass="form-control" id="dateInput"></form:input>
</div>
<button type="submit" class="btn btn-primary">Get Book</button>
</form:form>
<button type="submit" class="btn btn-primary">Add Book</button>
<button type="submit" class="btn btn-primary">Update Book</button>
</body>
Here is the controller class:
#Controller
public class MainController {
#GetMapping(value = "/")
public String welcome(Map<String, Object> model) {
model.put("newBook", new Book());
model.put("updateBook", new Book());
model.put("addBook",new Book());
return "home";
}
#PostMapping(value = "/get")
public String change(#RequestParam("author") String author, Model model,
#ModelAttribute("newBook")Book book) {
System.out.println(author);
Book b = BookDao.getBook(book.getAuthor(), book.getDate());
if(b == null){
return "home";
}
model.addAttribute("book", b);
model.addAttribute("newBook", new Book());
return "home";
}
#RequestMapping(value = "/add")
public String addBook(#RequestParam("author") String author, #RequestParam("isbn") int isbn, Model model,
#ModelAttribute("addBook") Book book){
System.out.println("Author: "+author + " ISBN: "+isbn);
model.addAttribute("addBook", new Book());
Book b= new Book(book.getName(), author,isbn, book.getDate());
model.addAttribute("add", book);
boolean result = BookDao.addBook(b);
if(result)
return "home";
else
return "error";
}
#RequestMapping( value = "/update")
public String updateBook(#RequestParam("author") String author, #RequestParam("isbn") int isbn, Model model,
#ModelAttribute("updateBook") Book book){
System.out.println("Author: "+author + " ISBN: "+isbn);
Book b= new Book(book.getName(), author,isbn, book.getDate());
model.addAttribute("updateBook", new Book());
model.addAttribute("update",b);
BookDao.updateBook(isbn, b);
return "home";
}
}
And here are the other two jsp pages:
Add.jsp:
<body>
<h1>Add a Book</h1>
<form:form method="POST" action="/add" modelAttribute="addBook">
<div class="form-group">
<label for="nameInput">Name</label>
<form:input path="name" cssClass="form-control" id="nameInput"></form:input>
</div>
<div class="form-group">
<label for="authorInput">Author</label>
<form:input path="author" cssClass="form-control" id="authorInput"></form:input>
</div>
<div class="form-group">
<label for="isbnInput">ISBN</label>
<form:input path="isbn" cssClass="form-control" id="isbnInput"></form:input>
</div>
<div class="form-group">
<label for="dateInput">Date</label>
<form:input path="date" cssClass="form-control" id="dateInput"></form:input>
</div>
<button type="submit" class="btn btn-primary">Add</button>
</form:form>
</body>
Update Book JSP Page:
<body>
<form:form method="POST" action="/update" modelAttribute="third">
<div class="form-group">
<label for="authorInput">ISBN</label>
<form:input path="isbn" cssClass="form-control" id="authorInput"></form:input>
</div>
<div class="form-group">
<label for="nameInput">Name</label>
<form:input path="name" cssClass="form-control" id="nameInput"></form:input>
</div>
<div class="form-group">
<label for="authorInput">Author</label>
<form:input path="author" cssClass="form-control" id="authorInput"></form:input>
</div>
<div class="form-group">
<label for="dateInput">Date</label>
<form:input path="date" cssClass="form-control" id="dateInput"></form:input>
</div>
<button type="submit" class="btn btn-primary">Update Book</button>
</form:form>
</body>
The problem is that the lines modelAttribute="addBook" and modelAttribute="third" in the add.jsp page and update.jsp page throw an error. The IDE says "Cannot resolve symbol 'addBook/third'". Those values are available in the home.jsp page though.
Since I found the answer, I will post it just in case somebody else gets stuck with it.
In order to access the forms on another JSP page, we can't just directly redirect to the page in an MVC design.
In order to do so, we need to create a #GetMapping annotation method for each of those JSP forms #PostMapping annotations and then redirect to the #GetMapping methods first and the #GetMapping will redirect to the JSP page. This is how it should be done:
Controller Class:
#Controller
public class MainController {
#GetMapping(value = "/")
public String welcome(Map<String, Object> model) {
model.put("newBook", new Book());
return "home";
}
#PostMapping(value = "/get")
public String change(#RequestParam("author") String author, Model model,
#ModelAttribute("newBook")Book book) {
System.out.println(author);
Book b = BookDao.getBook(book.getAuthor(), book.getDate());
if(b == null){
return "home";
}
model.addAttribute("book", b);
model.addAttribute("newBook", new Book());
return "home";
}
#GetMapping("/add")
public String show(Model model) {
model.addAttribute("addBook", new Book());
return "add";
}
#PostMapping(value = "/add")
public String addBook(#RequestParam("author") String author, #RequestParam("isbn") int isbn, Model model,
#ModelAttribute("addBook") Book book){
System.out.println("Author: "+author + " ISBN: "+isbn);
model.addAttribute("addBook", new Book());
Book b= new Book(book.getName(), author,isbn, book.getDate());
model.addAttribute("add", book);
boolean result = BookDao.addBook(b);
if(result)
return "home";
else
return "error";
}
#GetMapping("/update")
public String showUpdate(Model model) {
model.addAttribute("updateBook", new Book());
return "update";
}
#PostMapping( value = "/update")
public String updateBook(#RequestParam("author") String author, #RequestParam("isbn") int isbn, Model model,
#ModelAttribute("updateBook") Book book){
System.out.println("Author: "+author + " ISBN: "+isbn);
Book b= new Book(book.getName(), author,isbn, book.getDate());
model.addAttribute("updateBook", new Book());
model.addAttribute("update",b);
BookDao.updateBook(isbn, b);
return "home";
}
And the JSP page for Home.jsp page should be as follows:
<form:form method="POST" action="/get" modelAttribute="newBook">
<div class="form-group">
<label for="authorInput">Author</label>
<form:input path="author" cssClass="form-control" id="authorInput"></form:input>
</div>
<div class="form-group">
<label for="dateInput">Date</label>
<form:input path="date" cssClass="form-control" id="dateInput"></form:input>
</div>
<button type="submit" class="btn btn-primary">Get Book</button>
</form:form>
<button type="submit" class="btn btn-primary">Add Book</button>
<button type="submit" class="btn btn-primary">Update Book</button>
</body>
So the href maps to the #GetMapping method to get the ModelAttributes. The other JSP pages are fine as it is.
Also, another good practice I might suggest is to Use a Service layer/package to perform all the operations. So instead of performing it in the Controller, we delegate tasks like the CRUD operations to the Service layer which in turn interacts with the DAO layer.
I am creating an Spring Boot App, in which the user can create licences. The user can type the name, purchaseDate, renewalDate and expirationDate.
My problem is, that when I try to save the data, it returns null for the name, the purchaseDate, renewalDate and expirationDate.
I absolutely don't know what to do anymore, please help. The "// Comment" values in the Model:Licence are those who get null when executing the post.
Model: Licence
#Entity
#Table(name = "TBL_LICENCES")
public class Licence {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long Id;
private String licenceName; // --> null after the post
#DateTimeFormat(pattern = "yyyy-MM-dd")
private String purchaseDate; // --> null after the post
#DateTimeFormat(pattern = "yyyy-MM-dd")
private String renewalDate; // --> null after the post
#DateTimeFormat(pattern = "yyyy-MM-dd")
private String expirationDate; // --> null after the post
public Licence() {}
public Licence(Long id, String licenceName, String purchaseDate, String renewalDate, String expirationDate) {
Id = id;
this.licenceName = licenceName;
this.purchaseDate = purchaseDate;
this.renewalDate = renewalDate;
this.expirationDate = expirationDate;
}
// Getter and Setter
}
Model: LicenceRepository
#Repository
public interface LicenceRepository extends CrudRepository<Licence, Long> { }
Service: LicenceService
#Service
public class LicenceService {
#Autowired
private LicenceRepository licenceRepository;
public List<Licence> getLicences() {
return (List<Licence>) licenceRepository.findAll();
}
public Optional<Licence> getLicenceById(Long id) {
return licenceRepository.findById(id);
}
public void addLicence(Licence licence) {
licenceRepository.save(licence);
}
public void updateLicence(Licence licence) {
licenceRepository.save(licence);
}
public void deleteLicenceById(Long id) {
licenceRepository.deleteById(id);
}
}
Controller: LicenceController
#Controller
public class LicenceController {
#Autowired
private LicenceService licenceService;
#GetMapping("/licences")
public String getLicences(Model model) {
model.addAttribute("licences", licenceService.getLicences());
return "licences";
}
#GetMapping("/onelicence")
#ResponseBody
public Optional<Licence> getLicenceByID(Long id, Model model) {
model.addAttribute("onelicence", licenceService.getLicenceById(id));
return licenceService.getLicenceById(id);
}
#RequestMapping(value="/save", method = {RequestMethod.POST, RequestMethod.PUT, RequestMethod.GET})
public String updateLicence(Licence licence) {
licenceService.updateLicence(licence);
return "redirect:/licences";
}
**// Is performed, when clicking "New Licence > Save"**
#RequestMapping(value="/addNew", method = {RequestMethod.POST, RequestMethod.PUT, RequestMethod.GET})
public String addLicence(Licence licence) {
licenceService.addLicence(licence);
return "redirect:/licences";
}
#RequestMapping(value="/delete", method = {RequestMethod.DELETE, RequestMethod.PUT, RequestMethod.GET})
public String deleteLicence(Long id) {
licenceService.deleteLicenceById(id);
return "redirect:/licences";
}
}
licences.html
<!DOCTYPE html>
<html lang="de" xmlns="http://www.w3.org/1999/html"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<script type ="text/javascript" src="webjars/jquery/3.4.1/jquery.min.js"></script>
<script type ="text/javascript" src="webjars/bootstrap/4.4.1/js/bootstrap.min.js"></script>
<link href="webjars/bootstrap/4.4.1/css/bootstrap.css" rel="stylesheet"/>
<title>Licence</title>
</head>
<body>
<div class = "container">
<h2>Licences</h2>
<table class = "table table-striped">
<thead>
<tr>
<td>ID</td>
<td>Name</td>
<td>Kaufdatum</td>
<td>Erneuerungsdatum:</td>
<td>Auslaufdatum:</td>
</tr>
</thead>
<tbody>
<tr th:each = "licence: ${licences}">
<td th:text="${licence.id}">ID</td>
<td th:text="${licence.licenceName}">Name</td>
<td th:text="${licence.purchaseDate}">Kaufdatum</td>
<td th:text="${licence.renewalDate}">Erneuerungsdatum</td>
<td th:text="${licence.expirationDate}">Auslaufdatum</td>
<td><a class="btn btn-warning">Edit</a></td>
<td><a class="btn btn-danger">Delete</a></td>
</tr>
</tbody>
</table>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addModal" data-whatever="#mdo">New Licence</button>
</div>
// Bootstrap Varying Modal Content
<div class="modal fade" id="addModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<form th:action="#{/addNew}" method ="post">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">New Licence</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="name" class="col-form-label">Lizenz Name</label>
<input type="text" class="form-control" id="licenceName" name="name">
</div>
<div class="form-group">
<label for="purchase" class="col-form-label">purchaseDate</label>
<input type="date" class="form-control" id="purchaseDate" name="purchase">
</div>
<div class="form-group">
<label for="renewalAdd" class="col-form-label">renewalDate</label>
<input type="date" class="form-control" id="renewalAdd" name="renewal">
</div>
<div class="form-group">
<label for="expirationAdd" class="col-form-label">expirationDate</label>
<input type="date" class="form-control" id="expirationAdd" name="expiration">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Save</button>
</div>
</div>
</div>
</form>
</div>
</body>
</html>
schema.sql
DROP TABLE IF EXISTS TBL_LICENCES;
CREATE TABLE TBL_LICENCES (
id INT AUTO_INCREMENT PRIMARY KEY,
licence_name VARCHAR(250),
purchase_date VARCHAR(250),
renewal_date VARCHAR(250),
expiration_date VARCHAR(250)
);
data.sql --> This works and the data is shown.
INSERT INTO
TBL_LICENCES (licence_name, purchase_date, renewal_date, expiration_date)
VALUES
('Test1', '2020-01-31', '2020-06-31', '2020-12-31'),
('Test', '2021-01-31', '2021-06-31', '2021-12-31');
Properties: application.properties
spring.h2.console.enabled=true
spring.datasource.platform=h2
spring.datasource.url=jdbc:h2:mem:<dbLicences>
spring.jpa.hibernate.ddl-auto=update
The name attribute of the input control should match the name of the fields in the Licence class. Currently your id attribute is matching the name of the fields, but when a form is submitted it uses the name attribute to build the request parameters.
Update your HTML to match something like:
<input type="text" class="form-control" id="licenceName" name="licenceName" />
Fix the name for other fields and you will have the Licence object populated with data from the form.
Also, I see that
#DateTimeFormat(pattern = "yyyy-MM-dd")
private String licenceName;
licenceName is annotated with #DateTimeFormat. I guess this is a mistake, please correct that as well.
I am writing form that lets user to change his password. Instead of passing User object to form, I am passing 3 empty Strings. Everything is okay, but when I am passing Submit, Strings returns as empty. Is there any way to get String from forms in Spring without packaging them into objects like changePasswordForm with 3 String fields?
My code:
Change password view:
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org">
<head th:replace="/fragments/head"></head>
<body>
<div class="container">
<div th:replace="/fragments/header"> </div>
<div class="jumbotron">
<h1 class="display-4">Changing password</h1>
<form action="#" th:action="#{/user/changePassword/} + ${user.id}" method="post">
<div class="form-group">
<label>Current password</label>
<input type="password" th:field="${currentPassword}" class="form-control" placeholder="Your current password"/>
</div>
<div class="form-group">
<label>New password</label>
<input type="password" th:field="${newPassword}" class="form-control" placeholder="Your new password"/>
</div>
<div class="form-group">
<label>New password confirmation</label>
<input type="password" th:field="${newPasswordConfirmation}" class="form-control" placeholder="Confirm your new password"/>
</div>
<button class="btn btn-primary">Submit</button>
<button class="btn btn-secondary">Reset</button>
</form>
</div>
<div th:replace="/fragments/footer"> </div>
</div>
</body>
</html>
User controller:
package io.gromo13.personalBlog.controller;
import io.gromo13.personalBlog.service.RoleService;
import io.gromo13.personalBlog.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import io.gromo13.personalBlog.model.User;
import javax.validation.Valid;
#Controller
#RequestMapping("/user")
#SessionAttributes("user")
public class UserController {
#Autowired
UserService userService;
#Autowired
RoleService roleService;
public void setUserService(UserService userService) {
this.userService = userService;
}
public void setRoleService(RoleService roleService) {
this.roleService = roleService;
}
#GetMapping("/{id}")
public String profile(#PathVariable Long id, Model model) {
User user = userService.get(id);
model.addAttribute("user", user);
return "/user/profile";
}
#GetMapping("/register")
public String register(Model model) {
model.addAttribute("roles", roleService.getAll());
model.addAttribute("user", new User());
return "/user/register";
}
#PostMapping("/register")
public String registerSubmit(#Valid User user, BindingResult bindingResult) {
if (bindingResult.hasErrors())
return "/user/register";
userService.add(user);
return "redirect:/admin/users";
}
#GetMapping("/edit/{id}")
public String edit(#PathVariable Long id, Model model) {
User user = userService.get(id);
model.addAttribute("user", user);
model.addAttribute("password", "");
return "/user/edit";
}
#PostMapping("/edit/{id}")
public String editSubmit(#ModelAttribute("user") #Valid User user, BindingResult bindingResult) {
if (bindingResult.hasErrors())
return "/user/edit";
userService.edit(user);
return "redirect:/admin/users";
}
#GetMapping("/changePassword/{id}")
public String changePasword(Model model) {
model.addAttribute("currentPassword", "");
model.addAttribute("newPassword", "");
model.addAttribute("newPasswordConfirmation", "");
return "/user/changePassword";
}
#PostMapping("/changePassword/{id}")
public String changePasswordSubmit(#PathVariable Long id,
#ModelAttribute("currentPassword") String currentPassword,
#ModelAttribute("newPassword") String newPassword,
#ModelAttribute("newPasswordConfirmation") String newPasswordConfirmation,
BindingResult bindingResult) {
if (bindingResult.hasErrors())
return "/user/changePassword";
User user = userService.get(id);
if (newPassword.equals(newPasswordConfirmation) && user.getPassword().equals(currentPassword)) {
user.setPassword(newPassword);
userService.edit(user);
}
return "redirect:/admin/users";
}
#GetMapping("/delete/{id}")
public String delete(#PathVariable Long id) {
userService.delete(id);
return "redirect:/admin/users";
}
}
Actually my whole page is working fine, I just cannot read single Strings passed to forms without wrapping to objects.
Every tutorial about forms in Spring I found is passing object like xForm or User to view and read them. It works for me too, but I do not see sense in creating special object just for single form.
change th:field to name tag
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org">
<head th:replace="/fragments/head"></head>
<body>
<div class="container">
<div th:replace="/fragments/header"> </div>
<div class="jumbotron">
<h1 class="display-4">Changing password</h1>
<form action="#" th:action="#{/user/changePassword/} + ${user.id}" method="post">
<div class="form-group">
<label>Current password</label>
<input type="password" name="currentPassword" class="form-control" placeholder="Your current password"/>
</div>
<div class="form-group">
<label>New password</label>
<input type="password" name="newPassword" class="form-control" placeholder="Your new password"/>
</div>
<div class="form-group">
<label>New password confirmation</label>
<input type="password" name="newPasswordConfirmation" class="form-control" placeholder="Confirm your new password"/>
</div>
<button class="btn btn-primary">Submit</button>
<button class="btn btn-secondary">Reset</button>
</form>
</div>
<div th:replace="/fragments/footer"> </div>
</div>
</body>
</html>
remove this from controller
#GetMapping("/changePassword/{id}")
public String changePasword(Model model) {
model.addAttribute("currentPassword", ""); //remove
model.addAttribute("newPassword", ""); //remove
model.addAttribute("newPasswordConfirmation", ""); //remove
return "/user/changePassword";
}
and here change ModelAttribute to RequestParam Annotation
#PostMapping("/changePassword/{id}")
public String changePasswordSubmit(#PathVariable Long id,
#RequestParam("currentPassword") String currentPassword,
#RequestParam("newPassword") String newPassword,
#RequestParam("newPasswordConfirmation") String newPasswordConfirmation) {
this sentence bindingResult not work because this validate a POJO using validations annotations
//if (bindingResult.hasErrors())
// return "/user/changePassword";
for this case the best way is create a new POJO with those fields and then validate them.
if you want to use the validation you need to create a POJO and add the constraints.
1)
public class ChangePass {
#Size(min = 8,max = 13, message = "error current password between {min} to {max}")
private String currentPassword;
#Size(min = 8,max = 13,message = "error new password between {min} to {max}")
private String newPassword;
//validate later
private String newPasswordConfirmation;
}
2)
then you need to add a instance of this POJO in the view.
#GetMapping("/changePassword/{id}")
public String changePasword(Model model) {
model.addAttribute("userPass", new ChangePass()); // adding model
return "/user/changePassword";
}
3)
in your form you need to fix 2 things add
th:object="${userPass}" and add th:field="*{currentPassword}" not th:field="${currenctPassword}" the difference is " * "
<form th:action="#{/user/changePassword/} + ${user.id}" method="post" th:object="${userPass}">
<div class="form-group">
<label>Current password</label>
<input type="password" th:field="*{currentPassword}" class="form-control" placeholder="Your current password"/>
</div>
<div class="form-group">
<label>New password</label>
<input type="password" th:field="*{newPassword}" class="form-control" placeholder="Your new password"/>
</div>
<div class="form-group">
<label>New password confirmation</label>
<input type="password" th:field="*{newPasswordConfirmation}" class="form-control" placeholder="Confirm your new password"/>
</div>
<button class="btn btn-primary">Submit</button>
<button class="btn btn-secondary">Reset</button>
</form>
4)
and the Post Method should be...
#PostMapping("/changePassword/{id}")
public String changePassword(#PathVariable Long id,
#ModelAttribute("userPass"),
#Valid ChangePass change,
BindingResult errors){
if(errors.hasErrors()){
return "/user/changePassword";
}
//your next code
I rewrite code from Mastering Spring book's and it does not work because all time I got the exception:
Caused by: java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'profileForm' available as request attribute
My form:
<form th:action="#{/profile}" th:object="${profileForm}" method="post" class="col m8 s12 offset-m2">
<div class="row">
<div class="input-field col s6">
<input th:field="${profileForm.twitterHandle}" id="twitterHandle" type="text"/>
<label for="twitterHandle" th:text="#{twitter.handle}">Identyfikator Twitter</label>
</div>
<div class="input-field col s6">
<input th:field="${profileForm.email}" id="email" type="email"/>
<label for="email">Adres e-mail</label>
</div>
</div>
<div class="row">
<div class="input-field col s6">
<input th:field="${profileForm.birthDate}" id="birthDate" type="text"/>
<label for="birthDate" th:text="#{birthdate}">Data urodzenia</label>
</div>
</div>
<div class="row s12 center">
<button class="btn indigo waves-effect waves-light" type="submit" name="save">Wyślij
<i class="mdi-content-send right"></i>
</button>
</div>
</form>
My POJO:
package masterspringmvc.profile;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
public class ProfileForm {
private String twitterHandle;
private String email;
private LocalDate birthDate;
private List<String> tastes = new ArrayList<>();
// getters setters
}
My Controller:
#Controller
public class ProfileController {
#RequestMapping(value = "/profile", method = RequestMethod.GET)
public String displayProfile() {
return "profile/profilePage";
}
#RequestMapping(value = "/profile", method = RequestMethod.POST)
public String saveProfile(ProfileForm profileForm) {
System.out.println("Profil: " + profileForm);
return "redirect:/profile";
}
}
Tomcat prints shows:
Error during execution of processor 'org.thymeleaf.spring4.processor.attr.SpringInputGeneralFieldAttrProcessor' (profile/profilePage:16)
According to book everything should be ok, but I still getting errors, why?
I think you need to:
Add "profileForm" to the model.
Add "#ModelAttribute("profileForm")" to the post controller.
In addition, you can simplify your #RequestMappings
#Controller
public class ProfileController {
#GetMapping("/profile")
public String displayProfile(Map<String, Object> model) {
model.put("profileForm", new ProfileForm());
return "profile/profilePage";
}
#PostMapping("/profile")
public String saveProfile(#ModelAttribute("profileForm") ProfileForm profileForm) {
System.out.println("Profil: " + profileForm);
return "redirect:/profile";
}
}
I'm trying to have Spring boot convert my form data into an Object representation (ExampleInputForm), but for some reason it doesn't seem to bind (emailName is always null). Am I missing something here?
ExampleInputForm.java
public class ExampleInputForm {
#NotNull
public String emailName;
public ExampleInputForm() {
super();
}
#Override
public String toString() {
return "ExampleInputForm{" +
"emailName='" + emailName + '\'' +
'}';
}
}
MyController.java
#Controller
class MyController {
#RequestMapping(method = RequestMethod.POST, value="/save")
#ResponseBody
public Map<String, String> saveBrands(#Valid ExampleInputForm form, BindingResult bindingResult) {
LOG.info("Saving brands: " + form);
return ImmutableMap.of(
"emailName", form.emailName,
);
}
}
form.ftl
<div class="container">
<div class="row text-center">
<form name="input" action="/save" method="post">
<div class="form-group">
<label for="exampleInputEmail1">Email address</label>
<input type="email" class="form-control" id="exampleInputEmail1" placeholder="Email" name="emailName">
</div>
<input type="submit" value="Save" class="btn btn-default" />
</form>
</div>
</div>
You need to add getter/setter for your emailName attribute to your ExampleInputForm class.