亚洲国产AV无码专区亚洲AV,中文字幕亚洲乱码熟女一区二区,中文字幕亚洲乱码熟女一区二区http://www.tkk7.com/luoqx/category/3050.htmlzh-cnThu, 01 Mar 2007 02:44:24 GMTThu, 01 Mar 2007 02:44:24 GMT60關于使用utf8編碼實現全球化的幾點困惑(請大家幫忙想想辦法)http://www.tkk7.com/luoqx/articles/35704.htmlpublisher luopublisher luoThu, 16 Mar 2006 11:44:00 GMThttp://www.tkk7.com/luoqx/articles/35704.htmlhttp://www.tkk7.com/luoqx/comments/35704.htmlhttp://www.tkk7.com/luoqx/articles/35704.html#Feedback0http://www.tkk7.com/luoqx/comments/commentRss/35704.htmlhttp://www.tkk7.com/luoqx/services/trackbacks/35704.html某日一時興起將我們的內容管理發布系統改成uft-8格式(即將所有頁面encode變為utf8,mysql字符集也變成uft-8)來支持能夠建立各種語言的網站(產品現在可以免費下載,網址為:http://sourceforge.net/projects/nodepublisher)。但是在修改程序過程中發現了一個問題,那就是在客戶端頁面提交過來的請求的編碼格式在服務器端無法獲知。如果提交頁面的<head>里面如果包含<meta http-equiv="Content-Type" content="text/html; charset=utf-8">,漢字部分則以utf8編碼提交,如果沒有的話則以gbk編碼提交,而服務器端接受到的request無法判別編碼格式,取到的頭信息只有一些zh類似的說明,所以無法正確的將其轉換成正確的編碼格式。
另一需要注意的是不能將取到的參數從ISO8859轉換成中文系統默認的字符集GBK,然后再轉換成utf8,這樣的話如果出現奇數漢字的話會導致部分漢字亂碼,原因在于漢字在GBK編碼中為2個byte,而在utf8編碼則為3個byte,如果是偶數個漢字,從ISO8859(tomcat默認得到的request都是ISO8859編碼)轉換成GBK,然后再轉換成ISO8859到還無妨,但是奇數個,最后一個byte不知道會怎么轉換成GBK的,然后再轉回到utf8時最后那個字符就會成為亂碼,我想可能是跟String類里面的拆分char的方法有關,不知道誰有更加明確的分析和解釋。
再一數據庫方面使用mysql5,設置成utf8初始化數據腳本漢字轉換成uft8,一切正常。后來無意將數據庫轉換成GBK編碼,竟然程序運行也正常,后來經過測試將mysql設置成gbk,然后執行初始化sql腳本,漢字編碼格式為GBK,程序運行依然正常。不明白其中的原由。



publisher luo 2006-03-16 19:44 發表評論
]]>
spring本地事務與JTA事務實現解析http://www.tkk7.com/luoqx/articles/16451.htmlpublisher luopublisher luoSat, 22 Oct 2005 14:57:00 GMThttp://www.tkk7.com/luoqx/articles/16451.htmlhttp://www.tkk7.com/luoqx/comments/16451.htmlhttp://www.tkk7.com/luoqx/articles/16451.html#Feedback2http://www.tkk7.com/luoqx/comments/commentRss/16451.htmlhttp://www.tkk7.com/luoqx/services/trackbacks/16451.html      大家都知道spring支持兩種事務,一種是本地連接事務(使用DataSourceTransactionManager),一種是JTA事務(使用JtaTransactionManager)。并且支持聲明式事務和編程式事務兩種方式。采用聲明式事務使用AOP方式的TransactionProxyFactoryBean代理工廠類。
      JTA事務實現相對較好理解,在執行實際類的符合模式的方法時,代理類通過在連接點前后插入預處理過程(開始事務)和后處理過程(commit或rollbak)即可。因為JTA事務支持兩階段提交所以在代碼中啟動多少個連接(不同的connection)都能保證事務最終提交或者回滾。可是本地連接事務是如何實現的呢?因為必須后面的dao層必須使用的同一個連接才能保證事務正常提交和回滾,在業務邏輯層可以調用dao層的多個類的多個方法,每個方法如果顯式的將connection做為參數傳入到還可以,但是這樣connection就要出現調用的在業務邏輯層,而且dao的每個方法還要有個connection參數比較難看,而且開發人員要關注事務,這樣就沒有達到開發人員只要關注業務邏輯即可的要求。 
      web應用,各個類都要在多線程環境下運行,所以每個方法要保證線程安全,這樣,不在dao方法中加參數而是在dao類中加入connection屬性也就不可取了,怎么辦?查看一下JdbcTemplate類,在執行每個方法需要數據庫連接時都使用了DataSourceUtils.getConnection(getDataSource())方法?難道每回都從數據源里面取一條連接?不可能,這樣事務肯定沒法實現,可是怎么能保證取的是一條連接呢?對了是不是采用本地線程呀(TreadLocal),因為一段事務都是在一個線程中完成,所以只要在事務開始的時候將connection存放在本地線程中,然后事務過程中從本地線程中取出connection,直到事務結束即可。不錯,這樣只需要在每個dao方法的取數據庫連接的方法中有個事務狀態的判斷即可。不錯看看spring是不是這樣實現的?果然如此,DataSourceUtils.getConnection(DataSource)方法調用doGetConnection()方法,方法內容如下:
