一个webwork下功能强大的FormTag实现

原创 2005年05月11日 13:37:00

  上篇html标记看法中说到的tag标记实现,现在有了雏形,个人比较喜欢webwork,因此就写了个webwork兼容的tag实现。

  只需要在表单中修改form标记为<wwx:form ... ,所有的表单域属性都会自动帮定,无须改动原有html标记,也就是说不需要引入<ww:textfield>等标记,当然webwork的表单域标记中的自动错误输出我没实现,因为我不太喜欢这样的方式输出错误信息,如果想输出可以使用<ww:text>标记,此外这个form标记还可以自动输出webwork中客户端验证的javascript脚本。

  当然如果你喜欢在webwork中用jstl的话还得写个JSTLFilter。

package net.libo.web.taglib;

import java.io.Writer;
import java.util.HashMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyContent;

import org.apache.velocity.Template;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.context.Context;

import com.opensymphony.webwork.ServletActionContext;
import com.opensymphony.webwork.config.Configuration;
import com.opensymphony.webwork.views.jsp.ParametereizedBodyTagSupport;
import com.opensymphony.webwork.views.jsp.TagUtils;
import com.opensymphony.webwork.views.util.JavaScriptValidationHolder;
import com.opensymphony.webwork.views.util.UrlHelper;
import com.opensymphony.webwork.views.velocity.AbstractTagDirective;
import com.opensymphony.webwork.views.velocity.VelocityManager;
import com.opensymphony.xwork.ActionContext;
import com.opensymphony.xwork.ObjectFactory;
import com.opensymphony.xwork.config.ConfigurationManager;
import com.opensymphony.xwork.config.entities.ActionConfig;
import com.opensymphony.xwork.util.OgnlValueStack;

import net.libo.web.util.HtmlEncoder;
import net.libo.web.util.HtmlUtils;

/**
 * @author Boyce
 *
 * Form tag populates a included form with values and
 * generates the client-side validation script.
 */
public class FormTag extends ParametereizedBodyTagSupport  {

    final public static String OPEN_TEMPLATE = "form.vm";
    final public static String TEMPLATE = "form-close.vm";

    Class actionClass;
    String actionName;
    JavaScriptValidationHolder javaScriptValidationHolder;

    String nameAttr;
    String actionAttr;
    String targetAttr;
    String enctypeAttr;
    String methodAttr;
    String namespaceAttr;
    String validateAttr;
   
 
    //~ Methods ////////////////////////////////////////////////////////////////

    public void setAction(String action) {
        this.actionAttr = action;
    }

    public void setName(String name) {
        this.nameAttr = name;
    }
   
    public void setTarget(String target) {
        this.targetAttr = target;
    }

    public Class getActionClass() {
        return actionClass;
    }

    public String getActionName() {
        return actionName;
    }

    public void setEnctype(String enctype) {
        this.enctypeAttr = enctype;
    }

    public void setMethod(String method) {
        this.methodAttr = method;
    }

    public void setNamespace(String namespace) {
        this.namespaceAttr = namespace;
    }

    public void setValidate(String validate) {
        this.validateAttr = validate;
    }

    protected String getDefaultTemplate() {
        return TEMPLATE;
    }

    public String getDefaultOpenTemplate() {
        return OPEN_TEMPLATE;
    }


    public int doStartTag() {
        try {
            evaluateParams(getStack());
            mergeTemplate(getDefaultOpenTemplate());
        } catch (Exception e) {
            return SKIP_PAGE;
        }
        return EVAL_BODY_AGAIN;
    }

