Friday, November 16, 2012

ExtJS form validation using commons-validator



This page describes the process of using commons-validator to validate extJS form submissions.
Background
Commons validation is a mature project that’s been out there for a while now. It became popular when it was introduced as part of the Struts framework. Commons validation allows developers to specify validation rules inside XML files, thus allowing them to be applied uniformly across the site. In addition the same set of rules can be used to generate both client side and server side validation thus reducing maintenance cost.
In the interest of brevity, this page will only cover the server side validation.
Using commons-validator by itself doesn’t give you much benefit. All you get is the ability to specify rules and validation logic that returns whether the validation passed or failed.
You are left on your own to:
  1. Write your own code to iterate thru the form fields and collect the failure messages
  2. Write a servlet to handle requests over HTTP and present the failure messages back to the client
  3. Internationalization Support
Although its not that much work, when you start implementing it you quickly realize that this boiler plate code is something that a framework should provide.
This boiler plate code has been written years ago by the makers of the Struts framework. By extending the framework slightly, we can use it to validate forms submitted by extJS components.
Struts comes pre-packaged with the “html:errors” tag. Upon validation failures struts returns the user back to the “input” page and the input page contains a “html:errors” tag that displays the failed validation along with a description of the failure in HTML format.
The Approach
The approach presented here focues on extending the “html:errors” tag to return JSON instead of html. The JSON is parsed by the extJS formPanel and the errors are presented to the user.
On success the extJS formPanel expects:
{success: true, msg : 'Thank you for your submission.'}
On failure the extJS formPanel expects:
{
   success : false,

   msg     : 'This is an example error message',
   errors  : {

      firstName : 'Sample Error for First Name',
      lastName  : 'Sample Error for Last Name'

   }
}
Note:
Some of the code on this page are not core to the understanding “approach”, for this reason the code will initially be collapsed.
Requirements
Since this page is about integrating 3 different technologies together a basic understanding of struts, commons-validation, and extJS is assumed. If any of these technologies are not clear then please visit some of my other tutorial pages.
  1. Maven 2
  2. Basic Understanding of extJS, Struts 1 and commons-validator
Outline
This tutorial is quite lengthy.
Here is an outline:
  1. Create and configure a new project
  2. Extend the html:errors tag
  3. Configure the Struts Framework
  4. Create the struts action class and JSP
  5. Configure the page validation
Create and configure a new project
I would recommend starting from a new project.
Create a new project using Maven 2.
mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp
groupId: com.test
artifactId: form-validation
Answer the rest of the questions with defaults “Just hit the enter key”,
cd to the project base folder.
cd form-validation
Since this is a web project maven2 does not create the java source folder.
Create missing folder
mkdir -p src/main/java/com/test
Modify the project Configuration
Replace the pom.xml with the following.

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.test</groupId>

    <artifactId>form-validation</artifactId>
    <packaging>war</packaging>

    <version>1.0-SNAPSHOT</version>
    <name>form-validation Maven Webapp</name>

    <url>http://maven.apache.org</url>
    <dependencies>

        <dependency>
            <groupId>junit</groupId>

            <artifactId>junit</artifactId>
            <version>3.8.1</version>

            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>commons-validator</groupId>

            <artifactId>commons-validator</artifactId>
            <version>1.1.3</version>

        </dependency>
        <dependency>

            <groupId>struts</groupId>
            <artifactId>struts</artifactId>

            <version>1.1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.geronimo.specs</groupId>

            <artifactId>geronimo-servlet_2.5_spec</artifactId>
            <version>1.2</version>

            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>commons-logging</groupId>

            <artifactId>commons-logging</artifactId>
            <version>1.1</version>

        </dependency>
        <dependency>

            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>

            <version>1.7.0</version>
        </dependency>

        <dependency>
            <groupId>commons-digester</groupId>

            <artifactId>commons-digester</artifactId>
            <version>1.8</version>

        </dependency>
        <dependency>

            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>

            <version>3.1</version>
        </dependency>

        <dependency>
            <groupId>org.json</groupId>

            <artifactId>json</artifactId>
            <version>20090211</version>

        </dependency>
    </dependencies>

    <build>
        <finalName>form-validation</finalName>

        <plugins>
            <plugin>

                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>

                <version>2.0.2</version>
                <configuration>

                    <source>1.5</source>
                    <target>1.5</target>

                </configuration>
            </plugin>

            <plugin>
                <groupId>org.mortbay.jetty</groupId>

                <artifactId>jetty-maven-plugin</artifactId>
                <version>7.0.0.v20091005</version>

                <configuration>
                    <scanIntervalSeconds>2</scanIntervalSeconds>

                </configuration>
            </plugin>

        </plugins>
    </build>

