【CSII-PE】pe:hiddenData标签实现原理分析

【CSII-PE】pe:hiddenData标签实现原理分析

PE中有一个自定义标签hiddenData,它一般用在确认页面,主要作用是将上一步提交上来的数据(context.getDataMap)保存在确认页面,无论是提交到最终操作交易还是返回到前面的输入界面,都可以将数据和表单一起提交过去。


public int doEndTag() throws JspException{
    String stream = ""; 
    boolean xhtml = TagUtil.getXHTMLFlag(pageContext);
    
    try{
      //name=_dataMap
      Object saveItem = pageContext.getRequest().getAttribute(name);
      if (saveItem == null) {
        return 6;
      }

      //标签属性,可在使用是设置  
      if (usingSession){
        pageContext.getSession().setAttribute(name, saveItem);     
        return 6;
      }
    
      if ((saveItem instanceof String)) {
        stream = (String)saveItem;
      }else {

        //序列化编码数据
        stream = ExternUtil.format(saveItem);
      }
    }catch (Exception e) {
      e.printStackTrace();
      return 6;
    }
    

    //输出隐藏域将_dataMap数据保存
    JspWriter w = pageContext.getOut();
    try {
      if (withInputTag){
        if (xhtml){
          w.print("<input type=\"hidden\" id=\"");
          w.print(getName());
          w.print("\" name=\"");
          w.print(getName());
          w.print("\" value=\"");
          w.print(stream);
          w.print("\" />");

        } else{
          w.print("<input type=\"hidden\" name=\"");
          w.print(getName());
          w.print("\" value=\"");
          w.print(stream);
          w.print("\" >");
        }
        
      } else{
        w.print(getName());
        w.print("=");
        w.print(URLEncoder.encode(stream, "8859_1"));
      }
    }
    catch (Exception e) {
      e.printStackTrace();
    }
    
    return 6;
}

标签的内容比较直观明了,这里有一个问题,这里从pageContext中获取到的_dataMap是从哪里来的呢。答案就是从确认模版中来:

<template id="publicTrsConfirmTemplate" class="com.csii.ibs.workflow.TrsConfirmTemplate" chain="chainForPublicVR">
    <actions>
        <ref name="action">Placeholder</ref>
    </actions>
</template>

查看源码:

public void execute(Context context)throws PeException{
    Action action = getAction("action", context);
    
    if ((action instanceof PlaceholderAction)) {
      throw new PeException(
        "system.placeholders_error", 
        new Object[] { getClass().getName(), context.getTransactionId() });
    }
    
    if ((action instanceof Preparable)) {
      ((Preparable)action).prepare(context);
    }
    
    context.setData("signature", Boolean.valueOf(isSignatureEnabled(context)));
    context.setData("dynamicPassword", Boolean.FALSE);

    if (isDynamicPasswordEnabled(context)){
      context.setData("dynamicPassword", Boolean.TRUE);
      Map dataMap = context.getDataMap();
      context.setData("_dataMap", dataMap);
      
      tokenManager.createToken(context);
      
      if (notification != null)
        notification.notify(context);
      return;
    }
    
    //放置数据,共页面hiddenData标签使用
    Map dataMap = context.getDataMap();
    context.setData("_dataMap", dataMap);
}

hiddenData标签有几个属性:name存放在pageContext中的数据名称,usingSession是否使用session来存放数据,withInputTag是否使用input(hidden)表单存放数据。

那数据和存数据分析完了,下面看_dataMap这个字段在哪里解析的:CoreController(实现类ServiceBasedCoreController):

if ((context.getTransactionId() != null) && (transactionConfigs.containsKey(context.getTransactionId()))){
    TransactionConfig transactionConfig = (TransactionConfig)transactionConfigs.get(context.getTransactionId());
    ((TransactionConfigAware)context).setTransactionConfig(transactionConfig);
}

这里的setTransactionConfig暗藏玄机:

public void setTransactionConfig(TransactionConfig transactionConfig){
    this.transactionConfig = transactionConfig;
    Inner(transactionConfig);
}

public void Inner(TransactionConfig transactionConfig){
      //省略部分代码
      Object _dataMap = session == null ? null : session.getAttribute("_dataMap");
      if (_dataMap != null) {
        super.setDataMap((Map)_dataMap);
      }else{
        _dataMap = request.getParameter("_dataMap");
        if (_dataMap != null){
          ApplicationContext pac = (ApplicationContext)request.getAttribute(Constants.MAINSERVLET_APPLICATION_CONTEXT_ATTRIBUTE);
          ApplicationContext cac = transactionConfig.getApplicationContext();
          
          ClassLoader bcl;
          if (pac == cac) {
            bcl = pac.getClassLoader();
          } else {
            bcl = new MultiBundlesClassLoader(pac.getClassLoader(), cac.getClassLoader());
          }
          //解析返回数据
          Map _map = (Map)ExternUtil.parse((String)_dataMap, bcl);
          if (_map != null)
            super.setDataMap(_map);
        }
      }
}

这里就可以看到页面提交过来的_dataMap数据就可以被解析并且设置到context的dataMap中了。

注:从上述分析可以看出,虽然hiddenData可以通过name属性改变获取的数据,但是提交之后的解析就必须要手动来做了,因为LocalServletContext中默认的名字是_dataMap。如果不使用确认模版,那么也可以自己在action中将需要的数据放置到到context中(context.setData("_dataMap", dataMap)),页面上一样可以使用。

by CSII@王大仙

猜你喜欢

转载自blog.csdn.net/joxlin/article/details/81561557
PE
今日推荐