I'm testing for the first time Thymeleaf 3.x with a simples web app, and I'm having some issues doing form validation. I'm not able to change the graphical style of my form fields with the Thymeleaf attribute th:errorclass, and I don't know why.
Here is my controller:
#RequestMapping(value = {"/" , "" , "/home" , "/index" , "/login"} , method = RequestMethod.GET)
public String getLogin(final Model m)
{
if(m.containsAttribute("login") == false)
{
System.out.println("Creating login form...");
m.addAttribute("login", new For_Login());
}
return Util_Paginas.PAG_LOGIN.toString();
}
#RequestMapping(value = "/login" , method = RequestMethod.POST)
public String authenticate(
#Valid #ModelAttribute("login") final For_Login form ,
final BindingResult br ,
final Model m)
{
System.out.printf("Authentication received!%n");
System.out.printf("LOGIN: %s%n" , form.getLogin());
System.out.printf("PASS: %s%n" , form.getSenha());
if(br.hasErrors())
{
System.out.printf("Found %d fields!%n" , br.getErrorCount());
}
return Util_Paginas.PAG_LOGIN.toString();
}
My HTML file with Thymeleaf 3.x nature:
<!DOCTYPE html>
<html>
<head>
<title>Login page</title>
<link rel="stylesheet" type="text/css" media="all" th:href="#{/css/estilos.css}" />
</head>
<body>
<p>Welcome. Please login.</p>
<form action="#" th:action="#{/login}" th:object="${login}" method="post">
<fieldset>
<p>
Login:
<input
type="text"
th:field="*{login}"
th:class="campo"
th:errorclass="campo-invalido">
</p>
<p>
Password:
<input
type="password"
th:field="*{senha}"
th:class="campo"
th:errorclass="campo-invalido">
</p>
<p>
<input type="submit" value="Submit"/>
</p>
</fieldset>
</form>
</body>
</html>
My CSS file:
#CHARSET "ISO-8859-1";
.campo
{
background-color: gray;
border: 2px solid red;
}
.campo-invalido
{
background-color : #ff0000;
border: 1px solid #800000;
width: 230px;
color: white;
}
p
{
color: blue;
font-size: 22pt;
}
What is happening is that the style is not being applied. Errors are found on the server side, but when the page is returned, it is as if the th: errorclass attribute was not present. I do not know what I'm doing wrong.
I know that my css file is being read because the P tags are getting stylized.
I'm using:
Eclipse Mars.2 Release (4.5.2)
thymeleaf 3.0.3 RELEASE
thymeleaf-spring4 3.0.3 RELEASE
spring-webmvc 4.1.1 RELEASE
spring-context 4.1.1 RELEASE
validation-api 1.1.0 FINAL
hibernate-validator 5.3.4 FINAL
If in case someone wants to see some more code of my project, I'll be happy to present it here.
Thank you for your time and patience.
EDIT
I almost forgot something important too, my Spring MVC Application Context file:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd ">
<!-- ################################################################################### -->
<!-- MAPEAMENTO DE RECURSOS -->
<!-- ################################################################################### -->
<!-- Mapeamento de recursos (arquivos css, fontes, imagens, dentre outros). -->
<mvc:resources mapping="/css/**" location="/WEB-INF/recursos/css/" />
<mvc:resources mapping="/imagens/**" location="/WEB-INF/recursos/imagens/" />
<mvc:resources mapping="/fontes/**" location="/WEB-INF/recursos/fontes/" />
<!-- ################################################################################### -->
<!-- ANOTAÇÕES E RECURSOS SPRING -->
<!-- ################################################################################### -->
<!-- Possibilita o uso de anotações Spring Mvc. -->
<mvc:annotation-driven />
<!-- Define local para procura de componentes Spring (beans configurados
por anotações em classes). -->
<context:component-scan base-package="com.regra7.st.controle" />
<!-- ################################################################################### -->
<!-- INTERNACIONALIZAÇÃO -->
<!-- ################################################################################### -->
<!-- ################################################################################### -->
<!-- CONFIGURAÇÕES DO THYMELEAF -->
<!-- ################################################################################### -->
<!-- Template Resolver para Template Engine. -->
<!-- <bean id="templateResolver" class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
<property name="prefix" value="/WEB-INF/templates/" /> <property name="suffix"
value=".html" /> <property name="templateMode" value="HTML5" /> </bean> -->
<!-- SpringResourceTemplateResolver automatically integrates with Spring's
own -->
<!-- resource resolution infrastructure, which is highly recommended. -->
<bean id="templateResolver"
class="org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver">
<property name="prefix" value="/WEB-INF/templates/" />
<property name="suffix" value=".html" />
<!-- HTML is the default value, added here for the sake of clarity. -->
<property name="templateMode" value="HTML" />
<!-- Template cache is true by default. Set to false if you want -->
<!-- templates to be automatically updated when modified. -->
<property name="cacheable" value="true" />
</bean>
<!-- SpringTemplateEngine automatically applies SpringStandardDialect and -->
<!-- enables Spring's own MessageSource message resolution mechanisms. -->
<bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine">
<property name="templateResolver" ref="templateResolver" />
<!-- Enabling the SpringEL compiler with Spring 4.2.4 or newer can speed
up -->
<!-- execution in most scenarios, but might be incompatible with specific -->
<!-- cases when expressions in one template are reused across different
data -->
<!-- ypes, so this flag is "false" by default for safer backwards -->
<!-- compatibility. -->
<property name="enableSpringELCompiler" value="true" />
</bean>
<!-- ################################################################################### -->
<!-- CONFIGURAÇÕES DO SPRING MVC -->
<!-- ################################################################################### -->
<!-- View resolver do Thymeleaf. -->
<bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
<property name="templateEngine" ref="templateEngine" />
</bean>
<!-- Definição de HandlerMapping. -->
<!-- Cuida de classes controladoras. -->
<!-- <bean id="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
</bean> -->
<!-- ################################################################################### -->
<!-- INTERCEPTADORES -->
<!-- ################################################################################### -->
<!-- INTERCEPTADORES -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/usuario/*" />
<bean class="com.regra7.st.interceptadores.Login" />
</mvc:interceptor>
</mvc:interceptors>
</beans>
EDIT 2
After messing around a bit with the validation code, I changed the approach used and suddenly, things started to work.
Previously, I was using bean validation with my own annotations for data validation. I decided to change to the validation done with Spring, using org.springframework.validation.Validator, And magically everything went well.
However, I would not like to use the data validation approach with Spring, but rather with bean validation annotations. I've figured out where I'm wrong, but I do not understand why.
I'll put my login validation code:
// My bean validation annotation.
#Documented
#Constraint(validatedBy = Val_Login.class)
#Target({ElementType.METHOD , ElementType.FIELD , ElementType.ANNOTATION_TYPE})
#Retention(RetentionPolicy.RUNTIME)
public #interface Login
{
String message() default "{com.regra7.st.login}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
int min() default 10;
int max() default 20;
}
// Validator implementation.
public class Val_Login implements ConstraintValidator<Login , String>
{
private int min;
// private int max;
#Override
public void initialize(Login login)
{
this.min = login.min();
// this.max = login.max();
}
#Override
public boolean isValid(String value, ConstraintValidatorContext context)
{
return Util_Validador.isLoginValido(value , this.min);
}
}
// The form input object.
public class For_Login
{
#Login(min = 8)
private String login;
// Many things ommited
}
The Util_Validador class is able to return a true or false value, this has already been tested. If I do this:
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import com.regra7.st.formularios.For_Login;
import com.regra7.st.util.Util_Texto;
public class ValidadorFormulario implements Validator
{
#Override
public boolean supports(Class<?> clazz)
{
return For_Login.class.isAssignableFrom(clazz);
}
#Override
public void validate(Object objeto, Errors erros)
{
For_Login log = (For_Login) objeto;
if(Util_Texto.isVazia(log.getLogin()) ||
log.getLogin().length() < 8)
{
erros.rejectValue("login", "Login errado!");
}
if(Util_Texto.isVazia(log.getSenha()) ||
log.getSenha().length() < 14)
{
erros.rejectValue("senha", "Senha errada!");
}
}
}
Everything works out. Can you guys help me a bit, please? I think this can help many people who get on the same place as me.
As always, thank you.
I did two things wrong:
I forgot to import some libraries needed by Hibernate Validator.
I was using prefixes for form fields (For_Login). The data binding
was not happening properly. Actually, it was, but Thymeleaf was not
recognizing it properly. It's no use having a field named _myField
(for instance), and setting setMyField and getMyField methods. Either
you write the field with the name myField, or the methods with the
names get_myField and set_myField.
Related
I have a problem with Hibernate Validator. I putted in my code #Size annotation but when I am running app on Tomcat server I can submit without filled text field. What is wrong with this code?
Customer class:
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
public class Customer {
private String firstName;
#NotNull(message="is required")
#Size(min=1, message="is required")
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
CustomerController class:
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.validation.Valid;
#Controller
#RequestMapping("/customer")
public class CustomerController {
#RequestMapping("/showForm")
public String showForm(Model theModel) {
theModel.addAttribute("customer", new Customer());
return "customer-form";
}
#RequestMapping("/processForm")
public String processForm(
#Valid #ModelAttribute("customer") Customer theCustomer, BindingResult theBindingResult) {
if (theBindingResult.hasErrors()) {
return "customer-form";
} else {
return "customer-confirmation";
}
}
}
dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<!-- Add support for scanning countries from file -->
<util:properties id="countryOptions" location="WEB-INF/countries.properties" />
<!-- Step 3: Add support for component scanning -->
<context:component-scan base-package="com.rafal.springdemo" />
<!-- Step 4: Add support for conversion, formatting and validation support -->
<mvc:annotation-driven/>
<!-- Step 5: Define Spring MVC view resolver -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
customer-form.jsp
<%# page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Customer Registration Form</title>
<style>
.error {color:red}
</style>
</head>
<body>
<form:form action="processForm" modelAttribute="customer" >
First name: <form:input path="firstName" />
<br><br>
Last name (*): <form:input path="lastName" />
<form:errors path="lastName" cssClass="error" />
<br><br>
<input type="submit" value="Submit" />
</form:form>
</body>
</html>
And screenshots from lib folder and project structure.
You might need to add the following bean definition in your xml.
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
OR
for custom error messages you need to create a message.properties in the resource folder and use ResourceBundleMessageSource
<!-- bind your messages.properties -->
<bean class="org.springframework.context.support.ResourceBundleMessageSource"
id="messageSource">
<property name="basename" value="messages" />
</bean>
Did you try to place
<!-- Hibernate Validator -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.4.1.Final</version>
</dependency>
in your pom.xml?
I used the jar hibernate-validator-5.1.3.Final and it worked for me.
I was facing the same problem when I was using 6.
Restarting IntelliJ fixed this for me. Really. 25 minutes of my life I'll never get back.
I had the same problem.
My solution was using older version of Hybernate validator. The thing is they changed package name into jakarta. instead of javax. from version 6.2 and it was causing problems for me, because spring class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" was still implementing javax.validation.ValidatorFactory
I had the same problem using Hibernate Validator 7. I used Hibernate 6 and the problem was solved!
I was having the same problem, To solve this
use #NotEmpty instead of #NotNull,
this should fix the issue.
I am working on Spring MVC project. I am getting an error while binding the checkbox value to the back end file. Can any one please suggest whats the mistake or missing step please?
I have searched for similar threads but the answers did'nt solve my issue. Appreciate any help here.
Code:
JSP:
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%#taglib uri = "http://www.springframework.org/tags/form" prefix = "form"%>
<%# page session="false" %>
<html>
<head>
<title>Home</title>
</head>
<body>
<form:form modelAttribute="listOfShapes" action="/calculateArea">
<form:checkboxes items="${listOfShapes}" path="selectedShapes" />
</form:form>
</body>
</html>
MOdelAttribute:
#ModelAttribute("listOfShapes")
public List<String> getListOfShapes() {
List<String> shapesOfList = new ArrayList<String>();
shapesOfList.add("Circle");
shapesOfList.add("Rectangle");
shapesOfList.add("Square");
return shapesOfList;
}
POJO:
package model.pojo.org;
import java.util.List;
public class ListOfShapes {
private List<String> selectedShapes;
/**
* #return the selectedShapes
*/
public List<String> getSelectedShapes() {
return selectedShapes;
}
/**
* #param selectedShapes the selectedShapes to set
*/
public void setSelectedShapes(List<String> selectedShapes) {
this.selectedShapes = selectedShapes;
}
}
XML:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC #Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by #Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<context:component-scan base-package="calculate.area.org" />
</beans:beans>
I am getting the below Error. Can anyone please suggest?
org.springframework.beans.NotReadablePropertyException: Invalid property 'selectedShapes' of bean class [java.util.ArrayList]: Bean property 'selectedShapes' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
The Form Model should not be listOfShapes. The Form Model is what actually receives the input. So I believe this is wrong:
<form:form modelAttribute="listOfShapes" action="/calculateArea">
It's OK to use it as a Checkbox Display Constants getter in your <form:checkboxes items="${listOfShapes}" path="selectedShapes" /> but it's not OK to use it as an actual Form Model that gathers input. That would be your POJO instance, not a list of constants.
For example, see here:
http://www.baeldung.com/spring-mvc-form-tutorial
I assume you have a Controller that exposes the ModelAndView with the form model object, right? Something like
public String processForm(#ModelAttribute("employee")Employee employee,
BindingResult result, ModelMap model) {
}
in that case the Form Model would be
<form:form method="POST" action="/spring-mvc-xml/addEmployee" modelAttribute="employee">
as in that website example.
I have been trying to get this code to work. I've just started with Spring MVC (and I'm relatively new to web dev - my background is GUI dev/science) but I think the error may be triggered because there is a problem linking the jquery code in my jsp to the Spring controller. I've literally been trying to get this to work for days without success and I've tried all the suggestions made by posters on this forum with a similar problem - to no avail. I'd therefore very much appreciate your input. The project is being developed using Netbeans, Tomcat 8, Maven, Spring MVC, and Jquery.
projectDashboard.jsp (in WEB-INF/views):
<div class="col-lg-8 col-md-8 col-sm-8">
<div id="projectForm">
<div class="form-group">
<input id="name" name="name" type="text" class="form-control" placeholder="Project name (50 characters or less)"/>
<textarea id="description" name="description" class="form-control" placeholder="Project Description (200 characters or less)"></textarea>
</div>
<div class="form-group">
<input class="btn btn-primary pull-right" id="createProjectButton" value="Create" type="button"/>
</div>
</div>
</div>
JQuery:
<script>
$(document).ready(function(){
$("#createProjectButton").on("click", function(){
var projectJson = {
"name":$("#name").val(),
"description":$("#description").val()
};
$.ajax({
type: "POST",
url: "/ProgressManagerOnline/projectDashboard",
data: JSON.stringify(projectJson),
contentType: "application/json; charset=utf-8",
dataType: "json"
});
});
});
</script>
ProjectDashboard.java (Spring MVC controller class in src/main/java):
#RequestMapping(value = "/projectDashboard", method = RequestMethod.POST)
public String saveProject(#RequestBody Project project) throws Exception {
return "OK";
}
Relevant code in appconfig-mvc.xml:
<mvc:annotation-driven/>
<mvc:view-controller path="/" view-name="login"/> //home web page - login.jsp
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
Maven pom.xml includes:
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.8.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.5</version>
</dependency>
Tomcat context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/ProgressManagerOnline"/>
Error in Firefox web console:
The requested resource is not available. (404 error)
My Project.java:
#Entity
#Table(name = "projects")
public class Project implements Serializable {
private Long id;
private String name;
private String description;
private java.util.Date dateCreated;
public Project(){};
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id){
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#Column(name = "dateCreated", columnDefinition="DATETIME")
#Temporal(TemporalType.TIMESTAMP)
public Date getDateCreated() {
return dateCreated;
}
public void setDateCreated(Date dateCreated) {
this.dateCreated = dateCreated;
}
}
I've been at this for days now and have tried every suggestion posted on this forum and others.
Many thanks in advance to anyone who can help out.
You are missing couple of configurations I guess in your application.
You require auto conversion of json to java object ,
#RequestBody Project project
Hence you need to add json converter so please look documentation : http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/converter/json/MappingJackson2HttpMessageConverter.html
Add following in your configuration context xml along with required dependencies added in your pom.xml,
<!-- Configure bean to convert JSON to POJO and vice versa -->
<beans:bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
<!-- Configure to plugin JSON as request and response in method handler -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonMessageConverter"/>
</list>
</property>
</bean>
(Posted on behalf of the OP).
The solution suggested by TechBreak worked - I was missing the Spring context dependency in my pom.xml and the extra config in my xml:
<!-- Configure bean to convert JSON to POJO and vice versa -->
<bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
<!-- Configure to plugin JSON as request and response in method handler -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonMessageConverter"/>
</list>
</property>
</bean>
After a restart of the server and
mvn clean install
Cheers.
<form:form action="register/student.htm" method="post" modelAttribute="registerForm">
.....
</form:form>
When I initially submit this form the url is
"loclhost:8080/SpringSchool/register/student.htm"
If the submit fails and I submt it again, the new url gets appended and becomes:
"loclhost:8080/SpringSchool/register/register/student.htm"
As a result I get 404 error. How can I reset the url so that the url is not appended or just basically make this work?
#Controller
#RequestMapping("/register")
public class RegisterController {
#RequestMapping(method=RequestMethod.GET)
public ModelAndView registerPage(){
return new ModelAndView("registerStudent", "registerForm", new Student());
}
#RequestMapping(value="/student", method = RequestMethod.POST)
public ModelAndView registerStudent(#ModelAttribute("registerForm") final Student student, RedirectAttributes redirectAttr){
....
return new ModelAndView("registerStudent", "registerForm", student);
}
view resolver
<bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
If you start URL from '/' then it indicate the root of the context but if you start URL from word -- it means 'from the current path'. Your problem should be resolved if you add '/' to the URL:
<form:form action="/${pageContext.request.contextPath}/register/student.htm" method="post" modelAttribute="registerForm">
.....
</form:form>
This is because your form action is using a relative path. To fix your problem, you should organize your jsp in a folder and your controller should return views with the corresponding paths.
Move your jsp to:
/WEB-INF/jsp/register/registerStudent.jsp
Your controller should return the view name:
register/registerStudent
In your form, change action to:
<form:form action="student.htm" method="post" modelAttribute="registerForm">
.....
</form:form>
I'm having a problem formatting the contents of a bound Date field in a spring webflow form. The validation end of things is working, and correctly enforces the date format specified in my annotation. But whatever I try, I can't control the format of the initial display of the bound Date field (which is pre-populated with the current date). I'm using Spring 3.1.2.RELEASE, Webflow 2.3.2.RELEASE, and joda-time 2.2.
The date field in the form is initially populated with eg "Thu Apr 04 02:01:06 BST 2013", whereas I want it to contain "04:04:2013". (Don't mind the funny format with the colons - I'm only avoiding common formats for testing!)
If I overtype it with, eg 13:01:2013 and submit, the binding works fine and the webflow continues. Overtyping eg 13/01/2013 causes validation to fail with a ValueCoercionException, and the field on the webpage is re-populated with the "Thu Apr..." string. So validation, at least, seems to be OK.
I understood that the #DateTimeFormat annotations worked as both printer and parser, but I just can't get the printer side of things working.
Here are the relevant bits of my code...
event_add.xml (webflow)
<var name="event" class="project.persistence.DTO.EventDTO"/>
...
<view-state id="event_enterdates" model="flowScope.event">
<transition on="submit" to="saveEvent" />
</view-state>
EventDTO.java
public class EventDTO implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
#DateTimeFormat(pattern="dd:MM:yyyy")
private Date eventDate;
...
}
event_enterdates.jsp
<sf:form method="POST" commandName="event">
<input type="hidden" name="_flowExecutionKey" value="${flowExecutionKey}"/>
...
<div class="grid_3 formitemname"><label for="event_date">Event date:</label></div>
<div class="grid_3">
<sf:input path="eventDate" maxlength="255" id="event_date" class="form9colinput"/>
...
</sf:form>
project-servlet.xml
<mvc:annotation-driven />
<context:component-scan base-package="project"></context:component-scan>
<flow:flow-executor id="flowExecutor" flow-registry="flowRegistry" />
<flow:flow-registry id="flowRegistry" base-path="/WEB-INF/flows" flow-builder-services="flowBuilderServices">
<flow:flow-location-pattern value="*.xml" />
</flow:flow-registry>
<flow:flow-builder-services id="flowBuilderServices" conversion-service="defaultConversionService" view-factory-creator="viewFactoryCreator" />
<bean id="viewFactoryCreator" class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
<property name="viewResolvers" ref="tilesViewResolver" />
</bean>
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
<property name="flowRegistry" ref="flowRegistry" />
</bean>
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
<property name="flowExecutor" ref="flowExecutor" />
</bean>
<bean id="defaultConversionService" class="org.springframework.binding.convert.service.DefaultConversionService">
<constructor-arg ref="applicationConversionService"/>
</bean>
<bean id="applicationConversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean" />
Anyone have any idea how to get my bound date to display in the format specified in the #DateTimeFormat pattern?
Cheers,
Ian
Have you tried using a Property Editor. Spring already has one available for converting Dates.
In your #Controller that is handling the request you will instruct spring to convert to and from a particular format:
#InitBinder
protected void initBinder(final WebDataBinder binder) {
binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("dd:MM:yyyy") , false));
}