Spring MVC form validation not working - spring

I am using Spring 4.
My form contains the following variables:
#NotNull
#Email
private String email;
#NotNull
private String firstName;
#NotNull
private String lastName;
#Digits(fraction = 0, integer = 10)
private String phoneNo;
#NotNull
private String role;
My controller:
#Controller
#RequestMapping("/user")
public class UserController {
#RequestMapping(value = "/add", method = RequestMethod.POST)
public ModelAndView add(#ModelAttribute("user") #Valid UserBean user, BindingResult result) {
String message;
if (result.hasErrors() && user != null)
return new ModelAndView("userAdd");
else {
userService.addUser(user);
message = "Successfully added user";
}
return new ModelAndView("success", "message", message);
}
#RequestMapping(value = "/register")
public ModelAndView register(#ModelAttribute("user") UserBean user, BindingResult result) {
List<String> roles = new ArrayList<String>();
roles.add("Receiver");
roles.add("Resolver");
roles.add("Logger");
Map<String, List<String>> model = new HashMap<String, List<String>>();
model.put("roles", roles);
return new ModelAndView("userAdd", "model", model);
}
}
My jsp:
<c:url var="userAdd" value="user/add.do" />
<sf:form method="post" action="${userAdd}" modelAttribute="user">
<table>
<tr>
<td>First Name</td>
<td><sf:input path="firstName" /><br /> <sf:errors
path="firstName" cssClass="error" /></td>
</tr>
<tr>
<td>Last Name</td>
<td><sf:input path="lastName" /><br /> <sf:errors
path="lastName" cssClass="error" /></td>
</tr>
<tr>
<td>Email</td>
<td><sf:input path="email" /><br /> <sf:errors
path="email" cssClass="error" /></td>
</tr>
<tr>
<td>Phone No.</td>
<td><sf:input path="phoneNo" /><br /> <sf:errors
path="phoneNo" cssClass="error" /></td>
</tr>
<tr>
<td>Role</td>
<td><sf:select path="role" items="${model.roles}" /><br /> <sf:errors
path="role" cssClass="error" /></td>
</tr>
<tr>
<td><input type="submit" value="Submit" /></td>
</tr>
</table>
</sf:form>
When I leave the the inputs blank, the form does not validate and does not throw any error. The BindingResult does not have any errors in it.
My libraries are:
My dispatcher-serlvet.xml is:
<?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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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">
<!-- Scans for annotated #Controllers in the classpath -->
<context:component-scan base-package="com.mj.cchp.controller">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
</context:component-scan>
<bean id="myBeansValidator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
<mvc:annotation-driven validator="myBeansValidator" />
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/pages/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
My applicationContext is:
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="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">
<!-- Scans for annotated #Controllers in the classpath -->
<context:component-scan base-package="com.mj.cchp">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
</context:component-scan>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.ibm.db2.jcc.DB2Driver" />
<property name="url" value="jdbc:db2://172.16.2.181:60000/CCHP" />
<property name="username" value="db2inst1" />
<property name="password" value="db2inst1" />
</bean>
</beans>
My web.xml is:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>CCHP</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/application-context.xml</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>

You need to add
<bean id="myBeansValidator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
and
<mvc:annotation-driven validator="myBeansValidator">
and
<!-- Hibernate Validator -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.2.0.Final</version>
</dependency>
Should work!

I had a similar problem and in my case it was sufficient to just add dependency for hibernate validator: org.hibernate:hibernate-validator:5.2.4.Final.
The validation is done by LocalValidatorFactoryBean bean and documentation about it comes handy (here).
Yet at the same time it is worth mentioning that you do not have to instantiate LocalValidatorFactoryBean explicitly as long as you use #EnableWebMvc annotation : http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-config-validation
By default use of #EnableWebMvc or
automatically registers Bean Validation support in Spring MVC through
the LocalValidatorFactoryBean when a Bean Validation provider such as
Hibernate Validator is detected on the classpath.
Hope this helps.

