I read through the similar question and unfortunately didn't find a solution.
I am sending a Student entity as @ModelAttribute to my JSP, allowing user to edit it. When the Student is POST'ed back to the controller (StudentController) the fields rates and id are null. Null value for rates is OK, I pass student's rates as a separate @RequestParam. Other fields are OK. But id is unexpectedly null.
I am using Java 8, Spring 4.1, Tomcat 7.0.55, JSTL 1.2.
Here is a relevant part of my StudentController:
@Controller
@RequestMapping(value = "/student")
public class StudentController {
@Autowired
private StudentService studentService;
@Autowired
private FacultyService facultyService;
@RequestMapping(value = "/edit/{id:.+}", method = RequestMethod.GET)
public ModelAndView editStudentPage(@PathVariable Long id) {
ModelAndView mav = new ModelAndView("student-edit");
Student student = (id > 0)? studentService.findById(id) : new Student();
mav.addObject("student", student);
// or
//mav.getModelMap().addAttribute(student);
/* other objects omitted */
return mav;
}
@RequestMapping(value = "/edit/{id:.+}", method = RequestMethod.POST)
public ModelAndView editStudent(
@ModelAttribute Student student,
@RequestParam(value="rates", required = false) String ratesString,
@PathVariable Long id,
final RedirectAttributes redirectAttributes) throws StudentNotFoundException {
ModelAndView mav = new ModelAndView("redirect:/student/list");
student = studentService.update(student);
student.updateRates(ratesString);
String msg = "Student was successfully updated";
redirectAttributes.addFlashAttribute("message", msg);
return mav;
}
/* ... */
}
Here is a student-edit JSP file:
<jsp:useBean id="student" scope="request" class="by.naxa.demo.model.Student" />
<!-- I've tried to comment out the above line in order to avoid collision with `modelAttribute` (in hope that this was a culprit) -->
<%@page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<c:url var="formAction" value="/student/edit/${student.id}" /> <!-- simplified -->
<!-- <head> omitted -->
<body>
<form:form action="${formAction}" method="POST" modelAttribute="student" >
<form:hidden path="id" /> <!-- I've tried to specify `value="${student.id}"` here -->
<div>
<form:label path="name">Student's name:</form:label>
<form:input path="name" required="true"/><br />
<!-- other fields omitted -->
<input type="submit" value="Save" />
<!-- `Cancel` omitted -->
</div>
</form:form>
</body>
I see that inputs on a generated page are populated with right values:
<input id="id" name="id" value="1" type="hidden" />
<input id="name" name="name" required="true" type="text" value="John Snow"/>
web.xml:
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/app/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>/WEB-INF/views/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file />
</welcome-file-list>
ViewResolver in Spring servlet-context.xml:
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
Class Student extends AbstractNamedPersistable. Here they are (annotated with Lombok and JPA):
@Entity
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true, includeFieldNames = false)
@NamedQuery(name = "Student.findByTheStudentsName", query = "select s from Student s where s.name = ?1")
public @Data class Student extends AbstractNamedPersistable<Long> {
/* all fields and `updateRates(String)` omitted */
}
@MappedSuperclass
@EqualsAndHashCode(callSuper = false)
@NoArgsConstructor
@AllArgsConstructor
public abstract @Data class AbstractNamedPersistable<PK extends Serializable> extends AbstractPersistable<PK> {
@Column(name = "Name", nullable = false, unique = true)
private String name;
@Override
public String toString() {
return getName();
}
}
What could be the problem?