一个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>

实现一个配置简单功能强大的excel工具类搞定excel导入导出(二)

上篇文章留了个小悬念,您是否有这样的需求呢: 1.实体类中存放的值是一个编码,而导出的文件中需要把编码转成有意义的文字.例如:实体类中性别用0,1表示,而希望导出的excel文件中是"男","女"....
  • lk_blog
  • lk_blog
  • 2012年09月22日 17:54
  • 7082

一个简单、漂亮、功能强大的Android日志程序:logger

一个简单、漂亮、功能强大的Android日志程序。  日志程序提供了 :  线程信息Thread information 类信息Class information 方法信息Method inf...

joomla中的一个功能强大的相册

  • 2010年01月21日 11:52
  • 192KB
  • 下载

SuperSwipeRefreshLayout 一个功能强大的自定义下拉刷新组件

SuperSwipeRefreshLayout一个功能强大的自定义下拉刷新组件。Why?下拉刷新这种控件,想必大家用的太多了,比如使用很多的XListView等。最近,项目中很多列表都是使用Reycl...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:一个webwork下功能强大的FormTag实现
举报原因:
原因补充:

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