    /**
     * Performs smart form population.
     *
     * @return SKIP_BODY
     */
    public int doAfterBody() {
        BodyContent body = getBodyContent();
        try  {
            JspWriter out = body.getEnclosingWriter();
            String bodytext = body.getString();
            bodytext = populateForm(bodytext, getStack());
            out.print(bodytext);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return SKIP_BODY;
    }


    /**
     * End of tag.
     *
     * @return EVAL_PAGE
     * @throws JspException
     */
    public int doEndTag() throws JspException {
        try {
            try {
                evaluateParams(getStack());
                mergeTemplate(this.getDefaultTemplate());
                return EVAL_PAGE;
            } catch (Exception e) {
                throw new JspException("Fatal exception caught in " + this.getClass().getName() + " tag class, doEndTag: " + e.getMessage(), e);
            }
        } finally {
            // clean up after ourselves to allow this tag to be reused
            this.reset();
        }
    }


    protected void mergeTemplate(String templateName) throws Exception {

        // initialize the VelocityEngine
        // this may happen more than once, but it's not a big deal
        VelocityManager velocityManager = VelocityManager.getInstance();
        velocityManager.init(pageContext.getServletContext());
        VelocityEngine velocityEngine = velocityManager.getVelocityEngine();

        Template t = velocityEngine.getTemplate(templateName);

        Context context = velocityManager.createContext(getStack(),
                (HttpServletRequest) pageContext.getRequest(),
                (HttpServletResponse) pageContext.getResponse());

        Writer outputWriter = (Writer) ActionContext.getContext().get(AbstractTagDirective.VELOCITY_WRITER);
        if (outputWriter == null) {
            outputWriter = pageContext.getOut();
        }

        context.put("tag", this);
        context.put("parameters", getParameters());

        t.merge(context, outputWriter);
   
    }
   

    public void evaluateParams(OgnlValueStack stack) {

        if (actionAttr != null) {
            /**
             * If called from a JSP, pageContext will not be null.  otherwise, we'll get request and response from the
             * ServletActionContext.
             *
             * todo - determine if there's any reason we can't just always use ServletActionContext
             * -> because we want to be able to use the tags if we went directly to the page
             */
            HttpServletResponse response;
            HttpServletRequest request;

            if (pageContext != null) {
                response = (HttpServletResponse) pageContext.getResponse();
                request = (HttpServletRequest) pageContext.getRequest();
            } else {
                request = ServletActionContext.getRequest();
                response = ServletActionContext.getResponse();
            }

            final String action = (String) findString(actionAttr);
            String namespace;

            if (namespaceAttr == null) {
                namespace = TagUtils.buildNamespace(getStack(), (HttpServletRequest) pageContext.getRequest());
            } else {
                namespace = findString(namespaceAttr);
            }

            if (namespace == null) {
                namespace = "";
            }

            final ActionConfig actionConfig = ConfigurationManager.getConfiguration().getRuntimeConfiguration().getActionConfig(namespace, action);

            if (actionConfig != null) {
                try {
                    actionClass = ObjectFactory.getObjectFactory().getClassInstance(actionConfig.getClassName());
                } catch (ClassNotFoundException e) {
                    // this is ok
                }

                actionName = action;

                String result = UrlHelper.buildUrl(namespace + "/" + action + "." + Configuration.get("webwork.action.extension"), request, response, null);
                addParameter("action", result);
                addParameter("namespace", namespace);

                // if the name isn't specified, use the action name
                if (nameAttr == null) {
                    addParameter("name", action);
                }

                // if the id isn't specified, use the action name
                if (id == null) {
                    addParameter("id", action);
                }
            } else if (action != null) {
                String result = UrlHelper.buildUrl(action, request, response, null);
                addParameter("action", result);

                // namespace: cut out anything between the start and the last /
                int slash = result.lastIndexOf('/');
                if (slash != -1) {
                    addParameter("namespace", result.substring(0, slash));
                } else {
                    addParameter("namespace", "");
                }

                // name/id: cut out anything between / and . should be the id and name
                if (id == null) {
                    slash = result.lastIndexOf('/');
                    int dot = result.indexOf('.', slash);
                    if (dot != -1) {
                        id = result.substring(slash + 1, dot);
                    } else {
                        id = result.substring(slash + 1);
                    }
                    addParameter("id", id);
                }
            }

            // only create the javaScriptValidationHolder if the actionName,and class is known
            // and the javaScriptValidationHolder hasn't been created already
            // i.e. don'r re-create it on the second call to evaluateExtraParams
            if (actionName != null && actionClass != null && javaScriptValidationHolder == null) {
                javaScriptValidationHolder = new JavaScriptValidationHolder(actionName, actionClass, getStack());
            }
        }
       
        if (nameAttr != null) {
            addParameter("name", findString(nameAttr));
        }

        if (targetAttr != null) {
            addParameter("target", findString(targetAttr));
        }

        if (enctypeAttr != null) {
            addParameter("enctype", findString(enctypeAttr));
        }

        if (methodAttr != null) {
            addParameter("method", findString(methodAttr));
        }

        if (validateAttr != null) {
            addParameter("validate", findValue(validateAttr, Boolean.class));
        }

        if (javaScriptValidationHolder != null && javaScriptValidationHolder.hasValidators()) {
            addParameter("javascriptValidation", javaScriptValidationHolder.toJavaScript());
        } else {
            addParameter("javascriptValidation", "// cannot find any applicable validators");
        }
    }

 // ---------------------------------------------------------------- populate

 private String populateForm(String html, OgnlValueStack valueStack) {
  int i = 0, s = 0;
  StringBuffer result = new StringBuffer(html.length());
  String currentSelectName = null;
  while (true) {
   // find starting tag
   i = html.indexOf('<', s);
   if (i == -1) {
    result.append(html.substring(s));
    break;  // input tag not found
   }
   result.append(html.substring(s, i)); // tag found, all before tag is stored
   s = i;

   // find closing tag
   i = html.indexOf('>', i);
   if (i == -1) {
    result.append(html.substring(s));
    break;  // closing tag not found
   }
   i++;

   // match tags
   String tag = html.substring(s, i);
            //System.out.println(tag);
   String tagName = HtmlUtils.getTagName(tag);
   if (tagName.equalsIgnoreCase("input") == true) {
    String tagType = HtmlUtils.getAttribute(tag, "type");
    if (tagType != null) {
     String name = HtmlUtils.getAttribute(tag, "name");
                    HashMap params = new HashMap();
                    params.put("name", name);
                    javaScriptValidationHolder.registerValidateField((String) name, params);
     Object vobj = valueStack.findValue(name);
     if (vobj != null) {
      String value = vobj.toString();
      tagType = tagType.toLowerCase();
      if (tagType.equals("text")) {
       tag = HtmlUtils.addAttribute(tag, "value", value);
      } if (tagType.equals("hidden")) {
       tag = HtmlUtils.addAttribute(tag, "value", value);
      } if (tagType.equals("image")) {
       tag = HtmlUtils.addAttribute(tag, "value", value);
      } if (tagType.equals("password")) {
       tag = HtmlUtils.addAttribute(tag, "value", value);
      } if (tagType.equals("checkbox")) {
       String tagValue = HtmlUtils.getAttribute(tag, "value");
       if (tagValue == null) {
        tagValue = "true";
       }
       if (tagValue.equals(value)) {
        tag = HtmlUtils.addAttribute(tag, "checked");
       }
      } if (tagType.equals("radio")) {
       String tagValue = HtmlUtils.getAttribute(tag, "value");
       if (tagValue != null) {
        if (tagValue.equals(value)) {
         tag = HtmlUtils.addAttribute(tag, "checked");
        }
       }
      }
     }
    }
   } else if (tagName.equalsIgnoreCase("textarea") == true) {
    String name = HtmlUtils.getAttribute(tag, "name");
    Object value = valueStack.findValue(name);
    if (value != null) {
     if (value != null) {
      tag += HtmlEncoder.encode(value.toString());
     }
    }
   } else if (tagName.equalsIgnoreCase("select") == true) {
    currentSelectName = HtmlUtils.getAttribute(tag, "name");
   } else if (tagName.equalsIgnoreCase("/select") == true) {
    currentSelectName = null;
   } else if (tagName.equalsIgnoreCase("option") == true) {
    if (currentSelectName != null) {
     String tagValue = HtmlUtils.getAttribute(tag, "value");
     if (tagValue != null) {
      Object vals = valueStack.findValue(currentSelectName);

      if (vals != null) {
       if (vals.getClass().isArray() == false) {
        String value = vals.toString();
        if (value.equals(tagValue)) {
         tag = HtmlUtils.addAttribute(tag, "selected");
        }
       } else {
        Object[] arr = (Object[])vals;
        for (int j=0;j<arr.length;j++) {
         arr[j] = arr[j].toString();
        }
        String vs[] = (String[])arr;
        for (int k = 0; k < vs.length; k++) {
         String vsk = vs[k];
         if (vsk != null) {
          if (vsk.equals(tagValue)) {
           tag = HtmlUtils.addAttribute(tag, "selected");
          }
         }
        }
       }
      }

     }
    }
   }
   result.append(tag);
   s = i;
  }
  return result.toString();
 }


    protected void reset() {
        this.getParameters().clear();
        javaScriptValidationHolder = null;
        if (getActionName() != null && getActionClass() != null) {
            javaScriptValidationHolder = new JavaScriptValidationHolder(getActionName(), getActionClass(), getStack());
        }
    }

}

还有两个util类就不放到这了,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.1</tlibversion>
    <jspversion>1.2</jspversion>
    <shortname>wwx</shortname>
    <uri>wwx</uri>
   