</project>

Extend the html:errors tag
Extend the html:errors tag to return errors in JSON format.
src/main/java/com/test/ExtJsonErrorsTag.java
package com.test;


import java.util.Iterator;


import javax.servlet.jsp.JspException;


import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;

import org.apache.struts.taglib.html.ErrorsTag;
import org.apache.struts.util.RequestUtils;

import org.apache.struts.util.ResponseUtils;
import org.json.JSONException;

import org.json.JSONObject;


public class ExtJsonErrorsTag extends ErrorsTag {


    private static final long serialVersionUID = 1L;


    public int doStartTag() throws JspException {
        ActionErrors errors = null;

        JSONObject jsonReturn = new JSONObject();
        try {

            errors = RequestUtils.getActionErrors(this.pageContext, this.name);
        } catch (JspException e) {

            RequestUtils.saveException(this.pageContext, e);
            throw e;

        }
        if ((errors == null) || (errors.isEmpty())) {

             
            try {

                jsonReturn.put("success", true);
                jsonReturn.put("msg", "Thank you for your submission.");

            } catch (JSONException e) {
                throw new JspException(e);

            }


            ResponseUtils.write(this.pageContext, jsonReturn.toString());
            return 1;

        }


        Iterator errorIterator = errors.properties();
        JSONObject jsonErrors = new JSONObject();


        while (errorIterator.hasNext()) {

            String property = (String) errorIterator.next();
            processErrors(errors, property, jsonErrors);

        }


        try {
            jsonReturn.put("success", false);

            jsonReturn.put("msg", "There was a validation failure.");
            jsonReturn.put("errors", jsonErrors);

            ResponseUtils.write(this.pageContext, jsonReturn.toString());
        } catch (JSONException e) {

            throw new JspException(e);
        }


        return 1;

    }


    private void processErrors(ActionErrors errors, String property,
            JSONObject jsonErrors) throws JspException {

        String message;
        Iterator reports = (property == null) ? errors.get() : errors

                .get(property);
        while (reports.hasNext()) {

            ActionError report = (ActionError) reports.next();


            message = RequestUtils.message(this.pageContext, this.bundle,
                    this.locale, report.getKey(), report.getValues());


            if (message != null) {

                try {
                    jsonErrors.put(property, message);

                } catch (JSONException e) {
                    throw new JspException(e);

                }
            }

        }


    }
}
This is the tag descriptor for the above tag. Nothing interesting here. Just copy and paste this into struts-ext-html.tld.
src/main/webapp/WEB-INF/struts-ext-html.tld
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN" "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">

