上篇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> 
|