    <tag>
        <name>form</name>
        <tagclass>net.libo.web.taglib.FormTag</tagclass>
        <bodycontent>JSP</bodycontent>
        <info>An HTML Component UI widget</info>
        <attribute>
            <name>name</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
        </attribute>
        <attribute>
            <name>action</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
        </attribute>
        <attribute>
            <name>target</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
        </attribute>
        <attribute>
            <name>namespace</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
        </attribute>
        <attribute>
            <name>method</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
        </attribute>
        <attribute>
            <name>enctype</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
        </attribute>
        <attribute>
            <name>validate</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
        </attribute>
    </tag>
</taglib>

Spring Form Tags

在这个例子里你将会看到如何使用动态值来填充表单。 注册表单registration.jsp页面. [html] view plaincopy ...
  • cl1771066100
  • cl1771066100
  • 2013年12月06日 11:06
  • 1166

spring3 jsp页面使用<form:form modelAttribute="xxxx" action="xxxx">报错,附连接数据库的spring MVC annotation 案例

在写一个使用spring3 的form标签的例子时,一直报错,错误信息为:java.lang.IllegalStateException: Neither BindingResult nor plai...
  • yeohcooller
  • yeohcooller
  • 2012年05月18日 17:29
  • 31609

SpringMVC<from:form>表单标签和<input>表单标签简介

表单相关问题介绍
  • hp_yangpeng
  • hp_yangpeng
  • 2016年07月14日 10:11
  • 43609

【Rails】form_for与form_tag分别用于什么情况

中午在做网站的密码修改功能时,发现form_for无法使用,因为这个表单一共三个密码框,旧密码和两次新密码,跟REST里面的edit和new完全不同,无法对应到某个model  上ruby-...
  • chunyang2178
  • chunyang2178
  • 2013年10月16日 14:26
  • 2636

Spring web MVC和spring 2.0 form tag解说

