Spring 3 form validation shows error messages but field name not displayed - forms

I have a 2 item form, that requires that both fields be entered. I'm using annotated validations, and am getting error messages, but they do not print the field name, just "may not be blank" instead of "one may not be blank" where one is the field name.
Any ideas? This is a pretty simple example:
#Controller
#SessionAttributes
public class HomeController
{
private static final Logger logger = LoggerFactory
.getLogger(HomeController.class);
#RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model)
{
logger.info("Welcome home! The client locale is {}.", locale);
model.addAttribute("homeformitem", new HomeFormItem());
return "home";
}
#RequestMapping(value = "/", method = RequestMethod.POST)
public String home(
#ModelAttribute("homeformitem") #Valid HomeFormItem item,
BindingResult result)
{
logger.info("Posting form");
logger.info(item.toString());
if (result.hasErrors())
{
return "home";
} else
{
logger.info("No Errors");
return "done";
}
}
}
Here is the form. I get the error message, but not the field name.
Form Validation!
<f:form method="post" modelAttribute="homeformitem">
<fieldset>
<legend>Fields</legend>
<table>
<tr><td colspan="3"><f:errors path="*"/></td></tr>
<tr>
<td><f:label path="one" for="one">One: </f:label></td>
<td><f:input path="one" /></td>
<td><f:errors path="one" cssClass="errorblock"/></td>
</tr>
<tr>
<td><f:label path="two" for="two">Two: </f:label></td>
<td><f:input path="two" /></td>
<td><f:errors path="two" cssClass="errorblock"/></td>
</tr>
<tr>
<td colspan="3"><input type="submit" value="Test" /></td>
</tr>
</table>
</fieldset>
</f:form>

You need a validation.properties file at /WEB-INF/messages with an entry similar to this (for example):
NotEmpty.homeFormItem.one=The field {0} is empty
And don't forget to add a spring bean to resolve your validation messages:
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="/WEB-INF/messages/validation" />
</bean>

Related

Get list from DB using stuts2

I have a list in Stuts2 and I would like to see it in the jpa I put the name of the list but I dosen't work and I dont recive any error
<s:iterator value="UserService.users">
<tr>
<td><s:property value="nom" /></td>
<td><s:property value="prenom" /></td>
<td><s:property value="username" /></td>
<td><s:property value="password" /></td>
<td><s:property value="tel" /></td>
</tr>
</s:iterator>
public static void list() {
SessionFactory sessionFactory = new Configuration().
configure("hibernate.cfg.xml").
addAnnotatedClass(User.class).
buildSessionFactory();
Session session = sessionFactory.openSession();
try{
session.beginTransaction();
List<User> users = session.createQuery("from User").getResultList();
for(User u : users){
System.out.println(u);
}
session.getTransaction().commit();
}finally{
sessionFactory.close();
}
}
A Struts 2 tutorial will save you some time; this is very basic and shows little effort.
Make users a property on the action and expose it with a getter.
<s:iterator value="users">
<s:property value="nom" />
...

Spring MVC: Displaying of validation messages after redirect

I have some very strange problem with displaying of error messages after redirect. I use RedirectAttributes to pass BindingResult object with error messages to a view, but this solution doesn't work.
When I return just a view name withou redirect, everything works fine.
Can someone give an advice, but without session usage?
#Controller
public class UserRegistrationController {
#Autowired
private UserService userService;
#RequestMapping(value="/registration", method=RequestMethod.GET)
public ModelAndView registrationPage() {
ModelAndView modelAndView = new ModelAndView("user-registration/registration-form");
modelAndView.addObject("user", new User());
return modelAndView;
}
#RequestMapping(value="/registration", method=RequestMethod.POST)
public ModelAndView registerUser(#ModelAttribute #Valid User user,
BindingResult result,
final RedirectAttributes redirectAttributes) {
ModelAndView modelAndView = new ModelAndView("redirect:registration.html");
User tempUser = userService.get(user.getEmail());
Map<String, String> messages = new HashMap<String, String>();
if (tempUser == null && ! result.hasErrors()) {
userService.save(user);
messages.put("success", "message.user.success.register");
} else {
messages.put("error", "message.user.invalid.register");
redirectAttributes.addFlashAttribute("user", user);
redirectAttributes.addFlashAttribute("errors", result);
}
redirectAttributes.addFlashAttribute("messages", messages);
return modelAndView;
}
}
And the view code:
<p>
<c:forEach var="message" items="${messages}">
<span class="${message.key}"><spring:message code="${message.value}" /></span><br />
</c:forEach>
</p>
<form:form method="POST" commandName="user" action="${pageContext.request.contextPath}/registration.html">
<table>
<tbody>
<tr>
<td><spring:message code="user.registration.email" /></td>
<td><form:input path="email" /></td>
<td><form:errors cssClass="error" path="email" /></td>
</tr>
<tr>
<td><spring:message code="user.registration.password" /></td>
<td><form:password path="password" /></td>
<td><form:errors cssClass="error" path="password" /></td>
</tr>
<tr>
<td><input type="submit" /></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</form:form>
Might want to look at this:
https://jira.springsource.org/browse/SPR-8968
And try returning a String rather than a ModelAndView
There should really be no reason to redirect while there are errors remain on the same page and only on success redirect. The reason for redirecting has to do with ensuring the browser does not attempt to repeat the same form submission when the back button is used, but while input is invalid the simplest thing to do is remain on the same page.

