公司框架学习之JSP布局之自定义查询标签《四》

一、效果

  图1

  图2

 

二、源码

          <query:form name="Form">
			<query:selectx name="QUES_TYPE" label="题型" source="SYS.TLX" value=""/>
			<query:selectx name="QUES_CONFIG" label="题标识" source="SYS.TBS" value=""/>
		</query:form>

  

三、源码分析

  最外层是easyui的Form表单,源码上已经看不出easyui代码,全用自定义标签封装了,此处的标签内容全是作为输入,为后面封装做参数的。SYS.TLX和SYS.TBS两个参数是从数据库字典中获取的。

  1.自定义标签

    query标签库:  

<%@ taglib uri="http://dev.feiwei.cn/tags/query" prefix="query"%>

    query.tld

<?xml version="1.0" encoding="UTF-8" ?>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org   
/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2e   
e web-jsptaglibrary_2_0.xsd" version="2.0">
	<tlib-version>1.0</tlib-version>
	<jsp-version>2.0</jsp-version>
	<short-name>query tag</short-name>
	<uri>http://dev.feiwei.cn/tags/query</uri>
	<tag>
		<name>form</name>
		<tag-class>com.feiwei.framework.web.tag.query.FormTag</tag-class>
		<body-content>scriptless</body-content>
		<attribute>
			<name>id</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<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>onBeforeSubmit</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>cols</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>style</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>validate</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>queryCode</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>dataOptions</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>layout</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>queryParams</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
	</tag>
        <tag>
		<name>selectx</name>
		<tag-class>com.feiwei.framework.web.tag.query.SelectxTag</tag-class>
		<body-content>scriptless</body-content>
		<attribute>
			<name>id</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>name</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>placeholder</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>bind</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>event</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>bean</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>label</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>value</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>source</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>style</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>className</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>readonly</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>disabled</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>format</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>multiple</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>colspan</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>fill</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>required</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>validType</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>missingMessage</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>invalidMessage</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>formatter</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>parse</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>choose</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>chooseText</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>includes</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>excludes</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>merge</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>dataOptions</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>panelWidth</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>panelHeight</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>queryParams</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>showOperator</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>operators</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>autoQuery</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>tooltip</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
	</tag>
    </taglib>

  FormTag.java

  

package com.feiwei.framework.web.tag.query;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.feiwei.framework.config.QueryConfig;
import com.feiwei.framework.pojo.SysQuery;
import com.feiwei.framework.util.JSONUtils;
import com.feiwei.framework.util.StringUtils;
import com.feiwei.framework.web.html.QueryHtml;
import com.feiwei.framework.web.html.query.ButtonHtml;
import com.feiwei.framework.web.html.query.HiddenHtml;
import com.feiwei.framework.web.tag.AbstractTag;
import com.feiwei.framework.web.tag.FormContainer;
import com.feiwei.framework.web.tag.util.PageUtils;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

public class FormTag extends AbstractTag implements FormContainer<QueryHtml> {
    private static final Log log = LogFactory.getLog(FormTag.class);
    public static final String FORM_INSTANCE = "FORM_INSTANCE";
    private List<QueryHtml> inputs = new ArrayList();
    private int cols = 3;
    private String id;
    private String name;
    private String action;
    private String target;
    private String onBeforeSubmit;
    private String style;
    private boolean validate = true;
    private String queryCode;
    private String dataOptions;
    private String layout = "table";
    private String queryParams;

    public void setId(String id) {
        this.id = id;
        if (this.name == null) {
            this.name = id;
        }
    }

    public void setName(String name) {
        this.name = name;
        if (this.id == null) {
            this.id = name;
        }
    }

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

    public void setTarget(String target) {
        this.target = target;
    }

    public void setOnBeforeSubmit(String onBeforeSubmit) {
        this.onBeforeSubmit = onBeforeSubmit;
    }

    public void setCols(int cols) {
        this.cols = cols;
    }

    public void setStyle(String style) {
        this.style = style;
    }

    public void setQueryCode(String queryCode) {
        this.queryCode = queryCode;
    }

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

    public void setDataOptions(String dataOptions) {
        this.dataOptions = dataOptions;
    }

    public void setLayout(String layout) {
        this.layout = layout;
    }

