Spring MVC handling multipage forms with AbstractWizardFormController

In last Spring MVC form handling example, we should you the use of SimpleFormController to handle single page form submission, which is quite straightforward and easy.

But, sometimes, you may need to deal with “wizard form“, which need handle form into multiple pages, and ask user to fill in the form page by page. The main concern in this wizard form situation is how to store the model data (data filled in by user) and bring it across multiple pages?

SAbstractWizardFormController

Fortunately, Spring MVC comes with AbstractWizardFormController class to handle this wizard form easily. In this tutorial, we show you how to use AbstractWizardFormController class to store and bring the form’s data across multiple pages, apply validation and display the form’s data at the last page.

1. Wizard Form Pages

5 pages for this demonstration, work in following sequences :

[User] --> WelcomePage --> Page1 --> Page2 --> Page3 --> ResultPage

With AbstractWizardFormController, the page sequence is determined by the “name” of the submit button:

  1. _finish: Finish the wizard form.
  2. _cancel: Cancel the wizard form.
  3. _targetx: Move to the target page, where x is the zero-based page index. e.g _target0, _target1 and etc.

1. WelcomePage.jsp
A welcome page, with a hyperlink to start the wizard form process.

<html>
<body>
	<h2>Handling multipage forms in Spring MVC</h2>
	Click here to start playing -
	<a href="user.htm">AbstractWizardFormController example</a>
</body>
</html>

2. Page1Form.jsp
Page 1, with a “username” text box, display error message if any, and contains 2 submit buttons , where :

  1. _target1 – move to page 2.
  2. _cancel – cancel the wizard form process and move it to the cancel page
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<style>
.error {
	color: #ff0000;
}
 
.errorblock {
	color: #000;
	background-color: #ffEEEE;
	border: 3px solid #ff0000;
	padding: 8px;
	margin: 16px;
}
</style>
</head>
 
<body>
	<h2>Page1Form.jsp</h2>
 
	<form:form method="POST" commandName="userForm">
		<form:errors path="*" cssClass="errorblock" element="div" />
		<table>
			<tr>
				<td>Username :</td>
				<td><form:input path="userName" />
				</td>
				<td><form:errors path="userName" cssClass="error" />
				</td>
			</tr>
			<tr>
			<tr>
				<td colspan="3"><input type="submit" value="Next"
					name="_target1" /> <input type="submit" value="Cancel"
					name="_cancel" /></td>
			</tr>
		</table>
	</form:form>
 
</body>
</html>

3. Page2Form.jsp
Page 2, with a “password” field, display error message if any, and contains 3 submit buttons , where :

  1. _target0 – move to page 1.
  2. _target2 – move to page 3.
  3. _cancel – cancel the wizard form process and move it to the cancel page
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<style>
.error {
	color: #ff0000;
}
 
.errorblock {
	color: #000;
	background-color: #ffEEEE;
	border: 3px solid #ff0000;
	padding: 8px;
	margin: 16px;
}
</style>
</head>
 
<body>
	<h2>Page2Form.jsp</h2>
 
	<form:form method="POST" commandName="userForm">
		<form:errors path="*" cssClass="errorblock" element="div" />
		<table>
			<tr>
				<td>Password :</td>
				<td><form:password path="password" />
				</td>
				<td><form:errors path="password" cssClass="error" />
				</td>
			</tr>
			<tr>
			<tr>
				<td colspan="3"><input type="submit" value="Previous"
					name="_target0" /> <input type="submit" value="Next"
					name="_target2" /> <input type="submit" value="Cancel"
					name="_cancel" /></td>
			</tr>
		</table>
	</form:form>
 
</body>
</html>

4. Page3Form.jsp
Page 3, with a “remark” text box, display error message if any, and contains 3 submit buttons , where :

  1. _target1 – move to page 2.
  2. _finish – finish the wizard form process and move it to the finish page.
  3. _cancel – cancel the wizard form process and move it to the cancel page.
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
<style>
.error {
	color: #ff0000;
}
 
