JAVA基礎(chǔ)(form表單的雙向映射)

字號(hào):


    有的時(shí)候,我們會(huì)選擇不采用struts的html便簽等等,其實(shí)這樣的話,不是一個(gè)很好的處理,因?yàn)閟truts的標(biāo)簽不僅僅是相對(duì)于重復(fù)代碼的封裝,更多的是為了配合其自身某些功能的實(shí)現(xiàn);
    比如,我們會(huì)問,為什么我們會(huì)使用html標(biāo)簽?zāi)兀娴谋任覀冎苯邮褂胔tml標(biāo)簽更加的方便嗎,我們還得花費(fèi)時(shí)間來學(xué)習(xí)他,其實(shí)不是這樣的,考試.大提示看了下面的例子就會(huì)明白;
    一個(gè)頁面有兩個(gè)標(biāo)簽,分別采用的是上面的兩種表單形式,我們?cè)赼ctionmapping的action中進(jìn)行配置;
    我們可以看見我們把scope設(shè)置成為了session,我們填充這個(gè)表單進(jìn)行提交到一個(gè)新的頁面,然后在往回跳轉(zhuǎn),如果采用struts的html標(biāo)簽的話,我們可以看見我們的表單中自動(dòng)填充了我們進(jìn)行提交的值,而如果我們采用的是html的標(biāo)簽,那么這個(gè)表單是空的,默認(rèn)實(shí)現(xiàn)的,這一節(jié),我們來分析一個(gè)html表單與后臺(tái)的對(duì)應(yīng),以及后臺(tái)的值如何推到前臺(tái);
    首先,在頁面上,腳本會(huì)將前臺(tái)頁面的表單form與后臺(tái)的actionForm對(duì)應(yīng)起來,這是前臺(tái)與后臺(tái)的對(duì)應(yīng),我們來看一下如何實(shí)現(xiàn)的:
    在RequestProcessor的process的方法中,存在下面兩句代碼:
    ActionForm form = processActionForm(request, response, mapping);
    processPopulate(request, response, form, mapping);
    protected ActionForm processActionForm(HttpServletRequest request,
    HttpServletResponse response, ActionMapping mapping) {
    //生成一個(gè)新的ActionForm
    ActionForm instance =
    RequestUtils.createActionForm(request, mapping, moduleConfig,
    servlet);
    if (instance == null) {
    return (null);
    }
    // Store the new instance in the appropriate scope
    if (log.isDebugEnabled()) {
    log.debug(" Storing ActionForm bean instance in scope '"
    + mapping.getScope() + "' under attribute key '"
    + mapping.getAttribute() + "'");
    }
    //從ActionMapping中得到其scope,保存到設(shè)置的范圍中;
    if ("request".equals(mapping.getScope())) {
    request.setAttribute(mapping.getAttribute(), instance);
    } else {
    HttpSession session = request.getSession();
    session.setAttribute(mapping.getAttribute(), instance);
    }
    return (instance);
    }
    在createActionForm方法中,我們可見如下:
    ActionForm instance =
    //在其范圍域中查找ActionForm對(duì)象,如果存在則復(fù)用,
    lookupActionForm(request, attribute, mapping.getScope());
    if ((instance != null) && config.canReuse(instance)) {
    return (instance);
    }
    //如果不存在,則重新生成新的;
    return createActionForm(config, servlet);
    在populate方法中,有如下:
    如果不是上傳的文件,那么:
    if (!isMultipart) {
    names = request.getParameterNames();
    }
    //得到該頁面提交的參數(shù)
    while (names.hasMoreElements()) {
    String name = (String) names.nextElement();
    String stripped = name;
    if (prefix != null) {
    if (!stripped.startsWith(prefix)) {
    continue;
    }
    stripped = stripped.substring(prefix.length());
    }
    if (suffix != null) {
    if (!stripped.endsWith(suffix)) {
    continue;
    }
    stripped =
    stripped.substring(0, stripped.length() - suffix.length());
    }
    Object parameterValue = null;
    if (isMultipart) {
    parameterValue = multipartParameters.get(name);
    } else {
    parameterValue = request.getParameterValues(name);
    }
    // Populate parameters, except "standard" struts attributes
    // such as 'org.apache.struts.action.CANCEL'
    if (!(stripped.startsWith("org.apache.struts."))) {
    properties.put(stripped, parameterValue);
    }
    }
    // 將參數(shù)和actionForm的屬性對(duì)應(yīng)起來;形成了頁面數(shù)據(jù)和后臺(tái)的對(duì)應(yīng);
    try {
    BeanUtils.populate(bean, properties);
    } catch (Exception e) {
    throw new ServletException("BeanUtils.populate", e);
    } finally {
    if (multipartHandler != null) {
    // Set the multipart request handler for our ActionForm.
    // If the bean isn't an ActionForm, an exception would have been
    // thrown earlier, so it's safe to assume that our bean is
    // in fact an ActionForm.
    ((ActionForm) bean).setMultipartRequestHandler(multipartHandler);
    }
    }
    }
    我們可以看見知道這里為止,前臺(tái)頁面和后臺(tái)的數(shù)據(jù)對(duì)應(yīng)起來了。那么,我們?cè)趺纯赡苁沟眯薷暮笈_(tái)的actionForm表單的數(shù)據(jù)使得前臺(tái)和后臺(tái)的數(shù)據(jù)對(duì)應(yīng)起來呢?就像我們一開始的時(shí)候那樣,actionForm是session范圍的,使用了struts的標(biāo)簽我們依然能夠使得其自動(dòng)填充表單;
    那么我們就要分析一下struts的標(biāo)簽了;
    首先,在頁面上,我們會(huì)解析標(biāo)簽,表單控件要與后臺(tái)對(duì)應(yīng)起來,那么這個(gè)對(duì)應(yīng)的單位是form,所以,空間應(yīng)用都被包含在一個(gè)form中;
    public class FormTag extends TagSupport
    form表單據(jù)稱于TagSupport,他為整個(gè)表單與后臺(tái)的對(duì)應(yīng)做了很多預(yù)先的工作;
    public int doStartTag() throws JspException {
    postbackAction = null;
    //查找表單的范圍域,bean的名字,以及類型;
    this.lookup();
    //生成html的form控件的text;
    StringBuffer results = new StringBuffer();
    results.append(this.renderFormStartElement());
    results.append(this.renderToken());
    //將
    TagUtils.getInstance().write(pageContext, results.toString());
    //將當(dāng)前的form信息保存在pageContext下面
    //使得在form標(biāo)記結(jié)束之前,之間的表單控件能夠找到
    //自己所屬的form,以及后臺(tái)的actionForm;
    pageContext.setAttribute(Constants.FORM_KEY, this,
    PageContext.REQUEST_SCOPE);
    this.initFormBean();
    return (EVAL_BODY_INCLUDE);
    }
    lookUp()
    protected void lookup() throws JspException {
    // 首先查找到模塊;
    moduleConfig = TagUtils.getInstance().getModuleConfig(pageContext);
    if (moduleConfig == null) {
    JspException e =
    new JspException(messages.getMessage("formTag.collections"));
    pageContext.setAttribute(Globals.EXCEPTION_KEY, e,
    PageContext.REQUEST_SCOPE);
    throw e;
    }
    //得到其標(biāo)簽的action屬性,我們需要根據(jù)他在模塊配置信息中找到
    //對(duì)應(yīng)的配置信息;
    String calcAction = this.action;
    // If the action is not specified, use the original request uri
    if (this.action == null) {
    HttpServletRequest request =
    (HttpServletRequest) pageContext.getRequest();
    postbackAction =
    (String) request.getAttribute(Globals.ORIGINAL_URI_KEY);
    String prefix = moduleConfig.getPrefix();
    if (postbackAction != null && prefix.length() > 0 && postbackAction.startsWith(prefix))
    {
    postbackAction = postbackAction.substring(prefix.length());
    }
    calcAction = postbackAction;
    } else {
    //找到了對(duì)應(yīng)的action配置信息;
    ActionConfig actionConfig = moduleConfig.findActionConfigId(this.action);
    if (actionConfig != null) {
    this.action = actionConfig.getPath();
    calcAction = this.action;
    }
    }
    servlet =
    (ActionServlet) pageContext.getServletContext().getAttribute(Globals.ACTION_SERVLET_KEY);
    // Look up the action mapping we will be submitting to
    String mappingName =
    TagUtils.getInstance().getActionMappingName(calcAction);
    //得到了actionMapping信息;
    mapping = (ActionMapping) moduleConfig.findActionConfig(mappingName);
    if (mapping == null) {
    JspException e =
    new JspException(messages.getMessage("formTag.mapping",
    mappingName));
    pageContext.setAttribute(Globals.EXCEPTION_KEY, e,
    PageContext.REQUEST_SCOPE);
    throw e;
    }
    // 得到了表單的配置信息;
    FormBeanConfig formBeanConfig =
    moduleConfig.findFormBeanConfig(mapping.getName());
    if (formBeanConfig == null) {
    JspException e = null;
    if (mapping.getName() == null) {
    e = new JspException(messages.getMessage("formTag.name", calcAction));
    } else {
    e = new JspException(messages.getMessage("formTag.formBean",
    mapping.getName(), calcAction));
    }
    pageContext.setAttribute(Globals.EXCEPTION_KEY, e,
    PageContext.REQUEST_SCOPE);
    throw e;
    }
    beanName = mapping.getAttribute();
    beanScope = mapping.getScope();
    beanType = formBeanConfig.getType();
    }
    initFormBean:初始化了表單對(duì)象;
    protected void initFormBean()
    throws JspException {
    int scope = PageContext.SESSION_SCOPE;
    if ("request".equalsIgnoreCase(beanScope)) {
    scope = PageContext.REQUEST_SCOPE;
    }
    Object bean = pageContext.getAttribute(beanName, scope);
    if (bean == null) {
    // New and improved - use the values from the action mapping
    bean =
    RequestUtils.createActionForm((HttpServletRequest) pageContext
    .getRequest(), mapping, moduleConfig, servlet);
    if (bean instanceof ActionForm) {
    ((ActionForm) bean).reset(mapping,
    (HttpServletRequest) pageContext.getRequest());
    }
    if (bean == null) {
    throw new JspException(messages.getMessage("formTag.create",
    beanType));
    }
    pageContext.setAttribute(beanName, bean, scope);
    }
    pageContext.setAttribute(Constants.BEAN_KEY, bean,
    PageContext.REQUEST_SCOPE);
    }
    然后接下來就是解析之類的表單控件呢:
    public class TextTag extends BaseFieldTag {
    /**
    * Construct a new instance of this tag.
    */
    public TextTag() {
    super();
    this.type = "text";
    doReadonly = true;
    }
    } public int doStartTag() throws JspException {
    //將html寫入到頁面上去;
    TagUtils.getInstance().write(this.pageContext, this.renderInputElement());
    return (EVAL_BODY_TAG);
    }
    protected String renderInputElement()
    throws JspException {
    StringBuffer results = new StringBuffer("  prepareAttribute(results, "type", this.type);
    prepareAttribute(results, "name", prepareName());
    prepareAttribute(results, "accesskey", getAccesskey());
    prepareAttribute(results, "accept", getAccept());
    prepareAttribute(results, "maxlength", getMaxlength());
    prepareAttribute(results, "size", getCols());
    prepareAttribute(results, "tabindex", getTabindex());
    //在這里,將會(huì)到后臺(tái)對(duì)應(yīng)的actionForm中去拿值;
    //把后臺(tái)的數(shù)據(jù)推到前臺(tái)來;
    prepareValue(results);
    results.append(this.prepareEventHandlers());
    results.append(this.prepareStyles());
    prepareOtherAttributes(results);
    results.append(this.getElementClose());
    return results.toString();
    }
    protected void prepareValue(StringBuffer results)
    throws JspException {
    results.append(" value=\"");
    //如果設(shè)置了值的屬性;那么顯示他;
    if (value != null) {
    results.append(this.formatValue(value));
    //如果沒有的話,那么從后臺(tái)數(shù)據(jù)中取得;
    } else if (redisplay || !"password".equals(type)) {
    Object value =
    TagUtils.getInstance().lookup(pageContext, name, property, null);
    results.append(this.formatValue(value));
    }
    results.append('"');
    }
    public Object lookup(PageContext pageContext, String name, String property,
    String scope) throws JspException {
    //從頁面中取得bean
    Object bean = lookup(pageContext, name, scope);
    if (bean == null) {
    JspException e = null;
    if (scope == null) {
    e = new JspException(messages.getMessage("lookup.bean.any", name));
    } else {
    e = new JspException(messages.getMessage("lookup.bean", name,
    scope));
    }
    saveException(pageContext, e);
    throw e;
    }
    if (property == null) {
    return bean;
    }
    try {
    //從表單中取得該property標(biāo)記的屬性的值,返回,輸出到頁
    //面;
    return PropertyUtils.getProperty(bean, property);
    } catch (IllegalAccessException e) {
    saveException(pageContext, e);
    throw new JspException(messages.getMessage("lookup.access",
    property, name));
    } catch (IllegalArgumentException e) {
    saveException(pageContext, e);
    throw new JspException(messages.getMessage("lookup.argument",
    property, name));
    } catch (InvocationTargetException e) {
    Throwable t = e.getTargetException();
    if (t == null) {
    t = e;
    }
    saveException(pageContext, t);
    throw new JspException(messages.getMessage("lookup.target",
    property, name));
    } catch (NoSuchMethodException e) {
    saveException(pageContext, e);
    String beanName = name;
    // Name defaults to Contants.BEAN_KEY if no name is specified by
    // an input tag. Thus lookup the bean under the key and use
    // its class name for the exception message.
    if (Constants.BEAN_KEY.equals(name)) {
    Object obj = pageContext.findAttribute(Constants.BEAN_KEY);
    if (obj != null) {
    beanName = obj.getClass().getName();
    }
    }
    throw new JspException(messages.getMessage("lookup.method",
    property, beanName));
    }
    }
    最后,會(huì)為form元素“封口”
    public int doEndTag() throws JspException {
    // 從頁面上下文中消除掉當(dāng)前form的標(biāo)記
    pageContext.removeAttribute(Constants.BEAN_KEY,
    PageContext.REQUEST_SCOPE);
    pageContext.removeAttribute(Constants.FORM_KEY,
    PageContext.REQUEST_SCOPE);
    //封閉form標(biāo)記;
    StringBuffer results = new StringBuffer("");
    // 顯示當(dāng)前的焦點(diǎn);
    if (this.focus != null) {
    results.append(this.renderFocusJavascript());
    }
    // 顯示到頁面上去;
    JspWriter writer = pageContext.getOut();
    try {
    writer.print(results.toString());
    } catch (IOException e) {
    throw new JspException(messages.getMessage("common.io", e.toString()));
    }
    postbackAction = null;
    // 繼續(xù)執(zhí)行該頁面;
    return (EVAL_PAGE);
    }
    從上面,我們可見在struts里面是不支持表單嵌套的,表單的順序定義還是可以的;這樣不會(huì)造成pageContext頁面標(biāo)記的被覆蓋等現(xiàn)象;