    public void setQueryParams(String queryParams) {
        this.queryParams = queryParams;
    }

    protected void init() {
        this.jspContext.setAttribute("FORM_INSTANCE", this);
    }
    //添加QueryHtml类或其子类入list<QueryHtml>容器中
    public void add(QueryHtml item) {
        this.inputs.add(item);
    }

    public void doTag() throws JspException {
        try {
            StringBuilder html = getHtml();
            this.out.write(html.toString());
            this.out.flush();
        } catch (Exception e) {
            log.error(e);
            e.printStackTrace();
            e.printStackTrace(new PrintWriter(this.out));
        } finally {
            this.jspContext.setAttribute("FORM_INSTANCE", null);
        }
    }
    private StringBuilder getHtml() throws Exception {
        JspFragment body = getJspBody();
        //初始化时 layout = "table"
        if ("table".equals(this.layout)) {
            if (body != null) {
                //标签体对象的invoke()用于执行JspFragment对象所代表的JSP代码片段
                //参数用于指定将JspFragment对象的执行结果写入到哪个输出流对象中
                //执行标签体中标签<query:selectx></query:selectx>,执行完之后将添加两个QueryHtml对象到List中
                body.invoke(this.out);
            }
            return getTableHtml();
        }
        if ("float".equals(this.layout)) {
            if (body != null) {
                body.invoke(this.out);
            }
            return getFloatHtml();
        }
        if ("custom".equals(this.layout)) {
            this.jspContext.setAttribute("FORM_INSTANCE", null);
        }
        return new StringBuilder();
    }
    //拼接整个easyui-From表单
    public StringBuilder getTableHtml() throws Exception {
        List<QueryHtml> inputs = getQueryInputs();
        List<QueryHtml> params = getParams(getLayoutInputs(inputs));
        List<QueryHtml> hiddens = getHiddens(inputs);
        List<QueryHtml> buttons = getButtons(inputs);
        StringBuilder html = new StringBuilder(2048);
        //拼接html,根据jsp页面属性-值
        html.append("<form id='" + this.id + "' class='query-form' " + getAction() + getTarget() + getStyle()
                + getValidate() + getDataOptions() + onBeforeSubmit() + " method='post'> \n");
        //拼接input类型为hidden标签
        html.append(getHiddenHtml(hiddens));
        html.append("\t<table class='query-table' style='width:auto;height:32px;'> \n");
        int i = 0;
        for (int k = 1; i < params.size(); k++) {
            QueryHtml builder = (QueryHtml) params.get(i);
            if (k == 1) {
                html.append("<tr>\n");
            }
            //拼接标签体中子标签html
            html.append(getParamHtml(builder));
            //拼接查询按钮标签
            if (k == this.cols) {
                if (i <= this.cols) {
                    html.append("<td style='text-align:right;white-space:nowrap;'>\n");
                    for (QueryHtml button : buttons) {
                        html.append(button.getHtml(false));
                    }
                    html.append("<a type='button' name='_search' class='button query-btn'>查询</a>\n");
                    html.append("</td>\n");
                } else {
                    html.append("<td></td>\n");
                }
                html.append("</tr>\n");
                k = 0;
            }
            i++;
        }
        //收尾
        html.append("\t</table> \n");
        html.append(getQueryParamsHidden());
        html.append("</form> \n");
        return html;
    }

    public StringBuilder getFloatHtml() throws Exception {
        List<QueryHtml> params = getQueryInputs();
        List<QueryHtml> hiddens = getHiddens(this.inputs);
        StringBuilder html = new StringBuilder(2048);
        html.append("<form id='" + this.id + "' class='query-form' " + getAction() + getTarget() + getStyle()
                + getValidate() + getDataOptions() + " method='post'> \n");
        html.append(getHiddenHtml(hiddens));
        html.append("<ul style='height:30px;'> \n");
        for (int i = 0; i < params.size(); i++) {
            QueryHtml builder = (QueryHtml) params.get(i);
            if (builder != null) {
                String item = builder.getHtml(false);
                html.append("<li style='margin:5px;float:left'>");
                html.append(item);
                html.append("</li>");
            }
        }
        html.append("</ul> \n");
        html.append(getQueryParamsHidden());
        html.append("</form> \n");
        return html;
    }