.errorblock {
	color: #000;
	background-color: #ffEEEE;
	border: 3px solid #ff0000;
	padding: 8px;
	margin: 16px;
}
</style>
</head>
 
<body>
	<h2>Page3Form.jsp</h2>
 
	<form:form method="POST" commandName="userForm">
		<form:errors path="*" cssClass="errorblock" element="div" />
		<table>
			<tr>
				<td>Remark :</td>
				<td><form:input path="remark" />
				</td>
				<td><form:errors path="remark" cssClass="error" />
				</td>
			</tr>
			<tr>
			<tr>
				<td colspan="3"><input type="submit" value="Previous"
					name="_target1" /> <input type="submit" value="Finish"
					name="_finish" /> <input type="submit" value="Cancel"
					name="_cancel" /></td>
			</tr>
		</table>
	</form:form>
 
</body>
</html>

5. ResultForm.jsp
Display all the form’s data which collected from the previous 3 pages.

<html>
<body>
	<h2>ResultForm.jsp</h2>
 
	<table>
		<tr>
			<td>UserName :</td>
			<td>${user.userName}</td>
		</tr>
		<tr>
			<td>Password :</td>
			<td>${user.password}</td>
		</tr>
		<tr>
			<td>Remark :</td>
			<td>${user.remark}</td>
		</tr>
	</table>
 
</body>
</html>

2. Model

Create a model class to store the form’s data.

File : User.java

package com.mkyong.common.model;
 
public class User{
 
	String userName;
	String password;
	String remark;
 
	//getter and setter methods
}

3. AbstractWizardFormController

Extends the AbstractWizardFormController, just override following methods

  1. processFinish- Fire when user click on the submit button with a name of “_finish“.
  2. processCancel – Fire when user click on the submit button with a name of “_cancel“.
  3. formBackingObject – Use “User” model class to store all the form’s data in multiple pages.

File : UserController.java

package com.mkyong.common.controller;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.validation.BindException;
import org.springframework.validation.Errors;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractWizardFormController;
import com.mkyong.common.model.User;
import com.mkyong.common.validator.UserValidator;
 
public class UserController extends AbstractWizardFormController{
 
	public UserController(){
		setCommandName("userForm");
	}
 
	@Override
	protected Object formBackingObject(HttpServletRequest request)
		throws Exception {
 
		return new User();
	}
	@Override
	protected ModelAndView processFinish(HttpServletRequest request,
		HttpServletResponse response, Object command, BindException errors)
		throws Exception {
 
		//Get the data from command object
		User user = (User)command;
		System.out.println(user);
 
		//where is the finish page?
		return new ModelAndView("ResultForm", "user", user);
	}
 
	@Override
	protected ModelAndView processCancel(HttpServletRequest request,
		HttpServletResponse response, Object command, BindException errors)
		throws Exception {
 
		//where is the cancel page?
		return new ModelAndView("WelcomePage");
	}
}

A simple controller to return a “WelcomePage” view.

File : WelcomeController.java

package com.mkyong.common.controller;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;
 
public class WelcomeController extends AbstractController{
 
	@Override
	protected ModelAndView handleRequestInternal(HttpServletRequest request,
		HttpServletResponse response) throws Exception {
 
		return new ModelAndView("WelcomePage");
	}
 
}

4. Multipage / Wizard Form Validation

In SimpleFormController, you create a validator class, put all the validation logic inside the validate() method, and register the validator to the simple form controller decoratively.

But, it’s a bit different in AbstractWizardFormController. First, create a validator class, and also the validation method for each of the page, as following :

File : UserValidator.java

package com.mkyong.common.validator;
 
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
import com.mkyong.common.model.User;
 
public class UserValidator implements Validator{
 
	@Override
	public boolean supports(Class clazz) {
		//just validate the User instances
		return User.class.isAssignableFrom(clazz);
	}
 