<taglib>
    <tlibversion>1.2</tlibversion>

    <jspversion>1.1</jspversion>
    <shortname>html-ext</shortname>

    <tag>

        <name>errors</name>
        <tagclass>com.test.ExtJsonErrorsTag</tagclass>

        <bodycontent>empty</bodycontent>
        <attribute>

            <name>bundle</name>
            <required>false</required>

            <rtexprvalue>true</rtexprvalue>
        </attribute>

        <attribute>
            <name>footer</name>

            <required>false</required>
            <rtexprvalue>true</rtexprvalue>

        </attribute>
        <attribute>

            <name>header</name>
            <required>false</required>

            <rtexprvalue>true</rtexprvalue>
        </attribute>

        <attribute>
            <name>locale</name>

            <required>false</required>
            <rtexprvalue>true</rtexprvalue>

        </attribute>
        <attribute>

            <name>name</name>
            <required>false</required>

            <rtexprvalue>true</rtexprvalue>
        </attribute>

        <attribute>
            <name>prefix</name>

            <required>false</required>
            <rtexprvalue>true</rtexprvalue>

        </attribute>
        <attribute>

            <name>property</name>
            <required>false</required>

            <rtexprvalue>true</rtexprvalue>
        </attribute>

        <attribute>
            <name>suffix</name>

            <required>false</required>
            <rtexprvalue>true</rtexprvalue>

        </attribute>
    </tag>

</taglib>
Action Class and JSP
This is where you provide logic that will run after the form is validated. Control will only be passed to the execute method when the form is fully validated.
src/main/java/com/test/UserSubmitAction.java
package com.test;
  

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


import org.apache.struts.action.ActionForm;

import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

  
public class UserSubmitAction extends org.apache.struts.action.Action {

    public ActionForward execute(ActionMapping mapping,ActionForm form,
           HttpServletRequest request,HttpServletResponse response) throws Exception {

  
        System.out.println("action ran.");


        return mapping.findForward("success");

    }
}
The following JSP presents an extJS form to allow the user to enter data.
src/main/webapp/index.jsp
<html>
<head>

  
<link rel="stylesheet" type="text/css"

  

<script type="text/javascript"

</script>
<script type="text/javascript"

</script>

  
<script type="text/javascript">

function buildWindow() {
    Ext.QuickTips.init();

    Ext.form.Field.prototype.msgTarget = 'side';
    var bd = Ext.getBody();


    var fs = new Ext.FormPanel({

        labelWidth: 75,
        frame: true,

        title:'Form with crazy amount of validation',
        bodyStyle:'padding:5px 5px 0',

        width: 350,
        defaults: {width: 230},

        waitMsgTarget: true,
        defaultType: 'textfield',      

  
        items: [{

                fieldLabel: 'First Name',
                name: 'firstName'

            },{
                fieldLabel: 'Last Name',

                name: 'lastName'
            },{

                fieldLabel: 'Company',
                name: 'company'

            }, {
                fieldLabel: 'Email',

                name: 'email',
                vtype:'email'

            },{
                fieldLabel: 'Time',

                name: 'time'
            }

        ],      
  

    });
  

    var onSuccessOrFail = function(form, action) {
        var result = action.result;

  
        if(result.success) {

            Ext.MessageBox.alert('Success', 'Success!');
        } else { // put code here to handle form validation failure.

        }
  

    }
  

    var submit = fs.addButton({
        text: 'Submit',

        disabled:false,
        handler: function(){

            fs.getForm().submit({
                url:'/form/UserSubmit',

                waitMsg:'Submitting Data...',
                submitEmptyText: false,

                success : onSuccessOrFail,
                failure : onSuccessOrFail

            });
        }

    });
  

    fs.render('form-first');
}

Ext.onReady(buildWindow);
</script>

</head>
<body>

<div id="form-first"></div>
</body>

</html>
Success and Failure JSP’s
This JSP displays regardless if there was a validation failure or not. This is to satisfy the extJS component requirement that all form submissions should return a result.
src/main/webapp/WEB-INF/result.jsp
<%@ taglib uri="/tags/struts-html-ext" prefix="html-ext" %>
<html-ext:errors/>
Validation configuration
All the fields of the form are required. In addition the first name must be at least 10 and no more than 15 characters. The email address must be valid formatted and the time field must be in the proper format in order to proceed. All of this is coded into the following file.
src/main/webapp/WEB-INF/validation.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE form-validation PUBLIC

          "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1.3//EN"

  