    private List<QueryHtml> getQueryInputs() {
        //初始化 this.queryCode=null 返回原本list集合,有效元素:2
        if (this.queryCode != null) {
            SysQuery query = QueryConfig.getQuery(this.queryCode);
            List<QueryHtml> list = PageUtils.parseQueryParamJSON(query.getParams());
            this.inputs.addAll(list);
        }
        return this.inputs;
    }
    //判断是否有request
    private String getAction() {
        return this.action != null ? " action='" + this.ctx + this.action + "'" : "";
    }
    //判断是否在此页面打开url(response)
    private String getTarget() {
        return this.target != null ? " target='" + this.target + "'" : "";
    }
    //判断提交前是否有其他操作
    private String onBeforeSubmit() {
        return this.onBeforeSubmit != null ? " onBeforeSubmit='" + this.onBeforeSubmit + "'" : "";
    }
    
    private String getStyle() throws Exception {
        //初始this.style=null,so返回""
        if (StringUtils.isValid(this.style)) {
            return " style='" + this.style + "'";
        }
        return "";
    }

    protected String getDataOptions() {
        StringBuffer html = new StringBuffer(32);
        //初始this.dataOptions=null,so返回空字符串
        if (StringUtils.isValid(this.dataOptions)) {
            html.append(" data-options=\"" + this.dataOptions + "\"");
        }
        return html.toString();
    }
    //判断是否要验证,默认要验证
    private String getValidate() {
        return " validate='" + this.validate + "'";
    }
    //判断QueryHtml是否null,不会null就调用该QueryHtml的子类的getHtml实现html拼接
    //本案例中QueryHtml的子类为SelectxHtml
    private String getParamHtml(QueryHtml builder) throws Exception {
        if (builder == null) {
            return "<td></td><td></td><td></td>";
        }
        return builder.getHtml(true);
    }

    private List<QueryHtml> getParams(List<QueryHtml> items) {
        //初始化时 items.size=2 ,this.cols=3 
        int more = items.size() % this.cols;
        if (more > 0) {
            //more=1
            more = this.cols - more;
        }
        //在原基础上追加一个null元素
        for (int i = 0; i < more; i++) {
            items.add(null);
        }
        return items;
    }

    private List<QueryHtml> getLayoutInputs(List<QueryHtml> items) {
        List<QueryHtml> visibles = new ArrayList();
        //标签体中子标签返回list类型QueryHtml,本方法返回2个有效元素的List集合
        for (QueryHtml input : items) {
            if ((!(input instanceof HiddenHtml)) && (!(input instanceof ButtonHtml))) {
                visibles.add(input);
            }
        }
        return visibles;
    }

    private StringBuilder getHiddenHtml(List<QueryHtml> items) throws Exception {
        List<QueryHtml> hiddens = getHiddens(items);
        StringBuilder html = new StringBuilder(128);
        //hiddens为空集合,so返回空字符串
        for (QueryHtml hidden : hiddens) {
            html.append(hidden.getHtml(false));
        }
        return html;
    }

    private List<QueryHtml> getHiddens(List<QueryHtml> items) {
        List<QueryHtml> hiddens = new ArrayList();
        //items类型为QueryHtml,so返回空集合
        for (QueryHtml input : items) {
            if ((input instanceof HiddenHtml)) {
                hiddens.add(input);
            }
        }
        return hiddens;
    }

    private List<QueryHtml> getButtons(List<QueryHtml> items) {
        List<QueryHtml> hiddens = new ArrayList();
        //items类型为QueryHtml,so返回空集合
        for (QueryHtml input : items) {
            if ((input instanceof ButtonHtml)) {
                hiddens.add(input);
            }
        }
        return hiddens;
    }