public static Connection doGetConnection(DataSource dataSource) throws SQLException {
  Assert.notNull(dataSource, "No DataSource specified");

  ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
  if (conHolder != null) {
   conHolder.requested();
   return conHolder.getConnection();
  }

  logger.debug("Fetching JDBC Connection from DataSource");
  Connection con = dataSource.getConnection();

  if (TransactionSynchronizationManager.isSynchronizationActive()) {
   logger.debug("Registering transaction synchronization for JDBC Connection");
   // Use same Connection for further JDBC actions within the transaction.
   // Thread-bound object will get removed by synchronization at transaction completion.
   conHolder = new ConnectionHolder(con);
   conHolder.setSynchronizedWithTransaction(true);
   conHolder.requested();
   TransactionSynchronizationManager.registerSynchronization(
     new ConnectionSynchronization(conHolder, dataSource));
   TransactionSynchronizationManager.bindResource(dataSource, conHolder);
  }

  return con;
 }
conHolder?TransactionSynchronizationManager?很象呀,繼續看看TransactionSynchronizationManager類果真如此,里面使用TreadLocal來保存數據連接和事務狀態。原來如此,代碼里的各個層沒有特殊需要都不用再出現事務了,程序開發人員只要關注業務就可以了,不用再勞心編寫事務代碼了。



publisher luo 2005-10-22 22:57 發表評論
]]>
Spring遠程數據源JTA事務連接配置http://www.tkk7.com/luoqx/articles/16447.htmlpublisher luopublisher luoSat, 22 Oct 2005 14:09:00 GMThttp://www.tkk7.com/luoqx/articles/16447.htmlhttp://www.tkk7.com/luoqx/comments/16447.htmlhttp://www.tkk7.com/luoqx/articles/16447.html#Feedback0http://www.tkk7.com/luoqx/comments/commentRss/16447.htmlhttp://www.tkk7.com/luoqx/services/trackbacks/16447.html        因為整個項目組使用統一的配置管理,spring的applicationContext.xml大家都相同,每天還要做每日構建,部署到服務器上也與配置管理上的文件相同,所以想是否可以將數據源和JTAmanager配置成遠程的。
       查找spring官方文檔,太簡單沒有這方面描述,上網google了半天,沒找到(奇怪?其實后來想想也不奇怪,大家要么使用本地數據源(開發調試),要么使用應用服務的數據源也是在同一應用服務器上,而不是在遠程使用(部署的生產環境)。),所以干脆看看源碼算了。
       已知如下配置可以訪問到同一應用服務器的jndi數據源
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName">
        <value>jdbc/cqccms</value>
    </property>
 </bean>
        記得當初使用jndi時可以遠程訪問寫過client程序,主要除了要知道jndi名,還要設置jndi環境(Environment),所以查找一下JndiObjectFactoryBean的源代碼,看看有沒有設置jndi環境的方法,果然有setJndiEnvironment方法參數為properties,可以了,如下配置就能訪問遠程數據源了
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
 <property name="jndiName">
  <value>jdbc/cqccms</value>
 </property>
 <property name="jndiEnvironment">
     <props>
        <prop key="java.naming.factory.initial">
          weblogic.jndi.WLInitialContextFactory
        </prop>
        <prop key="java.naming.provider.url">t3://172.16.101.42:7001</prop>
        <prop key="java.naming.security.principal">weblogic</prop>
        <prop key="java.naming.security.credentials">weblogic</prop>
     </props>   
   </property> 
  </bean>
      不過要記得把weblogic.jar放到自己應用的lib下,要不找不到weblogic.jndi.WLInitialContextFactory類。
      數據源搞定了,測試一下果真好用,不過jta對象遠程訪問好像沒那么順利,同理查看org.springframework.transaction.jta.JtaTransactionManager類,沒有發現上述方法,不過看到了setJndiTemplate()方法,也不錯現配置一個jndiTemplate,如下:
 <bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate" singleton="true"
  lazy-init="default" autowire="default" dependency-check="default">
  <property name="environment">
     <props>
        <prop key="java.naming.factory.initial">
          weblogic.jndi.WLInitialContextFactory
        </prop>
        <prop key="java.naming.provider.url">t3://172.16.101.42:7001</prop>
        <prop key="java.naming.security.principal">weblogic</prop>
        <prop key="java.naming.security.credentials">weblogic</prop>
     </props>   
   </property> 
 </bean>
      然后在配置一下transactionManager,如下
 <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" singleton="true"
  lazy-init="default" autowire="default" dependency-check="default">
  <property name="jndiTemplate">
   <ref local="jndiTemplate" />
  </property>
  <property name="userTransactionName">
   <value>weblogic/transaction/UserTransaction</value>
  </property>
 </bean>
      不過JtaTransactionManager默認找jndi name為UserTransaction的jta對象,在同一應用服務器上可以,遠程訪問不到,后直接查看weblogic的jndi樹找到這個jndi名weblogic/transaction/UserTransaction,配置上測試果然成功。