  • 2008年07月19日 15:17
  • 241KB
  • 下载

WebWork主要配置文件(一)

WebWork有两个主要配置文件:web.xml 和 xwork.xml.在下面您可以找到WebWork必须和可选的配置文件的所有信息.下面是您需要注意的所有文件.为了使开发更容易,其中的一些是可以动...
  • yehell
  • yehell
  • 2008年01月08日 14:40
  • 2545

webwork中文件上传实现

 [简单介绍]webwork 文件上传采用拦截器的方式,叫fileUpload 可供选择的上传组件有pell(2.1.7默认)jakata(2.2及以后默认),cos[例子][注意事项]1、cos和p...
  • zoucui
  • zoucui
  • 2007年03月05日 13:45
  • 3138

一个webwork下功能强大的FormTag实现

  上篇html标记看法中说到的tag标记实现,现在有了雏形,个人比较喜欢webwork,因此就写了个webwork兼容的tag实现。  只需要在表单中修改form标记为等标记,当然webwork的表...
  • boyce_lee
  • boyce_lee
  • 2005年05月11日 13:37
  • 860

SpringMVC<from:form>表单标签封装表单对象

SpringMVC表单标签和表单标签简介 标签: spring mvcformforminput 2016-07-14 10:11 10965人阅读 评论(1) 收藏 ...
  • BeyondLCG
  • BeyondLCG
  • 2017年04月14日 20:44
  • 1881

Webwork文件上传

WebWork利用ognl实现的资料绑定是非常实用的功能, 能够避免繁琐调用request.getParameter, object setter, 也不需要任何的多余配置文件, 再加上转换器的功能(...
  • babydavic
  • babydavic
  • 2007年10月09日 09:55
  • 3332
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:一个webwork下功能强大的FormTag实现
举报原因:
原因补充:

(最多只允许输入30个字)