    private StringBuilder getQueryParamsHidden() {
        StringBuilder html = new StringBuilder(128);
        if (StringUtils.isEmpty(this.queryParams)) {
            return html;
        }
        JSONArray array = null;
        if (this.queryParams.startsWith("[")) {
            array = JSONArray.fromObject(this.queryParams);
        } else {
            JSONObject object = (JSONObject) JSONUtils.parse(this.queryParams);
            array = JSONUtils.toNameValueJSONArray(object);
        }
        for (int i = 0; i < array.size(); i++) {
            JSONObject object = array.getJSONObject(i);
            String name = JSONUtils.getString(object, "name");
            String value = JSONUtils.getString(object, "value", "");
            String op = JSONUtils.getString(object, "op");
            html.append("<input type='hidden' id='" + name + "' name='" + name + "' value='" + value + "'/>\n");
            if (StringUtils.isValid(op)) {
                html.append("<input type='hidden' id='" + name + "_OP' name='" + name + "_OP' value='" + op + "'/>\n");
            }
        }
        return html;
    }
}

  SelectxTag.java

  

package com.feiwei.framework.web.tag.query;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.feiwei.framework.web.html.QueryHtml;
import com.feiwei.framework.web.html.query.QueryHtmlFactory;
import com.feiwei.framework.web.util.TagParam;
import com.feiwei.framework.web.util.TagParamSupport;
/**
 * 本类中没有重写doTag()方法,so要到父类QueryTag中去找
 * @author hongloumeng
 *
 */
public class SelectxTag extends QueryTag implements TagParamSupport {
    private static final Log log = LogFactory.getLog(SelectxTag.class);

    public void setOnSelect(String onSelect) {
        this.context.set("onSelect", onSelect);
    }

    public void setSource(String source) {
        this.context.set("source", source);
    }

    public void setMultiple(String multiple) {
        this.context.set("multiple", multiple);
    }

    public void setIncludes(String includes) {
        this.context.set("includes", includes);
    }

    public void setExcludes(String excludes) {
        this.context.set("excludes", excludes);
    }

    public void setPanelHeight(String height) {
        this.context.set("panelHeight", height);
    }

    public void setPanelWidth(String width) {
        this.context.set("panelWidth", width);
    }

    protected QueryHtml getItem() {
        //this.request和this.cotext是父类AbstractTag中的属性return QueryHtmlFactory.getSelectx(this.request, this.context);
    }

    public void addTagParam(TagParam parameter) {
        if ("sql".equals(parameter.getName())) {
            this.context.set("source", "sql:\n" + parameter.getValue());
        } else {
            this.context.set(parameter.getName(), parameter.getValue());
        }
    }
}

  QueryTag.java

  

package com.feiwei.framework.web.tag.query;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.feiwei.framework.web.html.QueryHtml;
import com.feiwei.framework.web.html.bean.ParamContext;
import com.feiwei.framework.web.tag.AbstractTag;
import com.feiwei.framework.web.tag.FormContainer;
import com.feiwei.framework.web.util.TagParam;

public abstract class QueryTag extends AbstractTag {
    private static final Log log = LogFactory.getLog(QueryTag.class);
    protected ParamContext context = new ParamContext();
    protected String id;
    protected String name;
    public void setId(String id) {
        this.context.set("id", id);
        this.context.set("name", id);
    }

    public void setName(String name) {
        this.context.set("name", name);
    }

    public void setLabel(String label) {
        this.context.set("label", label);
    }

    public void setValidate(String validate) {
        this.context.set("validate", validate);
    }

    public void setReadonly(String readonly) {
        this.context.set("readonly", readonly);
    }

    public void setStyle(String style) {
        this.context.set("style", style);
    }

    public void setParse(String parse) {
        this.context.set("parse", parse);
    }

    public void setFormat(String format) {
        this.context.set("format", format);
    }

    public void setClassName(String className) {
        this.context.set("className", className);
    }

    public void setValue(String value) {
        this.context.set("value", value);
    }

    public void setRequired(String required) {
        this.context.set("required", required);
    }

    public void setOptions(String options) {
        this.context.set("options", options);
    }

    public void setOperators(String operators) {
        this.context.set("operators", operators);
    }

    public void setOnChange(String onchange) {
        this.context.set("onChange", onchange);
    }

    public void setOnClick(String onClick) {
        this.context.set("onClick", onClick);
    }

    public void setValidType(String validType) {
        this.context.set("validType", validType);
    }

    public void setDataOptions(String dataOptions) {
        this.context.set("dataOptions", dataOptions);
    }

    public void setCustom(String custom) {
        this.context.set("custom", custom);
    }