publisher luo 2005-10-22 22:09 發表評論
]]>
一個簡單"決策樹"的實現http://www.tkk7.com/luoqx/articles/11780.htmlpublisher luopublisher luoThu, 01 Sep 2005 11:55:00 GMThttp://www.tkk7.com/luoqx/articles/11780.htmlhttp://www.tkk7.com/luoqx/comments/11780.htmlhttp://www.tkk7.com/luoqx/articles/11780.html#Feedback0http://www.tkk7.com/luoqx/comments/commentRss/11780.htmlhttp://www.tkk7.com/luoqx/services/trackbacks/11780.html


?? 客戶的權限要求采集回來了,天哪,根本不是什么權限的設置和判斷了,原有內容管理中的權限管理(RBAC Role based Access Control 基于角色的訪問控制)根本不能解決問題.?經過仔細分析,所有要求具為領導拍腦袋定下來的不符合邏輯的一些邏輯。如何解決?隨即想到了采用專家系統來解決這個問題。找到開源的rete算法java實現包Drools(http://www.theserverside.com/articles/content/Drools/article.html), 并察看了專家系統的部分書籍。但是項目時間緊迫所以放棄了,主要是其規則存放于xml中,沒想出好的辦法與本工程良好的配合起來。所以還是決定先采用簡單 的決策樹(本系統中正好有樹狀結構的內容管理系統,很容易擴展)解決問題。在每個樹狀決策節點可以加入條件和行為,如何解析?成了一個問題。再 google一下,找找開源的腳本解析,哦不錯有java腳本的解析器( BeanShell---Java應用程序腳本引摯 )可以直接解析java語句,功能比較強大,包也不大。不得不佩服現在的開源真是如火如荼,還是早早的加入進去吧。

主要測試代碼:
//創建一個bsh解釋器實例
??Interpreter bsh = new Interpreter();
//測試執行一個接口實現的類
String program = "public Object excute(int aa,String bb){return \"Cool\";}";
program ="Command command= new Command(){"+program+"};";
program += "Object obj=command.excute(aa,bb);";
bsh.eval(program);
//測試執行一個函數
String program = "Object excute(int aa,String bb){return \"bb+aa\";}";
program += "Object obj=excute(aa,bb);";String program = "Object excute(int aa,String bb){return \"bb+aa\";}";
program += "Object obj=excute(aa,bb);";
bsh.eval(program);
??
??bsh.eval(program);



publisher luo 2005-09-01 19:55 發表評論
]]>
xalan包的版本問題http://www.tkk7.com/luoqx/articles/11779.htmlpublisher luopublisher luoThu, 01 Sep 2005 11:49:00 GMThttp://www.tkk7.com/luoqx/articles/11779.htmlhttp://www.tkk7.com/luoqx/comments/11779.htmlhttp://www.tkk7.com/luoqx/articles/11779.html#Feedback0http://www.tkk7.com/luoqx/comments/commentRss/11779.htmlhttp://www.tkk7.com/luoqx/services/trackbacks/11779.html


    一直好用的程序竟然不好用了,出現下列異常:

