Spring MVC form setting fields as null - spring

I´m studying Spring MVC with Tiles 3, JPA and all other cool stuff. I created a form to send data, below is the form:
<form:form method="POST" action="/users/save" enctype="multipart/form-data" modelAttribute="formUsuario">
<form:label path="username" for="username">Username</form:label>
<form:input type="text" id="username" path="username" class="span4" value="${user.username}" />
<form:label path="firstName" for="firstName">First name</form:label>
<form:input type="text" id="firstName" path="firstName" class="span4" value="${user.firstName}" />
</form:form>
The method inside the controller to add a new record:
#Secured("ROLE_USER")
#RequestMapping(value = "/new", method = RequestMethod.GET)
public String getNew(#ModelAttribute("formUsuario") br.com.rodrigoferra.domain.User user) {
logger.info("Add new user");
return "users/edit";
}
The method to save the new record:
#Secured("ROLE_USER")
#RequestMapping(value = "/save", method = RequestMethod.POST)
public #ResponseBody String doSave(#ModelAttribute("formUsuario") br.com.rodrigoferra.domain.User user, BindingResult results, Model model) {
if(results.hasErrors()) {
return "users/edit";
}
user = userRepository.save(user);
logger.info("Username: " + user.getUsername());
return "redirect:/users/";
}
It is saving the record, but it is saving everything as Null! The data from the form is being received by the controller. I searched a lot and found the same examples as this, but I can't get mine to work!
Is there any configuration I've missed?
Thanks and sorry for my bad english.
Edited:
Users bean:
#Entity(name="users")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue( strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
#Column(unique=true)
private String username;
private String password;
#Transient
private String passwordConfirmation;
private Date birthdate;
private String signature;
private String email;
private String sex;
private int active;

Use Firebug or similar tool to see if the form field values are correctly included in the request, and the request is sent to correct URI.
Log (or debug) and check the user object content right after receiving the request, in doSave().
Log (or debug) and check the user object content in userRepository.save() to make sure all values are available, prior to persisting it.
Following could be the actual reason, but first checking above would iron out other possiblities
Remove enctype="multipart/form-data" in form definition as this form does not intend to send binary data.
Check following for more info on that:
What does enctype='multipart/form-data' mean?
Form content types in HTML 4 spec
Multipart form data encoding in HTML 5 spec

Related

How do I upload a file to a Spring MVC controller

