少年阿賓

          那些青春的歲月

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            500 Posts :: 0 Stories :: 135 Comments :: 0 Trackbacks

          #

          第一種:(Thread)

          package com.abin.lee.servlet.mythread.thread;

          public class Mythread extends Thread{
           private String name;
           public Mythread(String name) {
            this.name=name;
           }
           public void run() {
            synchronized(this.name){
             System.out.println("開始時間:"+System.currentTimeMillis()+",線程名字:"+Thread.currentThread().getName());
             System.out.println("name="+name);
             System.out.println("結束時間:"+System.currentTimeMillis()+",線程名字:"+Thread.currentThread().getName());
           
            }
           }
           
          }



          測試代碼:

          package com.abin.lee.servlet.mythread.thread;

          public class MythreadTest {
           public static void main(String[] args) {
            Mythread mythread1=new Mythread("ManyThread");
            Mythread mythread2=new Mythread("ManyThread");
            mythread1.start();
            mythread2.start();
           }

          }




          第二種:(Runnable)

          package com.abin.lee.servlet.mythread.runnable;

          public class MyRunnable implements Runnable{
           private String name;
           public MyRunnable(String name) {
            this.name=name;
           }
           public synchronized void run(){
             System.out.println("開始時間:"+System.currentTimeMillis()+",線程名字:"+Thread.currentThread().getName());
             System.out.println("name="+name);
             try {
              Thread.sleep(3000);
             } catch (InterruptedException e) {
              e.printStackTrace();
             }
             System.out.println("結束時間:"+System.currentTimeMillis()+",線程名字:"+Thread.currentThread().getName());
           }
          }




          測試代碼:

          package com.abin.lee.servlet.mythread.runnable;

          public class MyRunnableTest {
           public static void main(String[] args) {
            MyRunnable myRunnable=new MyRunnable("ManyThread");
            Thread thread1=new Thread(myRunnable);
            Thread thread2=new Thread(myRunnable);
            thread1.start();
            thread2.start();
           }
          }




          第三種:(Callable)這種說明一下,這個實現多線程的方式是在JDK1.5引進的,在java.util.concurrent.Callable  這個并發包下面,并且提供同步返回結果的多線程。

          package com.abin.lee.servlet.mythread.callable;

          import java.util.concurrent.Callable;
          import java.util.concurrent.locks.Lock;
          import java.util.concurrent.locks.ReentrantLock;

          public class MyCallable implements Callable<String>{
           private String name;
           public MyCallable(String name) {
            this.name=name;
           }
           public String call() throws Exception {
            Lock lock=new ReentrantLock();
            lock.lock();
            String result="";
            try {
             System.out.println("開始時間:"+System.currentTimeMillis()+",線程名字:"+Thread.currentThread().getName());
             System.out.println("name="+name);
             if(name.equals("ManyThread")){
              result="success";
             }else{
              result="failure";
             }
             try {
              Thread.sleep(3000);
             } catch (InterruptedException e) {
              e.printStackTrace();
             }
             System.out.println("結束時間:"+System.currentTimeMillis()+",線程名字:"+Thread.currentThread().getName());
           
            } catch (Exception e) {
             e.printStackTrace();
            }finally{
             lock.unlock();
            }
               return result;  
           }
           
          }




          測試代碼:

          package com.abin.lee.servlet.mythread.callable;

          import java.util.concurrent.ExecutionException;
          import java.util.concurrent.ExecutorService;
          import java.util.concurrent.Executors;
          import java.util.concurrent.Future;

          import org.junit.Test;

          public class MyCallableTest {
           @Test
           public void testMyCallable() throws InterruptedException, ExecutionException{
            ExecutorService executor=Executors.newFixedThreadPool(3);
            MyCallable myCallable=new MyCallable("ManyThread");
            Future future1=executor.submit(myCallable);
            System.out.println("future1="+future1.get());
            Future future2=executor.submit(myCallable);
            System.out.println("future2="+future2.get());
            Future future3=executor.submit(myCallable);
            System.out.println("future3="+future3.get());
            
           }

          }

          測試結果:

          開始時間:1350056647659,線程名字:pool-1-thread-1
          name=ManyThread
          結束時間:1350056650661,線程名字:pool-1-thread-1
          future1=success
          開始時間:1350056650661,線程名字:pool-1-thread-2
          name=ManyThread
          結束時間:1350056653661,線程名字:pool-1-thread-2
          future2=success
          開始時間:1350056653662,線程名字:pool-1-thread-3
          name=ManyThread
          結束時間:1350056656663,線程名字:pool-1-thread-3
          future3=success
          posted @ 2012-10-12 23:41 abin 閱讀(933) | 評論 (0)編輯 收藏

          package com.abin.lee.servlet.important.type;

          import java.io.Serializable;

          public class LookValue implements Serializable{
           /**
            *
            */
           private static final long serialVersionUID = -7746631577693804188L;
           private int id;
           private String name;
           private transient String status;
           
           public LookValue() {
            super();
           }
           public LookValue(int id, String name, String status) {
            super();
            this.id = id;
            this.name = name;
            this.status = status;
           }
           public int getId() {
            return id;
           }
           public void setId(int id) {
            this.id = id;
           }
           public String getName() {
            return name;
           }
           public void setName(String name) {
            this.name = name;
           }
           public String getStatus() {
            return status;
           }
           public void setStatus(String status) {
            this.status = status;
           }
           
          }





          package com.abin.lee.servlet.important.type.test;

          import java.io.FileInputStream;
          import java.io.FileOutputStream;
          import java.io.IOException;
          import java.io.ObjectInputStream;
          import java.io.ObjectOutputStream;
          import java.io.OutputStream;

          import org.junit.Test;

          import com.abin.lee.servlet.important.type.LookValue;
          import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;

          public class LookValueTest {
           @Test
           public void testLookValue() throws IOException, ClassNotFoundException{
            LookValue look=new LookValue();
            look.setId(1);
            look.setName("abin");
            look.setStatus("abing");
            OutputStream out=new ByteOutputStream();
            FileOutputStream file=new FileOutputStream("data.ser");
            ObjectOutputStream obj=new ObjectOutputStream(file);
            obj.writeObject(look);
            obj.flush();
            obj.close();
            
            look=null;
            FileInputStream input=new FileInputStream("data.ser");
            ObjectInputStream oin=new ObjectInputStream(input);
            look=(LookValue)oin.readObject();
            oin.close();
            System.out.println("id="+look.getId());
            System.out.println("Name="+look.getName());
            System.out.println("Status="+look.getStatus());
           }
          }




          輸出結果:
          id=1
          Name=abin
          Status=null
          posted @ 2012-10-08 21:49 abin 閱讀(762) | 評論 (0)編輯 收藏

          mysql定時器是系統給提供了event,而oracle里面的定時器是系統給提供的job。廢話少說,下面創建表:
          create table mytable (
          id int auto_increment not null,
          name varchar(100) not null default '',
          introduce text not null,
          createtime timestamp not null,
          constraint pk_mytable primary key(id)
          )


          創建存儲過程,這里的存儲過程主要提供給mysql的定時器event來調用去執行:
          create procedure mypro()
          BEGIN
          insert into mytable (name,introduce,createtime) values ('1111','inner mongolia',now());
          end;
          這里只是簡單的寫了一下,只是為了說明例子。


          緊接著創建mysql的定時器event:
          create event if not exists eventJob 
          on schedule every 1 second
          on completion PRESERVE
          do call mypro();
          這里設置為每一秒執行一次


          至此所有的準備工作已經寫完了,做完這些,mysql要想利用定時器必須的做準備工作,就是把mysql的定時器給開啟了:
          SET GLOBAL event_scheduler = 1;  -- 啟動定時器
          SET GLOBAL event_scheduler = 0;  -- 停止定時器


          緊接著還要開啟事件:
          ALTER EVENT eventJob ON  COMPLETION PRESERVE ENABLE;   -- 開啟事件
          ALTER EVENT eventJob ON  COMPLETION PRESERVE DISABLE;  -- 關閉事件


          SHOW VARIABLES LIKE '%sche%'; -- 查看定時器狀態


          至此,你去數據庫里面的表mytable里面看下,系統會每隔一秒去插入一條數據,嘻嘻,任務完成了。
          select * from mytable
          posted @ 2012-10-08 20:22 abin 閱讀(14736) | 評論 (5)編輯 收藏

           在進行性能測試時,一般都需要對應用服務器進行監控,監控的指標包括應用服務器的JVM使用狀況、可用連接數、隊列長度等信息。商業的應用服務器如WebLogic、WebSphere等都提供了Console對這些指標進行監控,在性能測試時可以很容易觀察這些指標的情況。

            Tomcat作為在國內得到廣泛應用的J2EE服務器,在不少項目中都得到了使用。Tomcat小巧靈活、配置簡單,非常適合小的WEB應用使用。但在對使用Tomcat的應用系統進行性能測試時,最頭疼的問題就是不能獲得應用服務器的相關性能指標數據。

            其實,從Tomcat 5.0開始,Tomcat就已經為自己提供了一個用于監控應用服務器性能指標的servelet —— status servelet。安裝完Tomcat 5之后,通過訪問 http://yourhost:port/manager/status 就可以獲得當時的應用服務器監控數據。

            當然,為了安全起見,Tomcat 5在缺省安裝時是不允許用戶直接訪問 http://yourhost:port/manager/status 的,訪問的時候會給出一個403(forbidden)的錯誤信息。在Tomcat的Manual里說明了允許用戶訪問的方法:

             1. 轉到Tomcat的安裝目錄下;
             2. 修改conf/tomcat-users.xml文件,在其中加入一行  <user username="servermon" password="passwd" roles="manager"/>

            這樣就可以在訪問 http://yourhost:port/manager/status 時給出 servermon 的用戶名與口令,查看到應用服務器的相關性能指標數據。



          http://java.chinaitlab.com/server/783798.html 

          posted @ 2012-09-27 20:38 abin 閱讀(324) | 評論 (0)編輯 收藏

          實現servlet的跳轉,以輸入流的形式來傳輸數據

          測試UnionPayServlet的httpClient測試類:
            package com.abin.lee.https;
          import java.io.IOException;
          import java.io.OutputStream;
          import java.io.OutputStreamWriter;
          import java.io.Writer;
          import junit.framework.TestCase;
          import org.apache.http.HttpEntity;
          import org.apache.http.HttpResponse;
          import org.apache.http.client.HttpClient;
          import org.apache.http.client.methods.HttpPost;
          import org.apache.http.entity.ContentProducer;
          import org.apache.http.entity.EntityTemplate;
          import org.apache.http.impl.client.DefaultHttpClient;
          import org.apache.http.util.EntityUtils;
          import org.junit.Test;
          public class HttpClientTest extends TestCase {
          private static final String Url = "http://localhost:9090/Spa/UnionPayServlet";
          @Test
          public void testHttpClient() throws Exception {
          HttpClient client = new DefaultHttpClient();
          HttpPost post = new HttpPost(Url);
          ContentProducer create = new ContentProducer() {
          public void writeTo(OutputStream outstream) throws IOException {
          Writer writer = new OutputStreamWriter(outstream, "UTF-8");
          writer.write("start");
          writer.flush();
          writer.close();
          }
          };
          HttpEntity request = new EntityTemplate(create);
          post.setEntity(request);
          HttpResponse response = client.execute(post);
          HttpEntity entity = response.getEntity();
          String result = EntityUtils.toString(entity);
          System.out.println("the last message is: "+result);
          }
          }



          //被訪問的servlet,也就是中間servlet
          package org.litsoft.air.servlet;
          import java.io.BufferedReader;
          import java.io.BufferedWriter;
          import java.io.IOException;
          import java.io.InputStreamReader;
          import java.io.OutputStream;
          import java.io.OutputStreamWriter;
          import java.io.Writer;
          import javax.servlet.ServletException;
          import javax.servlet.ServletOutputStream;
          import javax.servlet.http.HttpServlet;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          import org.apache.http.HttpEntity;
          import org.apache.http.HttpResponse;
          import org.apache.http.client.HttpClient;
          import org.apache.http.client.methods.HttpPost;
          import org.apache.http.entity.ContentProducer;
          import org.apache.http.entity.EntityTemplate;
          import org.apache.http.impl.client.DefaultHttpClient;
          import org.apache.http.util.EntityUtils;
          public class UnionPayServlet extends HttpServlet {
          private static final String Url = "http://localhost:9090/Spa/changeServlet";
          @Override
          protected void doPost(HttpServletRequest request, HttpServletResponse response)
          throws ServletException, IOException {
          System.out.println("UnionPayServlet");
          String result=null;
          BufferedReader reader=new BufferedReader(new InputStreamReader(request.getInputStream()));
          int num=0;
          char[] buffer=new char[1024];
          while((num=reader.read(buffer))!=-1){
          result=new String(buffer,0,num);
          }
          System.out.println("from HttpCLient message is: ="+result);
          final String transfer=result;
          HttpClient client = new DefaultHttpClient();
          HttpPost post = new HttpPost(Url);
          ContentProducer create = new ContentProducer() {
          public void writeTo(OutputStream outstream) throws IOException {
          Writer writer = new OutputStreamWriter(outstream, "UTF-8");
          writer.write(transfer);
          writer.flush();
          writer.close();
          }
          };
          HttpEntity httpEntity = new EntityTemplate(create);
          post.setEntity(httpEntity);
          HttpResponse httpResponse = client.execute(post);
          HttpEntity entity = httpResponse.getEntity();
          String result1 = EntityUtils.toString(entity);
          // System.out.println(result1);
          ServletOutputStream out=response.getOutputStream();
          BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(out));
          writer.write("this message is received by UnionPayServlet is: "+result1);
          writer.flush();
          writer.close();
          }
          @Override
          public void destroy() {
          super.destroy();
          }
          }




          //最終要處理的servlet
          package org.litsoft.air.servlet;
          import java.io.BufferedReader;
          import java.io.BufferedWriter;
          import java.io.IOException;
          import java.io.InputStreamReader;
          import java.io.OutputStreamWriter;
          import java.io.PrintWriter;
          import java.net.HttpURLConnection;
          import java.net.URL;
          import javax.servlet.ServletException;
          import javax.servlet.ServletOutputStream;
          import javax.servlet.http.HttpServlet;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          import org.litsoft.air.unionpay.CreateJdomOne;
          public class ChangeServlet extends HttpServlet {
          @Override
          protected void doPost(HttpServletRequest request,
          HttpServletResponse response) throws ServletException, IOException {
          // 接收Servlet傳回來的信息
          BufferedReader reader = new BufferedReader(new InputStreamReader(
          request.getInputStream()));
          String show = null;
          StringBuffer stb = new StringBuffer();
          while ((show = reader.readLine()) != null) {
          stb.append(show);
          }
          System.out.println("from UnionPayServlet message is :" + stb.toString());
          reader.close();
          ServletOutputStream out=response.getOutputStream();
          BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(out));
          writer.write("this message is received by ChangeServlet is :"+stb.toString());
          writer.flush();
          writer.close();
          }
          }


          //servlet的配置
          <?xml version="1.0" encoding="UTF-8"?>
          <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
          http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
          <servlet>
          <servlet-name>UnionPayServlet</servlet-name>
          <servlet-class>org.litsoft.air.servlet.UnionPayServlet</servlet-class>
          </servlet>
          <servlet-mapping>
          <servlet-name>UnionPayServlet</servlet-name>
          <url-pattern>/UnionPayServlet</url-pattern>
          </servlet-mapping>
          <servlet>
          <servlet-name>changeServlet</servlet-name>
          <servlet-class>org.litsoft.air.servlet.ChangeServlet</servlet-class>
          </servlet>
          <servlet-mapping>
          <servlet-name>changeServlet</servlet-name>
          <url-pattern>/changeServlet</url-pattern>
          </servlet-mapping>
          <welcome-file-list>
          <welcome-file>index.jsp</welcome-file>
          </welcome-file-list>
          </web-app>
          posted @ 2012-09-27 20:31 abin 閱讀(1837) | 評論 (0)編輯 收藏

          以下文章都是整合了好多網上的好多朋友的優秀資源,才寫出來的。具體參考過誰的,我也記不清楚了。關于怎么生成https雙向的證書,地址在這里:
          http://www.aygfsteel.com/stevenjohn/archive/2012/08/22/385989.html 
          應該正常來說,按照這個教程做的話是沒有任何問題的,但是也有些朋友出過問題,主要問題是在,把證書導入到瀏覽器里面的時候出的,注意這里。

          我這里面的我都做過三四次了,基本沒啥問題。但也不排除不會不出問題。

          由于網上關于httpCilent來測試調用HTTPS的例子較少,經過在度娘和谷爹的查找,總算是也找到了一篇文章,參考以后,做出來一個測試類,在我機器上面是能夠跑通的。具體地址:http://www.aygfsteel.com/stevenjohn/archive/2012/09/27/388646.html 



          //首先說一下,這個是我隨便寫的一個發布到tomcat的httpsUrlConnection的Servlet服務,主要是用來測試一下https雙向驗證的,現在網上好多的文章都是https單向驗證的Java代碼,我在網上看過好多,但是好多都是半成品,然后總結了一下,在自己的機器上面是完全能夠跑通的,在這里做個筆記,以后用得著的時候來拿:
          package com.abin.lee.https;
          import java.io.BufferedReader;
          import java.io.IOException;
          import java.io.InputStreamReader;
          import java.io.PrintWriter;
          import java.util.Enumeration;
          import java.util.Map;
          import javax.servlet.ServletException;
          import javax.servlet.ServletOutputStream;
          import javax.servlet.http.HttpServlet;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          @SuppressWarnings("serial")
          public class ReceiveHttpsUrlConnectionRequest extends HttpServlet {
          public void service(HttpServletRequest request, HttpServletResponse response)
          throws ServletException, IOException {
          System.out.println("receive https request");
                          /**這個主要是接收,由對方給以POST形式發過來的內容,這種內容不是以key-value的形式發的,而是直接通過Java的
                          *string content="test https double auth";
                          *BufferedWriter writer  = new BufferedWriter();
                          *writer.writer(content.getBytes());
                          *通過這種形式發過來的內容的接收,由于直接放到request里面發送過來的,所以的從request里面來接收。
                          *之前做銀聯的手機支付的時候也是這么傳遞參數的。
                          */
          BufferedReader reader=new BufferedReader(new InputStreamReader(request.getInputStream()));
          String line=null;
          StringBuffer stb=new StringBuffer();
                          //循環的一行一行的讀取內容
               while((line=reader.readLine())!=null){
          stb.append(line);
          }
                          //打印讀取到的內容。
          System.out.println("stb="+stb.toString());
                          //給調用者返回內容
          PrintWriter write=response.getWriter();
          write.write("receive HttpsUrlConnection success");
          write.flush();
          write.close();
          }
          }




          //這個是在web工程里面的web.xml里面配置的發布的servlet服務
          //web.xml
          <servlet>
          <servlet-name>httpsUrlConnectionRequest</servlet-name>
          <servlet-class>com.abin.lee.https.ReceiveHttpsUrlConnectionRequest</servlet-class>
          </servlet>
          <servlet-mapping>
          <servlet-name>httpsUrlConnectionRequest</servlet-name>
          <url-pattern>/httpsUrlConnectionRequest</url-pattern>
          </servlet-mapping>

          //HttpsUrlConnection測試類
          package com.abin.lee.test;
          import java.io.BufferedReader;
          import java.io.IOException;
          import java.io.InputStreamReader;
          import java.io.OutputStream;
          import java.net.URL;
          import java.util.Date;
          import javax.net.ssl.HostnameVerifier;
          import javax.net.ssl.HttpsURLConnection;
          import javax.net.ssl.SSLSession;
          import junit.framework.TestCase;
          import org.junit.Before;
          import org.junit.Test;
          public class HttpsUrlConnectionClient extends TestCase {
          // 客戶端密鑰庫
          private String sslKeyStorePath;
          private String sslKeyStorePassword;
          private String sslKeyStoreType;
          // 客戶端信任的證書
          private String sslTrustStore;
          private String sslTrustStorePassword;
                  //上面發布的servlet請求地址
          private String httpsUrlConnectionUrl = "https://localhost:8443/global/httpsUrlConnectionRequest";
          @Before
          public void setUp() {
                          //這是密鑰庫
               sslKeyStorePath = "D:\\home\\tomcat.keystore";
          sslKeyStorePassword = "stevenjohn";
          sslKeyStoreType = "JKS"; // 密鑰庫類型,有JKS PKCS12等
                          //信任庫,這里需要服務端來新人客戶端才能調用,因為這個我是配置的https雙向驗證,不但是要客戶端信任服務端,服務端也要信任客戶端。
          sslTrustStore = "D:\\home\\tomcat.keystore";
          sslTrustStorePassword = "stevenjohn";
          System.setProperty("javax.net.ssl.keyStore", sslKeyStorePath);
          System.setProperty("javax.net.ssl.keyStorePassword",
          sslKeyStorePassword);
          System.setProperty("javax.net.ssl.keyStoreType", sslKeyStoreType);
          // 設置系統參數
          System.setProperty("javax.net.ssl.trustStore", sslTrustStore);
          System.setProperty("javax.net.ssl.trustStorePassword",
          sslTrustStorePassword);
          System.setProperty("java.protocol.handler.pkgs", "sun.net.www.protocol");
          }
          @Test
          public void testHttpsUrlConnectionClient() {
          try {
          URL url = new URL(httpsUrlConnectionUrl);
                                  //對于主機名的驗證,因為配置服務器端的tomcat.keystore的證書的時候,是需要填寫用戶名的,一般用戶名來說是本地ip地址,或者本地配置的域名
               HostnameVerifier hv = new HostnameVerifier() {
          public boolean verify(String urlHostName, SSLSession session) {
          return true;
          }
          };
          HttpsURLConnection.setDefaultHostnameVerifier(hv);
                                  //編寫HttpsURLConnection 的請求對象,這里需要注意HttpsURLConnection 比我們平時用的HttpURLConnection對了一個s,因為https是也是遵循http協議的,并且是采用ssl這個安全套接字來傳輸信息的,但是也有可能遭到黑客的攻擊  
          HttpsURLConnection connection = (HttpsURLConnection) url
          .openConnection();
          connection.setRequestProperty("Content-Type", "text/xml");
          connection.setDoOutput(true);
          connection.setDoInput(true);
                                  //設置請求方式為post,這里面當然也可以用get,但是我這里必須用post
               connection.setRequestMethod("POST");
          connection.setUseCaches(false);
          connection.setReadTimeout(30000);
          String user="abin";
          String pwd="abing";
          String request="user="+user+"&pwd="+pwd;
          OutputStream out = connection.getOutputStream();
                                  //下面的這句話是給servlet發送請求內容
          out.write(request.getBytes());
          out.flush();
          out.close();
          //接收請求的返回值
          BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
          StringBuffer stb = new StringBuffer();
          String line;
          while ((line = reader.readLine()) != null) {
          stb.append(line);
          }
          Integer statusCode = connection.getResponseCode();
          System.out.println("返回狀態碼:" + statusCode);
          reader.close();
          connection.disconnect();
          } catch (IOException e) {
          e.printStackTrace();
          }
          }
          }




          //發布好了服務,你需要在tomcat里面配置好了https服務的端口才能使用。
          //tomcat配置文件:
           <Connector port="6060" protocol="HTTP/1.1" 
                         connectionTimeout="20000" 
                         redirectPort="8443" />
                  
                  /**關于https端口的說明,銀聯一般用的都是0--9  443,這種類型的端口,第一位是0--9中的任意一位,然后后面三位是443,而通過我的測試,發覺隨便一個端口號都可           *   以的,只要不和你機器的其他端口沖突就行,911,95553這些端口都是可以滴。
                    *clientAuth="true"   這里設置為false是https單向認證,設置為true則是https雙向認證
                  */
          <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
            SSLEnabled="true" maxThreads="150" scheme="https"
            secure="true" clientAuth="true" sslProtocol="TLS"
            keystoreFile="D:\\home\\tomcat.keystore" keystorePass="stevenjohn"  //密鑰庫
            truststoreFile="D:\\home\\tomcat.keystore" truststorePass="stevenjohn" />//信任庫
          posted @ 2012-09-27 00:16 abin 閱讀(11254) | 評論 (1)編輯 收藏

          已經發布的準備要測試的https服務:
          package com.abin.lee.https;
          import java.io.IOException;
          import java.io.PrintWriter;
          import java.util.Map;
          import javax.servlet.ServletException;
          import javax.servlet.http.HttpServlet;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          @SuppressWarnings("serial")
          public class ReceiveHttpClientRequest extends HttpServlet {
          public void service(HttpServletRequest request, HttpServletResponse response)
          throws ServletException, IOException {
          System.out.println("receive https request");
          Map map=request.getParameterMap();
          String user=(((Object[])map.get("user"))[0]).toString();
          System.out.println("user="+user);
          String pwd=(((Object[])map.get("pwd"))[0]).toString();
          System.out.println("pwd="+pwd);
          //給調用者返回值
          PrintWriter write=response.getWriter();
          write.write("receive HttpClient success");
          write.flush();
          write.close();
          }
          }





          //web.xml
          <servlet>
          <servlet-name>httpsClientRequest</servlet-name>
          <servlet-class>com.abin.lee.https.ReceiveHttpClientRequest</servlet-class>
          </servlet>
          <servlet-mapping>
          <servlet-name>httpsClientRequest</servlet-name>
          <url-pattern>/httpsClientRequest</url-pattern>
          </servlet-mapping>




          //HttpClient測試類
          package com.abin.lee.test;
          import java.io.BufferedReader;
          import java.io.FileInputStream;
          import java.io.InputStreamReader;
          import java.security.KeyStore;
          import java.util.ArrayList;
          import java.util.List;
          import javax.net.ssl.KeyManagerFactory;
          import javax.net.ssl.SSLContext;
          import javax.net.ssl.TrustManager;
          import javax.net.ssl.TrustManagerFactory;
          import junit.framework.TestCase;
          import org.apache.http.HttpResponse;
          import org.apache.http.NameValuePair;
          import org.apache.http.client.HttpClient;
          import org.apache.http.client.entity.UrlEncodedFormEntity;
          import org.apache.http.client.methods.HttpPost;
          import org.apache.http.conn.scheme.Scheme;
          import org.apache.http.conn.ssl.SSLSocketFactory;
          import org.apache.http.impl.client.DefaultHttpClient;
          import org.apache.http.message.BasicNameValuePair;
          import org.apache.http.protocol.HTTP;
          import org.junit.Before;
          import org.junit.Test;
          public class HttpsClient extends TestCase {
          private String httpUrl = "https://localhost:8443/global/httpsClientRequest";
          // 客戶端密鑰庫
          private String sslKeyStorePath;
          private String sslKeyStorePassword;
          private String sslKeyStoreType;
          // 客戶端信任的證書
          private String sslTrustStore;
          private String sslTrustStorePassword;
          @Before
          public void setUp() {
          sslKeyStorePath = "D:\\home\\tomcat.keystore";
          sslKeyStorePassword = "stevenjohn";
          sslKeyStoreType = "JKS"; // 密鑰庫類型,有JKS PKCS12等
          sslTrustStore = "D:\\home\\tomcat.keystore";
          sslTrustStorePassword = "stevenjohn";
          System.setProperty("javax.net.ssl.keyStore", sslKeyStorePath);
          System.setProperty("javax.net.ssl.keyStorePassword",
          sslKeyStorePassword);
          System.setProperty("javax.net.ssl.keyStoreType", sslKeyStoreType);
          // 設置系統參數
          System.setProperty("javax.net.ssl.trustStore", sslTrustStore);
          System.setProperty("javax.net.ssl.trustStorePassword",
          sslTrustStorePassword);
          }
          @Test
          public void testHttpsClient() {
          SSLContext sslContext = null;
          try {
          KeyStore kstore = KeyStore.getInstance("jks");
          kstore.load(new FileInputStream(sslKeyStorePath),
          sslKeyStorePassword.toCharArray());
          KeyManagerFactory keyFactory = KeyManagerFactory
          .getInstance("sunx509");
          keyFactory.init(kstore, sslKeyStorePassword.toCharArray());
          KeyStore tstore = KeyStore.getInstance("jks");
          tstore.load(new FileInputStream(sslTrustStore),
          sslTrustStorePassword.toCharArray());
          TrustManager[] tm;
          TrustManagerFactory tmf = TrustManagerFactory
          .getInstance("sunx509");
          tmf.init(tstore);
          tm = tmf.getTrustManagers();
          sslContext = SSLContext.getInstance("SSL");
          sslContext.init(keyFactory.getKeyManagers(), tm, null);
          } catch (Exception e) {
          e.printStackTrace();
          }
          try {
          HttpClient httpClient = new DefaultHttpClient();
          SSLSocketFactory socketFactory = new SSLSocketFactory(sslContext);
          Scheme sch = new Scheme("https", 8443, socketFactory);
          httpClient.getConnectionManager().getSchemeRegistry().register(sch);
          HttpPost httpPost = new HttpPost(httpUrl);
          List<NameValuePair> nvps = new ArrayList<NameValuePair>();
          nvps.add(new BasicNameValuePair("user", "abin"));
          nvps.add(new BasicNameValuePair("pwd", "abing"));
          httpPost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
          HttpResponse httpResponse = httpClient.execute(httpPost);
          String spt = System.getProperty("line.separator"); 
          BufferedReader buffer = new BufferedReader(new InputStreamReader(
          httpResponse.getEntity().getContent()));
          StringBuffer stb=new StringBuffer();
          String line=null;
          while((line=buffer.readLine())!=null){
          stb.append(line);
          }
          buffer.close();
          String result=stb.toString();
          System.out.println("result="+result);
          } catch (Exception e) {
          e.printStackTrace();
          }
          }
          }







          //tomcat配置文件:(前提是https雙向驗證證書生成的沒有一點問題)

          <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
            SSLEnabled="true" maxThreads="150" scheme="https"
            secure="true" clientAuth="true" sslProtocol="TLS"
            keystoreFile="D:\\home\\tomcat.keystore" keystorePass="stevenjohn"
            truststoreFile="D:\\home\\tomcat.keystore" truststorePass="stevenjohn" />



          posted @ 2012-09-27 00:11 abin 閱讀(3203) | 評論 (0)編輯 收藏

          HttpClient程序包是一個實現了 HTTP 協議的客戶端編程工具包,要想熟練的掌握它,必須熟悉 HTTP協議。一個最簡單的調用如下:
           
          import java.io.IOException;
          import org.apache.http.HttpResponse;
          import org.apache.http.client.ClientProtocolException;
          import org.apache.http.client.HttpClient;
          import org.apache.http.client.methods.HttpGet;
          import org.apache.http.client.methods.HttpUriRequest;
          import org.apache.http.impl.client.DefaultHttpClient;
           
          public class Test {
              public static void main(String[] args) {
           
                 // 核心應用類
                 HttpClient httpClient = new DefaultHttpClient();
           
                  // HTTP請求
                  HttpUriRequest request =
                          new HttpGet("http://localhost/index.html");
           
                  // 打印請求信息
                  System.out.println(request.getRequestLine());
                  try {
                      // 發送請求,返回響應
                      HttpResponse response = httpClient.execute(request);
           
                      // 打印響應信息
                      System.out.println(response.getStatusLine());
                  } catch (ClientProtocolException e) {
                      // 協議錯誤
                      e.printStackTrace();
                  } catch (IOException e) {
                      // 網絡異常
                      e.printStackTrace();
                  }
              }
          }
           
          如果HTTP服務器正常并且存在相應的服務,則上例會打印出兩行結果:
           
              GET http://localhost/index.html HTTP/1.1
              HTTP/1.1 200 OK 
           
          核心對象httpClient的調用非常直觀,其execute方法傳入一個request對象,返回一個response對象。使用 httpClient發出HTTP請求時,系統可能拋出兩種異常,分別是ClientProtocolException和IOException。第一種異常的發生通常是協議錯誤導致,如在構造HttpGet對象時傳入的協議不對(例如不小心將”http”寫成”htp”),或者服務器端返回的內容不符合HTTP協議要求等;第二種異常一般是由于網絡原因引起的異常,如HTTP服務器未啟動等。
          從實際應用的角度看,HTTP協議由兩大部分組成:HTTP請求和HTTP響應。那么HttpClient程序包是如何實現HTTP客戶端應用的呢?實現過程中需要注意哪些問題呢?
          HTTP請求
           
          HTTP 1.1由以下幾種請求組成:GET, HEAD, POST, PUT, DELETE, TRACE and OPTIONS, 程序包中分別用HttpGet, HttpHead, HttpPost, HttpPut, HttpDelete, HttpTrace, and HttpOptions 這幾個類創建請求。所有的這些類均實現了HttpUriRequest接口,故可以作為execute的執行參數使用。
          所有請求中最常用的是GET與POST兩種請求,與創建GET請求的方法相同,可以用如下方法創建一個POST請求:
           
          HttpUriRequest request = new HttpPost(
                  "http://localhost/index.html");
           
           
          HTTP請求格式告訴我們,有兩個位置或者說兩種方式可以為request提供參數:request-line方式與request-body方式。
          request-line
           
          request-line方式是指在請求行上通過URI直接提供參數。
          (1)
          我們可以在生成request對象時提供帶參數的URI,如:
           
          HttpUriRequest request = new HttpGet(
                  "http://localhost/index.html?param1=value1&param2=value2");
           
          (2)
          另外,HttpClient程序包為我們提供了URIUtils工具類,可以通過它生成帶參數的URI,如:
           
          URI uri = URIUtils.createURI("http", "localhost", -1, "/index.html",
              "param1=value1&param2=value2", null);
          HttpUriRequest request = new HttpGet(uri);
          System.out.println(request.getURI());
           
          上例的打印結果如下:
           
              http://localhost/index.html?param1=value1&param2=value2
           
          (3)
          需要注意的是,如果參數中含有中文,需將參數進行URLEncoding處理,如:
           
          String param = "param1=" + URLEncoder.encode("中國", "UTF-8") + "&param2=value2";
          URI uri = URIUtils.createURI("http", "localhost", 8080,
          "/sshsky/index.html", param, null);
          System.out.println(uri);
           
          上例的打印結果如下:
           
              http://localhost/index.html?param1=%E4%B8%AD%E5%9B%BD&param2=value2
           
          (4)
          對于參數的URLEncoding處理,HttpClient程序包為我們準備了另一個工具類:URLEncodedUtils。通過它,我們可以直觀的(但是比較復雜)生成URI,如:
           
          List params = new ArrayList();
          params.add(new BasicNameValuePair("param1", "中國"));
          params.add(new BasicNameValuePair("param2", "value2"));
          String param = URLEncodedUtils.format(params, "UTF-8");
          URI uri = URIUtils.createURI("http", "localhost", 8080,
          "/sshsky/index.html", param, null);
          System.out.println(uri);
           
          上例的打印結果如下:
           
              http://localhost/index.html?param1=%E4%B8%AD%E5%9B%BD&param2=value2
           
          request-body
           
          與request-line方式不同,request-body方式是在request-body中提供參數,此方式只能用于POST請求。在 HttpClient程序包中有兩個類可以完成此項工作,它們分別是UrlEncodedFormEntity類與MultipartEntity類。這兩個類均實現了HttpEntity接口。
          (1)
          使用最多的是UrlEncodedFormEntity類。通過該類創建的對象可以模擬傳統的HTML表單傳送POST請求中的參數。如下面的表單:
           
          <form action="http://localhost/index.html" method="POST">
              <input type="text" name="param1" value="中國"/>
              <input type="text" name="param2" value="value2"/>
              <inupt type="submit" value="submit"/>
          </form>
           
          我們可以用下面的代碼實現:
           
          List formParams = new ArrayList();
          formParams.add(new BasicNameValuePair("param1", "中國"));
          formParams.add(new BasicNameValuePair("param2", "value2"));
          HttpEntity entity = new UrlEncodedFormEntity(formParams, "UTF-8");
           
          HttpPost request = new HttpPost(“http://localhost/index.html”);
          request.setEntity(entity);
           
          當然,如果想查看HTTP數據格式,可以通過HttpEntity對象的各種方法取得。如:
           
          List formParams = new ArrayList();
          formParams.add(new BasicNameValuePair("param1", "中國"));
          formParams.add(new BasicNameValuePair("param2", "value2"));
          UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formParams, "UTF-8");
           
          System.out.println(entity.getContentType());
          System.out.println(entity.getContentLength());
          System.out.println(EntityUtils.getContentCharSet(entity));
          System.out.println(EntityUtils.toString(entity));
           
          上例的打印結果如下:
           
              Content-Type: application/x-www-form-urlencoded; charset=UTF-8
              39
              UTF-8
              param1=%E4%B8%AD%E5%9B%BD&param2=value2 
           
          (2)
          除了傳統的application/x-www-form-urlencoded表單,我們另一個經常用到的是上傳文件用的表單,這種表單的類型為 multipart/form-data。在HttpClient程序擴展包(HttpMime)中專門有一個類與之對應,那就是 MultipartEntity類。此類同樣實現了HttpEntity接口。如下面的表單:
           
          <form action="http://localhost/index.html" method="POST"
                  enctype="multipart/form-data">
              <input type="text" name="param1" value="中國"/>
              <input type="text" name="param2" value="value2"/>
              <input type="file" name="param3"/>
              <inupt type="submit" value="submit"/>
          </form>
           
          我們可以用下面的代碼實現:
           
          MultipartEntity entity = new MultipartEntity();
          entity.addPart("param1", new StringBody("中國", Charset.forName("UTF-8")));
          entity.addPart("param2", new StringBody("value2", Charset.forName("UTF-8")));
          entity.addPart("param3", new FileBody(new File("C:\\1.txt")));
           
          HttpPost request = new HttpPost(“http://localhost/index.html”);
          request.setEntity(entity);
           
          HTTP響應
           
          HttpClient程序包對于HTTP響應的處理較之HTTP請求來說是簡單多了,其過程同樣使用了HttpEntity接口。我們可以從 HttpEntity對象中取出數據流(InputStream),該數據流就是服務器返回的響應數據。需要注意的是,HttpClient程序包不負責解析數據流中的內容。如:
           
          HttpUriRequest request = ...;
          HttpResponse response = httpClient.execute(request);
           
          // 從response中取出HttpEntity對象
          HttpEntity entity = response.getEntity();
           
          // 查看entity的各種指標
          System.out.println(entity.getContentType());
          System.out.println(entity.getContentLength());
          System.out.println(EntityUtils.getContentCharSet(entity));
           
          // 取出服務器返回的數據流
          InputStream stream = entity.getContent();
           
          // 以任意方式操作數據流stream
          // 調用方式 略
           
          附注:
           
          本文說明的是HttpClient 4.0.1,該程序包(包括依賴的程序包)由以下幾個JAR包組成:
           
          commons-logging-1.1.1.jar
          commons-codec-1.4.jar
          httpcore-4.0.1.jar
          httpclient-4.0.1.jar
          apache-mime4j-0.6.jar
          httpmime-4.0.1.jar
           
          可以在此處下載完整的JAR包。
           
           
           
           
          現在Apache已經發布了:HttpCore 4.0-beta3、HttpClient 4.0-beta1。
          到此處可以去下載這些源代碼:http://hc.apache.org/downloads.cgi
          另外,還需要apache-mime4j-0.5.jar 包。
           
          在這里先寫個簡單的POST方法,中文資料不多,英文不太好。
          package test;
           
          import java.util.ArrayList;
          import java.util.List;
          import org.apache.http.Header;
          import org.apache.http.HttpEntity;
          import org.apache.http.HttpResponse;
          import org.apache.http.NameValuePair;
          import org.apache.http.client.entity.UrlEncodedFormEntity;
          import org.apache.http.client.methods.HttpPost;
          import org.apache.http.client.params.CookiePolicy;
          import org.apache.http.client.params.ClientPNames;
          import org.apache.http.impl.client.DefaultHttpClient;
          import org.apache.http.message.BasicNameValuePair;
          import org.apache.http.protocol.HTTP;
          import org.apache.http.util.EntityUtils;
           
          public class Test2 {
              public static void main(String[] args) throws Exception {
                  DefaultHttpClient httpclient = new DefaultHttpClient();      //實例化一個HttpClient
                  HttpResponse response = null;
                  HttpEntity entity = null;
                  httpclient.getParams().setParameter(
                          ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY);  //設置cookie的兼容性
                  HttpPost httpost = new HttpPost("http://127.0.0.1:8080/pub/jsp/getInfo");           //引號中的參數是:servlet的地址
                  List <NameValuePair> nvps = new ArrayList <NameValuePair>();                     
                  nvps.add(new BasicNameValuePair("jqm", "fb1f7cbdaf2bf0a9cb5d43736492640e0c4c0cd0232da9de"));  
                  //   BasicNameValuePair("name", "value"), name是post方法里的屬性, value是傳入的參數值
                  nvps.add(new BasicNameValuePair("sqm", "1bb5b5b45915c8"));
                  httpost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));            //將參數傳入post方法中
                  response = httpclient.execute(httpost);                                               //執行
                  entity = response.getEntity();                                                             //返回服務器響應
                  try{
                      System.out.println("----------------------------------------");
                      System.out.println(response.getStatusLine());                           //服務器返回狀態
                      Header[] headers = response.getAllHeaders();                    //返回的HTTP頭信息
                      for (int i=0; i<headers.length; i++) {                              
                      System.out.println(headers[i]);
                      }
                      System.out.println("----------------------------------------");
                      String responseString = null;
                      if (response.getEntity() != null) {
                      responseString = EntityUtils.toString(response.getEntity());      / /返回服務器響應的HTML代碼
                      System.out.println(responseString);                                   //打印出服務器響應的HTML代碼
                      }
                  } finally {
                      if (entity != null)                          
                      entity.consumeContent();                                                   // release connection gracefully
                  }
                  System.out.println("Login form get: " + response.getStatusLine());
                  if (entity != null) {
                  entity.consumeContent();
                  }
                 
              }
          }
           
           
           
           
          HttpClient4.0 學習實例 - 頁面獲取
           
          HttpClient 4.0出來不久,所以網絡上面相關的實例教程不多,搜httpclient得到的大部分都是基于原 Commons HttpClient 3.1 (legacy) 包的,官網下載頁面:http://hc.apache.org/downloads.cgi,如果大家看了官網說明就明白httpclient4.0是從原包分支出來獨立成包的,以后原來那個包中的httpclient不會再升級,所以以后我們是用httpclient新分支,由于4.0與之前的3.1包結構以及接口等都有較大變化,所以網上搜到的實例大部分都是不適合4.0的,當然,我們可以通過那些實例去琢磨4.0的用法,我也是新手,記錄下學習過程方便以后檢索
           
          本實例我們來獲取抓取網頁編碼,內容等信息
           
          默認情況下,服務器端會根據客戶端的請求頭信息來返回服務器支持的編碼,像google.cn他本身支持utf-8,gb2312等編碼,所以如果你在頭部中不指定任何頭部信息的話他默認會返回gb2312編碼,而如果我們在瀏覽器中直接訪問google.cn,通過httplook,或者firefox 的firebug插件查看返回頭部信息的話會發現他返回的是UTF-8編碼
           
          下面我們還是看實例來解說吧,注釋等我也放代碼里面解釋,放完整代碼,方便新手理解
           
          本實例將
           
          使用的httpclient相關包
          httpclient-4.0.jar
          httpcore-4.0.1.jar
          httpmime-4.0.jar
          commons-logging-1.0.4.jar等其它相關包
           
          // HttpClientTest.java
          package com.baihuo.crawler.test;
           
          import java.util.regex.Matcher;
          import java.util.regex.Pattern;
           
          import org.apache.http.Header;
          import org.apache.http.HttpEntity;
          import org.apache.http.HttpHost;
          import org.apache.http.HttpResponse;
          import org.apache.http.client.HttpClient;
          import org.apache.http.client.methods.HttpGet;
          import org.apache.http.impl.client.DefaultHttpClient;
          import org.apache.http.util.EntityUtils;
           
          class HttpClientTest {
           
              public final static void main(String[] args) throws Exception {
           
                  // 初始化,此處構造函數就與3.1中不同
                  HttpClient httpclient = new DefaultHttpClient();
           
                  HttpHost targetHost = new HttpHost("www.google.cn");
                  //HttpGet httpget = new HttpGet("http://www.apache.org/");
                  HttpGet httpget = new HttpGet("/");
           
                  // 查看默認request頭部信息
                  System.out.println("Accept-Charset:" + httpget.getFirstHeader("Accept-Charset"));
                  // 以下這條如果不加會發現無論你設置Accept-Charset為gbk還是utf-8,他都會默認返回gb2312(本例針對google.cn來說)
                  httpget.setHeader("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.2)");
                  // 用逗號分隔顯示可以同時接受多種編碼
                  httpget.setHeader("Accept-Language", "zh-cn,zh;q=0.5");
                  httpget.setHeader("Accept-Charset", "GB2312,utf-8;q=0.7,*;q=0.7");
                  // 驗證頭部信息設置生效
                  System.out.println("Accept-Charset:" + httpget.getFirstHeader("Accept-Charset").getValue());
           
                  // Execute HTTP request
                  System.out.println("executing request " + httpget.getURI());
                  HttpResponse response = httpclient.execute(targetHost, httpget);
                  //HttpResponse response = httpclient.execute(httpget);
           
                  System.out.println("----------------------------------------");
                  System.out.println("Location: " + response.getLastHeader("Location"));
                  System.out.println(response.getStatusLine().getStatusCode());
                  System.out.println(response.getLastHeader("Content-Type"));
                  System.out.println(response.getLastHeader("Content-Length"));
                  
                  System.out.println("----------------------------------------");
           
                  // 判斷頁面返回狀態判斷是否進行轉向抓取新鏈接
                  int statusCode = response.getStatusLine().getStatusCode();
                  if ((statusCode == HttpStatus.SC_MOVED_PERMANENTLY) ||
                          (statusCode == HttpStatus.SC_MOVED_TEMPORARILY) ||
                          (statusCode == HttpStatus.SC_SEE_OTHER) ||
                          (statusCode == HttpStatus.SC_TEMPORARY_REDIRECT)) {
                      // 此處重定向處理  此處還未驗證
                      String newUri = response.getLastHeader("Location").getValue();
                      httpclient = new DefaultHttpClient();
                      httpget = new HttpGet(newUri);
                      response = httpclient.execute(httpget);
                  }
           
                  // Get hold of the response entity
                  HttpEntity entity = response.getEntity();
                  
                  // 查看所有返回頭部信息
                  Header headers[] = response.getAllHeaders();
                  int ii = 0;
                  while (ii < headers.length) {
                      System.out.println(headers[ii].getName() + ": " + headers[ii].getValue());
                      ++ii;
                  }
                  
                  // If the response does not enclose an entity, there is no need
                  // to bother about connection release
                  if (entity != null) {
                      // 將源碼流保存在一個byte數組當中,因為可能需要兩次用到該流,
                      byte[] bytes = EntityUtils.toByteArray(entity);
                      String charSet = "";
                      
                      // 如果頭部Content-Type中包含了編碼信息,那么我們可以直接在此處獲取
                      charSet = EntityUtils.getContentCharSet(entity);
           
                      System.out.println("In header: " + charSet);
                      // 如果頭部中沒有,那么我們需要 查看頁面源碼,這個方法雖然不能說完全正確,因為有些粗糙的網頁編碼者沒有在頁面中寫頭部編碼信息
                      if (charSet == "") {
                          regEx="(?=<meta).*?(?<=charset=[\\'|\\\"]?)([[a-z]|[A-Z]|[0-9]|-]*)";
                          p=Pattern.compile(regEx, Pattern.CASE_INSENSITIVE);
                          m=p.matcher(new String(bytes));  // 默認編碼轉成字符串,因為我們的匹配中無中文,所以串中可能的亂碼對我們沒有影響
                          result=m.find();
                          if (m.groupCount() == 1) {
                              charSet = m.group(1);
                          } else {
                              charSet = "";
                          }
                      }
                      System.out.println("Last get: " + charSet);
                      // 至此,我們可以將原byte數組按照正常編碼專成字符串輸出(如果找到了編碼的話)
                      System.out.println("Encoding string is: " + new String(bytes, charSet));
                  }
           
                  httpclient.getConnectionManager().shutdown();        
              }
           
          }



          http://www.cnblogs.com/loveyakamoz/archive/2011/07/21/2113252.html
          posted @ 2012-09-26 16:46 abin 閱讀(5402) | 評論 (1)編輯 收藏

          第六章 高級主題

          6.1 自定義客戶端連接

          在特定條件下,也許需要來定制HTTP報文通過線路傳遞,越過了可能使用的HTTP參數來處理非標準不兼容行為的方式。比如,對于Web爬蟲,它可能需要強制HttpClient接受格式錯誤的響應頭部信息,來搶救報文的內容。

          通常插入一個自定義的報文解析器的過程或定制連接實現需要幾個步驟:

          提供一個自定義LineParser/LineFormatter接口實現。如果需要,實現報文解析/格式化邏輯。

          class MyLineParser extends BasicLineParser {
          @Override
          public Header parseHeader(
          final CharArrayBuffer buffer) throws ParseException {
          try {
          return super.parseHeader(buffer);
          } catch (ParseException ex) {
          // 壓制ParseException異常
          return new BasicHeader("invalid", buffer.toString());
          }
          }
          }

          提過一個自定義的OperatedClientConnection實現。替換需要自定義的默認請求/響應解析器,請求/響應格式化器。如果需要,實現不同的報文寫入/讀取代碼。

          class MyClientConnection extends DefaultClientConnection {
          @Override
          protected HttpMessageParser createResponseParser(
          final SessionInputBuffer buffer,
          final HttpResponseFactory responseFactory,
          final HttpParams params) {
          return new DefaultResponseParser(buffer,
          new MyLineParser(),responseFactory,params);
          }
          }

          為了創建新類的連接,提供一個自定義的ClientConnectionOperator接口實現。如果需要,實現不同的套接字初始化代碼。

          class MyClientConnectionOperator extends
          DefaultClientConnectionOperator {
          public MyClientConnectionOperator(
          final SchemeRegistry sr) {
          super(sr);
          }
          @Override
          public OperatedClientConnection createConnection() {
          return new MyClientConnection();
          }
          }

          為了創建新類的連接操作,提供自定義的ClientConnectionManager接口實現。

          class MyClientConnManager extends SingleClientConnManager {
          public MyClientConnManager(
          final HttpParams params,
          final SchemeRegistry sr) {
          super(params, sr);
          }
          @Override
          protected ClientConnectionOperator createConnectionOperator(
          final SchemeRegistry sr) {
          return new MyClientConnectionOperator(sr);
          }
          }

          6.2 有狀態的HTTP連接

          HTTP規范假設session狀態信息通常是以HTTP cookie格式嵌入在HTTP報文中的,因此HTTP連接通常是無狀態的,這個假設在現實生活中通常是不對的。也有一些情況,當HTTP連接使用特定的用戶標識或特定的安全上下文來創建時,因此不能和其它用戶共享,只能由該用戶重用。這樣的有狀態的HTTP連接的示例就是NTLM認證連接和使用客戶端證書認證的SSL連接。

          6.2.1 用戶令牌處理器

          HttpClient依賴UserTokenHandler接口來決定給定的執行上下文是否是用戶指定的。如果這個上下文是用戶指定的或者如果上下文沒有包含任何資源或關于當前用戶指定詳情而是null,令牌對象由這個處理器返回,期望唯一地標識當前的用戶。用戶令牌將被用來保證用戶指定資源不會和其它用戶來共享或重用。

          如果它可以從給定的執行上下文中來獲得,UserTokenHandler接口的默認實現是使用主類的一個實例來代表HTTP連接的狀態對象。UserTokenHandler將會使用基于如NTLM或開啟的客戶端認證SSL會話認證模式的用戶的主連接。如果二者都不可用,那么就不會返回令牌。

          如果默認的不能滿足它們的需要,用戶可以提供一個自定義的實現:
          DefaultHttpClient httpclient = new DefaultHttpClient();
          httpclient.setUserTokenHandler(new UserTokenHandler() {
          public Object getUserToken(HttpContext context) {
          return context.getAttribute("my-token");
          }
          });

          6.2.2 用戶令牌和執行上下文

          在HTTP請求執行的過程中,HttpClient添加了下列和用戶標識相關的對象到執行上下文中:

          'http.user-token':對象實例代表真實的用戶標識,通常期望Principle接口的實例。

          我們可以在請求被執行后,通過檢查本地HTTP上下文的內容,發現是否用于執行請求的連接是有狀態的。
          DefaultHttpClient httpclient = new DefaultHttpClient();
          HttpContext localContext = new BasicHttpContext();
          HttpGet httpget = new HttpGet("http://localhost:8080/");
          HttpResponse response = httpclient.execute(httpget, localContext);
          HttpEntity entity = response.getEntity();
          if (entity != null) {
          entity.consumeContent();
          }
          Object userToken = localContext.getAttribute(ClientContext.USER_TOKEN);
          System.out.println(userToken);
          6.2.2.1 持久化有狀態的連接
          請注意帶有狀態對象的持久化連接僅當請求被執行時,相同狀態對象被綁定到執行上下文時可以被重用。所以,保證相同上下文重用于執行隨后的相同用戶,或用戶令牌綁定到之前請求執行上下文的HTTP請求是很重要的。
          DefaultHttpClient httpclient = new DefaultHttpClient();
          HttpContext localContext1 = new BasicHttpContext();
          HttpGet httpget1 = new HttpGet("http://localhost:8080/");
          HttpResponse response1 = httpclient.execute(httpget1, localContext1);
          HttpEntity entity1 = response1.getEntity();
          if (entity1 != null) {
          entity1.consumeContent();
          }
          Principal principal = (Principal) localContext1.getAttribute(
          ClientContext.USER_TOKEN);
          HttpContext localContext2 = new BasicHttpContext();
          localContext2.setAttribute(ClientContext.USER_TOKEN, principal);
          HttpGet httpget2 = new HttpGet("http://localhost:8080/");
          HttpResponse response2 = httpclient.execute(httpget2, localContext2);
          HttpEntity entity2 = response2.getEntity();
          if (entity2 != null) {
          entity2.consumeContent();
          }

          轉載自:http://www.cnblogs.com/loveyakamoz/archive/2011/07/21/2113251.html
          posted @ 2012-09-26 16:45 abin 閱讀(806) | 評論 (0)編輯 收藏

          第四章 HTTP認證
          HttpClient提供對由HTTP標準規范定義的認證模式的完全支持。HttpClient的認證框架可以擴展支持非標準的認證模式,比如NTLM和SPNEGO。

          4.1 用戶憑證

          任何用戶身份驗證的過程都需要一組可以用于建立用戶身份的憑據。用戶憑證的最簡單的形式可以僅僅是用戶名/密碼對。UsernamePasswordCredentials代表了一組包含安全規則和明文密碼的憑據。這個實現對由HTTP標準規范中定義的標準認證模式是足夠的

          UsernamePasswordCredentials creds = new UsernamePasswordCredentials("user", "pwd");
          System.out.println(creds.getUserPrincipal().getName());
          System.out.println(creds.getPassword());

          輸出內容為:

          user
          pwd

          NTCredentials是微軟Windows指定的實現,它包含了除了用戶名/密碼對外,一組額外的Windows指定的屬性,比如用戶域名的名字,比如在微軟的Windows網絡中,相同的用戶使用不同設置的認證可以屬于不同的域。

          NTCredentials creds = new NTCredentials("user", "pwd", "workstation", "domain");
          System.out.println(creds.getUserPrincipal().getName());
          System.out.println(creds.getPassword());

          輸出內容為:

          DOMAIN/user
          pwd

          4.2 認證模式

          AuthScheme接口代表了抽象的,面向挑戰-響應的認證模式。一個認證模式期望支持如下的功能:
          • 解析和處理由目標服務器在對受保護資源請求的響應中發回的挑戰。
          • 提供處理挑戰的屬性:認證模式類型和它的參數,如果可用,比如這個認證模型可應用的領域。
          • 對給定的憑證組和HTTP請求對響應真實認證挑戰生成認證字符串。
          要注意認證模式可能是有狀態的,涉及一系列的挑戰-響應交流。HttpClient附帶了一些AuthScheme實現:
          • Basic(基本):Basic認證模式定義在RFC 2617中。這個認證模式是不安全的,因為憑據以明文形式傳送。盡管它不安全,如果用在和TLS/SSL加密的組合中,Basic認證模式是完全夠用的。
          • Digest(摘要):Digest認證模式定義在RFC 2617中。Digest認證模式比Basic有顯著的安全提升,對不想通過TLS/SL加密在完全運輸安全上開銷的應用程序來說也是很好的選擇。
          • NTLM:NTLM是一個由微軟開發的優化Windows平臺的專有認證模式。NTLM被認為是比Digest更安全的模式。這個模式需要外部的NTLM引擎來工作。要獲取更多詳情請參考包含在HttpClient發布包中的NTLM_SUPPORT.txt文檔。

          4.3 HTTP認證參數

          有一些可以用于定制HTTP認證過程和獨立認證模式行為的參數:
          • 'http.protocol.handle-authentication':定義了是否認證應該被自動處理。這個參數期望的得到一個java.lang.Boolean類型的值。如果這個參數沒有被設置,HttpClient將會自動處理認證。
          • 'http.auth.credential-charset':定義了當編碼用戶憑證時使用的字符集。這個參數期望得到一個java.lang.String類型的值。如果這個參數沒有被設置,那么就會使用US-ASCII。

          4.4 認證模式注冊表

          HttpClient使用AuthSchemeRegistry類維護一個可用的認證模式的注冊表。對于每個默認的下面的模式是注冊過的:
          • Basic:基本認證模式
          • Digest:摘要認證模式
          請注意NTLM模式沒有對每個默認的進行注冊。NTLM不能對每個默認開啟是應為許可和法律上的原因。要獲取更詳細的關于如何開啟NTLM支持的內容請看這部分。

          4.5 憑據提供器

          憑據提供器意來維護一組用戶憑據,還有能夠對特定認證范圍生產用戶憑據。認證范圍包括主機名,端口號,領域名稱和認證模式名稱。當使用憑據提供器來注冊憑據時,我們可以提供一個通配符(任意主機,任意端口,任意領域,任意模式)來替代確定的屬性值。如果直接匹配沒有發現,憑據提供器期望被用來發現最匹配的特定范圍。

          HttpClient可以和任意實現了CredentialsProvider接口的憑據提供器的物理代表一同工作。默認的CredentialsProvider實現被稱為BasicCredentialsProvider,它是簡單的憑借java.util.HashMap的實現。
          CredentialsProvider credsProvider = new BasicCredentialsProvider();
          credsProvider.setCredentials(
          new AuthScope("somehost", AuthScope.ANY_PORT),
          new UsernamePasswordCredentials("u1", "p1"));
          credsProvider.setCredentials(
          new AuthScope("somehost", 8080),
          new UsernamePasswordCredentials("u2", "p2"));
          credsProvider.setCredentials(
          new AuthScope("otherhost", 8080, AuthScope.ANY_REALM, "ntlm"),
          new UsernamePasswordCredentials("u3", "p3"));
          System.out.println(credsProvider.getCredentials(
          new AuthScope("somehost", 80, "realm", "basic")));
          System.out.println(credsProvider.getCredentials(
          new AuthScope("somehost", 8080, "realm", "basic")));
          System.out.println(credsProvider.getCredentials(
          new AuthScope("otherhost", 8080, "realm", "basic")));
          System.out.println(credsProvider.getCredentials(
          new AuthScope("otherhost", 8080, null, "ntlm")));

          輸出內容為:

          [principal: u1]
          [principal: u2]
          null
          [principal: u3]

          4.6 HTTP認證和執行上下文

          HttpClient依賴于AuthState類來跟蹤關于認證過程狀態的詳細信息。在HTTP請求執行過程中,HttpClient創建2個AuthState的實例:一個對于目標主機認證,另外一個對于代理認證。如果目標服務器或代理需要用戶認證,那么各自的AuthState實例將會被在認證處理過程中使用的AuthScope,AuthScheme和Crednetials來填充。AuthState可以被檢查來找出請求的認證是什么類型的,是否匹配AuthScheme的實現,是否憑據提供器對給定的認證范圍去找用戶憑據。

          在HTTP請求執行的過程中,HttpClient添加了下列和認證相關的對象到執行上下文中:

          • 'http.authscheme-registry':AuthSchemeRegistry實例代表真實的認證模式注冊表。在本地內容中設置的這個屬性的值優先于默認的。
          • 'http.auth.credentials-provider':CookieSpec實例代表了真實的憑據提供器。在本地內容中設置的這個屬性的值優先于默認的。
          • 'http.auth.target-scope':AuthState實例代表了真實的目標認證狀態。在本地內容中設置的這個屬性的值優先于默認的。
          • 'http.auth.proxy-scope':AuthState實例代表了真實的代理認證狀態。在本地內容中設置的這個屬性的值優先于默認的。

          本地的HttpContext對象可以用于定制HTTP認證內容,并先于請求執行或在請求被執行之后檢查它的狀態:

          HttpClient httpclient = new DefaultHttpClient();
          HttpContext localContext = new BasicHttpContext();
          HttpGet httpget = new HttpGet("http://localhost:8080/");
          HttpResponse response = httpclient.execute(httpget, localContext);
          AuthState proxyAuthState = (AuthState) localContext.getAttribute(
          ClientContext.PROXY_AUTH_STATE);
          System.out.println("Proxy auth scope: " + proxyAuthState.getAuthScope());
          System.out.println("Proxy auth scheme: " + proxyAuthState.getAuthScheme());
          System.out.println("Proxy auth credentials: " + proxyAuthState.getCredentials());
          AuthState targetAuthState = (AuthState) localContext.getAttribute(
          ClientContext.TARGET_AUTH_STATE);
          System.out.println("Target auth scope: " + targetAuthState.getAuthScope());
          System.out.println("Target auth scheme: " + targetAuthState.getAuthScheme());
          System.out.println("Target auth credentials: " + targetAuthState.getCredentials());

          4.7 搶占認證

          HttpClient不支持開箱的搶占認證,因為濫用或重用不正確的搶占認證可能會導致嚴重的安全問題,比如將用戶憑據以明文形式發送給未認證的第三方。因此,用戶期望評估搶占認證和在它們只能應用程序環境內容安全風險潛在的好處,而且要求使用如協議攔截器的標準HttpClient擴展機制添加對搶占認證的支持。

          這是一個簡單的協議攔截器,如果沒有企圖認證,來搶先引入BasicScheme的實例到執行上下文中。請注意攔截器必須在標準認證攔截器之前加入到協議處理鏈中。

          HttpRequestInterceptor preemptiveAuth = new HttpRequestInterceptor() {
          public void process(final HttpRequest request,
          final HttpContext context) throws HttpException, IOException {
          AuthState authState = (AuthState) context.getAttribute(
          ClientContext.TARGET_AUTH_STATE);
          CredentialsProvider credsProvider = (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER);
          HttpHost targetHost = (HttpHost) context.getAttribute(
          ExecutionContext.HTTP_TARGET_HOST);
          // 如果沒有初始化auth模式
          if (authState.getAuthScheme() == null) {
          AuthScope authScope = new AuthScope(
          targetHost.getHostName(),
          targetHost.getPort());
          // 獲得匹配目標主機的憑據
          Credentials creds = credsProvider.getCredentials(authScope);
          // 如果發現了,搶先生成BasicScheme
          if (creds != null) {
          authState.setAuthScheme(new BasicScheme());
          authState.setCredentials(creds);
          }
          }
          }
          };
          DefaultHttpClient httpclient = new DefaultHttpClient();
          // 作為第一個攔截器加入到協議鏈中
          httpclient.addRequestInterceptor(preemptiveAuth, 0);

          4.8 NTLM 認證

          當前HttpClient沒有提對開箱的NTLM認證模式的支持也可能永遠也不會。這個原因是法律上的而不是技術上的。然而,NTLM認證可以使用外部的NTLM引擎比如JCIFS[http://jcifs.samba.org/]來開啟,類庫由Samba[http://www.samba.org/]項目開發,作為它們Windows的交互操作程序套裝的一部分。要獲取詳細內容請參考HttpClient發行包中包含的NTLM_SUPPORT.txt文檔。

          4.8.1 NTLM連接持久化

          NTLM認證模式是在計算開銷方面昂貴的多的,而且對標準的Basic和Digest模式的性能影響也很大。這很可能是為什么微軟選擇NTLM認證模式為有狀態的主要原因之一。也就是說,一旦認證通過,用戶標識是和連接的整個生命周期相關聯的。NTLM連接的狀態特性使得連接持久化非常復雜,對于明顯的原因,持久化NTLM連接不能被使用不同用戶標識的用戶重用。標準的連接管理器附帶HttpClient是完全能夠管理狀態連接的。而邏輯相關的,使用同一session和執行上下文為了讓它們了解到當前的用戶標識的請求也是極為重要的。否則,HttpClient將會終止對每個基于NTLM保護資源的HTTP請求創建新的HTTP連接。要獲取關于有狀態的HTTP連接的詳細討論,請參考這個部分。

          因為NTLM連接是有狀態的,通常建議使用相對簡單的方法觸發NTLM認證,比如GET或HEAD,而重用相同的連接來執行代價更大的方法,特別是它們包含請求實體,比如POST或PUT。

          DefaultHttpClient httpclient = new DefaultHttpClient();
          NTCredentials creds = new NTCredentials("user", "pwd", "myworkstation", "microsoft.com");
          httpclient.getCredentialsProvider().setCredentials(AuthScope.ANY, creds);
          HttpHost target = new HttpHost("www.microsoft.com", 80, "http");
          // 保證相同的內容來用于執行邏輯相關的請求
          HttpContext localContext = new BasicHttpContext();
          // 首先執行簡便的方法。這會觸發NTLM認證
          HttpGet httpget = new HttpGet("/ntlm-protected/info");
          HttpResponse response1 = httpclient.execute(target, httpget, localContext);
          HttpEntity entity1 = response1.getEntity();
          if (entity1 != null) {
          entity1.consumeContent();
          }
          //之后使用相同的內容(和連接)執行開銷大的方法。
          HttpPost httppost = new HttpPost("/ntlm-protected/form");
          httppost.setEntity(new StringEntity("lots and lots of data"));
          HttpResponse response2 = httpclient.execute(target, httppost, localContext);
          HttpEntity entity2 = response2.getEntity();
          if (entity2 != null) {
          entity2.consumeContent();
          }

           



          轉載自:http://www.cnblogs.com/loveyakamoz/archive/2011/07/21/2113247.html
          posted @ 2012-09-26 16:44 abin 閱讀(836) | 評論 (0)編輯 收藏

          僅列出標題
          共50頁: First 上一頁 25 26 27 28 29 30 31 32 33 下一頁 Last 
          主站蜘蛛池模板: 邛崃市| 桂林市| 敦化市| 滦南县| 鱼台县| 平乡县| 扶余县| 嘉荫县| 泰宁县| 武隆县| 望谟县| 吴旗县| 凤山县| 化隆| 边坝县| 浪卡子县| 叙永县| 平顶山市| 武宁县| 晋中市| 延川县| 五河县| 繁峙县| 绥江县| 南阳市| 哈尔滨市| 故城县| 伊金霍洛旗| 盘锦市| 景泰县| 新安县| 晋州市| 安阳县| 永登县| 前郭尔| 凤城市| 东阳市| 和龙市| 阳曲县| 呼图壁县| 涞源县|