    public void setBind(String bind) {
        this.context.set("bind", bind);
    }

    public void setEvent(String event) {
        this.context.set("event", event);
    }

    public void setPlaceholder(String placeholder) {
        this.context.set("placeholder", placeholder);
    }

    public void setShowOperator(String showOperator) {
        this.context.set("showOperator", showOperator);
    }

    public void setAutoQuery(String autoQuery) {
        this.context.set("autoQuery", autoQuery);
    }

    public void setTooltip(String tooltip) {
        this.context.set("tooltip", tooltip);
    }
    //判断是否在form标签体中
    public boolean isInForm() {
        return getFormInstance() != null;
    }
    //获取Form标签对象
    public FormTag getFormInstance() {
        //Tag文件为了给JSP页面返回一个对象,就必须将对象的名字以及该对象的引用存储到TomCat引擎提供的内置对象jspContext中,
        //这样,jsp页面才能使用该对象。
        FormTag instance = (FormTag) this.jspContext.getAttribute("FORM_INSTANCE");
        return instance;
    }

    public void addTagParam(TagParam bean) {
        super.addTagParam(bean);
        this.context.set(bean.getName(), bean.getValue());
    }
    //本类只是定义方法,实现在子类中完成,本案例是在Selectx类中重写
    protected abstract QueryHtml getItem();

    public void doTag() throws IOException, JspException {
        //判断是否在form标签体中
        boolean inForm = isInForm();
        //获取标签体内容
        JspFragment body = getJspBody();
        if (body != null) {
            //执行标签体JSP代码,将结果写入输出流中,本案例中该标签的标签体为空,so没有任何处理
            body.invoke(this.out);
        }
        //获取QueryHtml对应的子类对象
        QueryHtml builder = getItem();
        //判断是否在form标签体中
        if (inForm) {    
            //是则将该子标签对象添加进List<QueryHtml>容器中
            FormContainer<QueryHtml> form = getFormInstance();
            form.add(builder);
        } else {
            //不是则将该标签当作独立标签处理
            Writer out = getWriter();
            try {
                String html = builder.getHtml(false);
                out.write(html);
            } catch (Exception e) {
                log.error(e);
                e.printStackTrace(new PrintWriter(out));
            }
        }
    }
}

  QueryHtmlFactory.java

package com.feiwei.framework.web.html.query;

import com.feiwei.framework.web.html.QueryHtml;
import com.feiwei.framework.web.html.bean.ParamContext;
import javax.servlet.http.HttpServletRequest;

public class QueryHtmlFactory {
    //返回QueryHtml其下子类,本案例返回SelectxHtml类,ParamContext类用作将标签中属性和值按照键值对存入容器中
    public static QueryHtml getSelectx(HttpServletRequest request, ParamContext param) {
        return new SelectxHtml(request, param);
    }

}

  SelectxHtml.java

package com.feiwei.framework.web.html.query;

import com.feiwei.framework.config.DictConfig;
import com.feiwei.framework.pojo.SysDict;
import com.feiwei.framework.util.BeanUtils;
import com.feiwei.framework.util.Option;
import com.feiwei.framework.util.StringUtils;
import com.feiwei.framework.web.html.bean.ParamContext;
import java.util.List;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

public class SelectxHtml extends AbstractQueryHtml {
    public static final String CHOOSE_TEXT = "chooseText";