org.apache.xml.utils.WrappedRuntimeException: The output format must have a '{http://xml.apache.org/xalan}content-handler' property!

  終于找到原因,tomcat5 中自帶了xalan包,并且包的版本提升了,所以程序不好用了。詳細原因沒有查清。



publisher luo 2005-09-01 19:49 發表評論
]]>
哪里有好的樹狀結構的容器?沒辦法自己寫一個吧http://www.tkk7.com/luoqx/articles/11288.htmlpublisher luopublisher luoSat, 27 Aug 2005 03:18:00 GMThttp://www.tkk7.com/luoqx/articles/11288.htmlhttp://www.tkk7.com/luoqx/comments/11288.htmlhttp://www.tkk7.com/luoqx/articles/11288.html#Feedback0http://www.tkk7.com/luoqx/comments/commentRss/11288.htmlhttp://www.tkk7.com/luoqx/services/trackbacks/11288.html


到處找樹狀結構的容器都沒找到,TreeMap和TreeSet是什么紅-黑樹沒看明白,沒時間仔細研究了,干脆簡單寫一個吧,反正并發要求不是很高,也不怎么排序,就是內存緩存用。代碼如下:

/**
 * 樹操作類,定義樹型數據結構的常用操作,其中包括定位樹結點,插入樹結點 刪除樹結點,修改樹結點等。 注意:樹根節點的標志從0開始
 */
public class DataTree implements Serializable {

 private DataTreeNode rootDataTreeNode = null; //定義樹根
 private Hashtable nodeList = new Hashtable();

 /**
  * 設置根節點
  * @param nodeID 節點nodeid
  * @param node   節點數據對象
  */
 private void setRoot(String nodeID, Object node) {

  DataTreeNode treeNode = new DataTreeNode();
  treeNode.setLevel(0);
  treeNode.setNode(node);
  treeNode.setNodeID(nodeID);
  treeNode.setUpNodeID("0");
  this.rootDataTreeNode = treeNode;
  nodeList.put(nodeID, treeNode);
 }

 /**
  * 設置根節點
  * @param node Object,節點包含數據對象
  */
 public void setRoot(Object node) {
  String nodeID = DataAccess.getCode();
  setRoot(node);
 }
 /**
  * 取得根節點
  * @return 樹型節點
  */
 public DataTreeNode getRoot(){
  return rootDataTreeNode;
 }
 /**
  * 取得節點數據對象
  * @return 數據對象
  */
 public Object getRootNode(){
  return rootDataTreeNode.getNode() ;
 }
 
 /**
  * 給一個節點添加子節點
  * @param supNode 父節點
  * @param node 數據對象
  * @return 封裝過的樹型節點
  */
 public DataTreeNode addSubNode(DataTreeNode supNode,Object node){
  DataTreeNode newTreeNode =  supNode.addSubNode(node);
  this.nodeList.put( newTreeNode.getNodeID() ,newTreeNode);
  return newTreeNode;
 }
 /**
  * 刪除一個子節點
  * @param supNode 父節點
  * @param subNode 子節點
  * @return 成功,失敗
  */
 public boolean removeSubNode(DataTreeNode supNode,DataTreeNode subNode){
  if(supNode.removeSubNode( subNode)){
   this.nodeList.remove( subNode.getNodeID() );
   return true;
  }else{
   return false;
  }
 }
 /**
  * 刪除一個子節點
  * @param supNode 父節點
  * @param orderid 序號,從0開始
  * @return 成功,失敗
  */
 public boolean removeSubNode(DataTreeNode supNode,int orderid){
  DataTreeNode subNode = supNode.getSubNode( orderid);
  if(supNode.removeSubNode( orderid)){
   this.nodeList.remove( subNode.getNodeID() );
   return true;
  }else{
   return false;
  }
 }
 