	//validate page 1, userName
	public void validatePage1Form(Object target, Errors errors) {
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "userName",
		        "required.userName", "Field name is required.");
	}
 
	//validate page 2, password
	public void validatePage2Form(Object target, Errors errors) {
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password",
			"required.password", "Field name is required.");
	}
 
	//validate page 3, remark
	public void validatePage3Form(Object target, Errors errors) {
		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "remark",
			"required.remark", "Field name is required.");
	}
 
	@Override
	public void validate(Object target, Errors errors) {
		validatePage1Form(target, errors);
		validatePage2Form(target, errors);
		validatePage3Form(target, errors);
	}
}

File : User.properties – Properties to store the error message

required.userName = Username is required!
required.password = Password is required!
required.remark = Remark is required!

And, in the wizard form controller (UserController.java), override the validatePage() by calling the validator manually (no more declaration like simple form controller).

See the updated version of UserController.java.

public class UserController extends AbstractWizardFormController{
	//other methods, see above
 
	@Override
	protected void validatePage(Object command, Errors errors, int page) {
 
		UserValidator validator = (UserValidator) getValidator();
 
		//page is 0-indexed
		switch (page) {
		   case 0: //if page 1 , go validate with validatePage1Form
			validator.validatePage1Form(command, errors);
			break;
		   case 1: //if page 2 , go validate with validatePage2Form
			validator.validatePage2Form(command, errors);
			break;
		   case 2: //if page 3 , go validate with validatePage3Form
			validator.validatePage3Form(command, errors);
			break;
		}
	}
}

In the validatePage() method, use a “switch” function to determine which page is calling and associated it with the corresponds validator. The page is in 0-indexed.

5. Spring Configuration

Declare the wizard form controller (UserController.java), put all the pages in the correct order and register a validator.

	<bean class="com.mkyong.common.controller.UserController" >
    	   <property name="pages">
		<list>
		<!-- follow sequence -->
		<value>Page1Form</value> <!-- page1, _target0 -->
		<value>Page2Form</value> <!-- page2, _target1 -->
		<value>Page3Form</value> <!-- page3, _target2 -->
		</list>
	   </property>
	   <property name="validator">
		<bean class="com.mkyong.common.validator.UserValidator" />
	   </property>
       </bean>
Note
In the “pages” property, the order of the list value is used to define the sequence of the page in the wizard form.

See full example :

<beans xmlns="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-2.5.xsd">
 
 <bean 
  class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" />
 
    <bean class="com.mkyong.common.controller.WelcomeController" />  
    <bean class="com.mkyong.common.controller.UserController" >
    	<property name="pages">
	   <list>
		<!-- follow sequence -->
		<value>Page1Form</value> <!-- page1 -->
		<value>Page2Form</value> <!-- page2 -->
		<value>Page3Form</value> <!-- page3 -->
	   </list>
	   </property>
	   <property name="validator">
		<bean class="com.mkyong.common.validator.UserValidator" />
	   </property>
      </bean>
 
      <!-- Register User.properties for validation error message -->
      <bean id="messageSource"
           class="org.springframework.context.support.ResourceBundleMessageSource">
	   <property name="basename" value="User" />
      </bean>
 
      <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>

5. Demo

URL : http://localhost:8080/SpringMVC/welcome.htm

1. WelcomePage.jsp, click on the link, move to Page1Form.jsp.

SpringMVC-Multipage-Forms-Example1

2. Page1Form.jsp, contains a “username” text box field, and 2 buttons :

  1. “next” button – move to Page2Form.jsp.
  2. “cancel” button – move to WelcomePage.jsp
SpringMVC-Multipage-Forms-Example2

If the “username” is empty while submitting the form, display the error message.

SpringMVC-Multipage-Forms-Example2-Error

3. Page2Form.jsp, contains a “password” field, and 3 buttons :

  1. “previous” button – move to Page1Form.jsp.
  2. “next” button – move to Page3Form.jsp.
  3. “cancel” button – move to WelcomePage.jsp.
SpringMVC-Multipage-Forms-Example3

4. Page3Form.jsp, contains a “remark” textbox field, and 3 buttons :

  1. “previous” button – move to Page2Form.jsp.
  2. “finish” button – move to ResultForm.jsp.
  3. “cancel” button – move to WelcomePage.jsp.