<form-validation>

<formset>
<form name="userInformation">

    <field property="firstName" depends="required,minlength,maxlength">
        <arg0 key="userInformation.firstName" />

        <arg1 name="minlength" key="${var:minlength}" resource="false"/>
        <arg1 name="maxlength" key="${var:maxlength}" resource="false"/>

        <var>
            <var-name>minlength</var-name>

            <var-value>10</var-value>
        </var>

        <var>
            <var-name>maxlength</var-name>

            <var-value>15</var-value>
        </var>

         
    </field>

    <field property="lastName" depends="required">
        <arg key="userInformation.lastName" />

    </field>
    <field property="company" depends="required">

        <arg key="userInformation.company" />
    </field>

    <field property="email" depends="required,email">
        <arg key="userInformation.email" />

    </field>
    <field property="time" depends="required,mask">

        <msg name="mask" key="userInformation.time.maskmsg"/>
        <arg0 key="userInformation.time" />

        <var><var-name>mask</var-name><var-value>^[0-9]{1,2}:[0-9]{1,2} (AM|PM)$</var-value></var>
    </field>

</form>
</formset>

</form-validation>
Configure the Struts Framework
The following files are necessary to get the struts framework initialized and ready to process form submissions. The lines specific to this application have been highlighted.
Struts Config
The following struts configuration file contains a dyna-form and an action mapping. The /UserSubmit action mapping “input” page will be invoked if there are validation failures. If all goes well with validation the control will forward to “result.jsp” which will display JSON output expected by the extJS component.
src/main/webapp/WEB-INF/struts-config.xml
<?xml version="1.0" encoding="ISO-8859-1" ?>
    <!DOCTYPE struts-config PUBLIC

          "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"


<struts-config>

    <form-beans>
        <form-bean name="userInformation"

            type="org.apache.struts.validator.DynaValidatorForm">
            <form-property name="firstName" type="java.lang.String" />

            <form-property name="lastName" type="java.lang.String" />
            <form-property name="company" type="java.lang.String" />

            <form-property name="email" type="java.lang.String" />
            <form-property name="time" type="java.lang.String" />

        </form-bean>
    </form-beans>


    <action-mappings>

        <action name="userInformation" path="/UserSubmit" input="/WEB-INF/result.jsp"
            type="com.test.UserSubmitAction" validate="true">

            <forward name="success" path="/WEB-INF/result.jsp"></forward>
        </action>

    </action-mappings>


    <!-- The "application.properties" is located in the root of the classpath. -->
    <message-resources parameter="application" />


    <plug-in className="org.apache.struts.validator.ValidatorPlugIn">

        <set-property property="pathnames"
            value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml," />

    </plug-in>


</struts-config>
The following file was taken from the commons-validator framework. It contains information about the various classes that perform validation. Just copy and paste this into validator-rules.xml. The client side JavaScript validation code has been removed since we will only be performing server side validation. I am thinking about writing another tutorial on how to have commons validator generate extJS specific client side JavaScript validation. Let me know if you guys are interested in seeing this.
src/main/webapp/WEB-INF/validator-rules.xml
<!DOCTYPE form-validation PUBLIC
          "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.0//EN"