 public static DataTree creatDataTree(ArrayList nodeList,
   String upNodeIDName,
   String nodeIDName,
   Object root){
  
  String getNodeIDMethodName = "get"+nodeIDName;
  String getUpNodeIDMethodName = "get"+upNodeIDName;
  String rootNodeid = getValue(root ,getNodeIDMethodName);
  String nodeid = "";
  String upnodeid = "";
  
  
  
  Object[][] nodes = new Object[nodeList.size()][3];

  int count =0;
  //將arraylist數據存儲到兩個Hashtable中
  for(int i=0;i<nodeList.size();i++){
   Object obj = nodeList.get(i);
   if (obj != null){
    nodeid = new String(getValue(obj,getNodeIDMethodName));
    if (nodeid != null ){
     upnodeid = new String(getValue(obj ,getUpNodeIDMethodName));
     if (upnodeid != null){
      nodes[count][0] = nodeid;
      nodes[count][1] = upnodeid;
      nodes[count][2] = nodeList.get(i);
      count ++;
     }
    }
   }
  }  
  DataTree dataTree = new DataTree();
  dataTree.setRoot( rootNodeid,root);
  findChildNodeAndAdd(dataTree.getRoot(),nodes);
  return dataTree;
 }
 
 private static void findChildNodeAndAdd(DataTreeNode treeNode,Object[][] nodes){
  String nodeid = treeNode.getNodeID() ;
  for (int i=0;i<nodes.length ;i++){
   if (nodeid.equals(nodes[i][1])){
    DataTreeNode childTreeNode = treeNode.addSubNode( (String)nodes[i][0],nodes[i][2]);
    findChildNodeAndAdd(childTreeNode,nodes);
   }
  }  
 }
 
 private static String getValue(Object obj, String functionName){
  return (String)ObjectTool.invokeMethod(obj,null,null,functionName);
 }
 /**
  * 樹型數據結構定義類。定義樹型數據結構的基本單元--樹型節點的結構。
  * 
  */
 public class DataTreeNode  {

  private String upNodeID; //父節點ID

  private String nodeID; //屬性節點標志ID

  private int level; //層號

  private Object node; //存儲用數據對象

  private ArrayList subNodes; //所有子節點

  /**
   * 空構造
   * 
   */
  private DataTreeNode() {
   subNodes = new ArrayList();
  }

  /**
   * @return Returns the level.
   */
  public int getLevel() {
   return level;
  }

  /**
   * @param level
   *            The level to set.
   */
  private void setLevel(int level) {
   this.level = level;
  }

  /**
   * @return Returns the node.
   */
  public Object getNode() {
   return node;
  }

  /**
   * @param node
   *            The node to set.
   */
  private void setNode(Object node) {
   this.node = node;
  }

  /**
   * @return Returns the nodeID.
   */
  public String getNodeID() {
   return nodeID;
  }

  /**
   * @param nodeID
   *            The nodeID to set.
   */
  private void setNodeID(String nodeID) {
   this.nodeID = nodeID;
  }

  /**
   * @return Returns the orderid.
   */
  public int getSubNodeOrderid(DataTreeNode treeNode) {
   for (int i = 0; i < subNodes.size(); i++) {
    if (this.getSubNode(i).equals(treeNode)) {
     return i;
    }
   }
   return -1;
  }

  /**
   * @return Returns the subNode.
   */
  public ArrayList getSubNodes() {
   return (ArrayList) subNodes.clone();
  }

  /**
   * @param subNode
   *            The subNode to set.
   */
  private void setSubNodes(ArrayList subNodes) {
   this.subNodes = subNodes;
  }

  /**
   * @return Returns the subNodeNo.
   */
  private int getSubNodeNo() {
   return this.subNodes.size();
  }

  /**
   * @return Returns the upNodeID.
   */
  public String getUpNodeID() {
   return upNodeID;
  }

  /**
   * @param upNodeID
   *            The upNodeID to set.
   */
  private void setUpNodeID(String upNodeID) {
   this.upNodeID = upNodeID;
  }

  /**
   * 增加一個子節點
   *
   * @param treeNode
   *            帶樹結構的節點
   */
  private void addSubTreeNode(DataTreeNode treeNode) {
   this.subNodes.add(treeNode);
  }

  /**
   * 增加一個子節點,指定nodeid
   *
   * @param nodeID
   *            指定的nodeid
   * @param node
   *            節點附帶數據對象
   */
  private DataTreeNode addSubNode(String nodeID, Object node) {
   DataTreeNode treeNode = new DataTreeNode();
   treeNode.setLevel(this.level + 1);
   treeNode.setNode(node);
   treeNode.setNodeID(nodeID);
   //treeNode.setOrderid( getSubNodeNo() );
   treeNode.setUpNodeID(this.nodeID);
   addSubTreeNode(treeNode);
   return treeNode;
  }