SpringMVC-Multipage-Forms-Example4

5. ResultForm.jsp, display all the form’s data.

SpringMVC-Multipage-Forms-Example5

Download Source Code

References

  1. AbstractWizardFormController Javadoc
  2. Spring MVC form handling example
Tags :

About the Author

mkyong
Founder of Mkyong.com and HostingCompass.com, love Java and open source stuff. Follow him on Twitter, or befriend him on Facebook or Google Plus. If you like my tutorials, consider make a donation to these charities.

Comments

  • safeghost

    Hello,

    “setCommandClass(User.class);” is missing in Usercontroller constructor.

    This example should not work without this statement. Am I right ?

    Can you explain how it works for you ?

    Thank you.

  • Carsten

    Hello !

    Do you have this tuturial as an example where your use Spring MVC Portlet insted ?

    Regards

    Carsten

  • kei

    if open two tab with the same url
    http://127.0.0.1:8080/SpringMVC/welcome.htm

    the second tab content with overwrite the first tab content, that is, the formBackingObject “user” is in session scope? no other better method if I don’t want to save the user in HttpSession?

  • http://alasbarricadas.org/ateneo/index.php/Usuario:CharlesAT Alberta

    We are a gaggle of volunteers and opening a brand new scheme in our community.
    Your website offered us with valuable info to work on.
    You’ve performed a formidable task and our entire group might be grateful to you.

  • Gokul Dighe

    Thanks a lot Young .You have mentionedform handling very crisply.It helped me lot in understanding the things.Keep going and all the best!!!

  • http://nurroni.com/2013/05/02/melucuti-kebenaran-perang-gadget/ Muscle Warship

    Wow, this post is pleasant, my younger sister is analyzing such things,
    thus I am going to tell her.

  • prodeveloper

    A very good tutorial and helped a lot in understanding the basic concept. Thank you very much.

  • Pratik Joshi

    i like your demo of spring mvc.
    can you tell me how to handle concurrency in spring mvc?

  • udhay

    Is the pojo class required for form handling process using spring. Please tell the reason why we are using pojo class.

    Without pojo class cannot get the value from form in client side?

  • Dhananjay Talekar

    Hi !
    I found this tutorial very interesting – and tried it quickly on my system.
    Only problem I found is that :
    errors were shown after I went to next form-page and again back to the current page
    I think reason is that errors are shown only after form submission. And in this split-forms on any submission on form, control is moved to next form.
    Any idea how to come over this problem ?

  • Arjun

    Thanks for the nice Example…..
    Can you please provide a few Spring Web Flow example as well? It would be really helpful.

  • Andrey Shevchenko

    Good day! I realize that this is a pure test example of Spring MVC and AbstractWizardFormController without any enterprise features. But I have a very simple question: if I push browser “Return” button on the ResultForm and then, from page Page3Form, click Finish again I will visit the first page of the wizard. How can we prevent this situation and apply right logic in any way?

  • Chinna

    Please send the WizardFormContrller with Annotaions complete code

    This program is not working.

  • Harry

    This application is a bit weird.
    From second page if you go back to first page by pressing “Previous” Button. You are getting the page2 Validation error message on the first page.

  • Babu

    Can you please post full multiple forms example with Spring 3.0

  • Roger Pc Key

    with annotations, just add

    and

    in forms

    package com.mkyong.controller;
     
    import com.mkyong.model.User;
    import com.mkyong.validator.UserValidator;
    import java.util.HashMap;
    import java.util.Map;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import org.springframework.beans.factory.annotation.Autowired;
    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 org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.SessionAttributes;
    import org.springframework.web.bind.support.SessionStatus;
    import org.springframework.web.util.WebUtils;
     
    @Controller 
    @RequestMapping("/user") 
    @SessionAttributes("user")  
    public class FormUserController{
        private UserValidator userValidator;
     
        @Autowired 
        public FormUserController(UserValidator userValidator) { 
            this.userValidator = userValidator; 
        } 
     
        @RequestMapping(method = RequestMethod.GET) 
        public String setupForm(Model model) {      
            User user = new User();         
            model.addAttribute("user", user); 
            return "Page1Form";
        } 
     
        @RequestMapping(method = RequestMethod.POST) 
        public String submitForm( 
                HttpServletRequest request, HttpServletResponse response, 
                @ModelAttribute("user") User user, 
                BindingResult result, SessionStatus status, 
                @RequestParam("_page") int currentPage, Model model) {      
     
            Map pageForms = new HashMap(); 
            pageForms.put(0,"Page1Form"); 
            pageForms.put(1,"Page2Form"); 
            pageForms.put(2,"Page3Form"); 
            if (request.getParameter("_cancel") != null) { 
                // Return to current page view, since user clicked cancel 
                //return (String)pageForms.get(currentPage); 
                return "WizardPage";
            } else if (request.getParameter("_finish") != null) {            
                //new UserValidator().validate(user, result);
                userValidator.validate(user, result);
                if (!result.hasErrors()) {                
                    status.setComplete(); 
                    return "ResultForm"; 
                } else {  
                     // Errors  
                    return (String)pageForms.get(currentPage); 
                } 
            } else {  
                int targetPage = WebUtils.getTargetPage(request, "_target", currentPage); 
                // If targetPage is lesser than current page, user clicked 'Previous' 
                if (targetPage &lt; currentPage) { 
                    return (String)pageForms.get(targetPage); 
                }  
                // User clicked next  
                // Validate data based on page 
                switch (currentPage) { 
                    case 0:  
                        //new UserValidator().validatePage1Form(user, result);
                        userValidator.validatePage1Form(user, result);
                      break; 
                    case 1: 
                        //new UserValidator().validatePage2Form(user, result);
                        userValidator.validatePage2Form(user, result);
                        break; 
                    case 2:  
                        //new UserValidator().validatePage3Form(user, result);
                        userValidator.validatePage3Form(user, result);
                        break; 
                } 
                if (!result.hasErrors()) { 
                    // No errors, return target page 
                    return (String)pageForms.get(targetPage); 
                } else {  
                    // Errors, return current page 
                    return (String)pageForms.get(currentPage); 
                } 
          }
        }
    }
    • sri

      can u please upload the full code with annotation part?

  • salish

    hi,

    verymuch help full for beginners and those who want to search the required application,

    is there application with spring with JPA intergrated means my application use jpa with a lot relations so the entity bean is here the model means the pojo so the relation dont know and how to use in jsp page will u please post an example with spring3(annotation) with jpa feature its more help full and also i’m new in spring and jpa also

    please help me

    thanks for the very help.

    • http://www.mkyong.com mkyong

      Thanks for your suggestion, will try post some Spirng + JPA stuffs in future.

  • Swamy K

    Hi Young,

    Could you post multi form wizard example in Spring3.0

    • http://www.mkyong.com mkyong

      noted, may be next month.

    • Bryan

      I find your examples extremely helpful. Thank you!

      Did you ever complete a Spring 3 wizard example?

  • BikuDAA

    Hi,

    When I tried to run the example, I have been getting the exception shown below. Any help would be highly appreciated.

    Mar 23, 2011 1:06:41 AM org.apache.catalina.connector.CoyoteAdapter service
    SEVERE: An exception or error occurred in the container during the request processing
    java.lang.NullPointerException
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:541)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:383)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:243)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:188)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:166)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:288)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)
    Mar 23, 2011 1:06:54 AM org.apache.catalina.connector.CoyoteAdapter service
    SEVERE: An exception or error occurred in the container during the request processing
    java.lang.NullPointerException
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:541)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:383)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:243)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:188)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:288)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)
    Mar 23, 2011 1:06:55 AM org.apache.catalina.connector.CoyoteAdapter service
    SEVERE: An exception or error occurred in the container during the request processing
    java.lang.NullPointerException
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:541)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:383)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:243)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:188)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:288)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)

  • Pingback: Spring MVC Tutorials()