I am trying to pass the resume back to the Spring MVC controller. I have created a user class that saves resume/files
public class User {
private int id;
private String firstName;
private String lastName;
private String city;
private String state;
private String zip;
private String username;
private String password;
private int enabled;
private byte[] resume;
//getters/setters for them all
and the controller to take in the uploaded form from the site
#Controller
#RequestMapping(value = "/user")
public class UserController {
UserDao uDao;
#Inject
public UserController(UserDao uDao) {
this.uDao = uDao;
}
#RequestMapping(value = "/profile", method = RequestMethod.GET)
public String postPage(Principal principal, Map model) {
String name = principal.getName();
User u = uDao.getByUsername(name);
String fName = u.getFirstName();
String lName = u.getLastName();
String city = u.getCity();
String state = u.getState();
String zip = u.getZip();
String bc = u.getBootcampAttended();
model.put("fName", fName);
model.put("lName", lName);
model.put("city", city);
model.put("state", state);
model.put("zip", zip);
model.put("bc", bc);
return "user";
}
#RequestMapping(value = "/upload", method = RequestMethod.POST)
public String Upload(#RequestParam("file") MultipartFile file, Principal principal) throws IOException {
if (!file.isEmpty()) {
byte[] bytes = file.getBytes(); // alternatively, file.getInputStream();
// application logic
String name = principal.getName();
User u = uDao.getByUsername(name);
u.setResume(bytes);
uDao.update(u);
return "user";
}
return "user";
}
}
I am trying to pass the resume to display as a clickable file on the jsp in the postPage method. Here is the jsp
<h1>${fName}</h1>
<h1>${lName}</h1>
<h1>${state}</h1>
<h1>${city}</h1>
<h1>${zip}</h1>
<h1>${bc}</h1>
<form method="POST" action="${pageContext.request.contextPath}/user/upload" enctype="multipart/form-data">
<table border="0">
<tr>
<td>Pick file #1:</td>
<td><input type="file" name="file" size="50" /></td>
<td><input type="submit" value="Upload"/>
</tr>
</table>
</form>
Any tips on how to get the file on the Spring MVC controller. Preferably to be the value of the file input as default, instead of it saying "No File Chosen". Was thinking that maybe I could convert the file back into the MultiPartFile, like how I uploaded it, but im not sure how to pass that back to the Spring MVC controller.
Thanks!

Spring MVC Form Validation - The request sent by the client was syntactically incorrect

I am trying to add form validations to a working application. I started by adding a NotNull check to Login Form. I am using Hibernate impl of Bean Validation api.
Here's the code I have written
#Controller
#RequestMapping(value="/login")
#Scope("request")
public class LoginController {
#Autowired
private CommonService commonService;
#Autowired
private SiteUser siteUser;
#InitBinder
private void dateBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy");
CustomDateEditor editor = new CustomDateEditor(dateFormat, true);
binder.registerCustomEditor(Date.class, editor);
}
#ModelAttribute
protected ModelMap setupForm(ModelMap modelMap) {
modelMap.addAttribute("siteUser", siteUser);
return modelMap;
}
#RequestMapping(value="/form", method = RequestMethod.GET)
public ModelAndView form(ModelMap map){
if (siteUser.getId() == null){
map.addAttribute("command",new SiteUser());
return new ModelAndView("login-form",map);
}else {
return new ModelAndView("redirect:/my-dashboard/"+siteUser.getId());
}
}
#RequestMapping(value="/submit", method=RequestMethod.POST)
public ModelAndView submit(#Valid SiteUser user, ModelMap map, BindingResult result){
if (result.hasErrors()) {
map.addAttribute("command", user);
System.out.println("Login Error block");
return new ModelAndView("login/form",map);
}
else {
User loggedInUser = commonService.login(user.getEmail(), user.getPassword());
if (loggedInUser != null) {
siteUser.setId(loggedInUser.getId());
siteUser.setName(loggedInUser.getName());
System.out.println("site user attr set");
}
return new ModelAndView("redirect:/my-dashboard/"+loggedInUser.getId());
}
}
}
The Model is
#Component
#Scope("session")
public class SiteUser {
private Integer id = null;
#NotNull
private String name = null;
private String email = null;
private String password = null;
private List<String> displayPrivList = null;
private List<String> functionPrivList = null;
// And the getters and setters
}
The JSP is
<c:url var="loginSubmitUrl" value="/login/submit"/>
<form:form method="POST" action="${loginSubmitUrl}">
<form:errors path="*" />
<div class="row">
<div class="span4">
</div>
<div class="span4">
<h3>Please Login</h3>
<label><span style="color:red">*</span>Email</Label><form:input path="email" type="text" class="input-medium" />
<label><span style="color:red">*</span>Password</Label><form:input path="password" type="password" class="input-medium" />
<br/>
<button type="submit" class="btn btn-primary">Login</button>
<button type="button" class="btn">Cancel</button>
</div>
</div>
</form:form>
I have added messages.properties and the annotation driven bean def in the context xml.
Other answers on the subject talk about form fields not getting posted. In my case, that's the expected behavior - that if I submit a blank form, I should get an error.
Please advise what am I missing?
I think this question had the same issue as yours
Syntactically incorrect request sent upon submitting form with invalid data in Spring MVC (which uses hibernate Validator)
which just points out
You have to modify the order of your arguments. Put the BindingResult result parameter always directly after the parameter with the #Value annotation
You need this: <form:errors path="email" cssClass="errors" />
Use the tag form:errors for each input with the same "path" name.
It is also possible to list all the error at the same time if you don't put a path.
Here, check an full example with sample code that you can download to learn how to do:
http://www.mkyong.com/spring-mvc/spring-3-mvc-and-jsr303-valid-example/
Can you try changing the <form:form> by including the commandName to it like this
<form:form method="POST" action="${loginSubmitUrl}" commandName="user">

How to Set Form Bean before it goes to JSP page

I am an absolute beginner. So please bear with me if I miss the obvious.
Environment I am using: Spring Portlet MVC (3.0), Liferay 6.0.6
I have a controller, a form bean and a JSP page.
I am able to successfully submit a form and get the form bean by using the below code. However I am stuck on how to preload some values into my form bean before the bean is forwarded to JSP. Can somebody point out the right direction:
My Controller:
#ActionMapping(params = "spring_action=resetPasswordViewAction")
protected void resetPasswordAction(ActionRequest actionRequest, Map<String, Object> model, ActionResponse actionResponse, #RequestParam String customerId, #RequestParam String userName) {
model.put("customerId", customerId);//Preload form bean value with this
model.put("userName", userName);//Preload form bean value with this
actionResponse.setRenderParameter("spring_render", "resetPasswordView");
}
#RenderMapping(params = "spring_render=resetPasswordView")
protected ModelAndView resetPasswordView(RenderRequest renderRequest, Map<String, Object> model) {
return new ModelAndView("resetPassword", model);
}
#ActionMapping(params = "spring_action=resetPasswordUpdateAction")
protected void resetPasswordUpdateAction(ActionRequest actionRequest, Map<String, Object> model, ActionResponse actionResponse, final ResetPassword resetPasswordCriteria) {
LOG.info(resetPasswordCriteria.toString());// Form values are retrieved successfully
actionResponse.setRenderParameter("spring_render", "resetPasswordView");
}
#ModelAttribute("resetPasswordCriteria")
public ResetPassword getResetPasswordCriteria() {
return new ResetPassword();
}
My JSP Page:
<form:form id="resetPasswordForm" name="resetPasswordForm" commandName="resetPasswordCriteria" method="post" action="${resetPasswordUpdateActionURL}">
<form:label path="customerId" /><!--Preload this field value-->
<form:label path="userName" /><!--Preload this field value-->
<form:password path="password" />
<form:password path="confirmPassword" />
<input type="submit" value="Submit" />
</form:form>
Form Bean:
public class ResetPassword {
private String customerId = "";
private String userName = "";
private String password = "";
private String confirmPassword = "";
//Getters Setters
}
In your rendering method resetPasswordView, place an object named resetPasswordCriteria (your commandName in jsp) of type ResetPassword to the model.