    public SelectxHtml(HttpServletRequest request, ParamContext param) {
        super(request, param);
    }
    //拼接selectx
    public String getHtml(boolean wrap) throws Exception {
        StringBuilder html = new StringBuilder(1024);
        String uid = String.valueOf(System.nanoTime());
        List<Option> options = (List) getSource();
        int defPanelHeight = options.size() * 25 > 200 ? 200 : options.size() * 25;
        String value = StringUtils.asString(getValue());
        append(html, new String[] { "<input class='easyui-selectx' " + getStyle("width:120px;") + " id='" + this.name
                + "' name='" + this.name + "' uid='" + uid + "' parse='true' input='true' value='" + value + "'" });
        append(html,
                new String[] { getEvent(), getBind(), getPlaceholder(), getTooltip(), getDataOptions(), getLabel(),
                        getMultiple(), getRequired(), getValidType(), getReadonly(), getDict(), getIncludes(),
                        getExcludes(), getAutoQuery(), "/> \n" });
        String sourceId = "source-" + uid;
        String templateId = "template-" + uid;
        append(html, new String[] { getSource(options, sourceId) });
        append(html, new String[] { getTemplate(templateId) });
        return wrap(this.label, html.toString(), wrap);
    }
    //从数据库字典中加载数据
    protected String getSource(List<Option> options, String dataId) throws Exception {
        Set<String> excludes = BeanUtils.toSet(this.excludes);
        Set<String> includes = BeanUtils.toSet(this.includes);
        JSONArray array = new JSONArray();
        for (Option bean : options) {
            JSONObject object = new JSONObject();
            String value = StringUtils.asString(bean.getValue());
            if ((!excludes.contains(value)) && ((includes.isEmpty()) || (includes.contains(value)))
                    && (!"0".equals(bean.getStatus()))) {
                String text = StringUtils.asString(bean.getText());
                object.put("value", value);
                object.put("text", text);
                array.add(object);
            }
        }
        return toScriptTextPlain(array.toString(), dataId);
    }
}

  还有AbstractQueryHtml.java、QueryHtml.java、Html.java没写,根据名称,大概也能猜出他们的作用了。

  源码编译后html代码:

<form id="Form" class="query-form" validate="true" method="post"> 
   <table class="query-table" style="width:auto;height:32px;"> 
    <tbody>
     <tr> 
      <td class="label">题型:</td>
      <td class="condition" colspan="2"><input class="easyui-selectx" style="width:120px;" id="QUES_TYPE" name="QUES_TYPE" uid="672797880083098" parse="true" input="true" value="" data-event="" data-bind="value:QUES_TYPE" placeholder="" label="题型" dict="SYS.TLX" includes="" excludes="" /> <script id="source-672797880083098" type="text/plain">[{"value":"1","text":"Java基础"},{"value":"2","text":"Java多线程"},{"value":"3","text":"Java集合"},{"value":"4","text":"Http协议与Socket以及网络编程"},{"value":"5","text":"JavaWeb基础"},{"value":"6","text":"spring与spring mvc"},{"value":"7","text":"Hibernate与Mybatis"},{"value":"8","text":"Maven与Linux常用命令"},{"value":"9","text":"项目相关知识"}]</script> </td>
      <td class="label">题标识:</td>
      <td class="condition" colspan="2"><input class="easyui-selectx" style="width:120px;" id="QUES_CONFIG" name="QUES_CONFIG" uid="672797881060657" parse="true" input="true" value="" data-event="" data-bind="value:QUES_CONFIG" placeholder="" label="题标识" dict="SYS.TBS" includes="" excludes="" /> <script id="source-672797881060657" type="text/plain">[{"value":"0","text":"单选题"},{"value":"1","text":"多选题"}]</script> </td>
      <td></td>
      <td></td>
      <td></td>
      <td style="text-align:right;white-space:nowrap;"> <a type="button" name="_search" class="button query-btn">查询</a> </td> 
     </tr> 
    </tbody>
   </table> 
  </form> 

  整个源码阅读过来,只要清楚自定义标签基本流程,按照流程阅读源码,即使再多封装、继承以及其他设计模式、debug一步步追踪,整个流程走一遍,基本就清楚了。

  总结:用自定义标签来封装easyui_form表单,form标签下可以有多种查询标签,用一个Query来包含所有query类型的子类标签,每种query标签展示用工厂设计模式来同一展示,省去多余代码。

为何要封装原始html代码?如何每个页面都写手写easyui代码,存在大量重复代码,比如基本页面布局、css样式、js文件引入,在加上一种标签有很多属性,没种属性都有不同用法,导致代码庞大,代码没有规范等。一旦封装了,代码量大幅下降,代码编写也规范,性能也提高。至于为何公司要自己写内部框架?个人认为,通用框架搭建,在实现生产中会出现产能过剩或不够用等麻烦,而架构师就需要根据需求去平衡,到达性能最优(用最少的代码实现更优秀的功能)。

  

 

posted @ 2018-02-02 13:47  anionic  阅读(323)  评论(0)    收藏  举报