I faced the same problem. I resolved by adding below statement in dispatcher-serlvet.xml file.
<mvc:annotation-driven />

I'm not sure whether you have found ways to fix this. I am facing the same issue as well. and I managed to solve it. The problem with my setting is totally manual and I'm doing big mistake by placing the whole hibernate-validator-5.1.3.Final-dist.zip inside lib folder.
So what I did is I get this 6 files inside "hibernate-validator-5.1.3.Final-dist.zip" in dist folder and place this with web app lib.
classmate-1.0.0.jar
hibernate-validator-5.1.3.Final.jar
javax.el-2.2.4.jar
javax.el-api-2.2.4.jar
jboss-logging-3.1.3.GA.jar
validation-api-1.1.0.Final.jar
This fixed my issue.

i also faced the same issue where my entire code was properly written.
The problem was the different version of jar files that i was using .
I had hibernate-validator-cdi- 5.0.7.Final and hibernate-validator-6.0.2.Final.
Just make sure your jar files are of the same version.
When i kept all the jars of same version, my issue got resolved. I hope this will help you .

You need to add #Valid in register method
#RequestMapping(value = "/register") public ModelAndView register(#Valid #ModelAttribute("user") UserBean user, BindingResult result) {

If you are using hibernate-validator, use version-6.2.4
Version 7 might not work.

In my case hibernate-validator jars are not available in run time. I've copied them to .../WEB-INF/lib/ then it worked correctly.

