隨筆-57  評(píng)論-202  文章-17  trackbacks-0
           
                在JDK1.3版本中引入了Dynamic Proxy的代理機(jī)制,通過實(shí)現(xiàn)java.lang.reflect.InvocationHandler接口,可以實(shí)現(xiàn)攔截需要改寫的方法。下面是一個(gè)簡(jiǎn)單范例。
                有下面一個(gè)接口TestInterface和它的一個(gè)實(shí)現(xiàn)TestImpl:

          package sample.proxy;

          /**
           * <p>Title: </p>
           *
           * <p>Description: </p>
           *
           * <p>Copyright: Copyright (c) 2005</p>
           *
           * <p>Company: </p>
           *
           * @author George Hill
           * @version 1.0
           
          */


          public interface TestInterface {

            
          public String print();

          }


          package sample.proxy;

          /**
           * <p>Title: </p>
           *
           * <p>Description: </p>
           *
           * <p>Copyright: Copyright (c) 2005</p>
           *
           * <p>Company: </p>
           *
           * @author George Hill
           * @version 1.0
           
          */


          public class TestImpl implements TestInterface {
            
            
          public String print() {
              
          return "Hello, it's from TestImpl class";
            }

            
          }


                下面攔截print方法,調(diào)用自己的實(shí)現(xiàn),這需要實(shí)現(xiàn)java.lang.reflect.InvocationHandler接口。

          package sample.proxy;

          import java.lang.reflect.
          *;

          /**
           * <p>Title: </p>
           *
           * <p>Description: </p>
           *
           * <p>Copyright: Copyright (c) 2005</p>
           *
           * <p>Company: </p>
           *
           * @author George Hill
           * @version 1.0
           
          */


          public class TestHandler implements InvocationHandler {
            
            TestInterface test;
            
            
          /**
             * 將動(dòng)態(tài)代理綁定到指定的TestInterface
             * @param test TestInterface
             * @return TestInterface 綁定代理后的TestInterface
             
          */

            
          public TestInterface bind(TestInterface test) {
              
          this.test = test;
              
              TestInterface proxyTest 
          = (TestInterface) Proxy.newProxyInstance(
                test.getClass().getClassLoader(), test.getClass().getInterfaces(), 
          this);
              
              
          return proxyTest;
            }

            
            
          /**
             * 方法調(diào)用攔截器,攔截print方法
             * @param proxy Object
             * @param method Method
             * @param args Object[]
             * @return Object
             * @throws Throwable
             
          */

            
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              
          // 如果調(diào)用的是print方法,則替換掉
              if ("print".equals(method.getName())) {
                
          return "HaHa, It's come from TestHandler";
              }
           else {
                
          return method.invoke(this.test, args);
              }

            }

            
          }


                下面是測(cè)試用例:

          package sample.test;

          import junit.framework.
          *;

          import sample.proxy.
          *;

          /**
           * <p>Title: </p> 
           * 
           * <p>Description: </p> 
           * 
           * <p>Copyright: Copyright (c) 2005</p> 
           * 
           * <p>Company: </p>
           * 
           * @author George Hill
           * @version 1.0
           
          */


          public class TestDynamicProxy extends TestCase {
            
            
          private TestInterface test = null;

            
          protected void setUp() throws Exception {
              super.setUp();
              TestHandler handler 
          = new TestHandler();
              
          // 用handler去生成實(shí)例
              test = handler.bind(new TestImpl());
            }


            
          protected void tearDown() throws Exception {
              test 
          = null;
              super.tearDown();
            }


            
          public void testPrint() {
              System.
          out.println(test.print());
            }


          }


                運(yùn)行測(cè)試用例,可以看到輸出的是“HaHa, It's come from TestHandler”。
          posted @ 2005-05-24 17:47 小米 閱讀(3505) | 評(píng)論 (3)編輯 收藏
                昨天,終于收到了等待已久的《深入淺出Hibernate》一書,到現(xiàn)在已經(jīng)看了40多頁(yè),感覺很不錯(cuò),以前的一些問題在看了作者的剖析后,豁然開朗! 作者看來下了很大功夫去寫這本書,真正做到了深入淺出。我評(píng)價(jià)此書為,向大家推薦這本書。
                另外還買了一本《精通Spring》和《Java線程編程》,呵呵,看來有一段時(shí)間忙看書了。
          posted @ 2005-05-24 17:30 小米 閱讀(601) | 評(píng)論 (1)編輯 收藏
                在工作中,經(jīng)常需要寫充值這樣的功能,這個(gè)功能無非是要做下面四件事:
                1. 判斷是否可以充值;
                2. 將充值卡的余額減去充值金額;
                3. 將用戶的余額加上充值金額;
                4. 寫日志。
                在實(shí)際的應(yīng)用中,還是有不少地方需要考慮的,主要有以下幾個(gè)方面:
                1. 這四步中,后面三步都涉及到數(shù)據(jù)庫(kù)的操作,所以必須在一個(gè)事務(wù)中完成;
                2. 后面三步的執(zhí)行順序是需要考慮的,我覺得比較好的順序是這樣的:
                   a. 寫日志;
                   b. 將充值卡的余額減去充值金額;
                   c. 將用戶的余額加上充值金額。
                由于寫日志操作是不涉及到金額的,即使失敗了,對(duì)系統(tǒng)也沒有什么很大的影響,所以我放在第一步執(zhí)行。至于是先給用戶增加金額還是先減去充值卡的金額,似乎誰先誰后都沒有什么關(guān)系。不過,其實(shí)有一個(gè)微妙的地方,如果先給用戶加上余額而不幸在減去充值卡的余額時(shí)出錯(cuò),甚至很不幸數(shù)據(jù)庫(kù)也出了問題,沒有回滾事務(wù)。那么就等于用戶平白無故的多了錢,用戶當(dāng)然很高興,也許會(huì)投訴,也許不會(huì)投訴(是我肯定不投訴,高興都來不及呢)。如果是相反的情況,那么用戶必然投訴,也就可以發(fā)現(xiàn)系統(tǒng)的問題。所以我覺得應(yīng)該先減去充值卡的余額。
                3. 在執(zhí)行更改充值卡的余額時(shí),必須要在數(shù)據(jù)庫(kù)中進(jìn)行加減操作,而且要在數(shù)據(jù)庫(kù)中再檢查一遍充值卡的余額是否足夠。執(zhí)行的SQL語(yǔ)句類似下面:
                UPDATE card SET card_balance=card_balance-? WHERE card_number=? AND card_balance>=?
                由于現(xiàn)在大部分的系統(tǒng)都是多進(jìn)程或者多線程的,有可能在你提交之前,有其它的進(jìn)程或者線程更新了數(shù)據(jù)庫(kù)中的記錄,所以如果不在數(shù)據(jù)庫(kù)中進(jìn)行加減操作,不再檢查一遍余額是否充足,會(huì)給系統(tǒng)帶來隱患。
          posted @ 2005-05-20 18:19 小米 閱讀(508) | 評(píng)論 (0)編輯 收藏
               摘要:       使用Jakarta Commons Pool可以根據(jù)需要快速的實(shí)現(xiàn)自己的對(duì)象池,只需要實(shí)現(xiàn)PoolableObjectFactory或者KeyedPoolableObjectFactory接口。KeyedPoolableObjectFactory和PoolableObjectFactory的不同之處在于KeyedPoolabl...  閱讀全文
          posted @ 2005-05-20 14:08 小米 閱讀(4101) | 評(píng)論 (0)編輯 收藏
                續(xù)上一篇隨筆,struts1.2的源代碼和struts1.1的源代碼有些不同,struts1.1的eoncode方法是用的RequestUtils.encodeURL(String s)處理的,指定用UTF-8進(jìn)行encoding。所以我的修改有些不同。
                從struts的網(wǎng)站上下載1.1的源代碼:http://apache.justdn.org/jakarta/struts/source/jakarta-struts-1.1-src.zip,解壓到本地目錄。打開文件jakarta-struts-1.1-src\src\share\org\apache\struts\taglib\bean\WriteTag.java,新增一個(gè)布爾屬性encode,表示是否需要用UTF-8編碼輸出字符串。代碼片斷如下:

              /**
               * The encode flag for the value.
               * Added by George Hill, 05/19/2005
               
          */

              
          protected boolean encode = false;
              
              
          public boolean isEncode() {
                  
          return (this.encode);
              }

              
              
          public void setEncode(boolean encode) {
                  
          this.encode = encode;
              }

                修改方法formatValue,把這段:


                  
          // Return String object as is.
                  if ( value instanceof java.lang.String ) {
                          
          return (String)value;
                  }
           else {

                  }


                替換成:


                  
          // Return String object as is.
                  if ( value instanceof java.lang.String ) {
                      
          if (encode)
                          
          return RequestUtils.encodeURL((String)value);
                      
          else
                          
          return (String)value;
                  }
           else {

                  }


                保存修改后的文件。然后需要修改文件jakarta-struts-1.1-src\doc\userGuide\struts-bean.xml。這個(gè)文件在ant編譯時(shí)會(huì)變成strtus-bean.tld文件。在tag write后面增加一個(gè)attribute,如下所示:


              
          <attribute>
                
          <name>encode</name>
                
          <required>false</required>
                
          <rtexprvalue>true</rtexprvalue>
                
          <info>
                
          <p>Added by George Hill, specifies the value need UTF-8 encode or not.</p>
                
          </info>
                
          <default>false</default>
              
          </attribute>

                然后修改一下ant的編譯配置文件build.xml,這一部分和上一篇的隨筆類似,請(qǐng)參考上篇隨筆:<<用URLEncoder輸出<bean:write />的值>>
                運(yùn)行ant,編譯后的jar文件保存在jakarta-struts-1.1-src\target\library目錄中,把原來的struts.jar和struts-bean.tld文件替換掉,就可以用自定義的<bean:write /> tag了。
          posted @ 2005-05-20 11:52 小米 閱讀(1052) | 評(píng)論 (0)編輯 收藏
                我在JSP頁(yè)面中,當(dāng)處理<a href></a>時(shí),經(jīng)常不用<html:link/>的方式處理,而是用下面這樣的方式處理:
                <a href="foo.do?param1=<bean:write name="n1" property="p1"/>&param2=<bean:write name="n2" property="p2"/>">Test</a>
                這樣在處理多個(gè)參數(shù)時(shí),就不需要先放到一個(gè)Collection中。按照<html:link/>的多個(gè)參數(shù)的處理方法去做,有時(shí)確實(shí)是很繁瑣。不過這樣帶來一個(gè)新的問題,在處理中文參數(shù)值時(shí),這樣就行不通了。用request.getParameter("param1")獲取的中文,在中文的個(gè)數(shù)為奇數(shù)個(gè)時(shí),就會(huì)顯示不正確。例如“三個(gè)字”在getParameter中獲取的值是“三個(gè)?”。
                這個(gè)問題是由于<bean:write />沒有用URLEncoder的encode方法處理值,因?yàn)?lt;bean:write />主要是用來在頁(yè)面上顯示bean的信息,并不是用在鏈接中當(dāng)作參數(shù)的值。這個(gè)問題可以通過給<bean:write />增加新的屬性來解決。
                從Struts的網(wǎng)站上下載Struts 1.2.4的源代碼:http://apache.freelamp.com/struts/source/jakarta-struts-1.2.4-src.zip
                解壓到本地目錄,然后修改文件jakarta-struts-1.2.4-src\src\share\org\apache\struts\taglib\bean\WriteTag.java。新增一個(gè)屬性charset,表示需要用什么編碼進(jìn)行編碼。代碼片斷如下:

              /**
               * Added by George Hill, the string value charset to encoding.
               * 05/19/2005
               
          */

              
          protected String charset = null;

              
          public String getCharset() {
                  
          return (this.charset);
              }


              
          public void setCharset(String charset) {
                  
          this.charset = charset;
              }

                修改方法formatValue,把這段


                  
          if (value instanceof java.lang.String) {
                          
          return (String) value;
                  }
           else {

                  }


                替換為:


                  
          if (value instanceof java.lang.String) {
                      
          if (charset != null && charset.length() != 0)
                          
          return TagUtils.getInstance().encodeURL((String) value, charset);
                      
          else
                          
          return (String) value;
                  }
           else {

                  }


                保存修改后的文件。然后需要修改文件jakarta-struts-1.2.4-src\doc\userGuide\struts-bean.xml。這個(gè)文件在ant編譯時(shí)會(huì)變成strtus-bean.tld文件。在tag write后面增加一個(gè)attribute,如下所示:


            
          <tag>
              
          <name>write</name>

              
          <attribute>
                
          <name>charset</name>
                
          <required>false</required>
                
          <rtexprvalue>true</rtexprvalue>
                
          <info>
                
          <p>Added by George Hill, use this charset to encoding the value.</p>
                
          </info>
              
          </attribute>

            
          </tag>

                然后修改一下ant的編譯配置文件build.xml,有幾個(gè)部分需要修改:
                1.屬性catalina.home需要修改成你安裝的tomcat的目錄;
                2.compile.classpath需要修改,把jar文件的路徑指向正確;
                3.prepare.library taget部分的copy,把相關(guān)的jar文件的路徑指向正確。
                運(yùn)行ant,編譯后的jar文件保存在jakarta-struts-1.2.4-src\target\library目錄中,把原來的struts.jar和struts-bean.tld文件替換掉,就可以用自定義的<bean:write /> tag了。如果不寫charset屬性,那么和原來的<bean:write />處理是一樣的。
                這樣,類似于下面的鏈接地址:
                <a href="foo.do?param1=<bean:write name="n1" property="p1"/>&param2=<bean:write name="n2" property="p2"/>">Test</a>
                就可以修改成:
                <a href="foo.do?param1=<bean:write name="n1" property="p1" charset="UTF-8"/>&param2=<bean:write name="n2" property="p2" charset="UTF-8"/>">Test</a>
                在request.getParameter("param1")中將會(huì)獲得正確的中文值。
                對(duì)于struts 1.1,程序又稍微有些不同。我將在下一篇隨筆中介紹。
          posted @ 2005-05-20 00:50 小米 閱讀(2099) | 評(píng)論 (5)編輯 收藏
                等了好多天,總于等到了。在China-pub和第二書店都有售。地址:
                http://www.china-pub.com/computers/common/info.asp?id=24500
                http://www.dearbook.com.cn/book/viewbook.aspx?pno=TS0028982
                期待快遞公司快點(diǎn)送過來!
          posted @ 2005-05-18 18:21 小米 閱讀(400) | 評(píng)論 (0)編輯 收藏
                下面是我的一個(gè)簡(jiǎn)單的網(wǎng)絡(luò)服務(wù)器端的程序,程序的流程是監(jiān)聽ACCEPT事件,然后往客戶端輸出一串字符串。是不是很簡(jiǎn)單。

          package sample.nio;

          import java.io.
          *;
          import java.net.
          *;
          import java.nio.channels.
          *;
          import java.util.
          *;

          /**
           * <p>Title: </p>
           *
           * <p>Description: </p>
           *
           * <p>Copyright: Copyright (c) 2005</p>
           *
           * <p>Company: </p>
           *
           * @author George Hill
           * @version 1.0
           
          */


          public class Server {

            
          private int port;

            
          public Server(int port) {
              
          this.port = port;
            }


            
          public void startServer() throws IOException {
              
          // 創(chuàng)建ServerSocketChannel并且綁定到指定的端口
              ServerSocketChannel ssc = ServerSocketChannel.open();
              InetSocketAddress address 
          = new InetSocketAddress(InetAddress.getLocalHost(), port);
              ssc.socket().bind(address);
              ssc.configureBlocking(
          false);

              
          // 創(chuàng)建Selector,并且注冊(cè)ACCEPT事件
              Selector selector = Selector.open();
              SelectionKey skey 
          = ssc.register(selector, SelectionKey.OP_ACCEPT);

              boolean stop 
          = false;
              
          int n = 0;

              System.
          out.println("Server Start");

              
          // 輪詢
              while (!stop) {
                
          // 獲取Selector返回的時(shí)間值
                n = selector.select();

                
          // 當(dāng)傳回的值大于0事,讀時(shí)間發(fā)生了
                if (n > 0{
                  Set 
          set = selector.selectedKeys();
                  Iterator it 
          = set.iterator();

                  
          while (it.hasNext()) {
                    skey 
          = (SelectionKey) it.next();
                    it.remove();

                    
          if (skey.isAcceptable()) {
                      
          // 從channel()中取得剛剛注冊(cè)的Channel
                      Socket socket = ((ServerSocketChannel) skey.channel()).accept().socket();

                      PrintWriter writer 
          = new PrintWriter(socket.getOutputStream(), true);

                      
          // 將"Hello, World"寫入
                      writer.write("Hello, World!\n");

                      
          // 睡眠3秒
                      try {
                        Thread.sleep(
          3000);
                      }
           catch (InterruptedException ie) {
                      }


                      
          // 將"EXIT"寫入Buffer
                      writer.write("EXIT");

                      
          // 退出程序
                      writer.close();
                      
          // stop = true;
                    }

                  }

                }

              }


              ssc.close();
              System.
          out.println("Server Stop");
            }


            
          public static void main(String[] args) throws Exception {
              Server server 
          = new Server(5000);
              server.startServer();
            }

          }

          posted @ 2005-05-18 12:21 小米 閱讀(732) | 評(píng)論 (0)編輯 收藏
               摘要:       最近在做有關(guān)Socket的程序,寫了兩個(gè)客戶端程序,第一個(gè)客戶端程序如下:  1package sample.nio; 2 3import java.io.IOException; 4import java.net.*; 5import&nb...  閱讀全文
          posted @ 2005-05-18 12:18 小米 閱讀(3896) | 評(píng)論 (1)編輯 收藏

                從JDK1.4開始,SUN提供了JCE包,可以實(shí)現(xiàn)多種加密算法。下面是我的一個(gè)用JCE進(jìn)行DES加密解密的程序:

          package sample;

          import java.security.
          *;
          import javax.crypto.
          *;

          /**
           * <p>Title: </p>
           *
           * <p>Description: </p>
           *
           * <p>Copyright: Copyright (c) 2005</p>
           *
           * <p>Company: </p>
           *
           * @author George Hill
           * @version 1.0
           
          */


          public class Test {
            
            
          // 加密使用的Key
            private SecretKey key;
            
            
          // 加密算法,JCE可用DES,DESede和Blowfish
            private static final String algorithm = "DES";
            
            
          public Test() throws NoSuchAlgorithmException {
              KeyGenerator generator 
          = KeyGenerator.getInstance(algorithm);
              key 
          = generator.generateKey();
            }

            
            
          /**
             * 利用DES算法加密
             * @param s String 需要加密的字符串
             * @return String 加密后的字符串
             * @throws Exception
             
          */

            
          public String encryptData(String s) throws Exception {
              Cipher c 
          = Cipher.getInstance(algorithm);
              c.init(Cipher.ENCRYPT_MODE, key);

              
          return new String(c.doFinal(s.getBytes()));
            }

            
            
          /**
             * 利用DES算法解密
             * @param s String 需要解密的字符串
             * @return String 解密后的字符串
             * @throws Exception
             
          */

            
          public String decryptData(String s) throws Exception {
              Cipher c 
          = Cipher.getInstance(algorithm);
              c.init(Cipher.DECRYPT_MODE, key);

              
          return new String(c.doFinal(s.getBytes()));
            }

            
            
          /**
             * 測(cè)試程序
             * @param args String[]
             * @throws Exception
             
          */

            
          public static void main(String[] args) throws Exception {
              String s 
          = "Hello";
              Test test 
          = new Test();
              String encrypt 
          = test.encryptData(s);
              System.
          out.println(encrypt);
              String decrypt 
          = test.decryptData(encrypt);
              System.
          out.println(decrypt);
            }

          }



                在實(shí)際的使用中,往往需要對(duì)加密后的byte數(shù)組進(jìn)行轉(zhuǎn)換,可以自己實(shí)現(xiàn)轉(zhuǎn)換,或者用一些第三方的API。
          posted @ 2005-05-18 11:55 小米 閱讀(2637) | 評(píng)論 (4)編輯 收藏
          僅列出標(biāo)題
          共6頁(yè): 上一頁(yè) 1 2 3 4 5 6 下一頁(yè) 
          主站蜘蛛池模板: 乌兰察布市| 五华县| 平和县| 奉化市| 广德县| 阿图什市| 肥西县| 静宁县| 称多县| 得荣县| 阳春市| 来凤县| 崇礼县| 淄博市| 百色市| 麟游县| 吴旗县| 略阳县| 宜君县| 鹤庆县| 丰都县| 大关县| 大同市| 高平市| 昌黎县| 莫力| 会理县| 兰考县| 公主岭市| 台中县| 连平县| 崇明县| 山西省| 合江县| 龙岩市| 抚顺县| 马龙县| 石楼县| 莒南县| 江口县| 大城县|