I have one controller called IndexController. It has a #GetMapping and #PostMapping methods. When the user types in the URL to go to /index, it loads a list of books. On that index page, there's a 'Add a new book' button that triggers a modal pop up. When the user enters in information in the form and clicks the 'Add' button, it should call the #PostMapping method. It's not calling the method. The model for the form is the IndexBook.
IndexController class:
#Controller
public class IndexController {
#GetMapping("/index")
public String formGet(Model model) {
BookService bookService = new BookService();
ArrayList<ReviewedBook> reviewedBooks = bookService.getRecordedBooks(1);
model.addAttribute("indexbook", new IndexBook());
model.addAttribute("books", reviewedBooks);
return "index";
}
#PostMapping("/index")
public String formPost(#ModelAttribute IndexBook ib, Model model) {
System.out.println("Post for index called.");
BookService bookService = new BookService();
return "index";
}
}
IndexBook:
public class IndexBook {
private int userId;
private String title;
private String author;
private String isbn;
private String genre;
private String dateRead;
private int rating;
public void setUserId(int userId) {
this.userId = userId;
}
public int getUserId() {
return userId;
}
public void setTitle(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
public void setAuthor(String author) {
this.author = author;
}
public String getAuthor() {
return author;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getIsbn() {
return isbn;
}
public void setGenre(String genre) {
this.genre = genre;
}
public String getGenre() {
return genre;
}
public void setDateRead(String dateRead) {
this.dateRead = dateRead;
}
public String getDateRead() {
return dateRead;
}
public void setRating(int rating) {
this.rating = rating;
}
public int getRating() {
return rating;
}
}
index.html (scroll down a bit to the comment 'Modal content')
<!DOCTYPE html>
<html lang="en">
<head>
<title>Book Note Book</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="css/index_styles.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#myNavbar">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="index">Book Note Book</a>
</div>
<div class="collapse navbar-collapse" id="myNavbar">
<ul class="nav navbar-nav">
<li>Books</li>
<li>Badges</li>
<li>Wishlist</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li>Profile</li>
<li><span class="glyphicon glyphicon-off"></span> Logout</li>
</ul>
</div>
</div>
</nav>
<div class="container">
<h2>Books</h2>
<p>This is all the books you've read</p>
<table class="table">
<thead>
<tr>
<th>Title</th>
<th>Author</th>
<th>Genre</th>
<th>ISBN</th>
<th>Date read</th>
<th>Rating</th>
</tr>
</thead>
<tbody>
<tr th:if="${books.empty}">
<td colspan="2"> No Books Available </td>
</tr>
<tr th:each="book : ${books}">
<td><p th:text="${book.title}"/></td></td>
<td><p th:text="${book.author}"/></td>
<td><p th:text="${book.genre}"/></td>
<td><p th:text="${book.isbn}"/></td>
<td><p th:text="${book.dateRead}"/></td>
<td><p th:text="${book.rating}"/></td>
</tr>
</tbody>
</table>
</div>
<div class="container">
<button type="button" class="btn btn-info btn-lg" data-toggle="modal" data-target="#addNewBook">Add new book</button>
<div class="modal fade" id="addNewBook" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Add a new book</h4>
</div>
<div class="modal-body">
**<form action="#" class="form-horizontal" th:action="#{/index}" th:object="${indexbook}" method="post">
<input type="hidden" th:field="*{userId}" />
<div class="form-group">
<label class="control-label col-sm-2" for="title">Title</label>
<div class="col-sm-10">
<input type="text" th:field="*{title}" class="form-control" id="title" placeholder="Enter title" name="title">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="author">Author</label>
<div class="col-sm-10">
<input type="text" th:field="*{author}" class="form-control" id="author" placeholder="Enter author" name="author">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="genre">Genre</label>
<div class="col-sm-10">
<input type="text" th:field="*{genre}" class="form-control" id="genre" placeholder="Enter genre" name="genre">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="isbn">ISBN</label>
<div class="col-sm-10">
<input type="text" th:field="*{isbn}" class="form-control" id="isbn" placeholder="Enter ISBN" name="isbn">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="dateRead">Date read</label>
<div class="col-sm-10">
<input type="text" th:field="*{dateRead}" class="form-control" id="dateRead" placeholder="Enter date read" name="Enter the date read">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="rating">Rating</label>
<div class="col-sm-10">
<input type="text" th:field="*{rating}" class="form-control" id="rating" placeholder="Enter rating" name="Enter the rating">
</div>
</div>
</form>**
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Add</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="footer navbar-fixed-bottom">
<footer class="container-fluid text-center">
<p>© 2018 Book Note Book</p>
</footer>
</div>
</body>
</html>
You need to change your button type, in order to submit your form.
<div class="modal-footer">
<button type="submit" class="btn btn-default" data-dismiss="modal">Add</button>
</div>
When you have a button element with type button, it is only clickable, but it won't submit a form, unless you specified an action in js.
Related
I am new in development tool and i am trying to use spring with thymeleaf to create a form to register on a website. I am currently not able to recover information from the form to another page which only show the list of users.
I create a classic Spring boot security in Eclipse with model/service/dao/controller java files.
My Model java file --> Register.java
#Entity
public class Register {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String pseudo;
private String lastname;
private String firstname;
private String sex;
private String country;
private String phone;
private String spokenlanguages;
private String email;
private String password;
private String job;
private boolean premium;
public void updateRegister(String pseudo, String lastname, String firstname, String sex, String country, String phone,
String spokenlanguages, String email, String password, String job, boolean premium) {
this.pseudo = pseudo;
this.lastname = lastname;
this.firstname = firstname;
this.sex = sex;
this.country = country;
this.phone = phone;
this.spokenlanguages = spokenlanguages;
this.email = email;
this.password = password;
this.job = job;
this.premium = premium;
// with all the getters & setters
}
My Service java file --> RegisterService.java
public interface RegisterService {
public List<Register> list();
public Register getById(long id);
}
My Repository Java file --> RegisterRepository.java
#Repository
public interface RegisterRepository extends PagingAndSortingRepository<Register, Long> {}
My Controller Java file --> RegisterController.java
#Controller
public class RegisterController {
#Autowired
RegisterRepository registerRepository;
#RequestMapping(value="/register", method=RequestMethod.GET)
public String form (Model model) {
return "register/form";
}
#PostMapping("/register/add")
public String registerAdd(
#Valid Register register,
BindingResult result,
Model model) {
if (result.hasErrors()) {
return "redirect:/error";
}
else {
Register r = new Register();
r.updateRegister(register.getPseudo(),
register.getLastname(),
register.getFirstname(),
register.getSex(),
register.getCountry(),
register.getPhone(),
register.getSpokenlanguages(),
register.getEmail(),
register.getPassword(),
register.getJob(),
register.isPremium());
System.out.println(r);
registerRepository.save(r);
model.addAttribute("registerlist", registerRepository.findAll());
return "register/valid";
}
}
#RequestMapping(value="/register/valid", method=RequestMethod.GET)
public String list (Model model) {
return "redirect:/home";
}
}
My Form in HTML --> form.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org/">
<head>
<title>Formulaire d'inscription</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin="anonymous">
<script
src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
crossorigin="anonymous"></script>
</head>
<body>
<h1 class="register">Formulaire d'inscription</h1>
<form action="#" method="post" th:object="${register}" th:action="#{/register/add}">
<div class="form-group">
<label for="pseudo">Pseudo</label> <input type="text"
class="form-control" id="pseudo" placeholder="Pseudo"
th:field="*{pseudo}" required="required">
</div>
<div class="form-group">
<label for="lastname">Nom</label> <input type="text"
class="form-control" id="lastname" placeholder="Nom"
th:field="*{lastname}" required="required">
</div>
<div class="form-group">
<label for="firstname">Prénom</label> <input type="text"
class="form-control" id="firstname" placeholder="Prenom"
th:field="*{firstname}" required="required">
</div>
<div class="form-group radio">
<label for="sex">Sexe</label><br />
<label for="male">Homme<input
type="radio" class="form-control" id="sex" value="male"
th:field="*{sex}" required="required">
</label> <label for="female">Femme<input type="radio"
class="form-control" th:field="*{sex}" id="sex" value="female">
</label> <label for="other">Autre<input type="radio"
class="form-control" th:field="*{sex}" id="sex" value="other"></label>
</div>
<div class="form-group">
<label for="country">Pays</label> <br /> <select th:field="*{country}" required="required">
<option value="France" selected="selected">France</option>
....other countries...
</select>
</div>
<div class="form-group">
<label for="phone">Téléphone</label> <label
class="optional">(Facultatif)</label> <input type="text"
class="form-control" id="phone" placeholder="Téléphone" th:field="*{phone}">
</div>
<div class="form-group">
<label for="spokenlanguages">Langues parlées</label> <input
type="text" class="form-control" id="spokenlanguages"
placeholder="Langues" th:field="*{spokenlanguages}" required="required">
</div>
<div class="form-group">
<label for="email">Adresse Email</label> <input type="email"
class="form-control" id="email" aria-describedby="emailHelp"
placeholder="Email" th:field="*{email}" required="required">
</div>
<div class="form-group">
<label for="emailconf">Confirmez votre adresse Email</label> <input
type="email" class="form-control" id="emailconf"
aria-describedby="emailHelp" placeholder="" required="required">
</div>
<div class="form-group">
<label for="password">Mot de passe</label> <input type="password"
class="form-control" id="password" placeholder=""
th:field="*{password}" required="required">
</div>
<div class="form-group">
<label for="passwordconf">Confirmez votre mot de passe</label> <input
type="password" class="form-control" id="passwordconf"
placeholder="" required="required">
</div>
<div class="form-group">
<label for="job">Travail</label> <br /> <select id="job"
th:field="*{job}" required="required">
<option value="alexandre">Alexandre</option>
<option value="filmlover">Cinéphile</option>
<option value="scenarist">Scénariste</option>
<option value="productor">Producteur</option>
<option value="other">Autres</option>
</select>
</div>
<div class="form-group radio">
<label for="premium">Premium</label><br />
<label for="yes">Oui<input
type="radio" class="form-control" id="premium"
value="yes" th:field="*{premium}" required="required">
</label>
<label for="no">Non<input type="radio" class="form-control"
th:field="*{premium}" id="premium" value="no">
</label>
</div>
<input type="submit" class="btn btn-primary" id="valider" name="valider" value="Valider" />
</form>
<a href="../home" > <input class="btn btn-primary" type="reset" value="Annuler" /></a>
</body>
</html>
and my second HTML --> valid.html where i want to see at first now that the register was successful...but I got in this page this message --> org.thymeleaf.spring5.processor.SpringInputGeneralFieldTagProcessor and my trial sysout in the controller lead to an null values for everything except the id and the premium stuff (boolean)
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org/">
<head>
<title>Formulaire d'inscription</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin="anonymous">
<script
src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
crossorigin="anonymous"></script>
</head>
<body>
<h1 class="register">Confirmation de votre inscription</h1>
<!-- <h2 class ="register" th:text="${'Bienvenue ' + register.pseudo}"></h2> -->
<div class="container">
<div class="page-header" id="banner">
<div class="row">
<div class="col-lg-8 col-md-7 col-sm-6">
<h1>Utilisateurs</h1>
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Id</th>
<th>Pseudo</th>
<th>Nom</th>
<th>Prénom</th>
<th>Sexe</th>
<th>Pays</th>
<th>Téléphone</th>
<th>Langues parlées</th>
<th>E-mail</th>
<th>Mot de passe</th>
<th>Travail</th>
<th>Premium</th>
</tr>
</thead>
<tbody>
<tr th:each="register : ${registerlist}">
<td th:text="${register.id}"></td>
<td th:text="${register.pseudo}"></td>
<td th:text="${register.lastname}"></td>
<td th:text="${register.firstname}"></td>
<td th:text="${register.sex}"></td>
<td th:text="${register.country}"></td>
<td th:text="${register.phone}"></td>
<td th:text="${register.spokenlanguages}"></td>
<td th:text="${register.email}"></td>
<td th:text="${register.password}"></td>
<td th:text="${register.job}"></td>
<td th:text="${register.premium}"></td>
<td th:text="${register.id}"></td>
</tr>
</tbody>
</table>
</div>
</div>
<a href="../home" > <input class="btn btn-primary" type="reset" value="Retour" /></a>
</body>
</html>
Thanks in advance for the help.
Feel free to ask me more in order to a better unterstanding...
Try to add #ModelAttribute("register") in your registerAdd method, so it should look like
#RequestMapping(value="/register/add", method=RequestMethod.POST)
public String registerAdd(#ModelAttribute("register") #Valid Register register, BindingResult result, Model model)
Let me know if it was the problem.
Edit1
Add this line to your GET mapping
model.addAttribute("register", new Register());
So it should look like:
#RequestMapping(value = "/register", method = RequestMethod.GET)
public String form(Model model) {
model.addAttribute("register", new Register());
return "register/form";
}
Hope it solves the problem :)
When I go to /add endpoint my Controller creates a Contact object and generates an ID for it. This ID is then properly passed to a Thymeleaf view and showed on the webpage. When the form from the view is submitted (with POST) to another endpoint in my Controller all of the properties are passed except the ID field. I use Spring Model and #ModelAttribute annotation to pass the object to and from the view. Getters and setters for the entity are generated with Lombok.
Controller class:
#Controller
public class PhonebookController {
private final PhonebookService phonebookService;
#Autowired
public PhonebookController(PhonebookService phonebookService) {
this.phonebookService = phonebookService;
}
#GetMapping("/add")
public String addContact(Model model) {
model.addAttribute("contact", new Contact(EntityUtils.generateId()));
return "contact";
}
#PostMapping("/save")
public String validateAndSaveContact(#ModelAttribute("contact") #Valid Contact contact, BindingResult bindingResult) { // contact.getId() returns null
if (bindingResult.hasErrors()) {
return "contact";
}
phonebookService.getContactRepository().save(contact);
return "redirect:/contacts";
}
}
Entity class:
#Data
#NoArgsConstructor
#AllArgsConstructor
#Document(indexName = "contact")
public class Contact implements Comparable<Contact> {
#Id
private String id;
#NotEmpty(message = "Name can not be empty.")
private String name;
#NotEmpty(message = "Number can not be empty.")
#Pattern(regexp = "[0-9]+", message = "Number can contains only numbers.")
private String number;
public Contact(String id) {
this.id = id;
}
#Override
public int compareTo(Contact o) {
return this.getName().compareTo(o.name);
}
}
Thymeleaf view:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" href="/webjars/bootstrap/css/bootstrap.min.css"/>
<script type="text/javascript" src="/webjars/jquery/jquery.min.js"></script>
<script type="text/javascript" src="/webjars/bootstrap/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="/webjars/font-awesome/css/font-awesome.min.css"/>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-12">
<h1>Add new contact</h1>
<form th:action="#{/save}" method="post" th:object="${contact}">
<div class="form-group">
<label for="idText">Identifier (automaticaly generated):</label>
<strong id="idText" th:text="${contact.getId()}"></strong>
</div>
<div class="form-group">
<label for="nameInput">Contact name:</label>
<input type="text" th:field="*{name}" th:value="*{name}" class="form-control" id="nameInput"/>
<div class="alert alert-warning" role="alert" th:if="${#fields.hasErrors()}" th:errors="*{name}"></div>
</div>
<div class="form-group">
<label for="numberInput">Phone number:</label>
<input type="text" th:field="*{number}" th:value="*{number}" class="form-control" id="numberInput"/>
<div class="alert alert-warning" role="alert" th:if="${#fields.hasErrors()}" th:errors="*{number}"></div>
</div>
<div class="form-group text-right">
<button type="submit" class="btn btn-success">Confirm</button>
<a class="btn btn-danger" th:href="#{/contacts}" role="button">Cancel</a>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
You need to have a hidden input field which contains the id value.
<div class="form-group">
<label for="idText">Identifier (automaticaly generated):</label>
<strong id="idText" th:text="${contact.getId()}"></strong>
<input id="id" th:field="*{id}" type="hidden"/>
</div>
I would like to help you, but I don´t know if you are using the same object to save the data in your table (your entity) and for return your view model in your controller. Normally you should use a different objects and mapping this in your service. It is posible that you have problems if you are using the same object.
I want to get the name and email address from a user through following form
<!-- Contatct Us-->
<section>
<div class="grey-bg">
<div class="container p-y-40">
<h1>Contact Us</h1>
<div class="row">
<div class="col-md-6">
<div class="form-horizontal contact-us" th:action="#{/contact-us}">
<div class="form-group">
<label for="FirstName" class="col-sm-3 control-label mandatory">Name</label>
<div class="col-sm-9">
<input type="text" class="form-control" th:value="${name}" placeholder=""/>
<input name="name" type="text" th:value="${name}" placeholder=""/>
<span th:text = "${name}"/>
</div>
</div>
<!-- -->
<div class="form-group">
<label for="Email" class="col-sm-3 control-label mandatory">Email</label>
<div class="col-sm-9">
<input type="email" class="form-control" th:value="${email}" placeholder=""/>
<input type="email" name="email" class="form-control" th:value="${email}" placeholder=""/>
</div>
</div>
<!-- -->
<div class="form-group">
<label for="Telephone" class="col-sm-3 control-label">Telephone</label>
<div class="col-sm-9">
<input type="text" class="form-control" th:value="${telephone}" placeholder=""/>
</div>
</div>
<!-- -->
<div class="form-group">
<label for="Message" class="col-sm-3 control-label ">Message</label>
<div class="col-sm-9">
<textarea class="form-control" rows="4" th:value="${message}"> </textarea>
</div>
</div>
<!-- -->
<div class="form-group">
<div class="col-sm-9 col-sm-offset-3 col-md-offset-3">
<input type="button" value="Send" class="btn btn-primary btn-flat w-min-120"
data-toggle="modal" data-target="#myModal" />
</div>
</div>
<!-- -->
</div>
</div>
<div class="col-md-6">
<iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d63371.792586563766!2d79.85603378454613!3d6.922006503004973!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x0%3A0x5f6f0f981a359f05!2sDialog+Axiata+PLC!5e0!3m2!1sen!2slk!4v1503969814382" width="100%" height="350" frameborder="0" style="border:0" allowfullscreen="true"></iframe>
</div>
</div>
</div>
</div>
</section>
I have used html and thymeleaf here. This is my controller. In the controller I want to pass parameters to the sendUserRegisterEmail method which I was taken from the user.
#Autowired
private EmailService emailService;
#ResponseBody
#RequestMapping(value = "/contact-us", method = RequestMethod.POST)
public String showContactForm(#RequestParam("name") String contactName, #RequestParam("email") String contactEmail) {
emailService.sendUserRegisterEmail(contactName, contactEmail);
return "index";
}
I wrote a DTO class as well.
public class ContactUsDto {
private String name;
private String email;
private String telephone;
private String message;
public ContactUsDto(String name, String email, String telephone, String message) {
this.name = name;
this.email = email;
this.telephone = telephone;
this.message = message;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
Currently I get no errors. But the email is not receiving. I have no any issues with the method which I used to send the email. Because I have used it in another instances. The only issue is passing form data to it. Please help me to resolve this
#RequestParam is used to pass the request parameters e.g.
http://example.com/path?name=myName&email=myEmail
Whereas #RequestBody is used to get the request's body, which in most cases for REST is a json (application/json) body. So your method will be
#ResponseBody
#RequestMapping(value = "/contact-us", method = RequestMethod.POST)
public String showContactForm(#RequestBody ContactUsDto contactUsDto ) {
emailService.sendUserRegisterEmail(contactUsDto.getContactName(), contactUsDto.getContactEmail());
return "index";
}
add to your input attibute name like this
<input type="email" name="email" class="form-control" th:value="${email}" placeholder=""/>
<input name="name" type="text" th:value="${name}" placeholder=""/>
and try again .
When trying to submit my form to create a new auction this error appears in the browser:
Whitelabel Error Page:
This application has no explicit mapping for /error, so you are seeing
this as a fallback.
Thu Mar 30 21:00:15 BST 2017
There was an unexpected error (type=Bad Request, status=400)
Validation failed for object='auctionItem'. Error count: 2
I can't seem to find any specific errors within my log, so I am having trouble finding the two validation errors show on the error page. I am pretty lost at this point. Hopefully someone can help me out, its preventing me from making progress at the moment.
JSP File:
<body id="product" class="product">
<header>
<%#include file="../jsp/Header.jsp" %>
</header>
<div>
<div class="container">
<div class ="row">
<div class="center_column">
<h2 style=" ">Create New Listing</h2>
<mvc:form class="form-inline" action="sell" method="post" modelAttribute="newAuction" id="addNewAuc">
<div class="form-inline" cssClass="TitleBlock">
<label class="control-label">Title</label>
<div>
<mvc:input path="aTitle" type="text" required="true" cssClass="Title" class="form-control" placeholder="Please enter title of item" maxlength="55" minlength="40"/>
</div>
</div>
<div class="form-group ">
<label class="control-label">Item Condition</label>
<div style="padding-top: 4px;">
<mvc:select path="aCondition">
<mvc:option value="New">New</mvc:option>
<mvc:option value="Used">Used</mvc:option>
</mvc:select>
</div>
</div>
<div class="form-group ">
<label class="control-label" style = "padding-left: 15px;">Can the item be returned?</label>
<div style="padding-top: 4px; padding-left: 15px;">
<mvc:select path="aReturns">
<mvc:option value="You can return">Yes</mvc:option>
<mvc:option value="Seller does not offer returns">No</mvc:option>
</mvc:select>
</div>
</div>
<div class="form-inline">
<label class="control-label">Description</label>
<div>
<mvc:textarea path="aDescription" required="true" cssClass="Desc" class="form-control" rows="3" name="Description" placeholder="Item description"/>
</div>
</div>
<div class="form-inline">
<label class="control-label">Category</label>
<div style="padding-top: 4px;">
<mvc:select path="categories">
<mvc:option value="category1">Electronics</mvc:option>
<mvc:option value="category2">Fashion</mvc:option>
<mvc:option value="category3">Home & Gardens</mvc:option>
<mvc:option value="category4">Toys & Games</mvc:option>
<mvc:option value="category5">Sports & Leisure</mvc:option>
</mvc:select>
</div>
</div>
<div class="form-inline">
<label class="control-label ">Minimum Price</label>
<div style="padding-top: 4px;">
<mvc:input path="aBottomPrice" type="number" step="any" required="true" class="form-control" placeholder="?"/>
</div>
</div>
<div class="form-inline">
<label class="control-label ">Starting Price</label>
<div style="padding-top: 4px;">
<mvc:input path="aTopPrice" type="number" step="any" required="true" class="form-control" placeholder="?"/>
</div>
</div>
<div class="form-inline">
<label class="control-label">End of listing</label>
<div style="padding-top: 4px;">
<mvc:input path="aEnd" type="text" id="datetimepicker" required="true" class="form-control" placeholder="YYYY-MM-DD"/>
</div>
</div>
</mvc:form>
<div class="form-inline">
<div style="padding-top: 10px;">
<button type="submit" name="submit" class="btn btn-success" form="addNewAuc">Next</button>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
AuctionItem Class
#Entity
#Table(name = "auction_items")
public class AuctionItem {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int idauction;
#Column(name = "auctionTitle")
private String aTitle;
#Column(name = "auctionDescription")
private String aDescription;
#Column(name = "auctionStatus")
private String aStatus;
#Column(name = "auctionStart")
private Date aStart;
#Column(name = "auctionEnd")
private Date aEnd;
private String endTimeAsString;
#Column(name = "auctionCondition")
private String aCondition;
#Column(name = "auctionTopPrice")
private double aTopPrice;
#Column(name = "auctionBottomPrice")
private double aBottomPrice;
private long auctionDuration;
private String aReturns;
#ManyToOne
#JoinColumn(name = "owner")
private User owner;
#ManyToOne
#JoinColumn(name = "cId")
private Category categories;
public long getAuctionDuration() {
return auctionDuration;
}
public void setAuctionDuration(long auctionDuration) {
this.auctionDuration = auctionDuration;
}
public int getaID() {
return idauction;
}
public void setaID(int idauction) {
this.idauction = idauction;
}
public String getaTitle() {
return aTitle;
}
public void setaTitle(String aTitle) {
this.aTitle = aTitle;
}
public String getaDescription() {
return aDescription;
}
public void setaDescription(String aDescription) {
this.aDescription = aDescription;
}
public String getaStatus() {
return aStatus;
}
public void setaStatus(String aStatus) {
this.aStatus = aStatus;
}
public Date getaStart() {
return aStart;
}
public void setaStart(Date aStart) {
this.aStart = aStart;
}
public Date getaEnd() {
return aEnd;
}
public void setaEnd(Date aEnd) {
this.aEnd = aEnd;
}
public String getaCondition() {
return aCondition;
}
public void setaCondition(String aCondition) {
this.aCondition = aCondition;
}
public double getaTopPrice() {
return aTopPrice;
}
public void setaTopPrice(double aTopPrice) {
this.aTopPrice = aTopPrice;
}
public double getaBottomPrice() {
return aBottomPrice;
}
public void setaBottomPrice(double aBottomPrice) {
this.aBottomPrice = aBottomPrice;
}
public User getOwner() {
return owner;
}
public void setOwner(User owner) {
this.owner = owner;
}
public String getaReturns() {
return aReturns;
}
public void setaReturns(String aReturns) {
this.aReturns = aReturns;
}
public Category getCategories() {
return categories;
}
public void setCategories(Category categories) {
this.categories = categories;
}
public String getEndTimeAsString() {
return endTimeAsString;
}
public void setEndTimeAsString(String EndTimeAsString) {
this.endTimeAsString = EndTimeAsString;
}
}
Maybe you missed " BindingResult " in Controller.
Example:
import org.springframework.validation.BindingResult;
#RequestMapping(value = "/registration", method = RequestMethod.POST)
public String registration(
#ModelAttribute("userlogin") #Valid LoginProfile userlogin,
BindingResult userloginResult)
When I load page for create a new article, all categories is displayed in select box.
When I complete form for a new article and click on the submit button, it saves all data from form to the database but categories isn't joined with an article.
Do you understand me what I think? What could be an issue?
ArticleController.class
#Controller
public class ArticleController {
#Autowired
ArticleService articleService;
#Autowired
CategoryService categoryService;
#Autowired
UserService userService;
#ModelAttribute("article")
public Article construct() {
return new Article();
}
/**
* Method displays page with all articles, categories and users
* (articles.jsp)
* */
#RequestMapping("/admin/articles")
public String articles(Model model) {
model.addAttribute("articles", articleService.findAll());
model.addAttribute("categories", categoryService.findAll());
model.addAttribute("users", userService.findAll());
return "articles";
}
/**
* Method for display article's detail (article-detail.jsp)
* */
#RequestMapping("/admin/articles/{id}")
public String userDetail(Model model, #PathVariable Integer id) {
model.addAttribute("articles", articleService.findAll());
model.addAttribute("article", articleService.findById(id));
return "article-detail";
}
/**
* Method for display article's add page (article-add.jsp)
* */
#RequestMapping("/admin/articles/new")
public String articleAdd(Model model) {
model.addAttribute("articles", articleService.findAll());
model.addAttribute("categories", categoryService.findAll());
model.addAttribute("users", userService.findAll());
return "article-add";
}
/**
* Method for save article
* */
#RequestMapping(value = "/admin/articles/new", method = RequestMethod.POST)
public String saveArticle(#ModelAttribute("article") Article article,
BindingResult result) {
Date publishDate = new Date();
article.setPublishDate(publishDate);
articleService.save(article);
return "redirect:/admin/articles.html?success=true";
}
/**
* Binder for required date format
* */
#InitBinder
public void initBinder(WebDataBinder webDataBinder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm");
dateFormat.setLenient(false);
webDataBinder.registerCustomEditor(Date.class, "publishDate",
new CustomDateEditor(dateFormat, false));
}}
article-add.jsp
<%# page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%# include file="../layouts/taglibs.jsp"%>
<form:form commandName="article" cssClass="form-horizontal">
<div class="form-group">
<form:hidden path="id" class="form-control input-sm" />
</div>
<div class="form-group">
<label for="title" class="col-sm-2 control-label">Titulek</label>
<div class="col-sm-10">
<form:input path="title" cssClass="form-control" />
</div>
</div>
<div class="form-group">
<label for="content" class="col-sm-2 control-label">Text</label>
<div class="col-sm-10">
<form:textarea path="content" cssClass="form-control" rows="10" />
</div>
</div>
<div class="form-group">
<label for="categories" class="col-sm-2 control-label">Kategorie</label>
<div class="col-sm-10">
<form:select path="categories" items="${categories}" itemLabel="name" itemValue="id" multiple="true" cssClass="form-control" />
</div>
</div>
<div class="form-group">
<label for="user" class="col-sm-2 control-label">Uživatel</label>
<div class="col-sm-10">
<form:select path="user.id" items="${users}" value="${user.id}" itemLabel="name" itemValue="id" cssClass="form-control" />
</div>
</div>
<div class="form-group">
<div class="col-sm-2">
<input type="submit" value="Uložit" class="btn btn-primary">
</div>
</div>
Category.class
#Entity
public class Category {
#Id
#GeneratedValue
private Integer id;
#Size(min=3, max=20, message="Název musí obsahovat 3-20 znaků!")
private String name;
#ManyToMany(mappedBy = "categories", cascade = CascadeType.REMOVE)
private List<Article> articles;
/**
* Getters and setters
* */
}
-- SOLVED --
I solved this problem by adding:
#InitBinder
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
binder.registerCustomEditor(Category.class, "categories", new PropertyEditorSupport() {
#Override
public void setAsText(String text) {
Category c = categoryService.findById(Integer.parseInt(text));
setValue(c);
}
});
}