  /**
   * 增加一個子節點,自動分配nodeid
   *
   * @param node
   *            節點附帶數據對象
   */
  private DataTreeNode addSubNode(Object node) {
   String nodeID = DataAccess.getCode();
   return addSubNode(nodeID, node);
  }

  /**
   * 按序號取出節點
   *
   * @param orderid
   *            序號
   * @return
   */
  private DataTreeNode getSubNode(int orderid) {
   return (DataTreeNode) this.subNodes.get(orderid);
  }

  private boolean removeSubNode(int orderid) {
   try {
    subNodes.remove(orderid);
    return true;
   } catch (Exception ex) {
    return false;
   }
  }

  private boolean removeSubNode(DataTreeNode treeNode) {
   return subNodes.remove(treeNode);
  }

  /*
   * (non-Javadoc)
   *
   * @see java.lang.Object#equals(java.lang.Object)
   */
  public boolean equals(Object treeNode) {
   if (treeNode instanceof DataTreeNode) {
    if (this.nodeID.equals(((DataTreeNode) treeNode).getNodeID())) {
     return true;
    } else {
     return false;
    }
   } else {
    return false;
   }
  }

  /*
   * (non-Javadoc)
   *
   * @see java.lang.Object#toString()
   */
  public String toString() {
   return this.nodeID + " " + node.toString();
  }
 }

}




publisher luo 2005-08-27 11:18 發表評論
]]>
why? EnterpriseBean extend Serializablehttp://www.tkk7.com/luoqx/articles/11287.htmlpublisher luopublisher luoSat, 27 Aug 2005 03:17:00 GMThttp://www.tkk7.com/luoqx/articles/11287.htmlhttp://www.tkk7.com/luoqx/comments/11287.htmlhttp://www.tkk7.com/luoqx/articles/11287.html#Feedback0http://www.tkk7.com/luoqx/comments/commentRss/11287.htmlhttp://www.tkk7.com/luoqx/services/trackbacks/11287.html

    同事問了一個這樣的問題,大家都知道,ejb的本地接口,遠程接口還有參數都需要序列話,這是因為這些東西都需要分布式傳輸,可是在容器了的bean不需要分布傳輸為什么也要實現serializable接口呢?
    上網差了些資料,主要有兩種說法,一個是app server要作cluster,交換內存中數據(包括ejb)。二是ejbPassivate(鈍化)和ejbActivate() (活化)時需要使用序列話。第二種說法可能性比較大。
參考資料:
 


publisher luo 2005-08-27 11:17 發表評論
]]>
如何從response里面取出向客戶端輸出的html流http://www.tkk7.com/luoqx/articles/10338.htmlpublisher luopublisher luoWed, 17 Aug 2005 06:40:00 GMThttp://www.tkk7.com/luoqx/articles/10338.htmlhttp://www.tkk7.com/luoqx/comments/10338.htmlhttp://www.tkk7.com/luoqx/articles/10338.html#Feedback0http://www.tkk7.com/luoqx/comments/commentRss/10338.htmlhttp://www.tkk7.com/luoqx/services/trackbacks/10338.html    但是此方法需要耗費兩次網絡傳輸,肯定性能不加,而且處理起來要幾塊程序同時協作才行。還是想辦法從服務器端直接獲取。因為從response無法直接得到輸出流,得想其他的辦法。一種是干脆在服務器端寫一個監控socket接口的客戶端程序,或者用httpunit幫助完成,就是把客戶端程序移到服務器端執行。還是相對比較復雜,能不能從response入手?
   答案是肯定的,采用response代理來截獲response的幾個輸出函數,然后存儲起來,已備查詢。
靈感來自于前一陣一直研究的java動態代理機制(現在應用在spring的aop實現中),此處不用動態代理,就使用靜態代理,proxy模式就足夠了。
  分別實現三個代理類:ServletResponseProxy,ServletOutputStreamProxy,PrintWriterProxy
Responseproxy 主要代碼:
public class ServletResponseProxy implements HttpServletResponse {
 private HttpServletResponse obj;//實際的HttpServletResponse 實例
 