Spring portlet form: #ModelAttribute not populated

I am a beginner at Spring and I was wondering why my ModelAttribute did not populate (All the values were null)
I want to create a multipart from that allows me to upload a csv file as well as the type of CSV file too.
My codes are as such:
In the CSVUpload-portlet.xml:
<bean class="org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<bean class="org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="100000000"></property>
</bean>
<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/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
CSVUploadPortlet.java (Controller)
*All imports
#Controller("uploadCsvToDatabase")
#RequestMapping(value = "VIEW")
public class CSVUploadPortlet {
private static final Logger log = Logger.getLogger(CSVUploadPortlet.class);
private static IWBCSVUploadRemote csvupload;
#RenderMapping
public String viewCSVUploadBase(Model model, RenderRequest request) {
try {
} catch (Exception e) {
e.printStackTrace();
log.info("problem in retrieving the CSV Upload service" + e);
}
return "csvupload/csvupload_view";
}
#ModelAttribute("csvFileUploadVO")
public CSVFileUploadVO getCommandObject()
{
System.out.println("SpringFileController -> getCommandObject -> Building VO");
return new CSVFileUploadVO();
}
#ActionMapping(params="action=uploadCsvToDatabase")
public void uploadCsvToDatabase(
#ModelAttribute("csvFileUploadVO") CSVFileUploadVO csvFileUploadVO, BindingResult result, ActionRequest request, ActionResponse response, SessionStatus sessionStatus){
try{
System.out.println("FileType:"+csvFileUploadVO.getFileType()); //This returns null
System.out.println("CSVFile Size:"+csvFileUploadVO.getCsvFile().getSize()); //This returns a null-pointer exception
} catch (Exception e) {
log.info("Problem in retrieving the CSVUpload configuration list " + e);
e.printStackTrace();
}
}
}
CSVFileUploadVO.java
import org.springframework.web.multipart.commons.CommonsMultipartFile;
public class CSVFileUploadVO {
private String fileType;
private CommonsMultipartFile csvFile;
private String message;
public CSVFileUploadVO() {
}
public String getFileType() {
return fileType;
}
public void setFileType(String fileType) {
this.fileType = fileType;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public CommonsMultipartFile getCsvFile() {
return csvFile;
}
public void setCsvFile(CommonsMultipartFile csvFile) {
this.csvFile = csvFile;
}
}
Form JSP
All taglibs imported...
<portlet:actionURL var="fileUploadURL">
<portlet:param name="action" value="uploadCsvToDatabase" />
</portlet:actionURL>
<form:form method="post" action="${fileUploadURL}"
commandName="csvFileUploadVO" enctype="multipart/form-data">
<table>
<tbody>
<tr>
<td><label>Department:</label></td>
<td><form:select path="fileType">
<form:option value="BRMAdd" label="BRM Add" />
<form:option value="FOSAdmin" label="FOS Admin" />
<form:option value="FOSRM" label="FOS RM" />
<form:option value="FOSTeam" label="FOS Team" />
<form:option value="ITRelationships" label="IT Relationships" />
<form:option value="HRAttendance" label="HR Attendance" />
<form:option value="iCareCallReport" label="iCare Call Report" />
</form:select></td>
</tr>
<tr>
<td><label>Specify your File:</label></td>
<td><form:input path="csvFile" type="file" /></td>
</tr>
<tr>
<tr>
<td colspan="100%"><input type="submit" value="Submit" /></td>
</tr>
<tr>
<td colspan="100%">${csvFileUploadVO.message}</td>
</tr>
</tbody>
</table>
</form:form>
I know it seems like asking you to help solve a problem for me but I've been stuck on this for 8 hours, reading every resource and stackoverflow website i could google on. But despite that, I wasn't able to find anything.
Thank you for your help in this.
You will want to look at http://static.springsource.org/spring/docs/3.0.x/reference/mvc.html#mvc-multipart-resolver particularly the RequestMapping where the parameter is MultipartFile
#RequestMapping(value = "/form", method = RequestMethod.POST)
public String handleFormUpload(#RequestParam("name") String name,
#RequestParam("file") MultipartFile file) {
You have to define the ModelAttribute in your JSP form, something like this:
<form:form method="post" action="${fileUploadURL}"
modelAttribute="csvFileUploadVO" enctype="multipart/form-data">
Liferay 6.0.5 and Spring 3.2.2.RELEASE:
I tried with editing spring classes, but there is much easier solution to this problem. Just check whether your CommonsPortletMultipartResolver really has been initilized. The fact that it is declared in spring.xml does not mean that it is loaded.
If it is not initialized, than the file part of the request would never be converted to CommonsMultipartFile because your request would not be a commons Multipart request.
CommonsPortletMultipartResolver will be invoked by org.springframework.web.portlet.DispatcherPortlet lifecycle if it is loaded and spring uses this class.
Your multipart resolver must have the id portletMultipartResolver and be of type org.springframework.web.portlet.multipart.CommonsPortletMultipartResolver
<bean id="portletMultipartResolver" class="org.springframework.web.portlet.multipart.CommonsPortletMultipartResolver">
</bean>

Spring Form Neither BindingResult nor plain target object for bean name order available

I have create a Spring form like this:
index.jsp
Order
Order.jsp
<form:form action="createOrder" method="Post" modelAttribute="order">
<table>
<tr>
<th>
Order ID:
</th>
<td>
<form:input path="order.orderId"/>
</td>
</tr>
<tr>
<th>
Product Name:
</th>
<td>
<form:input path="order.productName"/>
</td>
</tr>
<tr>
<td>
<input type="submit" value="Submit"/>
</td>
</tr>
</table>
</form:form>
Order.java:
public class Order {
private String orderId;
private String productName;
/**
*
*/
public Order() {
}
public Order(String orderId, String productName) {
super();
this.orderId = orderId;
this.productName = productName;
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
}
OrderController.java:
#Controller
public class OrderController {
private static final Logger logger = Logger.getLogger(LoginController.class.getName());
/**
*
*/
public OrderController() {
super();
}
#RequestMapping(value = "/createOrder", method=RequestMethod.POST)
public String createOrder(#ModelAttribute("order")Order order, BindingResult result) {
logger.log(Level.INFO, "Order ID: " + order.getOrderId());
logger.log(Level.INFO, "Product Name: " + order.getProductName());
// Implementation validator
// Data Binding the form properties to Order field
if (result.hasErrors()) {
logger.log(Level.INFO, "Error in Binding Result");
}
return "/order";
}
}
I get the Neither BindingResult nor plain target object for bean name order available. Is it i need to create a bean name order using GET and pass to the web first before POST back to server.
Please help.
Thanks.
The problem is in your JSP page.
You have used the field names wrongly in the path attribute of the input tag.
it should be like this.
<form:input path="orderId"/>
Hope this helps you.
Cheers.
Based on reference, your path attribute inside the input tag should not include the model attribute name order; e.g.:
<form:input path="orderId" />

DefaultModelBinder Implementation does not populate the model - ASP.NET MVC 2

I have a very simple implementation of the DefaultModelBinder, I need it to fire some custom validation.
public class MyViewModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
ModelStateDictionary modelState = bindingContext.ModelState;
var model = (MyViewModel)base.BindModel(controllerContext, bindingContext);
var result = ValidationFactory.ForObject<MyViewModel>().Validate(model);
CustomValidation(result, modelState);
return model;
}
}
MyViewModel is a public sealed class.
The model binder is registered in the Global.asax this way:
ModelBinders.Binders.Add(typeof(MyViewModel), new MyViewModelBinder());
The problem is that the model is never populated! But the MVC default model binder (I remove the registration in global.asax) works fine.
This is the view HTML:
<table>
<tr>
<td><label for="Name">Name</label></td>
<td><input id="Name" name="Name" type="text" value="" /></td>
</tr>
<tr>
<td><label for="Code">Code</label></td>
<td><input id="Code" name="Code" type="text" value="" /></td>
</tr>
</table> </div>
Every field matches a property of the model.
From the information you provided I am unable to reproduce the problem. Here's what I did.
View model:
public sealed class MyViewModel
{
public string Name { get; set; }
public string Code { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
// at this stage the model is populated perfectly fine
return View();
}
}
Index View:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<% using (Html.BeginForm()) { %>
<table>
<tr>
<td><label for="Name">Name</label></td>
<td><input id="Name" name="Name" type="text" value="" /></td>
</tr>
<tr>
<td><label for="Code">Code</label></td>
<td><input id="Code" name="Code" type="text" value="" /></td>
</tr>
</table>
<input type="submit" value="OK" />
<% } %>
</body>
</html>
Model binder:
public class MyViewModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var model = (MyViewModel)base.BindModel(controllerContext, bindingContext);
// at this stage the model is populated perfectly fine
return model;
}
}
So now the question is, how does your code differs than mine and what is it in those CustomValidation and Validate methods?