I added the usual stuff you have done (libraries in pom, #Valid on RequestBody etc)
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.3.Final</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>3.0.1-b11</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
What the Spring docs (and many blogs) leave it as subtle is that Spring looks for an exit point to throw the error but if that exit doesn't exist, it will reply with 404. After reading a lot especially this blog, adding this class got Spring to recognize #Valid and find an exit point to throw the error
#RestControllerAdvice
#Order(1)
public class RestControllerExceptionHandler {
#RequestMapping(value = { "error/404" }, method = RequestMethod.GET)
#ExceptionHandler(Exception.class)
public String handleUnexpectedException(Exception e) {
return "views/base/rest-error";
}
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ExceptionHandler(MethodArgumentNotValidException.class)
public String handlemethodArgumentNotValid(MethodArgumentNotValidException exception) { //
// TODO you can choose to return your custom object here, which will then get transformed to json/xml etc.
return "Sorry, that was not quite right: " + exception.getMessage();
}
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ExceptionHandler(ConstraintViolationException.class)
public String handleConstraintViolation(ConstraintViolationException exception) { //
// TODO you can choose to return your custom object here, which will then get transformed to json/xml etc.
return "Sorry, that was not quite right: " + exception.getMessage();
}
}

i spent nearly 2 days fixing the same problem and ultimately found one solution, if you still have this problem, i would like to suggest you one answer, in my case, i tried using hibernate-validator-5.1.3.Final-dist.zip,5.2.4.Final-dist.zip, 7.0.0.Final-dist.zip but none of these worked for me but when i used *hibernate-validator-6.2.0.Final-dist*, it supports jarkarta validation but it works perfectly even though people say because of Jakarta Bean Validation it does not work in hibernate-validator's version post 5. it worked miraculously and believe me, it might work for you as well.

Related

Spring4 MVC form validation result.hasErrors() is always false

I'm using validation-api-1.1.0.Final.jar to valid form input in Spring 4 MVC. But I'm stuck in here, the result.hasErrors() seems always false(it means #Valid doesn't work properly). I followed this guideValidating Form Input, but that guide validating form input using Spring Boot. I'm using Tomcat 8 instead of using Spring Boot. I've search a lot about this, but the issue still existed.
Seaking for help.
Thanks!
Project Structure:
UserController.java
package com.ro.user.controller;
import com.ro.user.model.UserModel;
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 org.springframework.web.bind.annotation.RequestMethod;
import javax.validation.Valid;
#Controller
public class UserController {
#RequestMapping(value = "/user", method = RequestMethod.GET)
public UserModel user(Model model) {
UserModel userModel = new UserModel();
model.addAttribute("userModel", userModel);
return userModel;
}
#RequestMapping(value = "/userLogin", method = RequestMethod.POST)
public String userLogin(#Valid #ModelAttribute("userModel") UserModel userModel, BindingResult bindingResult) {
System.out.println("Before: bindingResult.hasErrors()");
if (bindingResult.hasErrors()) {
System.out.println("After: bindingResult.hasErrors()");
return "user";
}
return "result";
}
}
UserModel.java
package com.ro.user.model;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
public class UserModel {
#NotNull
#Size(min = 6, max = 12)
private String username;
#Size(min = 8, max = 16)
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
user.jsp
<%# page contentType="text/html;charset=UTF-8" language="java" %>
<%# taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<html>
<head>
<title>Spring MVC Form Handling</title>
<style>
.error {
color: #ff0000;
}
.errorblock {
color: #000;
background-color: #ffEEEE;
border: 3px solid #ff0000;
padding: 8px;
margin: 16px;
}
</style>
</head>
<body>
<h2>User Information</h2>
<form:form action="userLogin" modelAttribute="userModel" method="POST">
<form:errors path="*" cssClass="errorblock" element="div"/>
<table>
<tr>
<td><form:label path="username">Username:</form:label></td>
<td><form:input path="username"/></td>
<td><form:errors path="username" cssClass="error"/></td>
</tr>
<tr>
<td><form:label path="password">Password:</form:label></td>
<td><form:input path="password"/></td>
<td><form:errors path="username" cssClass="error"/></td>
</tr>
<tr>
<td colspan="3">
<input type="submit" value="Submit"/>
</td>
</tr>
</table>
</form:form>
</body>
</html>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>UserLogin</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>UserLogin</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
UserLogin-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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="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
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<mvc:annotation-driven/>
<context:component-scan base-package="com.ro.user.controller"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<bean class="org.springframework.context.support.ResourceBundleMessageSource" id="messageSource">
<property name="basename" value="com.ro.user.model.error"/>
</bean>
</beans>
This issue is caused by lack of the dependency of Hibernate Validator. It is supposed to add all Jars in a folder named required to project's lib(download zip from the official website and unzip it, you will see this folder). Not just the hibernate-validator.jar and validation-api.jar.
I guess you've created a custom HandlerAdapter, then you need to initialize the webBinding manually.
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="webBindingInitializer">
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="validator" ref="validator"/>
</bean>
</property>
</bean>
I had the same issue. I resolved it by changing hibernate validator version. In my case, it worked with version 6.2 and it didn't work with version 7.

404 error on a simple spring mvc aplication

Project Folder structureI have gone through most of the question on this site related to 404 resource not found error on Sring mvc application. I tried all solutions and still ended up with no resolution for over two days. I am new to spring MVC and tried out a sample application from the link
Simple Spring MVC app
My code is exactly as mentioned on the site above. But no matter what change I make, still get a 404 error.
Here's my web.xml section
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>abc</display-name>
<welcome-file-list>
<welcome-file>/</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>sdnext</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name><param-value>/WEB-INF/config/sdnext-servlet.xml</param-value></init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>sdnext</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
The controller file,
EmployeeController.java
#Controller
public class EmployeeController {
#RequestMapping(value = "/employee", method = RequestMethod.GET)
public ModelAndView employee() {
return new ModelAndView("employeeForm", "command", new Employee());
}
#RequestMapping(value = "/addEmployee", method = RequestMethod.POST)
public String addEmployee(#ModelAttribute("SpringWeb")Employee employee, ModelMap model) {
model.addAttribute("name", employee.getName());
model.addAttribute("age", employee.getAge());
model.addAttribute("empId", employee.getEmpId());
model.addAttribute("salary", employee.getSalary());
return "employeeDetail";
}
}
where Employee is my POJO class with setter and getter methods.
Here is my employeeForm.jsp
<form:form action="/addEmployee" method="POST">
<table><tbody>
<tr> <td><form:label path="empId">Employee :</form:label></td> <td><form:input path="empId"></form:input></td> </tr>
<tr> <td><form:label path="name">EmployeeName:/form:label></form:label></td> <td><form:input path="name"></form:input></td> </tr>
<tr> <td><form:label path="age">Employee Age:</form:label></td> <td><form:input path="age"></form:input></td> </tr>
<tr> <td><form:label path="salary">Employee Salary:</form:label></td> <td><form:input path="salary"></form:input></td> </tr>
<tr> <td colspan="2"><input type="submit" value="Submit"/> </td> </tr>
</tbody></table>
</form:form>
here is my sdnext-servlet.xml
<context:component-scan base-package="com.dineshonjava.emp.controller">
</context:component-scan>
<context:annotation-config/>
<bean
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="viewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
You are doing a fundamental mistake. Say your project name is bunbub-proj, so the url to access is localhost:8080/bunbub-proj. When you POST to /addEmployee, you are actually hitting localhost:8080/addEmployee instead of localhost:8080/bunbub-proj/addEmployee
The fix is to simply append a . to all of your links/urls. E.g. <form:form action="./addEmployee" method="POST">
Note: Browser considers localhost:8080 as the base url or the host
url.

Spring MVC, Form Submission not working

Can some one help me with this?
My Controller class looks like this, and i have created the customer model class..
/**
* Handles requests for the application home page.
*/
#Controller
#RequestMapping("/customer")
public class CustomerController {
#RequestMapping(method = RequestMethod.GET)
public ModelAndView student() {
return new ModelAndView("customer", "command", new Customer());
}
#RequestMapping(value = "/addCustomer", method = RequestMethod.POST)
public String addStudent(#ModelAttribute Customer customer,
ModelMap model) {
model.addAttribute("customerName", customer.getCustomerName());
model.addAttribute("emailId", customer.getEmailId());
model.addAttribute("sex", customer.getSex());
return "customerDetails";
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>Customer Form Handling</display-name>
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<!-- 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>Customer</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/Customer/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Customer</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
JSP Pages
customer.jsp
<%#taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<html>
<head>
<title>Customer Form Handling</title>
</head>
<body>
<h2>Customer Information</h2>
<form:form method="POST" commandName = "command" action="/addCustomer">
<table>
<tr>
<td><form:label path="customerName">customerName</form:label></td>
<td><form:input path="customerName" /></td>
</tr>
<tr>
<td><form:label path="emailId">emailId</form:label></td>
<td><form:input path="emailId" /></td>
</tr>
<tr>
<td><form:label path="sex">sex</form:label></td>
<td><form:input path="sex" /></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="Submit"/>
</td>
</tr>
</table>
</form:form>
</body>
</html>
customerDetails.jsp
<%#taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<html>
<head>
<title>Customer Form Handling</title>
</head>
<body>
<h2>Customer Detail Information</h2>
<table>
<tr>
<td>CustomerName</td>
<td>${customerName}</td>
</tr>
<tr>
<td>emailId</td>
<td>${emailId}</td>
</tr>
<tr>
<td>sex</td>
<td>${sex}</td>
</tr>
</table>
</body>
</html>
Servlet-Context.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="com.customerinfo.controller" />
</beans:beans>
But when I run this application in Tomcat Server.. The first url points to
localhost:8080/controller/.
If I append localhost:8080/controller/customer I get the first form page..
But once I click on submit.. it says page not found error.
It's a relative path problem. Your form action is /addCustomer (has / prefix), if you resolve it it's http://localhost:8080/addCustomer. What you wanted is probably http://localhost:8080/appname/customer/addCustomer.
In some cases simply changing it into customer/addCustomer might resolve it, but if your page can also be accessed by http://localhost:8080/appname/customer/ (pay attention to the trailing slash) then this could be a problem. The relative path will translate into http://localhost:8080/appname/customer/customer/addCustomer
Of course now you can think to just do /appname/customer/addCustomer and problem solved, but in fact you are now hard-coding the context path name. If one day the context path changes all this code will break.
One approach I like to use so my JSP can figure out the context path is by defining a root variable
<c:set var="root" value="${pageContext.request.contextPath}"/>
...
<form:form action="${root}/customer/addCustomer">
try as
<form:form method="POST" commandName = "command" action="addCustomer">
instead of
<form:form method="POST" commandName = "command" action="/addCustomer">

Spring custom JSF login page, always "Bad credentials"

I'm trying to get a JSF login page to work with Spring security. I've looked around for numerous examples but none works. Every time I try to log in using the JSF page I get a "Bad credentials" warning in my server log.
Spring-Security.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" 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/security
http://www.springframework.org/schema/security/spring-security.xsd">
<http auto-config="true">
<intercept-url pattern="/Login.xhtml*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/**/*.css*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/**/*.js*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/**" access="ROLE_USER,ROLE_ADMIN" />
<form-login login-page="/Login.xhtml" default-target-url="/Secure.xhtml"
authentication-failure-url="/Login.xhtml" />
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="admin" authorities="ROLE_ADMIN" password="admin"/>
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="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
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="com.example" />
<context:annotation-config />
<tx:annotation-driven />
<import resource="classpath:spring/security/Spring-Security.xml" />
</beans>
Login.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head></h:head>
<body>
<h:form>
<h:outputLabel value="username" for="j_username"
style="float:left" />
<h:inputText id="j_username" style="float:left" />
<h:outputLabel value="password" for="j_password"
style="float:left; clear:both" />
<h:inputSecret id="j_password" style="float:left" />
<h:commandButton value="login"
actionListener="#{loginBean.login}" style="float:left;clear:both" />
</h:form>
<h:messages style="float:left;clear:both" />
</body>
</html>
LoginBean
#Named
#Scope("request")
public class LoginBean
{
public void login() throws ServletException, IOException
{
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
externalContext.dispatch("/j_spring_security_check");
facesContext.responseComplete();
}
}
Web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<filter>
<filter-name>OpenEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
<init-param>
<param-name>singleSession</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>sessionFactoryBeanName</param-name>
<param-value>sessionFactory</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>OpenEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
</web-app>
When I use a non-JSF page as Login.xhtml it works flawlessly.
Page that does work:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head></h:head>
<body>
<form action="j_spring_security_check" method="post">
<table>
<tr>
<td>User:</td>
<td><input type="text" name="j_username" /></td>
</tr>
<tr>
<td>Password:</td>
<td><input type="password" name="j_password" /></td>
</tr>
<tr>
<td colspan='2'><input name="submit" type="submit"
value="submit" /></td>
</tr>
</table>
</form>
</body>
</html>
Any help is appreciated.
This is an old problem. By default the FilterSecurityInterceptor will only execute once-per-request and doesn't do security re-checking unless there is change in the url but with JSP/JSF forwards the page is rendered as a response to the current request and the url in the browser contains the address of the previous page.
Before Spring Security 3.0 this was bypassed doing a GET request something like this:
String encodedURL = externalcontext.encodeResourceURL(externalcontext.getRequestContextPath() + "/j_spring_security_check?j_username=" + username + "&j_password=" + password);
externalcontext.redirect(encodedURL);
But from Spring Security 3.0, by default it supports POST only.
So one way, probably the easiest to use is a simple HTML form. Otherwise you need to manually authenticate the request by getting the AuthenticationManager.
I guess the whole story originated from this post on Spring forums.
And the best working example can be found on the ICEFaces wiki
Here is the relevant LoginController class from the tutorial.zip
/**
* This class handles all login attempts except html forms that directly
* post to the /j_spring_security_check method.
*
* #author Ben Simpson
*/
#ManagedBean(name = "loginController")
#RequestScoped
public class LoginController implements Serializable {
private static final long serialVersionUID = 1L;
/**
* This action logs the user in and returns to the secure area.
*
* #return String path to secure area
*/
public String loginUsingSpringAuthenticationManager() {
//get backing bean for simple redirect form
LoginFormBackingBean loginFormBean =
(LoginFormBackingBean) FacesUtils.getBackingBean("loginFormBean");
//authentication manager located in Spring config: /WEB-INF/authenticationContext-security.xml
AuthenticationManager authenticationManager =
(AuthenticationManager) getSpringBean("authenticationManager");
//simple token holder
Authentication authenticationRequestToken = createAuthenticationToken(loginFormBean);
//authentication action
try {
Authentication authenticationResponseToken =
authenticationManager.authenticate(authenticationRequestToken);
SecurityContextHolder.getContext().setAuthentication(authenticationResponseToken);
//ok, test if authenticated, if yes reroute
if (authenticationResponseToken.isAuthenticated()) {
//lookup authentication success url, or find redirect parameter from login bean
return "/secure/examples";
}
} catch (BadCredentialsException badCredentialsException) {
FacesMessage facesMessage =
new FacesMessage("Login Failed: please check your username/password and try again.");
FacesContext.getCurrentInstance().addMessage(null,facesMessage);
} catch (LockedException lockedException) {
FacesMessage facesMessage =
new FacesMessage("Account Locked: please contact your administrator.");
FacesContext.getCurrentInstance().addMessage(null,facesMessage);
} catch (DisabledException disabledException) {
FacesMessage facesMessage =
new FacesMessage("Account Disabled: please contact your administrator.");
FacesContext.getCurrentInstance().addMessage(null,facesMessage);
}
return null;
}
private Authentication createAuthenticationToken(LoginFormBackingBean loginFormBean) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
new UsernamePasswordAuthenticationToken(
loginFormBean.getUserName(),
loginFormBean.getPassword()
);
return usernamePasswordAuthenticationToken;
}
private Object getSpringBean(String name){
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(
(ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext());
return ctx.getBean(name);
}
}
OPTION 3 : I haven't personally tried but even this should work:
By setting once-per-request attribute to false in your http element in applicationContext thus forcing security rechecking. But I don't recommend it.
<http auto-config="true" use-expressions="true" once-per-request="false">
The answer to the question left me a little wanting.
So to get this working with a minimal amount of code in the controller (I wanted to avoid manually authenticating), I used a combination of a JSF (primefaces) form and a simple form.
I ended up with a view like this:
<h:form id="login-form" prependId="false">
<p:focus for="userName" />
<p:fieldset id="login-fs" legend="User Authentication">
<h:panelGrid id="login-grid" columns="3">
<p:outputLabel for="userName" value="User Name" />
<p:inputText id="userName" value="#{loginView.userName}" required="true" />
<p:message for="userName" />
<p:outputLabel for="password" value="Password" />
<p:inputText type="password" id="password" value="#{loginView.password}" required="true" />
<p:message for="password" />
</h:panelGrid>
<br />
<p:commandButton value="Submit" icon="ui-icon-check" process="#form" update="login-grid" actionListener="#{loginView.login}" />
</p:fieldset>
</h:form>
<form id="hidden-form" action="#{request.contextPath}/j_spring_security_check" method="post">
<h:inputHidden id="j_username" />
<h:inputHidden id="j_password" />
</form>
<script type="text/javascript">
function mysubmit() {
$('#j_username').val($('#userName').val());
$('#j_password').val($('#password').val());
$('#hidden-form').submit();
}
</script>
And the backing bean could do the typical jsf lifecycle, after which it would send javascript back to transfer values from the successfully validated JSF form to the hidden one and submit the hidden form:
#ManagedBean
public class LoginView {
private String userName;
private String password;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public void login() {
RequestContext.getCurrentInstance().execute("mysubmit()");
}
}
You could do anything else you want on the server-side before the submit actually happens, if you need to.
Someone correct me if i'm wrong, but I think you are specifying your backing bean incorrectly.
The correct JSF way to specify your backing bean scope is like this:
#ManagedBean
#RequestScoped
public class LoginBean
{
public void login() throws ServletException, IOException
{
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
externalContext.dispatch("/j_spring_security_check");
facesContext.responseComplete();
}
}
Change your h:commandButton to use an action method instead of an actionListener:
<h:commandButton value="login"
action="#{loginBean.login}" style="float:left;clear:both" />
See also: Differences between action and actionListener

validation form using Spring 3

i'm creating validation form on Spring 3, My problem is, that i saw a lot of examples with validation form. I even created one. but my form passing "result.hasErrors()" method, even when there are errors.
My code is:
Controller:
package com.esb.sso;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import javax.servlet.http.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.validation.BindingResult;
import java.util.Map;
import javax.validation.Valid;
import com.esb.sso.form.LoginForm;
import javax.servlet.http.HttpServletRequest;
/**
* Handles requests for the application home page.
*/
#Controller
#RequestMapping(value = "/")
public class HomeController {
LoginForm loginForm = new LoginForm();
model.put("loginForm", loginForm);
return "home";
}
#RequestMapping(method = RequestMethod.POST)
public String validation(#Valid LoginForm loginForm, BindingResult result,
Map model) throws IOException {
logger.info("Login POST var");
logger.info(loginForm.getLogin());
logger.info(loginForm.getPassword());
if (result.hasErrors()) {
logger.info("error");
return "home";
}
model.put("loginForm", loginForm);
return "logged";
}
}
Validator:
package com.esb.sso.form;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
public class LoginForm {
#NotNull(message = "notNull")
#Size(min=1, max=50, message="mote charters")
private String login;
#NotNull(message = "notNull")
#Size(min=1, max=50, message="mote charters")
private String password;
public void setLogin(String login){
this.login = login;
}
public String getLogin(){
return login;
}
public void setPassword(String password){
this.password = password;
}
public String getPassword(){
return password;
}
}
View:
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<title>Home</title>
</head>
<body>
Autoryzacja!!!
<form:form action="" commandName="loginForm">
<table>
<tr>
<td>User Name:<FONT color="red"><form:errors path="login" /></FONT></td>
</tr>
<tr>
<td><form:input path="login" /></td>
</tr>
<tr>
<td>Password:<FONT color="red"><form:errors path="password" /></FONT></td>
</tr>
<tr>
<td><form:password path="password" /></td>
</tr>
<tr>
<td><input type="submit" value="Submit" /></td>
</tr>
</table>
</form:form>
</body>
</html>
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<!-- 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/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
servlet-context:
<?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-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.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="com.esb.sso" />
<beans:bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<beans:property name="basename" value="/WEB-INF/messages" />
</beans:bean>
</beans:beans>
and messages.properties:
NotNull.loginForm.login=must not be blank.
NotNull.loginForm.password=must not be blank.
Size.loginForm.login=Login size must be between 1 and 50 charters.
Size.loginForm.password=Password size must be between 1 and 50 charters.
I don't know where is the problem
Coul'd enybody help me ?
Assuming copy paste error in HomeController-get method of the "/" mapping method.
To answer your question - You must specify the LoginForm object as model attribute in order to bind validations on it with BindingResult. Below is the correct code
public String validation((#ModelAttribute("loginForm") #Valid LoginForm loginForm, BindingResult result,
Map model) throws IOException {
For reference see the documentation

Resources