I know the title of this question is not clear, but before disliking let me explain my problem.
I have a social media with java spring using JPA and thymeleaf.
Users have ids, usernames, and creation dates.
In the posts table there is a field called "authorid", so when someone makes a new post the system only writes his user id, not his username.
Now, I have a page on the site, available at "localhost:8080/showAllPosts/" which shows ALL the application posts from the most recent to the least recent. The controller looks something like this:
#Controller
public class MyController {
#GetMapping("/showAllPosts")
public String showAllPosts(Model model) {
List<Post> post = new ArrayList<>();
model.addAttribute("post", post);
List<Post> posts = postRepository.findAll();
model.addAttibute("posts", posts);
return "showallposts.html";
}
}
The showallposts.html page looks like this:
<table>
<tbody>
<tr th:if="${posts.empty}">
<td colspan="2">No Posts Available</td>
</tr>
<tr th:each="post : ${posts}">
<td>
<span th:text="'posted by ' + ${post.authorid}>
<span th:text="${post.postcontent}"></span>
<br>
</td>
<td>
</td>
</tr>
</tbody>
</table>
As you can see, it shows the post content, and "posted by" plus the author. The only problem is that the post.authorid returns the numeric id of user who posted, and I wanted the username. Is there something we can do with the users model?
Notice that in the users repository I have this method:
#Query(value = "SELECT u.username FROM Users u WHERE u.userid = ?1")
public String findUsernameById(Long userid);
ALL help is appreciated! <3
Alternatively, you can use a DTO to move the post with the author's name into the Thymeleaf view.
Create a new class like PostDto:
public class PostDto {
private Long id;
private String postContent;
private Long authorId;
private String String authorName;
// other fields
// getters and setters
}
Convert your post entity class to PostDto using the Stream API. During the mapping, you can get the username by authorId via UserRespository and supplement the post dto object with the author's name.
#Controller
public class MyController {
#Autowired
private UserRepository userRepository;
#GetMapping("/showAllPosts")
public String showAllPosts(Model model) {
List<Post> post = new ArrayList<>();
model.addAttribute("post", post);
List<Post> posts = postRepository.findAll().stream()
.map(post -> {
PostDto dto = toDto(post);
dto.setAuthorName(userRepository.findUsernameById(post.getAuthorId()));
})
model.addAttibute("posts", posts);
return "showallposts.html";
}
private PostDto toDto(Post post) {
PostDto dto = new PostDto();
dto.setId(post.getId);
dto.setPostContent(post.getPostContent());
dto.setAuthorId(post.getAuthorId());
}
}
Use in the Thymeleaf view as ${post.authorName}.
<table>
<tbody>
<tr th:if="${posts.empty}">
<td colspan="2">No Posts Available</td>
</tr>
<tr th:each="post : ${posts}">
<td>
<span th:text="'posted by ' + ${post.authorName}>
<span th:text="${post.postcontent}"></span>
<br>
</td>
<td>
</td>
</tr>
</tbody>
</table>
Related
I am trying to return the data as a response body in java spring boot when a button is click in an html page.I have a list of countries displayed in my page with an edit button assigned to each. I want to find the data that was clicked by id so I have defined the method in my controller class. That's when the edit button is click, it should take the id of the country in the clicked row and display the information based on that id. When I test the api in Postman, it returns the data correctly but when I called the same api in my html page, it's giving me this error.
org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "/findById/{id=${country.id}}" (template: "country" - line 555, col 26)
at org.thymeleaf.spring5.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:292) ~[thymeleaf-spring5-3.0.14.RELEASE.jar:3.0.14.RELEASE]
Caused by: org.springframework.expression.spel.SpelParseException: Expression [/findById/{id=${country.id}}] #0: EL1070E: Problem parsing left operand
This is my data class
Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String code;
private String capital;
private String description;
private String nationality;
private String continent;
}
My Controller class
#Controller
public class CountryController {
#Autowired
private CountryService countryService;
#GetMapping("/countries")
public String getCountry(Model model){
List<Country> countryList = countryService.getAllCountry();
model.addAttribute("countries",countryList);
return "country";
}
#PostMapping("/countries/addNew")
public String saveInfo(Country country){
countryService.saveCountryInfo(country);
return "redirect:/countries";
}
#GetMapping("/findById/{id}")
#ResponseBody
public ResponseEntity<Country> getCountryById(#PathVariable("id") Long countryId){ //Bind PathVariable id to id
return ResponseEntity.ok(countryService.getCountryById(countryId)) ;
}
#GetMapping("/country/code/{code}")
public Country getCountryCode(#PathVariable("code") String code){
return countryService.getCountryByCode(code);
}
}
My Service class
#Service
public class CountryService {
#Autowired
private CountryRepository countryRepository;
public List<Country> getAllCountry() {
return countryRepository.findAll();
}
public void saveCountryInfo(Country country){
countryRepository.save(country);
}
public Country getCountryById(Long id){
return countryRepository.findById(id).get();
}
public Country getCountryByCode(String code){
return countryRepository.findByCode(code);
}
}
My Repository class
#Repository
public interface CountryRepository extends JpaRepository<Country,Long> {
public Country findByCode(String code);
}
Here is the html code
<section class="section dashboard">
<div class="row">
<!-- Left side columns -->
<div class="row">
<div class="col-lg-9 col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<!-- Image background -->
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addModal" data-whatever="#mdo">Add A Country</button>
<h1>List of Country</h1>
<table class="table">
<thead>
<tr>
<th>Id</th>
<th>Code</th>
<th>Capital</th>
<th>Description</th>
<th>Nationality</th>
<th>Continent</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr th:each="country:${countries}">
<td th:text="${country.id}"></td>
<td th:text="${country.code}">Code</td>
<td th:text="${country.capital}">Capital</td>
<td th:text="${country.description}">Description</td>
<td th:text="${country.nationality}">Nationality</td>
<td th:text="${country.continent}">Continent</td>
<td>
<div class="btn-group">
<a th:href="${/findById/{id=${country.id}}}" class="btn btn-primary" id="editButton" data-bs-toggle="modal" data-bs-target="#editModal">Edit</a>
</div>
</td>
</tr>
</tbody>
</table>
</div><!-- End of Image background -->
</div><!-- End Left side columns -->
</div>
</div>
</div>
</section>
I am having issues indexing my for each objects. I have a list that I pull from the repository, that is called MonthlyAcct. I want to iterate over the list in the thymeleaf html file and show each property of the MonthlyAcct object displayed as an editable input field inside a table. I keep getting errors that Indexing into type 'monthAcct' is not supported, or currently, the error is: "Neither BindingResult nor plain target object for bean name 'monthAcct[0]' available as request attribute."
This is definitely an issue with how I've set up th:field, as if I switch it out to th:name, it shows up and does not throw errors. Do I have to make this into a form to get the th:field to work?
I have used this same style/tactic in other areas of my project and it works, so I am not sure why this time this type of set up is not working. Any ideas? I also have a different form on this page, that updates details for a client class, can this be causing any issues?
Just for reference I have tried * and $ with the th:each statement, and have tried both symbols with the th:field as well. Both throw the above mentioned error.
<table class="table table-striped" data-toggle="table" data-show-toggle="true" data-classes="table-no-bordered" data-striped="true" data-search="true" data-show-columns="true" >
<thead>
<th>year</th>
<th>January</th>
</thead>
<tbody>
<tr th:each="acct, stat : ${monthAcct}">
<td th:text="${acct.year}"></td>
<td>
<input type="number" class="text-left form-control" th:field="${monthAcct[__${stat.index}__].janAmt}"/>
</td>
</tr>
</tbody>
</table>
In the controller:
#RequestMapping(value="/accounting/client/{id}")
public String accountingDetails(#PathVariable("id")Client client, MonthlyAccountingTracker monthlyAccountingTracker, Model model) {
List<MonthlyAccountingTracker> monthAcct = monthlyAccountingTrackerRepository.findByClient(client);
model.addAttribute("client",clientRepository.findById(client.getId()));
model.addAttribute("monthAcct",monthAcct);
return "accounting";
}
#DynamicUpdate
#Entity
#Table(name="MonthlyMinAcctTracker")
#EntityListeners(AuditingEntityListener.class)
public class MonthlyAccountingTracker {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#ManyToOne
#JoinColumn(name="client")
private Client client;
private BigDecimal year;
private BigDecimal janAmt;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Client getClient() {
return client;
}
public void setClient(Client client) {
this.client = client;
}
public BigDecimal getJanAmt() {
return janAmt;
}
public void setJanAmt(BigDecimal janAmt) {
this.janAmt = janAmt;
}
}
I get my monthAcct list from the repository:
public interface MonthlyAccountingTrackerRepository extends CrudRepository<MonthlyAccountingTracker,Long>, JpaSpecificationExecutor {
MonthlyAccountingTracker save(MonthlyAccountingTracker entity);
MonthlyAccountingTracker findById(Long id);
List<MonthlyAccountingTracker> findByClient(Client client);
void delete(MonthlyAccountingTracker entity);
List<MonthlyAccountingTracker> findAll();
}
*{monthAcct} should be ${monthAcct} as you are setting the value in modelAndView or in your case model. The monthAcct is not a field of the th:object.
You can't use a List as a form backing object. You need another object that wraps your array (and to use that object as your backing object). For example:
Java:
// Backing object
class BackingObject {
List<MonthlyAccountingTracker> accounts;
public BackingObject(List<MonthlyAccountingTracker> accounts) {
this.accounts = accounts;
}
// Put in getters/setters...
}
// Controller
#RequestMapping(value="/accounting/client/{id}")
public String accountingDetails(#PathVariable("id")Client client, MonthlyAccountingTracker monthlyAccountingTracker, Model model) {
model.addAttribute("client",clientRepository.findById(client.getId()));
model.addAttribute("form", new BackingObject(monthlyAccountingTrackerRepository.findByClient(client)));
return "accounting";
}
Form:
<form th:object="${form}">
.
.
.
<tr th:each="acct, stat : *{accounts}">
<td th:text="${acct.year}"></td>
<td>
<input type="number" class="text-left form-control" th:field="*{accounts[__${stat.index}__].janAmt}"/>
</td>
</tr>
.
.
.
</form>
You should use an * instead of $ sign for monthAcct field:
<input type="number" class="text-left form-control" th:field="*{monthAcct[__${stat.index}__].janAmt}"/>
I've tried to create an object with another object inside, with a form but the Object picked from a dropdown list gets converted into a String when returned from the Thymeleaf form.
Those are the entities in my project, with an 1:n relatioship between them:
Entity User
//imports
#Entity
#Table(name = "USERS")
public class User {
#Id
#GeneratedValue
#Column( name ="USER_ID")
private int id;
#Column( name ="username")
private String username;
#Column( name ="password")
private String password;
#Column( name ="email")
private String email;
#OneToMany(fetch= FetchType.LAZY, mappedBy="user", cascade = CascadeType.ALL)
private List<Post> posts;
//setter & getters & toString
}
Entity Post
//imports
#Entity
#Table(name="POSTS")
public class Post {
#Id
#GeneratedValue
#Column(name="POST_ID")
private int id;
#Column(name="tittle")
private String tittle;
#Column(name="text")
private String text;
#ManyToOne
#JoinColumn(name="USER_ID",referencedColumnName="USER_ID")
private User user;
//getters & setters & toString
To create a new Post:
//In Controller
#RequestMapping(value = "/posts/new")
public String newPost(Model model) {
model.addAttribute("post", new Post());
model.addAttribute("users", userService.list());
return "addPost";
}
Which returns the template that has this form:
<form th:action="#{/savePost}" th:object="${post}" method="post">
<tr>
<td><input type="hidden" th:field="${post.id}" /></td>
</tr>
<tr>
<td>Titulo</td>
<td>Texto</td>
<td>Usuario</td>
</tr>
<tr>
<td><input type="text" th:field="${post.tittle}"
th:value="${post.tittle}" /></td>
<td><input type="text" th:field="${post.text}"
th:value="${post.text}" /></td>
<td><select th:field="${post.user}">
<option th:each="user : ${users}" th:text="${user.username}"
th:value="${user.id}"></option>
</select></td>
</tr>
<tr>
<td colspan="3"><input class="btn btn-primary" type="submit"
value="GUARDAR"></td>
</tr>
</form>
The action attribute in the form calls:
#PostMapping("/savePost")
//#RequestMapping(value = "users/save",method = RequestMethod.POST)
public String savePost(#ModelAttribute Post post) {
postService.add(post);
return "redirect:/posts";
}
At this point, I try to create a Post and select a User from the dropdown but when attempting to save it gives me this error:
Field error in object 'post' on field 'user': rejected value [16]; codes [typeMismatch.post.user,typeMismatch.user,typeMismatch.com.julian.bootmvchibernate.model.User,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [post.user,user]; arguments []; default message [user]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'com.julian.bootmvchibernate.model.User' for property 'user'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [#javax.persistence.ManyToOne #javax.persistence.JoinColumn com.julian.bootmvchibernate.model.User] for value '16'; nested exception is java.lang.NullPointerException]
So I tried to implement a Formatter like so:
public class UserFormatter implements Formatter<User> {
#Autowired
#Qualifier("userService")
public GeneralService<User> userService;
#Override
public String print(User object, Locale locale) {
return (object != null ? object.getUsername() : "");
}
#Override
public User parse(String text, Locale locale) throws ParseException {
final Integer userId = Integer.parseInt(text);
return userService.get(userId);
}
}
Registering it:
#SpringBootApplication
public class BootmvchibernateApplication implements WebMvcConfigurer{
#SuppressWarnings("unchecked")
#Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new UserFormatter());
}
public static void main(String[] args) {
SpringApplication.run(BootmvchibernateApplication.class, args);
}
}
But when this approach is tried the next error is found, this just uppon accessing the /post/new direcction (the template addPost doesn't work):
An error happened during template parsing (template: "class path resource [templates/addPost2.html]")
org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "class path resource [templates/addPost2.html]")
.....
Caused by: org.attoparser.ParseException: Error during execution of processor 'org.thymeleaf.spring5.processor.SpringOptionFieldTagProcessor' (template: "addPost2" - line 43, col 8)
.....
Caused by: org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [#javax.persistence.ManyToOne #javax.persistence.JoinColumn com.julian.bootmvchibernate.model.User] for value '2'; nested exception is java.lang.NullPointerException
at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:47)
If any more information is needed, tell me and I post it.
EDIT: this is the repository if someone is interested.
github.com/JulianBautistaVelez/JPA_Spring_Excercise
The problem is in your addPost.html except that everything is ok now.
<table>
<form th:action="#{/posts/new/mod}" th:object="${post}"
method="POST">
<tr>
<td><input type="hidden" th:field="${post.id}" /></td>
</tr>
<tr>
<td>Titulo</td>
<td>Texto</td>
<td>Usuario</td>
</tr>
<tr>
<td><input type="text" th:field="${post.tittle}"
th:value="${post.tittle}" /></td>
<td><input type="text" th:field="${post.text}"
th:value="${newPost.text}" /></td>
<!-- <td><select th:field="${newPost.user}">
<option th:each="user : ${users}" th:text="${user.username}"
th:value="${user.id}"></option>
</select></td> -->
<td><select th:field="*{user}" class="form-control">
<option th:each="user: ${users}"
th:value="${user.id}" th:text="${user.username}"></option>
</select></td>
</tr>
<tr>
<td colspan="3"><input class="btn btn-primary" type="submit"
value="GUARDAR"></td>
</tr>
</form>
</table>
I changed newPost as post , because you are adding in here as post model.
#RequestMapping(value = "/posts/new")
public String newPost(Model model) {
logger.info("-- en NEW Usuario");
model.addAttribute("post", new Post());
model.addAttribute("users", userService.list());
logger.info("-- -- -- LISTA DE USUARIOS -- -- --");
System.out.println(userService.list());
return "addPost";
}
I am populate a List of String as radio button in the JSP. I add the List to the ModelMap but still the below Exception occurred. What am i missing please?
Attribute 'items' must be an array, a Collection or a Map:
java.lang.IllegalArgumentException: Attribute 'items' must be an
array, a Collection or a Map
#Controller
public class EmployeeController {
#Autowired
private EmployeeManager employeeManager;
#RequestMapping(value = {"/"}, method = RequestMethod.GET)
public String homePage(ModelMap map) {
map.addAttribute("employee", new Employee());
populateDepartments(map);
return "addEmployee";
}
private void populateDepartments(ModelMap map){
List<String> departments = new ArrayList<String>();
departments.add("Dept 1");
departments.add("Dept 2");
map.addAttribute("departments",departments);
}
}
addEmployee.jsp:
<form:form method="post" action="add" commandName="employee">
<table>
<tr>
<td><form:label path="name">Name</td>
<td><form:input path="name" /></td>
<td>Address</td>
<td><form:input path="address" /></td>
<td>Departments</td>
<td><form:radiobuttons path="empDepartment" items="${departments}"/></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="Add"/>
</td>
</tr>
</table>
</form:form>
The entity
#Entity
public class Employee {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
private String address;
#Transient
private String empDepartment;
}
After reading tutorials and docs I still do not understand the mechanism behind binding certain Object properties in SpringMVC + hibernate.
Suppose we have a class Poem:
package com.test.poems.model;
import com.tastyminerals.poems.model.Author;
import com.tastyminerals.poems.model.Genre;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
#Entity
#Table(name = "P_POEM")
public class Poem {
#Id
#GeneratedValue
#Column(name="ID")
private Integer id;
#Column(name="TITLE")
private String title;
#Column(name="BODY")
private String body;
#Column(name="DATE")
private String date;
#ManyToOne
#JoinColumn(name="ID", referencedColumnName="ID_AUTHOR", insertable = false, updatable = false)
private Author author;
#ManyToOne
#JoinColumn(name="ID", referencedColumnName="ID_GENRE", insertable = false, updatable = false)
private Genre genre;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Author getAuthor() {
return author;
}
public Genre getGenre() {
return genre;
}
public void setAuthor(Author author) {
this.author = author;
}
public void setGenre(Genre genre) {
this.genre = genre;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
}
and a class Author:
#Entity
#Table(name = "AUTHORS")
public class Author {
#Id
#GeneratedValue
#Column(name="ID_AUTHOR")
private Integer id;
#Column(name="NAME")
private String name;
/* getters and setters */
I need to submit my poem to mysql database via hibernate. For this purpose I created a simple jsp page which has input fields for all Poem properties.
Upon submission RequestMethod.POST returns String values for title, body and author's name.
However that creates a type conversion error like: Failed to convert property value of type 'java.lang.String' to required type 'com.test.model.Author' for property 'author'.
Poem class expects Author object to be set into it but getting String name instead. I wonder why doesn't Spring make the necessary conversions since I explicitely create Author in my controller method? Shouldn't its values be automatically resolved and set after the page submission?
#RequestMapping(value = "/poem/add", method = RequestMethod.GET)
public ModelAndView addPoemPage() {
ModelAndView modelAndView = new ModelAndView("poem-add");
modelAndView.addObject("author", new Author());
modelAndView.addObject("poem", new Poem());
return modelAndView;
}
#RequestMapping(value = "/poem/add", method = RequestMethod.POST)
public ModelAndView addingPoem(#ModelAttribute Poem poem,
#ModelAttribute Author author) {
ModelAndView modelAndView = new ModelAndView("home");
authorService.addAuthor(author);
poem.setAuthor(author);
poemService.addPoem(poem);
return modelAndView;
}
My jsp page:
<%# page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%# taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<c:set var="url">${pageContext.request.requestURL}</c:set>
<link
href="${pageContext.request.contextPath}/resources/css/poem-add.css"
rel="stylesheet" />
<title>Writing a poem</title>
</head>
<body>
<h1>New poem</h1>
<p>Here you can write your poem.</p>
<form:form method="POST" commandName="poem"
action="${pageContext.request.contextPath}/poem/add.html">
<table>
<tbody>
<tr>
<td>Title:</td>
<td><input id="" title="Your poem's title" id="title"
name="title" type="text" class="input" /></td>
</tr>
<tr>
<td>Author:</td>
<td><input title="Author's name" id="author" name="author"
type="text" class="input" /></td>
</tr>
<tr>
<td>Date:</td>
<td><input title="Date of creation" id="date" name="date"
type="text" class="input" /></td>
</tr>
<tr>
<td>Text:</td>
<td><textarea title="Your poem goes here" rows="15" cols="50"
class="input"> </textarea></td>
</tr>
</tbody>
</table>
<table class="actions">
<tr>
<td><a
href="${pageContext.request.contextPath}/collection.html"><input
type="button" value="Back" class="button" /></a></td>
<td><a
href="${pageContext.request.contextPath}/collection.html"><input
type="submit" value="Submit" class="button" /></a></td>
</tr>
</table>
</form:form>
</body>
</html>
I know that I need a PropertyEditor or BeanWrapper. But I simply do not understand where and how do I implement them? What is the difference?
Summing my questions up, I need an explanation of what is going on "behind-the-scenes" between hibernate and SpringMVC right after I click submit button. If you could provide a sample of PropertyEditor or BeanWrapper for my case I would be endlessly grateful.
I need an explanation of what is going on "behind-the-scenes" between
hibernate and SpringMVC
: There is no hibernate yet. You are simply mapping a plain bean (model) to a JSP using Spring MVC.
I know that I need a PropertyEditor or BeanWrapper.
: You don't need a PropertyEditor at this stage. PropertyEditor is used for advanced type conversion like when you want an incoming date string "dd-mm-yyyy Zone" to be converted into a java.util.Date object and vice versa.
I wonder why doesn't Spring make the necessary
conversions since I explicitely create Author in my controller method?
Shouldn't its values be automatically resolved and set after the page
submission?
:Spring will automatically resolve if the JSP fields are mapped to the model attribute correctly using Spring Form tags. In your case, JSP form fields are not mapped to the model correctly and it should be as below
<form:form method="POST" modelAttribute="poem"
action="${pageContext.request.contextPath}/poem/add.html">
<table>
<tbody>
<tr>
<td>Title:</td>
<td><form:input path="poem.title" title="Your poem's title"
type="text" class="input" /></td>
</tr>
<tr>
<td>Author:</td>
<td><form:input path="poem.author.name" title="Author's name"
type="text" class="input" /></td>
</tr>
<tr>
<td>Text:</td>
<td><form:textarea path="poem.body" title="Your poem goes here" rows="15" cols="50"
class="input" /></td>
</tr>
</tbody>
</table>
<table class="actions">
<tr>
<td><a
href="${pageContext.request.contextPath}/collection.html"><input
type="button" value="Back" class="button" /></a></td>
<td><a
href="${pageContext.request.contextPath}/collection.html"><input
type="submit" value="Submit" class="button" /></a></td>
</tr>
</table>
</form:form>
You can add many attributes to the model but you can attach only one model attribute to the <form> and not two. Your controller would look like this.
#RequestMapping(value = "/poem/add", method = RequestMethod.GET)
public ModelAndView addPoemPage() {
ModelAndView modelAndView = new ModelAndView("poem-add");
Author author = new Author();
Poem poem = new Poem();
poem.setAuthor(author);
modelAndView.addObject("poem", new Poem());
return modelAndView;
}
#RequestMapping(value = "/poem/add", method = RequestMethod.POST)
public ModelAndView addingPoem(#ModelAttribute("poem") Poem poem) {
ModelAndView modelAndView = new ModelAndView("home");
authorService.addAuthor(poem.getAuthor);
poemService.addPoem(poem);
return modelAndView;
}