 public ServletResponseProxy(HttpServletResponse obj) {
  this.obj = obj;
  HtmlBuffer.cleanStr(); //情空緩存
 }   
 
//獲得outputStreamProxy
 public ServletOutputStream getOutputStream() throws IOException {
  ServletOutputStream so = obj.getOutputStream();
  ServletOutputStreamProxy sop = new ServletOutputStreamProxy(so);
  return sop;
 }
 //獲得printWriterProxy
 public PrintWriter getWriter() throws IOException {
  PrintWriter pw = obj.getWriter();
  PrintWriterProxy pwp = new PrintWriterProxy(pw);
  return (PrintWriter) pwp;
 }
}
PrintWriterProxy:
 
public class PrintWriterProxy
    extends PrintWriter {
  private PrintWriter pw = null;
 
  public PrintWriterProxy(PrintWriter pw) {
    super(pw);
    this.pw = pw;
  }
//截獲寫內容寫入buffer
  public void write(int c) {
    char a = (char) c;
    String s = new String(new char[] {a});
    HtmlBuffer.addStr(s);
    pw.write(c);
  }
}
 
ServletOutputStreamProxy:
public class ServletOutputStreamProxy
    extends ServletOutputStream {
  private ServletOutputStream obj;
  public ServletOutputStreamProxy(ServletOutputStream obj){
    this.obj = obj;
  }
//截獲寫內容寫入buffer
  public void write(int b) throws IOException {
    Integer it = new Integer(b);
    HtmlBuffer.addStr(new String(new byte[]{it.byteValue()}));
    obj.write(b);
  }
}

 
    由于web Httpserver 是多線程執行服務端程序,所以buffer應該分線程來存取,這樣大家才能不互相干擾。所以buffer需要實現TreadLocal接口。
    HtmlBuffer代碼簡單實現如下:
public class HtmlBuffer {
 private static class HtmlInfo extends ThreadLocal {
  private Map values = Collections.synchronizedMap(new HashMap());
  public Object initialValue() {
   return new String();
  }
  public String getHtmlStr() {
   return (String) this.get();
  }
  public Object get() {
   Thread curThread = Thread.currentThread();
   Object o = values.get(curThread);
   if (o == null && !values.containsKey(curThread)) {
    o = initialValue();
    values.put(curThread, o);
   }
   return o;
  }
  public void set(Object newValue) {
   values.put(Thread.currentThread(), newValue);
  }
 } 
 private static HtmlInfo htmlInfo = new HtmlInfo();
 
 public static void cleanStr(){
  htmlInfo.set( "");
 }
 public static void addStr(String htmlStr) {
  String htmlstr = (String)htmlInfo.get();
  if(htmlstr == null) htmlstr ="";
  htmlstr += htmlStr;
  htmlInfo.set( htmlstr);
 }
 public static String getStr() {
  return (String)htmlInfo.get();
 }
}


publisher luo 2005-08-17 14:40 發表評論
]]>
主站蜘蛛池模板: fc2成年免费共享视频网站| 亚洲区日韩精品中文字幕| 特黄特色的大片观看免费视频| 最新猫咪www免费人成| 亚洲妇女水蜜桃av网网站| 少妇人妻偷人精品免费视频| 久久国产亚洲电影天堂| 久久伊人免费视频| 亚洲色图校园春色| 免费看成人AA片无码视频羞羞网| 亚洲男人电影天堂| 国产精品成人免费视频网站京东| 亚洲最大中文字幕无码网站| 成年女人免费v片| 亚洲AV无码一区二区一二区| 日韩a级毛片免费观看| 校园亚洲春色另类小说合集| 国产av无码专区亚洲国产精品| 国产精品一区二区三区免费| 亚洲av无码无在线观看红杏| 久久综合给合久久国产免费| 亚洲中文久久精品无码1| 成人毛片18岁女人毛片免费看| 色偷偷尼玛图亚洲综合| 亚洲熟伦熟女新五十路熟妇 | gogo全球高清大胆亚洲| 精品在线免费视频| 色噜噜亚洲精品中文字幕| 日本在线看片免费人成视频1000 | 亚洲日韩精品国产一区二区三区| 成人永久免费高清| 成人国产精品免费视频| 久久亚洲日韩看片无码| 午夜a级成人免费毛片| 巨胸喷奶水视频www免费视频| 蜜芽亚洲av无码精品色午夜| 日韩免费无砖专区2020狼| 丝瓜app免费下载网址进入ios| 91亚洲自偷在线观看国产馆| 国产免费69成人精品视频| 免费在线看黄网站|