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.
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.
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.
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
How to display this message from custom class type annotation in Spring as a warning message in HTML form? I am using Spring Boot MVC and Thymeleaf. Thymeleaf can handle field errors and global errors that are not associated with any specific fields in the form, but still exist. If this custom annotation finds that passwords don't match is this global error or field error? How can I show this message?
Custom annotation:
#Target({ TYPE, ANNOTATION_TYPE })
#Retention(RUNTIME)
#Constraint(validatedBy = PasswordMatchesValidator.class)
#Documented
public #interface PasswordMatches {
String message() default "Passwords don't match";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Validator class:
public class PasswordMatchesValidator implements ConstraintValidator<PasswordMatches, Object> {
#Override
public void initialize(PasswordMatches passwordMatches) {
}
#Override
public boolean isValid(Object obj, ConstraintValidatorContext context) {
UserDto userDto = (UserDto) obj;
return userDto.getPassword().equals(userDto.getMatchingPassword());
}
}
Post Controller
#PostMapping(value = "/register")
public ModelAndView processRegistration(ModelAndView modelAndView, #Valid #ModelAttribute ("userDto") UserDto userDto,
BindingResult bindingResult, HttpServletRequest request, Errors errors) {
// Lookup user in database by e-mail
User userExists = userService.findByEmail(userDto.getEmail());
System.out.println(userExists);
if (userExists != null) {
modelAndView.addObject("alreadyRegisteredMessage", "Oops! There is already a user registered with the email provided.");
modelAndView.setViewName("register");
bindingResult.reject("email");
}
if (bindingResult.hasErrors()) {
modelAndView.setViewName("register");
} else { // new user so we create user and send confirmation e-mail
User user = userService.createNewAccount(userDto);
user.setEnabled(false);
userService.saveUser(user);
modelAndView.addObject("confirmationMessage", "A confirmation e-mail has been sent to " + userDto.getEmail());
modelAndView.setViewName("registered");
}
}
HTML form:
<div class="container">
<div class="row">
<div class="card col-6 mx-auto" style="width: 20rem; margin: 20px;">
<div class="card-body">
<h4 class="card-title">Registration form:</h4>
<form th:action="#{register}" th:object="${userDto}" th:method="post" method="post" action="register">
<div class="form-group">
<label th:for="name" for="Name">Name</label>
<input type="text" class="form-control" th:field="*{name}" id="name" placeholder="Enter name">
<p class="text-danger" th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></p>
</div>
<div class="form-group">
<label th:for="surname" for="Surname">Surname</label>
<input type="text" class="form-control" th:field="*{surname}" id="surname" placeholder="Enter surname">
<p class="text-danger" th:if="${#fields.hasErrors('surname')}" th:errors="*{surname}"></p>
</div>
<div class="form-group">
<label th:for="username" for="Username">Username</label>
<input type="text" class="form-control" th:field="*{username}" id="username" placeholder="Enter username">
<p class="text-danger" th:if="${#fields.hasErrors('username')}" th:errors="*{username}"></p>
</div>
<div class="form-group">
<label th:for="email" for="Email">Email address</label>
<input type="email" class="form-control" th:field="*{email}" id="email" aria-describedby="emailHelp" placeholder="Enter email">
<small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small>
<p class="text-danger"th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></p>
<p class="text-danger" th:text="${alreadyRegisteredMessage}"></p>
</div>
<div class="form-group">
<label th:for="password" for="Password">Password</label>
<input type="password" class="form-control" th:field="*{password}" id="password" placeholder="Password">
<p class="text-danger"th:if="${#fields.hasErrors('password')}" th:errors="*{password}"></p>
</div>
<div class="form-group">
<label th:for="matchingPassword" for="matchingPassword">Confirm Password</label>
<input type="password" class="form-control" th:field="*{matchingPassword}" id="matchingPassword" placeholder="Password">
<p class="text-danger"th:if="${#fields.hasErrors('matchingPassword')}" th:errors="*{matchingPassword}"></p>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
</div>
</div>
You can customize the PasswordMatchesValidator class to display the warning message.
public class PasswordMatchesValidator implements ConstraintValidator<PasswordMatches, Object> {
private String message;
#Override
public void initialize(PasswordMatches passwordMatches) {
this.message = passwordMatches.message();
}
#Override
public boolean isValid(Object obj, ConstraintValidatorContext context) {
final UserDto userDto = (UserDto) obj;
boolean isValid = userDto.getPassword().equals(userDto.getMatchingPassword());
if (!isValid) {
context.disableDefaultConstraintViolation();
context
.buildConstraintViolationWithTemplate( message )
.addPropertyNode( "matchingPassword" ).addConstraintViolation();
}
return isValid;
}
}
The solution is to include global errors Thymeleaf syntax in HTML form. But for some reason single quote in this message: "Passwords don't match", doesn't get rendered. The answer to this problem is here.
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";
}
}