<form-validation>
   <global>

      <validator name="required"
            classname="org.apache.struts.validator.FieldChecks"

               method="validateRequired"
         methodParams="java.lang.Object,

                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,

                       org.apache.struts.action.ActionErrors,
                       javax.servlet.http.HttpServletRequest"

                  msg="errors.required">
      </validator>


      <validator name="requiredif"

                 classname="org.apache.struts.validator.FieldChecks"
                 method="validateRequiredIf"

                 methodParams="java.lang.Object,
                               org.apache.commons.validator.ValidatorAction,

                               org.apache.commons.validator.Field,
                               org.apache.struts.action.ActionErrors,

                               org.apache.commons.validator.Validator,
                               javax.servlet.http.HttpServletRequest"

                 msg="errors.required">
      </validator>


      <validator name="minlength"

            classname="org.apache.struts.validator.FieldChecks"
               method="validateMinLength"

         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,

                       org.apache.commons.validator.Field,
                       org.apache.struts.action.ActionErrors,

                       javax.servlet.http.HttpServletRequest"
              depends=""

                  msg="errors.minlength">
      </validator>




      <validator name="maxlength"
            classname="org.apache.struts.validator.FieldChecks"

               method="validateMaxLength"
         methodParams="java.lang.Object,

                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,

                       org.apache.struts.action.ActionErrors,
                       javax.servlet.http.HttpServletRequest"

              depends=""
                  msg="errors.maxlength">


      </validator>




      <validator name="mask"
            classname="org.apache.struts.validator.FieldChecks"

               method="validateMask"
         methodParams="java.lang.Object,

                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,

                       org.apache.struts.action.ActionErrors,
                       javax.servlet.http.HttpServletRequest"

              depends=""
                  msg="errors.invalid">


      </validator>




      <validator name="byte"
            classname="org.apache.struts.validator.FieldChecks"

               method="validateByte"
         methodParams="java.lang.Object,

                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,

                       org.apache.struts.action.ActionErrors,
                       javax.servlet.http.HttpServletRequest"

              depends=""
                  msg="errors.byte"

       jsFunctionName="ByteValidations">
      </validator>


      <validator name="short"

            classname="org.apache.struts.validator.FieldChecks"
               method="validateShort"

         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,

                       org.apache.commons.validator.Field,
                       org.apache.struts.action.ActionErrors,

                       javax.servlet.http.HttpServletRequest"
              depends=""

                  msg="errors.short"
       jsFunctionName="ShortValidations">

      </validator>


      <validator name="integer"
            classname="org.apache.struts.validator.FieldChecks"

               method="validateInteger"
         methodParams="java.lang.Object,

                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,

                       org.apache.struts.action.ActionErrors,
                       javax.servlet.http.HttpServletRequest"

              depends=""
                  msg="errors.integer"

       jsFunctionName="IntegerValidations">
      </validator>


      <validator name="long"

            classname="org.apache.struts.validator.FieldChecks"
               method="validateLong"

         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,

                       org.apache.commons.validator.Field,
                       org.apache.struts.action.ActionErrors,

                       javax.servlet.http.HttpServletRequest"
              depends=""

                  msg="errors.long"/>
      <validator name="float"

            classname="org.apache.struts.validator.FieldChecks"
               method="validateFloat"

         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,

                       org.apache.commons.validator.Field,
                       org.apache.struts.action.ActionErrors,

                       javax.servlet.http.HttpServletRequest"
              depends=""

                  msg="errors.float"
       jsFunctionName="FloatValidations">

      </validator>


      <validator name="double"
            classname="org.apache.struts.validator.FieldChecks"

               method="validateDouble"
         methodParams="java.lang.Object,

                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,

                       org.apache.struts.action.ActionErrors,
                       javax.servlet.http.HttpServletRequest"

              depends=""
                  msg="errors.double"/>


      <validator name="date"

            classname="org.apache.struts.validator.FieldChecks"
               method="validateDate"

         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,

                       org.apache.commons.validator.Field,
                       org.apache.struts.action.ActionErrors,

                       javax.servlet.http.HttpServletRequest"
              depends=""

                  msg="errors.date"
       jsFunctionName="DateValidations">




      </validator>