Form input constraints not being enforced?

I'm new to Tomcat and Spring Web. I'm trying to use Spring's form validation features by following this tutorial. Everything seems to run smoothly except for one thing... my form doesn't do any validation and I can always get to the success page when I send the form no matter which data I provide.
Am I using the constraints correctly? I want to enforce that the user fills in their first name and that the first name be at least two characters long.
package net.devmanuals.form;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.NotEmpty;
public class RegistrationForm {
#NotEmpty(message = "You surely have a name, don't you?")
#Size(min = 2, message = "I'm pretty sure that your name consists of more than one letter.")
private String firstName;
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getFirstName() {
return this.firstName;
}
}
Form code:
<form:form method="post" commandName="regform">
<p><form:input path="firstName" /> <form:errors path="firstName" /></p>
<p><input type="submit" /></p>
</form:form>
The controller:
#Controller
#RequestMapping("/register")
public class RegistrationController {
#RequestMapping(method = RequestMethod.GET)
public String showRegForm(Map model) {
RegistrationForm regForm = new RegistrationForm();
model.put("regform", regForm);
return "regform";
}
#RequestMapping(method = RequestMethod.POST)
public String validateForm(#Valid RegistrationForm regForm, BindingResult result, Map model) {
if (result.hasErrors()) {
return "regform";
}
model.put("regform", regForm);
return "regsuccess";
}
}
Am I applying the constraints incorrectly?
In addition to adding <mvc:annotation-driven/> to your config, you need to make sure the JSR-303 jar is on your classpath. From the docs:
[AnnotationDrivenBeanDefinitionParser] ... configures the validator if specified, otherwise defaults to a fresh Validator instance created by the default LocalValidatorFactoryBean if the JSR-303 API is present on the classpath.

Spring Framework - New object is created in DB instead of updating

I have an application written in Spring 3.0 hooked up using Hibernate to a database. I have a controller to an update form. Whenever the form is submitted, I expect the object that is shown to be updated however a new object is created with a new ID value. I've looked over the "petclinic" sample and i can't see how it is different.
POJO
public class Person
{
private int id;
#NotNull
private String name;
//getter/setter for id
//getter/setter for name
}
Controller
public class PersonUpdateController
{
//injected
private PersonService personService;
#RequestMapping(value="/person/{personId}/form", method=RequestMethod.POST)
public String updateForm(ModelMap modelMap, #PathVariable personId)
{
Person person = personService.getById(personId);
modelMap.addAttribute(person);
return "person/update";
}
#RequestMapping(value="/person/{personId}", method=RequestMethod.POST)
public String update(ModelMap modelMap, #Valid Person person, BindingResult bindingResult)
{
if(bindingResult.hasErrors())
{
modelMap.addAttribute(person);
return "person/update";
}
personService.save(person);
return "redirect:person/" + person.getId() + "/success";
}
}
JSP
<spring:url value="/person/${person.id}" var="action_url" />
<spring:form action="${action_url}" modelAttribute="person" method="POST">
<spring:input name="name" path="name" />
<input type="submit" value="Save" />
</spring:form>
PersonService Implementation
public class HibernatePersonService
implements PersonService
{
//injected
private SessionFactory sessionFactory;
//other methods
public void save(Person person)
{
Session session = sessionFactory.getCurrentSession();
session.saveOrUpdate(person);
}
}
Spring MVC doesn't do any magic with HTML forms. Since your form contains only one field, you get only one field populated in update method. So, you have two options:
Pass id as a hidden field in the form: <spring:hidden path = "id" />. Note that in this case you need to check possible consequences for security (what happens if malicious person changes the id).
Store Person in the session so that data from the form is used to update the stored object (note that it may cause interference if several instances of the form is opened in one session). That's how it's done in Petclinic:
-
#SessionAttributes("person")
public class PersonUpdateController {
...
#RequestMapping(value="/person/{personId}", method=RequestMethod.POST)
public String update(ModelMap modelMap, #Valid Person person,
BindingResult bindingResult, SessionStatus status)
{
...
personService.save(person);
status.setComplete(); // Removes person from the session after successful submit
...
}
#InitBinder
public void setAllowedFields(WebDataBinder dataBinder) {
dataBinder.setDisallowedFields("id"); // For security
}
}

Resources