<!-- range is deprecated use intRange instead -->
      <validator name="range"

            classname="org.apache.struts.validator.FieldChecks"
               method="validateIntRange"

         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,

                       org.apache.commons.validator.Field,
                       org.apache.struts.action.ActionErrors,

                       javax.servlet.http.HttpServletRequest"
              depends="integer"

                  msg="errors.range">
      </validator>


      <validator name="intRange"

            classname="org.apache.struts.validator.FieldChecks"
               method="validateIntRange"

         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,

                       org.apache.commons.validator.Field,
                       org.apache.struts.action.ActionErrors,

                       javax.servlet.http.HttpServletRequest"
              depends="integer"

                  msg="errors.range">


      </validator>


      <validator name="floatRange"
            classname="org.apache.struts.validator.FieldChecks"

               method="validateFloatRange"
         methodParams="java.lang.Object,

                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,

                       org.apache.struts.action.ActionErrors,
                       javax.servlet.http.HttpServletRequest"

              depends="float"
                  msg="errors.range">

      </validator>


      <validator name="creditCard"
            classname="org.apache.struts.validator.FieldChecks"

               method="validateCreditCard"
         methodParams="java.lang.Object,

                       org.apache.commons.validator.ValidatorAction,
                       org.apache.commons.validator.Field,

                       org.apache.struts.action.ActionErrors,
                       javax.servlet.http.HttpServletRequest"

              depends=""
                  msg="errors.creditcard">


      </validator>


     <validator name="email"

            classname="org.apache.struts.validator.FieldChecks"
              method="validateEmail"

         methodParams="java.lang.Object,
                       org.apache.commons.validator.ValidatorAction,

                      org.apache.commons.validator.Field,
                      org.apache.struts.action.ActionErrors,

                       javax.servlet.http.HttpServletRequest"
              depends=""

                  msg="errors.email">
      </validator>

   </global>
</form-validation>
The following file contains the messages to display to the user.
src/main/resources/application.properties
errors.required={0} is required.
errors.minlength={0} can not be less than {1} characters.

errors.maxlength={0} can not be greater than {1} characters.
errors.invalid={0} is invalid.

  
errors.byte={0} must be a byte.

errors.short={0} must be a short.
errors.integer={0} must be an integer.

errors.long={0} must be a long.
errors.float={0} must be a float.

errors.double={0} must be a double.
  

errors.date={0} is not a date.
errors.range={0} is not in the range {1} through {2}.

errors.creditcard={0} is an invalid credit card number.
errors.email={0} is an invalid e-mail address.


userInformation.firstName=First Name

userInformation.lastName=Last Name
userInformation.company=company

userInformation.email=email
userInformation.time=time

userInformation.time.maskmsg=Time must be formatted like (##:## AM|PM)
This is a bare minimum log4j.properties file.
src/main/resources/log4j.properties
# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=INFO, A1

  
log4j.appender.A1=org.apache.log4j.ConsoleAppender

log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d %-5p %c - %m%n
src/main/webapp/WEB-INF/web.xml
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"



<web-app>
  <display-name>Archetype Created Web Application</display-name>


    <servlet>

        <servlet-name>action</servlet-name>
        <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>

        <init-param>
            <param-name>config</param-name>

            <param-value>
         /WEB-INF/struts-config.xml

        </param-value>
        </init-param>

        <load-on-startup>1</load-on-startup>
  

    </servlet>
  

    <servlet-mapping>
        <servlet-name>action</servlet-name>

        <url-pattern>/form/*</url-pattern>
    </servlet-mapping>


  <!-- Struts Tag Library Descriptors -->

  
  <taglib>

    <taglib-uri>/tags/struts-html-ext</taglib-uri>
    <taglib-location>/WEB-INF/struts-ext-html.tld</taglib-location>

  </taglib>
   

</web-app>
Test the application
In the project top folder type in the following command to compile and run the code in jetty servlet engine.
mvn clean compile jetty:run
Navigate to the following URL:
http://localhost:8080/
An extJS form should display allowing you to enter values. Click submit and an Ajax form submission will be made to the Struts Action. Any validation failures will show next to the component.
That’s all for now.

0 comments:

Post a Comment