青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

tbwshc

tbw

  C++博客 :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
  95 Posts :: 8 Stories :: 3 Comments :: 0 Trackbacks

常用鏈接

留言簿(4)

我參與的團(tuán)隊(duì)

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

#

作網(wǎng)頁的過程中,你有時(shí)候需要知道某個(gè)元素在網(wǎng)頁上的確切位置。

下面的教程總結(jié)了Javascript在網(wǎng)頁定位方面的相關(guān)知識。

一、網(wǎng)頁的大小和瀏覽器窗口的大小

首先,要明確兩個(gè)基本概念。

一張網(wǎng)頁的全部面積,就是它的大小。通常情況下,網(wǎng)頁的大小由內(nèi)容和CSS樣式表決定。

瀏覽器窗口的大小,則是指在瀏覽器窗口中看到的那部分網(wǎng)頁面積,又叫做viewport(視口)。

很顯然,如果網(wǎng)頁的內(nèi)容能夠在瀏覽器窗口中全部顯示(也就是不出現(xiàn)滾動(dòng)條),那么網(wǎng)頁的大小和瀏覽器窗口的大小是相等的。如果不能全部顯示,則滾動(dòng)瀏覽器窗口,可以顯示出網(wǎng)頁的各個(gè)部分。

二、獲取網(wǎng)頁的大小

網(wǎng)頁上的每個(gè)元素,都有clientHeight和clientWidth屬性。這兩個(gè)屬性指元素的內(nèi)容部分再加上padding的所占據(jù)的視覺面積,不包括border和滾動(dòng)條占用的空間。

(圖一 clientHeight和clientWidth屬性)

因此,document元素的clientHeight和clientWidth屬性,就代表了網(wǎng)頁的大小。

  function getViewport(){
    if (document.compatMode == "BackCompat"){
      return {
        width: document.body.clientWidth,
        height: document.body.clientHeight
      }
    } else {
      return {
        width: document.documentElement.clientWidth,
        height: document.documentElement.clientHeight
      }
    }
  }

上面的getViewport函數(shù)就可以返回瀏覽器窗口的高和寬。使用的時(shí)候,有三個(gè)地方需要注意:

1)這個(gè)函數(shù)必須在頁面加載完成后才能運(yùn)行,否則document對象還沒生成,瀏覽器會(huì)報(bào)錯(cuò)。

2)大多數(shù)情況下,都是document.documentElement.clientWidth返回正確值。但是,在IE6的quirks模式中,document.body.clientWidth返回正確的值,因此函數(shù)中加入了對文檔模式的判斷。

3)clientWidth和clientHeight都是只讀屬性,不能對它們賦值。

三、獲取網(wǎng)頁大小的另一種方法

網(wǎng)頁上的每個(gè)元素還有scrollHeight和scrollWidth屬性,指包含滾動(dòng)條在內(nèi)的該元素的視覺面積。

那么,document對象的scrollHeight和scrollWidth屬性就是網(wǎng)頁的大小,意思就是滾動(dòng)條滾過的所有長度和寬度。

仿照getViewport()函數(shù),可以寫出getPagearea()函數(shù)。

  function getPagearea(){
    if (document.compatMode == "BackCompat"){
      return {
        width: document.body.scrollWidth,
        height: document.body.scrollHeight
      }
    } else {
      return {
        width: document.documentElement.scrollWidth,
        heightb: document.documentElement.scrollHeight
      }
    }
  }

但是,這個(gè)函數(shù)有一個(gè)問題。如果網(wǎng)頁內(nèi)容能夠在瀏覽器窗口中全部顯示,不出現(xiàn)滾動(dòng)條,那么網(wǎng)頁的clientWidth和scrollWidth應(yīng)該相等。但是實(shí)際上,不同瀏覽器有不同的處理,這兩個(gè)值未必相等。所以,我們需要取它們之中較大的那個(gè)值,因此要對getPagearea()函數(shù)進(jìn)行改寫。

  function getPagearea(){
    if (document.compatMode == "BackCompat"){
      return {
        width: Math.max(document.body.scrollWidth,
                document.body.clientWidth),
        height: Math.max(document.body.scrollHeight,
                document.body.clientHeight)
      }
    } else {
      return {
        width: Math.max(document.documentElement.scrollWidth,
                document.documentElement.clientWidth),
        height: Math.max(document.documentElement.scrollHeight,
                document.documentElement.clientHeight)
      }
    }
  }

四、獲取網(wǎng)頁元素的絕對位置

網(wǎng)頁元素的絕對位置,指該元素的左上角相對于整張網(wǎng)頁左上角的坐標(biāo)。這個(gè)絕對位置要通過計(jì)算才能得到。

首先,每個(gè)元素都有offsetTop和offsetLeft屬性,表示該元素的左上角與父容器(offsetParent對象)左上角的距離。所以,只需要將這兩個(gè)值進(jìn)行累加,就可以得到該元素的絕對坐標(biāo)。

(圖二 offsetTop和offsetLeft屬性)

下面兩個(gè)函數(shù)可以用來獲取絕對位置的橫坐標(biāo)和縱坐標(biāo)。

  function getElementLeft(element){
    var actualLeft = element.offsetLeft;
    var current = element.offsetParent;

    while (current !== null){
      actualLeft += current.offsetLeft;
      current = current.offsetParent;
    }

    return actualLeft;
  }

  function getElementTop(element){
    var actualTop = element.offsetTop;
    var current = element.offsetParent;

    while (current !== null){
      actualTop += current.offsetTop;
      current = current.offsetParent;
    }

    return actualTop;
  }

由于在表格和iframe中,offsetParent對象未必等于父容器,所以上面的函數(shù)對于tb表格和iframe中的元素不適用。

五、獲取網(wǎng)頁元素的相對位置

網(wǎng)頁元素的相對位置,指該元素左上角相對于瀏覽器窗口左上角的坐標(biāo)。

有了絕對位置以后,獲得相對位置就很容易了,只要將絕對坐標(biāo)減去頁面的滾動(dòng)條滾動(dòng)的距離就可以了。滾動(dòng)條滾動(dòng)的垂直距離,是document對象的scrollTop屬性;滾動(dòng)條滾動(dòng)的水平距離是document對象的scrollLeft屬性。

(圖三 scrollTop和scrollLeft屬性)

對上一節(jié)中的兩個(gè)函數(shù)進(jìn)行相應(yīng)的改寫:

  function getElementViewLeft(element){
    var actualLeft = element.offsetLeft;
    var current = element.offsetParent;

    while (current !== null){
      actualLeft += current.offsetLeft;
      current = current.offsetParent;
    }

    if (document.compatMode == "BackCompat"){
      var elementScrollLeft=document.body.scrollLeft;
    } else {
      var elementScrollLeft=document.documentElement.scrollLeft; 
    }

    return actualLeft-elementScrollLeft;
  }

  function getElementViewTop(element){
    var actualTop = element.offsetTop;
    var current = element.offsetParent;

    while (current !== null){
      actualTop += current. offsetTop;
      current = current.offsetParent;
    }

     if (document.compatMode == "BackCompat"){
      var elementScrollTop=document.body.scrollTop;
    } else {
      var elementScrollTop=document.documentElement.scrollTop; 
    }

    return actualTop-elementScrollTop;
  }

scrollTop和scrollLeft屬性是可以賦值的,并且會(huì)立即自動(dòng)滾動(dòng)網(wǎng)頁到相應(yīng)位置,因此可以利用它們改變網(wǎng)頁元素的相對位置。另外,element.scrollIntoView()方法也有類似作用,可以使網(wǎng)頁元素出現(xiàn)在瀏覽器窗口的左上角。

六、獲取元素位置的快速方法

除了上面的函數(shù)以外,還有一種快速方法,可以立刻獲得網(wǎng)頁元素的位置。

那就是使用getBoundingClientRect()方法。它返回一個(gè)對象,其中包含了left、right、top、bottom四個(gè)屬性,分別對應(yīng)了該元素的左上角和右下角相對于瀏覽器窗口(viewport)左上角的距離。

所以,網(wǎng)頁元素的相對位置就是

  var X= this.getBoundingClientRect().left;

  var Y =this.getBoundingClientRect().top;

再加上滾動(dòng)距離,就可以得到絕對位置

  var X= this.getBoundingClientRect().left+document.documentElement.scrollLeft;

  var Y =this.getBoundingClientRect().top+document.documentElement.scrollTop;

目前,IE、Firefox 3.0+、Opera 9.5+都支持該方法,而Firefox 2.x、Safari、Chrome、Konqueror不支持

posted @ 2012-06-22 12:55 tbwshc 閱讀(977) | 評論 (0)編輯 收藏

中新社舊金山5月19日電 (記者 劉丹)北京大學(xué)常務(wù)副校長吳志攀19日在美國舊金山表示,靈活的創(chuàng)造力是中國大學(xué)生最缺少的才能,中國的大學(xué)沒能夠?yàn)閷W(xué)生提供這種幫助。

  吳志攀當(dāng)天在舊金山出席北京大學(xué)北加州校友會(huì)舉辦的20周年年會(huì)暨未名論壇,就“傳承與發(fā)展:你心目中的北大人、北大精神和社會(huì)責(zé)任感”主題與300多位tb校友交流。

  吳志攀表示,目前中國高等教育面臨兩個(gè)問題。一是世界進(jìn)入了亞太時(shí)代,許多學(xué)者均認(rèn)同亞太時(shí)代的特點(diǎn)就是多元化。“高等教育如何適應(yīng)并培養(yǎng)多元化人才,如何重新設(shè)計(jì)、教以后10年都用得著的課程,如何滿足學(xué)生的期待,是我們遇到的很大問題。”

  如何應(yīng)對世界的迅速變化,培養(yǎng)學(xué)生適應(yīng)經(jīng)濟(jì)轉(zhuǎn)型,是中國高等教育遇到的第二個(gè)問題。對于學(xué)術(shù)的敏感性、靈活性、創(chuàng)新型能否適應(yīng)加速發(fā)展的社會(huì)需求,吳志攀表示擔(dān)憂。

  他指出,“學(xué)術(shù)自由,兼容并包”的北大精神與亞太時(shí)代的精神是融合的,就是多元化、寬容和包容。“蔡元培校長老早就提出‘兼容并包’,在今天更要求我們有包容心態(tài),借鑒國外先進(jìn)經(jīng)驗(yàn),理解他們的文化和做法,培養(yǎng)多元化人才。”

  吳志攀認(rèn)為,靈活的創(chuàng)造力是中國大學(xué)生最缺少的才能。“我們注意到,美國最成功的IT人士,比如比爾?蓋茨、扎克伯格等,大學(xué)沒畢業(yè)就創(chuàng)業(yè),顯然他們的成功與大學(xué)的多元化相關(guān)。”

  吳志攀指出,中國的大學(xué)沒能給學(xué)生提供這種幫助,或者幫助得不夠,同時(shí),要中國的社會(huì)和家庭接納也需要時(shí)間。例如,美國允許大學(xué)生休學(xué)一個(gè)、兩個(gè)學(xué)期,有人利用這個(gè)機(jī)會(huì)做自己有興趣的事情。“而我們的大學(xué)只有學(xué)生生病才可以休學(xué)。”

  當(dāng)天, 北京大學(xué)北加州校友會(huì)還向在硅谷培訓(xùn)企業(yè)領(lǐng)導(dǎo)能力的徐玲和發(fā)起海外華人互助會(huì)的林世東頒發(fā)了杰出校友“社區(qū)貢獻(xiàn)獎(jiǎng)”。
posted @ 2012-06-13 15:06 tbwshc 閱讀(151) | 評論 (0)編輯 收藏

package downloadMap;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import javax.swing.JOptionPane;
import javax.swing.ProgressMonitorInputStream;
import TIp.Jframet;
import doFile.ZipToFile;
import sun.net.TelnetInputStream;
import sun.net.TelnetOutputStream;
import sun.net.ftp.FtpClient;
public class FtpZipOption {
/**
  *
  * 從ftp服務(wù)器下載zip文件
  *
  * @param
  *
  *@throws Exception
  **/
public static void downLoadZipFile(String wantFileName ) throws Exception {
/*new Thread(){
  public void run(){
   Jframet jf = new Jframet("正在鏈接ftp,qing'shao'h", "確定");
   jf.jb.setVisible(false);
  }
}.start();*/
  String[] localFileNameArray = getLocalFileNameArray("c:\\BaseMap");// 得到所有已經(jīng)下載的tb文件名
  File downFile=new File("c:\\BaseMap");
  if(!downFile.exists()) downFile.mkdir();
  
  if (ifToDownLoadFile(wantFileName, localFileNameArray)) {// 判斷是否需要下載
   String str; // 輸出信息字符串
   /**
    *
    * 和服務(wù)器建立連接
    */
   FtpClient ftp = new FtpClient("172.18.2.66"); // 根據(jù)服務(wù)器ip建立連接
   
   //JOptionPane.showMessageDialog(null, "");
   str = ftp.getResponseString(); // 獲得響應(yīng)信息
   System.out.println("連接服務(wù)器:" + str);
   
   /**
    *
    * 登陸到Ftp服務(wù)器
    */
   ftp.login("admin", "1"); // 根據(jù)用戶名和密碼登錄服務(wù)器
   str = ftp.getResponseString();
   System.out.println("登錄:" + str);
   
   
   /**
    *
    * 打開并定位到服務(wù)器目錄
    */
   ftp.cd("mapdata2"); // 打開服務(wù)器上的文件目錄
   str = ftp.getResponseString();
   System.out.println("打開服務(wù)器目錄:" + str);
   ftp.binary();// 轉(zhuǎn)化為二進(jìn)制的文件
   TelnetInputStream ftpIn = ftp.get(wantFileName + ".zip");// 找到要讀取的文件
   
   /*Jframet jf=new Jframet("正在下載地圖,請稍候...","確定");
   jf.jb.setVisible(false);*/
   long fileLength=FtpZipOption.getFileSize("wantFileName.zip");
   System.out.println(fileLength);
   byte[] buf = new byte[204800];
   int bufsize = 0;
   File f=new File("c:\\BaseMap");
   if(!f.exists()) f.mkdirs();
   String toLocalPath = "c:\\BaseMap\\" + wantFileName + ".zip";
   /*File f=new File(toLocalPath);
   f.mkdirs();*/
   FileOutputStream ftpOut = new FileOutputStream(toLocalPath);
   int readLine=0;
   while ((bufsize = ftpIn.read(buf, 0, buf.length)) != -1) {
    //System.out.println(bufsize);
    ftpOut.write(buf, 0, bufsize);
    readLine=+bufsize;
   
   }
   System.out.println(readLine);
   ftpOut.close();
   ftpIn.close();
   ZipToFile ziptofile=new ZipToFile();
   
         String  PostFilePath = "c:\\BaseMap";   
          ziptofile.zipToFile(toLocalPath, PostFilePath);
  // JOptionPane.showMessageDialog(null, "下載" + wantFileName + ".zip完成!");
   System.out.println("下載" + wantFileName + ".zip完成!");
  /* jf.jl.setText("下載地圖成功");
   jf.jb.setVisible(true);*/
  } else {
   
  }
}
public static long getFileSize(String filename) throws IOException {
  String str; // 輸出信息字符串
  /**
   *
   * 和服務(wù)器建立連接
   */
  FtpClient ftp = new FtpClient("172.18.2.66"); // 根據(jù)服務(wù)器ip建立連接
  str = ftp.getResponseString(); // 獲得響應(yīng)信息
  System.out.println("連接服務(wù)器:" + str);
  /**
   *
   * 登陸到Ftp服務(wù)器
   */
  ftp.login("admin", "1"); // 根據(jù)用戶名和密碼登錄服務(wù)器
  str = ftp.getResponseString();
  System.out.println("登錄:" + str);
  /**
   *
   * 打開并定位到服務(wù)器目錄
   */
  ftp.cd("mapdata2"); // 打開服務(wù)器上的文件目錄
  str = ftp.getResponseString();
  System.out.println("打開服務(wù)器目錄:" + str);
  ftp.binary();// 轉(zhuǎn)化為二進(jìn)制的文件
  long fileSize = -1;
  String s = "SIZE " + filename + "\r\n";
  ftp.sendServer(s);
  try {
  int status = ftp.readServerResponse();
  if (status == 213) {
  String msg = ftp.getResponseString();
  fileSize = Long.parseLong(msg.substring(3).trim());
  }
  } catch (IOException e) {
  e.printStackTrace();
  }
  return fileSize;
  }
// 上傳文件;并返回上傳文件的信息
/*private static String upLoadZipToServer(String filename) throws Exception {
  String str; // 輸出信息字符串
  String timeStr = getNowTime();// 獲得當(dāng)前時(shí)間
  String recordStr = "上傳時(shí)間:" + timeStr + "\r\n";// 信息記錄字符串
  *//**
   *
   * 和服務(wù)器建立連接
   *//*
  FtpClient ftp = new FtpClient("192.168.39.189"); // 根據(jù)服務(wù)器ip建立連接
  str = ftp.getResponseString(); // 獲得響應(yīng)信息
  System.out.println(str);
  recordStr += "連接服務(wù)器:" + str + "\r\n";
  *//**
   *
   * 登陸到Ftp服務(wù)器
   *//*
  ftp.login("test", "test"); // 根據(jù)用戶名和密碼登錄服務(wù)器
  str = ftp.getResponseString();
  System.out.println(str);
  recordStr += "登錄:" + str + "\r\n";
  *//**
   *
   * 打開并定位到test目錄
   *//*
  ftp.cd("uptest"); // 打開服務(wù)器上的test文件夾
  ftp.binary();// 轉(zhuǎn)化為二進(jìn)制的文件
  str = ftp.getResponseString();
  System.out.println(str);
  FileInputStream is = null;
  TelnetOutputStream os = null;
  try {
   // "upftpfile"用ftp上傳后的新文件名
   os = ftp.put("uptest.zip");
   File file_in = new java.io.File(filename);
   if (file_in.length() == 0) {
    return "上傳文件為空!";
   }
   is = new FileInputStream(file_in);
   byte[] bytes = new byte[1024];
   int c;
   while ((c = is.read(bytes)) != -1) {
    os.write(bytes, 0, c);
   }
  } finally {
   if (is != null) {
    is.close();
   }
   if (os != null) {
    os.close();
   }
  }
  return "上傳文件成功!";
}*/
/**
  *
  * zip壓縮功能,壓縮sourceFile(文件夾目錄)下所有文件,包括子目錄
  *
  * @param sourceFile
  *            ,待壓縮目錄; toFolerName,壓縮完畢生成的目錄
  *
  * @throws Exception
  */
/*public static void fileToZip(String sourceFile, String toFolerName)
   throws Exception {
  List fileList = getSubFiles(new File(sourceFile)); // 得到待壓縮的文件夾的所有內(nèi)容
  ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(
  toFolerName));
  ZipEntry ze = null;
  byte[] buf = new byte[1024];
  int readLen = 0;
  for (int i = 0; i < fileList.size(); i++) { // 遍歷要壓縮的所有子文件
   File file = (File) fileList.get(i);
   System.out.println("壓縮到的文件名:" + file.getName());
   ze = new ZipEntry(getAbsFileName(sourceFile, file));
   ze.setSize(file.length());
   ze.setTime(file.lastModified());
   zos.putNextEntry(ze);
   InputStream is = new BufferedInputStream(new FileInputStream(file));
   while ((readLen = is.read(buf, 0, 1024)) != -1) {
    zos.write(buf, 0, readLen);
   }
   is.close();
  }
  zos.close();
  System.out.println("壓縮完成!");
}
*//**
  *
  * 解壓zip文件
  *
  * @param sourceFile
  *            ,待解壓的zip文件; toFolder,解壓后的存放路徑
  *
  * @throws Exception
  **//*
public static void zipToFile(String sourceFile, String toFolder)
   throws Exception {
  String toDisk = toFolder;// 接收解壓后的存放路徑
  ZipFile zfile = new ZipFile(sourceFile);// 連接待解壓文件
  System.out.println("要解壓的文件是:" + zfile.getName());
  Enumeration zList = zfile.entries();// 得到zip包里的所有元素
  ZipEntry ze = null;
  byte[] buf = new byte[1024];
  while (zList.hasMoreElements()) {
   ze = (ZipEntry) zList.nextElement();
   if (ze.isDirectory()) {
    System.out.println("打開zip文件里的文件夾:" + ze.getName()
    + " skipped...");
    continue;
   }
   System.out.println("zip包里的文件: " + ze.getName() + "\t" + "大小為:"
   + ze.getSize() + "KB");
   // 以ZipEntry為參數(shù)得到一個(gè)InputStream,并寫到OutputStream中
   OutputStream outputStream = new BufferedOutputStream(
   new FileOutputStream(getRealFileName(toDisk, ze.getName())));
   InputStream inputStream = new BufferedInputStream(zfile
   .getInputStream(ze));
   int readLen = 0;
   while ((readLen = inputStream.read(buf, 0, 1024)) != -1) {
    outputStream.write(buf, 0, readLen);
   }
   inputStream.close();
   outputStream.close();
   System.out.println("已經(jīng)解壓出:" + ze.getName());
  }
  zfile.close();
}
*//**
  *
  * 給定根目錄,返回另一個(gè)文件名的相對路徑,用于zip文件中的路徑.
  *
  * @param baseDir
  *            java.lang.String 根目錄
  *
  * @param realFileName
  *            java.io.File 實(shí)際的文件名
  *
  * @return 相對文件名
  *//*
private static String getAbsFileName(String baseDir, File realFileName) {
  File real = realFileName;
  File base = new File(baseDir);
  String ret = real.getName();
  while (true) {
   real = real.getParentFile();
   if (real == null)
    break;
   if (real.equals(base))
    break;
   else
    ret = real.getName() + "/" + ret;
  }
  return ret;
}
*//**
  *
  * 取得指定目錄下的所有文件列表,包括子目錄.
  *
  * @param baseDir
  *            File 指定的目錄
  *
  * @return 包含java.io.File的List
  *//*
private static List<File> getSubFiles(File baseDir) {
  List<File> ret = new ArrayList<File>();
  File[] tmp = baseDir.listFiles();
  for (int i = 0; i < tmp.length; i++) {
   if (tmp.isFile())
    ret.add(tmp);
   if (tmp.isDirectory())
    ret.addAll(getSubFiles(tmp));
  }
  return ret;
}
*//**
  *
  * 給定根目錄,返回一個(gè)相對路徑所對應(yīng)的實(shí)際文件名.
  *
  * @param zippath
  *            指定根目錄
  *
  * @param absFileName
  *            相對路徑名,來自于ZipEntry中的name
  *
  * @return java.io.File 實(shí)際的文件
  *//*
private static File getRealFileName(String zippath, String absFileName) {
  String[] dirs = absFileName.split("/", absFileName.length());
  File ret = new File(zippath);// 創(chuàng)建文件對象
  if (dirs.length > 1) {
   for (int i = 0; i < dirs.length - 1; i++) {
    ret = new File(ret, dirs);
   }
  }
  if (!ret.exists()) {// 檢測文件是否存在
   ret.mkdirs();// 創(chuàng)建此抽象路徑名指定的目錄
  }
  ret = new File(ret, dirs[dirs.length - 1]);// 根據(jù) ret 抽象路徑名和 child
             // 路徑名字符串創(chuàng)建一個(gè)新 File 實(shí)例
  return ret;
}
*/
/**
  *
  * 取得ftp服務(wù)器上某個(gè)目錄下的所有文件名
  *
  * @param ftp
  *            , FtpClient類實(shí)例; folderName,服務(wù)器的文件夾名
  *
  * @throws Exception
  *
  * @return list 某目錄下文件名列表
  **/
private static List getServerFileNameList(FtpClient ftp, String folderName)
   throws Exception {
  BufferedReader dr = new BufferedReader(new InputStreamReader(ftp
    .nameList(folderName)));
  List<String> list = new ArrayList<String>();
  String s;
  while ((s = dr.readLine()) != null) {
   list.add(s);
  }
  return list;
}
/**
  *
  * 得到已經(jīng)下載的目錄下的所有文件名的數(shù)組
  *
  * @param localPath
  *            本地的下載文件保存路徑
  *
  * @return 該路徑下所有tb文件名
  *
  * **/
private static String[] getLocalFileNameArray(String localPath) {
  File diskFile = new File(localPath);
  if (diskFile != null) {
   String[] fileNameList = diskFile.list();
   return fileNameList;
  } else {
   return null;
  }
}
/**
  *
  *獲得當(dāng)前系統(tǒng)時(shí)間
  */
/*public static String getNowTime() {
  String timeStr;
  DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
  Date currentTime = new Date(System.currentTimeMillis());
  timeStr = format.format(currentTime);
  return timeStr;
}
public static String getWantFileName() throws Exception {
  *//** 得到當(dāng)前的系統(tǒng)精確時(shí)間 **//*
  Date currentTime = new Date(System.currentTimeMillis());
  *//** 接下來得到系統(tǒng)當(dāng)前的年月日 **//*
  DateFormat df1 = new SimpleDateFormat("yyyyMMdd");
  Date todayDate = new Date(System.currentTimeMillis());
  String todayStr = df1.format(todayDate);// 得到當(dāng)前的年月日
  *//** 接下來得到四個(gè)比較時(shí)間的String類型;分別在00點(diǎn),06點(diǎn),12點(diǎn)和18點(diǎn) **//*
  String compareTimeStr1 = todayStr + "00";
  String compareTimeStr2 = todayStr + "06";
  String compareTimeStr3 = todayStr + "12";
  String compareTimeStr4 = todayStr + "18";
  *//** 接下來得到四個(gè)比較時(shí)間的date類型 **//*
  DateFormat df2 = new SimpleDateFormat("yyyyMMddHH");
  Date compareTime1 = df2.parse(compareTimeStr1);
  Date compareTime2 = df2.parse(compareTimeStr2);
  Date compareTime3 = df2.parse(compareTimeStr3);
  Date compareTime4 = df2.parse(compareTimeStr4);
  *//** 接下來由當(dāng)前系統(tǒng)時(shí)間和四個(gè)參照時(shí)間進(jìn)行比較,找出該下載的文件名 **//*
  if (currentTime.after(compareTime1) && currentTime.before(compareTime2)) {
   // 此時(shí)應(yīng)該下載00點(diǎn)的文件,文件名為:compareTimeStr1
   System.out.println("此時(shí)要下載的文件名為:" + compareTimeStr1 + ".zip");
   return compareTimeStr1;
  } else if (currentTime.after(compareTime2)
    && currentTime.before(compareTime3)) {
   // 此時(shí)應(yīng)該下載06點(diǎn)的文件,文件名為:compareTimeStr2
   System.out.println("此時(shí)要下載的文件名為:" + compareTimeStr2 + ".zip");
   return compareTimeStr2;
  } else if (currentTime.after(compareTime3)
    && currentTime.before(compareTime4)) {
   // 此時(shí)應(yīng)該下載12點(diǎn)的文件,文件名為:compareTimeStr3
   System.out.println("此時(shí)要下載的文件名為:" + compareTimeStr3 + ".zip");
   return compareTimeStr3;
  } else if (currentTime.after(compareTime4)) {
   // 此時(shí)應(yīng)該下載18點(diǎn)的文件,文件名為:compareTimeStr4
   System.out.println("此時(shí)要下載的文件名為:" + compareTimeStr4 + ".zip");
   return compareTimeStr4;
  } else {
   // nothing to do
   return null;
  }
}
*/
/**
  *
  * 判斷此時(shí)是否需要下載文件
  *
  * @param wantFileName
  *            ,此時(shí)該下載的文件名; localFileNameArray ,本地已經(jīng)有的文件名
  *
  * @return ture--需要下載; false--本地已經(jīng)有了,不需要下載
  *
  * **/
public static boolean ifToDownLoadFile(String wantFileName,
   String[] localFileNameArray) {
  if (wantFileName == null && localFileNameArray == null) {// 當(dāng)想要下載的文件名獲得失敗
   return false;
  } else if (wantFileName == null && localFileNameArray != null) {// 當(dāng)想要下載的文件名獲得失敗
   return false;
  } else if (wantFileName != null && localFileNameArray == null) {// 當(dāng)本地沒有已下載的文件
   return true;
  } else if (wantFileName != null && localFileNameArray != null) {// 當(dāng)要下載的文件在本地還沒有
   if (localFileNameArray.length > 0) {
    for (int i = 0; i < localFileNameArray.length; i++) {
     if (localFileNameArray.equals(wantFileName + ".zip")) {
      return false;
     }
    }
    return true;
   } else {
    return true;
   }
  } else {
   return false;
  }
}
public static void main(String args[]) {
  try {
   long aa=FtpZipOption.getFileSize("2.zip");
   System.out.println(aa);
   FtpZipOption.downLoadZipFile("2");
   
  } catch (Exception e) {
   e.printStackTrace();
  }
}
}

這個(gè)是我從網(wǎng)上找的,可是下載2個(gè)G的壓縮包打不開,幾百兆的可以!求解
posted @ 2012-06-13 15:01 tbwshc 閱讀(2211) | 評論 (0)編輯 收藏

1.如何學(xué)習(xí)程序設(shè)計(jì)?

JAVA是一種平臺,也是一種程序設(shè)計(jì)語言,如何學(xué)好程序設(shè)計(jì)不僅僅適用于JAVA,TB對C++等其他程序設(shè)計(jì)語言也一樣管用。有編程高手認(rèn)為,JAVA也好C也好沒什么分別,拿來就用。為什么他們能達(dá)到如此境界?我想是因?yàn)榫幊陶Z言之間有共通之處,領(lǐng)會(huì)了編程的精髓,自然能夠做到一通百通。如何學(xué)習(xí)程序設(shè)計(jì)理所當(dāng)然也有許多共通的地方。

1.1 培養(yǎng)興趣

興趣是能夠讓你堅(jiān)持下去的動(dòng)力。如果只是把寫程序作為謀生的手段的話,你會(huì)活的很累,也太對不起自己了。多關(guān)心一些行業(yè)趣事,多想想蓋茨。不是提倡天天做白日夢,但人要是沒有了夢想,你覺得有味道嗎?可能像許多深圳本地農(nóng)民一樣,打打麻將,喝喝功夫茶,拜拜財(cái)神爺;每個(gè)月就有幾萬十幾萬甚至更多的進(jìn)帳,憑空多出個(gè)"食利階層"。你認(rèn)為,這樣有味道嗎?有空多到一些程序員論壇轉(zhuǎn)轉(zhuǎn),你會(huì)發(fā)現(xiàn),他們其實(shí)很樂觀幽默,時(shí)不時(shí)會(huì)冒出智慧的火花。

1.2 慎選程序設(shè)計(jì)語言

男怕入錯(cuò)行,女怕嫁錯(cuò)郎。初學(xué)者選擇程序設(shè)計(jì)語言需要謹(jǐn)慎對待。軟件開發(fā)不僅僅是掌握一門編程語言了事,它還需要其他很多方面的背景知識。軟件開發(fā)也不僅僅局限于某幾個(gè)領(lǐng)域,而是已經(jīng)滲透到了各行各業(yè)幾乎每一個(gè)角落。

如果你對硬件比較感興趣,你可以學(xué)習(xí)C語言/匯編語言,進(jìn)入硬件開發(fā)領(lǐng)域。如果你對電信的行業(yè)知識及網(wǎng)絡(luò)比較熟悉,你可以在C/C++等之上多花時(shí)間,以期進(jìn)入電信軟件開發(fā)領(lǐng)域。如果你對操作系統(tǒng)比較熟悉,你可以學(xué)習(xí)C/Linux等等,為Linux內(nèi)核開發(fā)/驅(qū)動(dòng)程序開發(fā)/嵌入式開發(fā)打基礎(chǔ)。如果你想介入到應(yīng)用范圍最廣泛的應(yīng)用軟件開發(fā)(包括電子商務(wù)電子政務(wù)系統(tǒng))的話,你可以選擇J2EE或.NET,甚至LAMP組合。每個(gè)領(lǐng)域要求的背景知識不一樣。做應(yīng)用軟件需要對數(shù)據(jù)庫等很熟悉??傊?,你需要根據(jù)自己的特點(diǎn)來選擇合適你的編程語言。

1.3 要腳踏實(shí)地,快餐式的學(xué)習(xí)不可取

先分享一個(gè)故事。

有一個(gè)小朋友,他很喜歡研究生物學(xué),很想知道那些蝴蝶如何從蛹?xì)だ锍鰜恚兂珊銜?huì)飛。有一次,他走到草原上面看見一個(gè)蛹,便取了回家,然后看著,過了幾天以后,這個(gè)蛹出了一條裂痕,看見里面的蝴蝶開始掙扎,想抓破蛹?xì)わw出來。這個(gè)過程達(dá)數(shù)小時(shí)之久,蝴蝶在蛹里面很辛苦地拼命掙扎,怎么也沒法子走出來。這個(gè)小孩看著看著不忍心,就想不如讓我?guī)蛶退桑汶S手拿起剪刀在蛹上剪開,使蝴蝶破蛹而出。但蝴蝶出來以后,因?yàn)槌岚虿粔蛄Γ兊煤苡纺[,飛不起來。

這個(gè)故事給我們的啟示是:欲速則不達(dá)。

浮躁是現(xiàn)代人最普遍的心態(tài),能怪誰?也許是貧窮落后了這么多年的緣故,就像當(dāng)年的大躍進(jìn)一樣,都想大步跨入共產(chǎn)主義社會(huì)。現(xiàn)在的軟件公司、客戶、政府、學(xué)校、培訓(xùn)機(jī)構(gòu)等等到處彌漫著浮躁之氣。就拿筆者比較熟悉的深圳IT培訓(xùn)行業(yè)來說吧,居然有的打廣告宣稱"參加培訓(xùn),100%就業(yè)",居然報(bào)名的學(xué)生不少,簡直是藐視天下程序員。社會(huì)環(huán)境如是,我們不能改變,只能改變自己,鬧市中的安寧,彌足珍貴。許多初學(xué)者C++/JAVA沒開始學(xué),立馬使用VC/JBuilder,會(huì)使用VC/JBuilder開發(fā)一個(gè)HelloWorld程序,就忙不迭的向世界宣告,"我會(huì)軟件開發(fā)了",簡歷上也大言不慚地寫上"精通VC/JAVA"。結(jié)果到軟件公司面試時(shí)要么被三兩下打發(fā)走了,要么被駁的體無完膚,無地自容。到處碰壁之后才知道捧起《C++編程思想》《JAVA編程思想》仔細(xì)鉆研,早知如此何必當(dāng)初呀。

"你現(xiàn)在講究簡單方便,你以后的路就長了",好象也是佛經(jīng)中的勸戒。

1.4 多實(shí)踐,快實(shí)踐

彭端淑的《為學(xué)一首示子侄》中有窮和尚與富和尚的故事。

從前,四川邊境有兩個(gè)和尚,一個(gè)貧窮,一個(gè)有錢。一天,窮和尚對富和尚說:"我打算去南海朝圣,你看怎么樣?"富和尚說:"這里離南海有幾千里遠(yuǎn),你靠什么去呢?"窮和尚說:"我只要一個(gè)水缽,一個(gè)飯碗就夠了。"富和尚為難地說:"幾年前我就打算買條船去南海,可至今沒去成,你還是別去吧!"一年以后,富和尚還在為租賃船只籌錢,窮和尚卻已經(jīng)從南海朝圣回來了。

這個(gè)故事可解讀為:任何事情,一旦考慮好了,就要馬上上路,不要等到準(zhǔn)備周全之后,再去干事情。假如事情準(zhǔn)備考慮周全了再上路的話,別人恐怕捷足先登了。軟件開發(fā)是一門工程學(xué)科,注重的就是實(shí)踐,"君子動(dòng)口不動(dòng)手"對軟件開發(fā)人員來講根本就是錯(cuò)誤的,他們提倡"動(dòng)手至上",但別害怕,他們大多溫文爾雅,沒有暴力傾向,雖然有時(shí)候蓬頭垢面的一副"比爾蓋茨"樣。有前輩高人認(rèn)為,學(xué)習(xí)編程的秘訣是:編程、編程、再編程,筆者深表贊同。不僅要多實(shí)踐,而且要快實(shí)踐。我們在看書的時(shí)候,不要等到你完全理解了才動(dòng)手敲代碼,而是應(yīng)該在看書的同時(shí)敲代碼,程序運(yùn)行的各種情況可以讓你更快更牢固的掌握知識點(diǎn)。

1.5 多參考程序代碼

程序代碼是軟件開發(fā)最重要的成果之一,其中滲透了程序員的思想與靈魂。許多人被《仙劍奇?zhèn)b傳》中凄美的愛情故事感動(dòng),悲劇的結(jié)局更有一種缺憾美。為什么要以悲劇結(jié)尾?據(jù)說是因?yàn)閷憽断蓜ζ鎮(zhèn)b傳》的程序員失戀而安排了這樣的結(jié)局,他把自己的感覺融入到游戲中,卻讓眾多的仙劍迷扼腕嘆息。

多多參考代碼例子,對JAVA而言有參考文獻(xiàn)[4.3],有API類的源代碼(JDK安裝目錄下的src.zip文件),也可以研究一些開源的軟件或框架。

1.6 加強(qiáng)英文閱讀能力

對學(xué)習(xí)編程來說,不要求英語,但不能一點(diǎn)不會(huì),。最起碼像JAVAAPI文檔(參考文獻(xiàn)[4.4])這些東西還是要能看懂的,連猜帶懵都可以;旁邊再開啟一個(gè)"金山詞霸"。看多了就會(huì)越來越熟練。在學(xué)JAVA的同時(shí)學(xué)習(xí)英文,一箭雙雕多好。另外好多軟件需要到英文網(wǎng)站下載,你要能夠找到它們,這些是最基本的要求。英語好對你學(xué)習(xí)有很大的幫助??谡Z好的話更有機(jī)會(huì)進(jìn)入管理層,進(jìn)而可以成為剝削程序員的"周扒皮"。

1.7 萬不得已才請教別人

筆者在ChinaITLab網(wǎng)校的在線輔導(dǎo)系統(tǒng)中解決學(xué)生問題時(shí)發(fā)現(xiàn),大部分的問題學(xué)生稍做思考就可以解決。請教別人之前,你應(yīng)該先回答如下幾個(gè)問題。

你是否在google中搜索了問題的解決辦法?

你是否查看了JAVAAPI文檔?

你是否查找過相關(guān)書籍?

你是否寫代碼測試過?

如果回答都是"是"的話,而且還沒有找到解決辦法,再問別人不遲。要知道獨(dú)立思考的能力對你很重要。要知道程序員的時(shí)間是很寶貴的。

1.8 多讀好書

書中自有顏如玉。比爾?蓋茨是一個(gè)飽讀群書的人。雖然沒有讀完大學(xué),但九歲的時(shí)候比爾?蓋茨就已經(jīng)讀完了所有的百科全書,所以他精通天文、歷史、地理等等各類學(xué)科,可以說比爾?蓋茨不僅是當(dāng)今世界上金錢的首富,而且也可以稱得上是知識的巨富。

筆者在給學(xué)生上課的時(shí)候經(jīng)常會(huì)給他們推薦書籍,到后來學(xué)生實(shí)在忍無可忍開始抱怨,"天吶,這么多書到什么時(shí)候才能看完了","學(xué)軟件開發(fā),感覺上了賊船"。這時(shí)候,我的回答一般是,"別著急,什么時(shí)候帶你們?nèi)タ纯次业臅?,到現(xiàn)在每月花在技術(shù)書籍上的錢400元,這在軟件開發(fā)人員之中還只能夠算是中等的",學(xué)生當(dāng)場暈倒。(注:這一部分學(xué)生是剛學(xué)軟件開發(fā)的)

對于在JAVA開發(fā)領(lǐng)域的好書在筆者另外一篇文章中會(huì)專門點(diǎn)評。該文章可作為本文的姊妹篇。

1.9 使用合適的工具

工欲善其事必先利其器。軟件開發(fā)包含各種各樣的活動(dòng),需求收集分析、建立用例模型、建立分析設(shè)計(jì)模型、編程實(shí)現(xiàn)、調(diào)試程序、自動(dòng)化測試、持續(xù)集成等等,沒有工具幫忙可以說是寸步難行。工具可以提高開發(fā)效率,使軟件的質(zhì)量更高BUG更少。組合稱手的武器。到飛花摘葉皆可傷人的境界就很高了,無招勝有招,手中無劍心中有劍這樣的境界幾乎不可企及。在筆者另外一篇文章中會(huì)專門闡述如何選擇合適的工具(該文章也可作為本文的姊妹篇)。

2.軟件開發(fā)學(xué)習(xí)路線

兩千多年的儒家思想孔孟之道,中庸的思想透入骨髓,既不冒進(jìn)也不保守并非中庸之道,而是找尋學(xué)習(xí)軟件開發(fā)的正確路線與規(guī)律。

從軟件開發(fā)人員的生涯規(guī)劃來講,我們可以大致分為三個(gè)階段,軟件工程師→軟件設(shè)計(jì)師→架構(gòu)設(shè)計(jì)師或項(xiàng)目管理師。不想當(dāng)元帥的士兵不是好士兵,不想當(dāng)架構(gòu)設(shè)計(jì)師或項(xiàng)目管理師的程序員也不是好的程序員。我們應(yīng)該努力往上走。讓我們先整理一下開發(fā)應(yīng)用軟件需要學(xué)習(xí)的主要技術(shù)。

A.基礎(chǔ)理論知識,如操作系統(tǒng)、編譯原理、數(shù)據(jù)結(jié)構(gòu)與算法、計(jì)算機(jī)原理等,它們并非不重要。如不想成為計(jì)算機(jī)科學(xué)家的話,可以采取"用到的時(shí)候再來學(xué)"的原則。

B.一門編程語言,現(xiàn)在基本上都是面向?qū)ο蟮恼Z言,JAVA/C++/C#等等。如果做WEB開發(fā)的話還要學(xué)習(xí)HTML/Jav**ript等等。

C.一種方法學(xué)或者說思想,現(xiàn)在基本都是面向?qū)ο笏枷耄∣OA/OOD/設(shè)計(jì)模式)。由此而衍生的基于組件開發(fā)CBD/面向方面編程AOP等等。

D.一種關(guān)系型數(shù)據(jù)庫,ORACLE/SqlServer/DB2/MySQL等等

E.一種提高生產(chǎn)率的IDE集成開發(fā)環(huán)境JBuilder/Eclipse/VS.NET等。

F.一種UML建模工具,用ROSE/VISIO/鋼筆進(jìn)行建模。

G.一種軟件過程,RUP/XP/CMM等等,通過軟件過程來組織軟件開發(fā)的眾多活動(dòng),使開發(fā)流程專業(yè)化規(guī)范化。當(dāng)然還有其他的一些軟件工程知識。

H.項(xiàng)目管理、體系結(jié)構(gòu)、框架知識。

正確的路線應(yīng)該是:B→C→E→F→G→H。

還需要補(bǔ)充幾點(diǎn):

1).對于A與C要補(bǔ)充的是,我們應(yīng)該在實(shí)踐中逐步領(lǐng)悟編程理論與編程思想。新技術(shù)雖然不斷涌現(xiàn),更新速度令人眼花燎亂霧里看花;但萬變不離其宗,編程理論與編程思想的變化卻很慢。掌握了編程理論與編程思想你就會(huì)有撥云見日之感。面向?qū)ο蟮乃枷朐谀壳皝碇v是相當(dāng)關(guān)鍵的,是強(qiáng)勢技術(shù)之一,在上面需要多投入時(shí)間,給你的回報(bào)也會(huì)讓你驚喜。

2).對于數(shù)據(jù)庫來說是獨(dú)立學(xué)習(xí)的,這個(gè)時(shí)機(jī)就由你來決定吧。

3).編程語言作為學(xué)習(xí)軟件開發(fā)的主線,而其余的作為輔線。

4).軟件工程師著重于B、C、E、D;軟件設(shè)計(jì)師著重于B、C、E、D、F;架構(gòu)設(shè)計(jì)師著重于C、F、H。

3.如何學(xué)習(xí)JAVA?

3.1 JAVA學(xué)習(xí)路線

3.1.1 基礎(chǔ)語法及JAVA原理

基礎(chǔ)語法和JAVA原理是地基,地基不牢靠,猶如沙地上建摩天大廈,是相當(dāng)危險(xiǎn)的。學(xué)習(xí)JAVA也是如此,必須要有扎實(shí)的基礎(chǔ),你才能在J2EE、J2ME領(lǐng)域游刃有余。參加SCJP(SUN公司認(rèn)證的JAVA程序員)考試不失為一個(gè)好方法,原因之一是為了對得起你交的1200大洋考試費(fèi),你會(huì)更努力學(xué)習(xí),原因之二是SCJP考試能夠讓你把基礎(chǔ)打得很牢靠,它要求你跟JDK一樣熟悉JAVA基礎(chǔ)知識;但是你千萬不要認(rèn)為考過了SCJP就有多了不起,就能夠獲得軟件公司的青睞,就能夠獲取高薪,這樣的想法也是很危險(xiǎn)的。獲得"真正"的SCJP只能證明你的基礎(chǔ)還過得去,但離實(shí)際開發(fā)還有很長的一段路要走。

3.1.2 OO思想的領(lǐng)悟

掌握了基礎(chǔ)語法和JAVA程序運(yùn)行原理后,我們就可以用JAVA語言實(shí)現(xiàn)面向?qū)ο蟮乃枷肓恕C嫦驅(qū)ο?,是一種方法學(xué);是獨(dú)立于語言之外的編程思想;是CBD基于組件開發(fā)的基礎(chǔ);屬于強(qiáng)勢技術(shù)之一。當(dāng)以后因工作需要轉(zhuǎn)到別的面向?qū)ο笳Z言的時(shí)候,你會(huì)感到特別的熟悉親切,學(xué)起來像喝涼水這么簡單。

使用面向?qū)ο蟮乃枷脒M(jìn)行開發(fā)的基本過程是:

●調(diào)查收集需求。

●建立用例模型。

●從用例模型中識別分析類及類與類之間的靜態(tài)動(dòng)態(tài)關(guān)系,從而建立分析模型。

●細(xì)化分析模型到設(shè)計(jì)模型。

●用具體的技術(shù)去實(shí)現(xiàn)。

●測試、部署、總結(jié)。

3.1.3 基本API的學(xué)習(xí)

進(jìn)行軟件開發(fā)的時(shí)候,并不是什么功能都需要我們?nèi)?shí)現(xiàn),也就是經(jīng)典名言所說的"不需要重新發(fā)明輪子"。我們可以利用現(xiàn)成的類、組件、框架來搭建我們的應(yīng)用,如SUN公司編寫好了眾多類實(shí)現(xiàn)一些底層功能,以及我們下載過來的JAR文件中包含的類,我們可以調(diào)用類中的方法來完成某些功能或繼承它。那么這些類中究竟提供了哪些方法給我們使用?方法的參數(shù)個(gè)數(shù)及類型是?類的構(gòu)造器需不需要參數(shù)?總不可能SUN公司的工程師打國際長途甚至飄洋過海來告訴你他編寫的類該如何使用吧。他們只能提供文檔給我們查看,JAVADOC文檔(參考文獻(xiàn)4.4)就是這樣的文檔,它可以說是程序員與程序員交流的文檔。

基本API指的是實(shí)現(xiàn)了一些底層功能的類,通用性較強(qiáng)的API,如字符串處理/輸入輸出等等。我們又把它成為類庫。熟悉API的方法一是多查JAVADOC文檔(參考文獻(xiàn)4.4),二是使用JBuilder/Eclipse等IDE的代碼提示功能。

3.1.4 特定API的學(xué)習(xí)

JAVA介入的領(lǐng)域很廣泛,不同的領(lǐng)域有不同的API,沒有人熟悉所有的API,對一般人而言只是熟悉工作中要用到的API。如果你做界面開發(fā),那么你需要學(xué)習(xí)Swing/AWT/SWT等API;如果你進(jìn)行網(wǎng)絡(luò)游戲開發(fā),你需要深入了解網(wǎng)絡(luò)API/多媒體API/2D3D等;如果你做WEB開發(fā),就需要熟悉Servlet等API啦??傊?,需要根據(jù)工作的需要或你的興趣發(fā)展方向去選擇學(xué)習(xí)特定的API。

3.1.5 開發(fā)工具的用法

在學(xué)習(xí)基礎(chǔ)語法與基本的面向?qū)ο蟾拍顣r(shí),從鍛煉語言熟練程度的角度考慮,我們推薦使用的工具是Editplus/JCreator+JDK,這時(shí)候不要急于上手JBuilder/Eclipse等集成開發(fā)環(huán)境,以免過于關(guān)注IDE的強(qiáng)大功能而分散對JAVA技術(shù)本身的注意力。過了這一階段你就可以開始熟悉IDE了。

程序員日常工作包括很多活動(dòng),編輯、編譯及構(gòu)建、調(diào)試、單元測試、版本控制、維持模型與代碼同步、文檔的更新等等,幾乎每一項(xiàng)活動(dòng)都有專門的工具,如果獨(dú)立使用這些工具的話,你將會(huì)很痛苦,你需要在堆滿工具的任務(wù)欄上不斷的切換,效率很低下,也很容易出錯(cuò)。在JBuilder、Eclipse等IDE中已經(jīng)自動(dòng)集成編輯器、編譯器、調(diào)試器、單元測試工具JUnit、自動(dòng)構(gòu)建工具ANT、版本控制工具CVS、DOC文檔生成與更新等等,甚至可以把UML建模工具也集成進(jìn)去,又提供了豐富的向?qū)椭煽蚣艽a,讓我們的開發(fā)變得更輕松。應(yīng)該說IDE發(fā)展的趨勢就是集成軟件開發(fā)中要用到的幾乎所有工具。

從開發(fā)效率的角度考慮,使用IDE是必經(jīng)之路,也是從一個(gè)學(xué)生到一個(gè)職業(yè)程序員轉(zhuǎn)變的里程碑。

JAVA開發(fā)使用的IDE主要有Eclipse、JBuilder、JDeveloper、NetBeans等幾種;而Eclipse、JBuilder占有的市場份額是最大的。JBuilder在近幾年來一直是JAVA集成開發(fā)環(huán)境中的霸主,它是由備受程序員尊敬的Borland公司開發(fā),在硝煙彌漫的JAVAIDE大戰(zhàn)中,以其快速的版本更新?lián)魯BM的VisualAgeforJAVA等而成就一番偉業(yè)。IBM在VisualAgeforJAVA上已經(jīng)無利可圖之下,干脆將之貢獻(xiàn)給開源社區(qū),成為Eclipse的前身,真所謂"柳暗花明又一村"。浴火重生的Eclipse以其開放式的插件擴(kuò)展機(jī)制、免費(fèi)開源獲得廣大程序員(包括幾乎所有的骨灰級程序員)的青睞,極具發(fā)展?jié)摿Α?/p>

3.1.6 學(xué)習(xí)軟件工程

對小型項(xiàng)目而言,你可能認(rèn)為軟件工程沒太大的必要。隨著項(xiàng)目的復(fù)雜性越來越高,軟件工程的必要性才會(huì)體現(xiàn)出來。參見"軟件開發(fā)學(xué)習(xí)路線"小節(jié)。

3.2 學(xué)習(xí)要點(diǎn)

確立的學(xué)習(xí)路線之后,我們還需要總結(jié)一下JAVA的學(xué)習(xí)要點(diǎn),這些要點(diǎn)在前文多多少少提到過,只是筆者覺得這些地方特別要注意才對它們進(jìn)行匯總,不要嫌我婆婆媽媽啊。

3.2.1 勤查API文檔

當(dāng)程序員編寫好某些類,覺得很有成就感,想把它貢獻(xiàn)給各位苦難的同行。這時(shí)候你要使用"javadoc"工具(包含在JDK中)生成標(biāo)準(zhǔn)的JAVADOC文檔,供同行使用。J2SE/J2EE/J2ME的DOC文檔是程序員與程序員交流的工具,幾乎人手一份,除了菜鳥之外。J2SEDOC文檔官方下載地址:,你可以到google搜索CHM版本下載。也可以在線查看:

對待DOC文檔要像毛主席語錄,早上起床念一遍,吃飯睡覺前念一遍。

當(dāng)需要某項(xiàng)功能的時(shí)候,你應(yīng)該先查相應(yīng)的DOC文檔看看有沒有現(xiàn)成的實(shí)現(xiàn),有的話就不必勞神費(fèi)心了直接用就可以了,找不到的時(shí)候才考慮自己實(shí)現(xiàn)。使用步驟一般如下:

●找特定的包,包一般根據(jù)功能組織。

●找需要使用類,類命名規(guī)范的話我們由類的名字可猜出一二。

●選擇構(gòu)造器,大多數(shù)使用類的方式是創(chuàng)建對象。

●選擇你需要的方法。

3.2.2 查書/google->寫代碼測試->查看源代碼->請教別人

當(dāng)我們遇到問題的時(shí)候該如何解決?

這時(shí)候不要急著問別人,太簡單的問題,沒經(jīng)過思考的問題,別人會(huì)因此而瞧不起你??梢韵日艺視?,到google中搜一下看看,絕大部分問題基本就解決了。而像"某些類/方法如何使用的問題",DOC文檔就是答案。對某些知識點(diǎn)有疑惑是,寫代碼測試一下,會(huì)給你留下深刻的印象。而有的問題,你可能需要直接看API的源代碼驗(yàn)證你的想法。萬不得已才去請教別人。

3.2.3 學(xué)習(xí)開源軟件的設(shè)計(jì)思想

JAVA領(lǐng)域有許多源代碼開放的工具、組件、框架,JUnit、ANT、Tomcat、Struts、Spring、Jive論壇、PetStore寵物店等等多如牛毛。這些可是前輩給我們留下的瑰寶呀。入寶山而空手歸,你心甘嗎?對這些工具、框架進(jìn)行分析,領(lǐng)會(huì)其中的設(shè)計(jì)思想,有朝一日說不定你也能寫一個(gè)XXX框架什么的,風(fēng)光一把。分析開源軟件其實(shí)是你提高技術(shù)、提高實(shí)戰(zhàn)能力的便捷方法。

3.2.4 規(guī)范的重要性

沒有規(guī)矩,不成方圓。這里的規(guī)范有兩層含義。第一層含義是技術(shù)規(guī)范,多到下載JSRXXX規(guī)范,多讀規(guī)范,這是最權(quán)威準(zhǔn)確最新的教材。第二層含義是編程規(guī)范,如果你使用了大量的獨(dú)特算法,富有個(gè)性的變量及方法的命名方式;同時(shí),沒給程序作注釋,以顯示你的編程功底是多么的深厚。這樣的代碼別人看起來像天書,要理解談何容易,更不用說維護(hù)了,必然會(huì)被無情地掃入垃圾堆。JAVA編碼規(guī)范到此查看或下載,中文的也有,啊,還要問我在哪,請參考3.2.2節(jié)。

3.2.5 不局限于JAVA

很不幸,很幸運(yùn),要學(xué)習(xí)的東西還有很多。不幸的是因?yàn)橐獙W(xué)的東西太多且多變,沒時(shí)間陪老婆家人或女朋友,導(dǎo)致身心疲憊,嚴(yán)重者甚至導(dǎo)致抑郁癥。幸運(yùn)的是別人要搶你飯碗絕非易事,他們或她們需要付出很多才能達(dá)成心愿。

JAVA不要孤立地去學(xué)習(xí),需要綜合學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)、OOP、軟件工程、UML、網(wǎng)絡(luò)編程、數(shù)據(jù)庫技術(shù)等知識,用橫向縱向的比較聯(lián)想的方式去學(xué)習(xí)會(huì)更有效。如學(xué)習(xí)JAVA集合的時(shí)候找數(shù)據(jù)結(jié)構(gòu)的書看看;學(xué)JDBC的時(shí)候復(fù)習(xí)數(shù)據(jù)庫技術(shù);采取的依然是"需要的時(shí)候再學(xué)"的原則。

posted @ 2012-06-11 13:03 tbwshc 閱讀(213) | 評論 (0)編輯 收藏

一、術(shù)語session

  在我的經(jīng)驗(yàn)里,session這個(gè)詞被濫用的程度大概僅次于transaction,更加有趣的是transaction與session在某些語境下的含義是相同的。

  session,中文經(jīng)常翻譯為會(huì)話,其本來的含義是指有始有終的一系列動(dòng)作/消息,比如打電話時(shí)從拿起電話撥號到掛斷電話這中間的一系列過程可以稱之為一個(gè)session。有時(shí)候我們可以看到這樣的話“在一個(gè)瀏覽器會(huì)話期間,...”,這里的會(huì)話一詞用的就是其本義,是指從一個(gè)瀏覽器窗口打開到關(guān)閉這個(gè)期間①。最混亂的是“用戶(客戶端)在一次會(huì)話期間”這樣一句話,它可能指用戶的一系列動(dòng)作(一般情況下是同某個(gè)具體目的相關(guān)的一系列動(dòng)作,比如從登錄到選購商品到結(jié)賬登出這樣一個(gè)網(wǎng)上購物的過程,有時(shí)候也被稱為一個(gè)transaction),然而有時(shí)候也可能僅僅是指一次連接,也有可能是指含義①,其中的差別只能靠上下文來推斷②。

  然而當(dāng)session一詞與網(wǎng)絡(luò)協(xié)議相關(guān)聯(lián)時(shí),它又往往隱含了“面向連接”和/或“保持狀態(tài)”這樣兩個(gè)含義,“面向連接”指的是在通信雙方在通信之前要先建立一個(gè)通信的渠道,比如打電話,直到對方接了電話通信才能開始,與此相對的是寫信,在你把信發(fā)出去的時(shí)候你并不能確認(rèn)對方的地址是否正確,通信渠道不一定能建立,但對發(fā)信人來說,通信已經(jīng)開始了。“保持狀態(tài)”則是指通信的一方能夠把一系列的消息關(guān)聯(lián)起來,使得消息之間可以互相依賴,比如一個(gè)服務(wù)員能夠認(rèn)出再次光臨的老顧客并且記得上次這個(gè)顧客還欠店里一塊錢。這一類的例子有“一個(gè)TCP session”或者“一個(gè)POP3 session”③。

  而到了web服務(wù)器蓬勃發(fā)展的時(shí)代,session在web開發(fā)語境下的語義又有了新的擴(kuò)展,它的含義是指一類用來在客戶端與服務(wù)器之間保持狀態(tài)的解決方案④。有時(shí)候session也用來指這種解決方案的存儲(chǔ)結(jié)構(gòu),如“把xxx保存在session里”⑤。由于各種用于web開發(fā)的語言在一定程度上都提供了對這種解決方案的支持,所以在某種特定語言的語境下,session也被用來指代該語言的解決方案,比如經(jīng)常把Java里提供的javax.servlet.http.HttpSession簡稱為session⑥。

  鑒于這種混亂已不可改變,本文中session一詞的運(yùn)用也會(huì)根據(jù)上下文有不同的含義,請大家注意分辨。

  在本文中,使用中文“瀏覽器會(huì)話期間”來表達(dá)含義①,使用“session機(jī)制”來表達(dá)含義④,使用“session”表達(dá)含義⑤,使用具體的“HttpSession”來表達(dá)含義⑥

  二、HTTP協(xié)議與狀態(tài)保持

  HTTP協(xié)議本身是無狀態(tài)的,這與HTTP協(xié)議本來的目的是相符的,客戶端只需要簡單的向服務(wù)器請求下載某些文件,無論是客戶端還是服務(wù)器都沒有必要紀(jì)錄彼此過去的行為,每一次請求之間都是獨(dú)立的,好比一個(gè)顧客和一個(gè)自動(dòng)售貨機(jī)或者一個(gè)普通的(非會(huì)員制)大賣場之間的關(guān)系一樣。

  然而聰明(或者貪心?)的人們很快發(fā)現(xiàn)如果能夠提供一些按需生成的動(dòng)態(tài)信息會(huì)使web變得更加有用,就像給有線電視加上點(diǎn)播功能一樣。這種需求一方面迫使HTML逐步添加了表單、腳本、DOM等客戶端行為,另一方面在服務(wù)器端則出現(xiàn)了CGI規(guī)范以響應(yīng)客戶端的動(dòng)態(tài)請求,作為傳輸載體的HTTP協(xié)議也添加了文件上載、cookie這些特性。其中cookie的作用就是為了解決HTTP協(xié)議無狀態(tài)的缺陷所作出的努力。至于后來出現(xiàn)的session機(jī)制則是又一種在客戶端與服務(wù)器之間保持狀態(tài)的解決方案。

  讓我們用幾個(gè)例子來描述一下cookie和session機(jī)制之間的區(qū)別與聯(lián)系。筆者曾經(jīng)常去的一家咖啡店有喝5杯咖啡免費(fèi)贈(zèng)一杯咖啡的優(yōu)惠,然而一次性消費(fèi)5杯咖啡的機(jī)會(huì)微乎其微,這時(shí)就需要某種方式來紀(jì)錄某位顧客的消費(fèi)數(shù)量。想象一下其實(shí)也無外乎下面的幾種方案:

  1、該店的店員很厲害,能記住每位顧客的消費(fèi)數(shù)量,只要顧客一走進(jìn)咖啡店,店員就知道該怎么對待了。這種做法就是協(xié)議本身支持狀態(tài)。

  2、發(fā)給顧客一張卡片,上面記錄著消費(fèi)的數(shù)量,一般還有個(gè)有效期限。每次消費(fèi)時(shí),如果顧客出示這張卡片,則此次消費(fèi)就會(huì)與以前或以后的消費(fèi)相聯(lián)系起來。這種做法就是在客戶端保持狀態(tài)。

  3、發(fā)給顧客一張會(huì)員卡,除了卡號之外什么信息也不紀(jì)錄,每次消費(fèi)時(shí),如果顧客出示該卡片,則店員在店里的紀(jì)錄本上找到這個(gè)卡號對應(yīng)的紀(jì)錄添加一些消費(fèi)信息。這種做法就是在服務(wù)器端保持狀態(tài)。

  由于HTTP協(xié)議是無狀態(tài)的,而出于種種考慮也不希望使之成為有狀態(tài)的,因此,后面兩種方案就成為現(xiàn)實(shí)的選擇。具體來說cookie機(jī)制采用的是在客戶端保持狀態(tài)的方案,而session機(jī)制采用的是在服務(wù)器端保持狀態(tài)的方案。同時(shí)我們也看到,由于采用服務(wù)器端保持狀態(tài)的方案在客戶端也需要保存一個(gè)標(biāo)識,所以session機(jī)制可能需要借助于cookie機(jī)制來達(dá)到保存標(biāo)識的目的,但實(shí)際上它還有其他選擇。

  三、理解cookie機(jī)制

  cookie機(jī)制的基本原理就如上面的例子一樣簡單,但是還有幾個(gè)問題需要解決:“會(huì)員卡”如何分發(fā);“會(huì)員卡”的內(nèi)容;以及客戶如何使用“會(huì)員卡”。

  正統(tǒng)的cookie分發(fā)是通過擴(kuò)展HTTP協(xié)議來實(shí)現(xiàn)的,服務(wù)器通過在HTTP的響應(yīng)頭中加上一行特殊的指示以提示瀏覽器按照指示生成相應(yīng)的cookie。然而純粹的客戶端腳本如JavaScript或者VBScript也可以生成cookie。

  而cookie的使用是由瀏覽器按照一定的原則在后臺自動(dòng)發(fā)送給服務(wù)器的。瀏覽器檢查所有存儲(chǔ)的cookie,如果某個(gè)cookie所聲明的作用范圍大于等于將要請求的資源所在的位置,則把該cookie附在請求資源的HTTP請求頭上發(fā)送給服務(wù)器。意思是麥當(dāng)勞的會(huì)員卡只能在麥當(dāng)勞的店里出示,如果某家分店還發(fā)行了自己的會(huì)員卡,那么進(jìn)這家店的時(shí)候除了要出示麥當(dāng)勞的會(huì)員卡,還要出示這家店的會(huì)員卡。

  cookie的內(nèi)容主要包括:名字,值,過期時(shí)間,路徑和域。

  其中域可以指定某一個(gè)域比如.google.com,相當(dāng)于總店招牌,比如寶潔公司,也可以指定一個(gè)域下的具體某臺機(jī)器比如www.google.com或者froogle.google.com,可以用飄柔來做比。

  路徑就是跟在域名后面的URL路徑,比如/或者/foo等等,可以用某飄柔專柜做比。

  路徑與域合在一起就構(gòu)成了cookie的作用范圍。
如果不設(shè)置過期時(shí)間,則表示這個(gè)cookie的生命期為瀏覽器會(huì)話期間,只要關(guān)閉瀏覽器窗口,cookie就消失了。這種生命期為瀏覽器會(huì)話期的cookie被稱為會(huì)話cookie。會(huì)話cookie一般不存儲(chǔ)在硬盤上而是保存在內(nèi)存里,當(dāng)然這種行為并不是規(guī)范規(guī)定的。如果設(shè)置了過期時(shí)間,瀏覽器就會(huì)把cookie保存到硬盤上,關(guān)閉后再次打開瀏覽器,這些cookie仍然有效直到超過設(shè)定的過期時(shí)間。

  存儲(chǔ)在硬盤上的cookie可以在不同的瀏覽器進(jìn)程間共享,比如兩個(gè)IE窗口。而對于保存在內(nèi)存里的cookie,不同的瀏覽器有不同的處理方式。對于IE,在一個(gè)打開的窗口上按Ctrl-N(或者從文件菜單)打開的窗口可以與原窗口共享,而使用其他方式新開的IE進(jìn)程則不能共享已經(jīng)打開的窗口的內(nèi)存cookie;對于Mozilla Firefox0.8,所有的進(jìn)程和標(biāo)簽頁都可以共享同樣的cookie。一般來說是用javascript的window.open打開的窗口會(huì)與原窗口共享內(nèi)存cookie。瀏覽器對于會(huì)話cookie的這種只認(rèn)cookie不認(rèn)人的處理方式經(jīng)常給采用session機(jī)制的web應(yīng)用程序開發(fā)者造成很大的困擾。

  下面就是一個(gè)goolge設(shè)置cookie的響應(yīng)頭的例子

HTTP/1.1 302 Found
Location: http://www.google.com/intl/zh-CN/
Set-Cookie: PREF=ID=0565f77e132de138:NW=1:TM=1098082649:LM=1098082649:S=KaeaCFPo49RiA_d8; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com
Content-Type: text/html


  這是使用HTTPLook這個(gè)HTTP Sniffer軟件來俘獲的HTTP通訊紀(jì)錄的一部分

 

  瀏覽器在再次訪問goolge的資源時(shí)自動(dòng)向外發(fā)送cookie


  使用Firefox可以很容易的觀察現(xiàn)有的cookie的值

  使用HTTPLook配合Firefox可以很容易的理解cookie的工作原理。

 

  IE也可以設(shè)置在接受cookie前詢問


  這是一個(gè)詢問接受cookie的對話框。

  四、理解session機(jī)制

 session機(jī)制是一種服務(wù)器端的機(jī)制,服務(wù)器使用一種類似于散列表的結(jié)構(gòu)(也可能就是使用散列表)來保存信息。

  當(dāng)程序需要為某個(gè)客戶端的請求創(chuàng)建一個(gè)session的時(shí)候,服務(wù)器首先檢查這個(gè)客戶端的請求里是否已包含了一個(gè)session標(biāo)識 - 稱為session id,如果已包含一個(gè)session id則說明以前已經(jīng)為此客戶端創(chuàng)建過session,服務(wù)器就按照session id把這個(gè)session檢索出來使用(如果檢索不到,可能會(huì)新建一個(gè)),如果客戶端請求不包含session id,則為此客戶端創(chuàng)建一個(gè)session并且生成一個(gè)與此session相關(guān)聯(lián)的session id,session id的值應(yīng)該是一個(gè)既不會(huì)重復(fù),又不容易被找到規(guī)律以仿造的字符串,這個(gè)session id將被在本次響應(yīng)中返回給客戶端保存。

  保存這個(gè)session id的方式可以采用cookie,這樣在交互過程中瀏覽器可以自動(dòng)的按照規(guī)則把這個(gè)標(biāo)識發(fā)揮給服務(wù)器。一般這個(gè)cookie的名字都是類似于SEEESIONID,而。比如weblogic對于web應(yīng)用程序生成的cookie,JSESSIONID=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764,它的名字就是JSESSIONID。

  由于cookie可以被人為的禁止,必須有其他機(jī)制以便在cookie被禁止時(shí)仍然能夠把session id傳遞回服務(wù)器。經(jīng)常被使用的一種技術(shù)叫做URL重寫,就是把session id直接附加在URL路徑的后面,附加方式也有兩種,一種是作為URL路徑的附加信息,表現(xiàn)形式為http://...../xxx;jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764另一種是作為查詢字符串附加在URL后面,表現(xiàn)形式為http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
這兩種方式對于用戶來說是沒有區(qū)別的,只是服務(wù)器在解析的時(shí)候處理的方式不同,采用第一種方式也有利于把session id的信息和正常程序參數(shù)區(qū)分開來。

  為了在整個(gè)交互過程中始終保持狀態(tài),就必須在每個(gè)客戶端可能請求的路徑后面都包含這個(gè)session id。

  另一種技術(shù)叫做表單隱藏字段。就是服務(wù)器會(huì)自動(dòng)修改表單,添加一個(gè)隱藏字段,以便在表單提交時(shí)能夠把session id傳遞回服務(wù)器。比如下面的表單

 

 

 

  在被傳遞給客戶端之前將被改寫成

 

 
 
  這種技術(shù)現(xiàn)在已較少應(yīng)用,筆者接觸過的很古老的iPlanet6(SunONE應(yīng)用服務(wù)器的前身)就使用了這種技術(shù)。實(shí)際上這種技術(shù)可以簡單的用對action應(yīng)用URL重寫來代替。

  在談?wù)搒ession機(jī)制的時(shí)候,常常聽到這樣一種誤解“只要關(guān)閉瀏覽器,session就消失了”。其實(shí)可以想象一下會(huì)員卡的例子,除非顧客主動(dòng)對店家提出銷卡,否則店家絕對不會(huì)輕易刪除顧客的資料。對session來說也是一樣的,除非程序通知服務(wù)器刪除一個(gè)session,否則服務(wù)器會(huì)一直保留,程序一般都是在用戶做log off的時(shí)候發(fā)個(gè)指令去刪除session。然而瀏覽器從來不會(huì)主動(dòng)在關(guān)閉之前通知服務(wù)器它將要關(guān)閉,因此服務(wù)器根本不會(huì)有機(jī)會(huì)知道瀏覽器已經(jīng)關(guān)閉,之所以會(huì)有這種錯(cuò)覺,是大部分session機(jī)制都使用會(huì)話cookie來保存session id,而關(guān)閉瀏覽器后這個(gè)session id就消失了,再次連接服務(wù)器時(shí)也就無法找到原來的session。如果服務(wù)器設(shè)置的cookie被保存到硬盤上,或者使用某種手段改寫瀏覽器發(fā)出的HTTP請求頭,把原來的session id發(fā)送給服務(wù)器,則再次打開瀏覽器仍然能夠找到原來的session。

  恰恰是由于關(guān)閉瀏覽器不會(huì)導(dǎo)致session被刪除,迫使服務(wù)器為seesion設(shè)置了一個(gè)失效時(shí)間,當(dāng)距離客戶端上一次使用session的時(shí)間超過這個(gè)失效時(shí)間時(shí),服務(wù)器就可以認(rèn)為客戶端已經(jīng)停止了活動(dòng),才會(huì)把session刪除以節(jié)省存儲(chǔ)空間。

  五、理解javax.servlet.http.HttpSession

  HttpSession是Java平臺對session機(jī)制的實(shí)現(xiàn)規(guī)范,因?yàn)樗鼉H僅是個(gè)接口,具體到每個(gè)web應(yīng)用服務(wù)器的提供商,除了對規(guī)范支持之外,仍然會(huì)有一些規(guī)范里沒有規(guī)定的細(xì)微差異。這里我們以BEA的Weblogic Server8.1作為例子來演示。

  首先,Weblogic Server提供了一系列的參數(shù)來控制它的HttpSession的實(shí)現(xiàn),包括使用cookie的開關(guān)選項(xiàng),使用URL重寫的開關(guān)選項(xiàng),session持久化的設(shè)置,session失效時(shí)間的設(shè)置,以及針對cookie的各種設(shè)置,比如設(shè)置cookie的名字、路徑、域,cookie的生存時(shí)間等。

  一般情況下,session都是存儲(chǔ)在內(nèi)存里,當(dāng)服務(wù)器進(jìn)程被停止或者重啟的時(shí)候,內(nèi)存里的session也會(huì)被清空,如果設(shè)置了session的持久化特性,服務(wù)器就會(huì)把session保存到硬盤上,當(dāng)服務(wù)器進(jìn)程重新啟動(dòng)或這些信息將能夠被再次使用,Weblogic Server支持的持久性方式包括文件、數(shù)據(jù)庫、客戶端cookie保存和復(fù)制。

  復(fù)制嚴(yán)格說來不算持久化保存,因?yàn)閟ession實(shí)際上還是保存在內(nèi)存里,不過同樣的信息被復(fù)制到各個(gè)cluster內(nèi)的服務(wù)器進(jìn)程中,這樣即使某個(gè)服務(wù)器進(jìn)程停止工作也仍然可以從其他進(jìn)程中取得session。

  cookie生存時(shí)間的設(shè)置則會(huì)影響瀏覽器生成的cookie是否是一個(gè)會(huì)話cookie。默認(rèn)是使用會(huì)話cookie。有興趣的可以用它來試驗(yàn)我們在第四節(jié)里提到的那個(gè)誤解。

  cookie的路徑對于web應(yīng)用程序來說是一個(gè)非常重要的選項(xiàng),Weblogic Server對這個(gè)選項(xiàng)的默認(rèn)處理方式使得它與其他服務(wù)器有明顯的區(qū)別。后面我們會(huì)專題討論。

  關(guān)于session的設(shè)置參考[5] http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869

  六、HttpSession常見問題

  (在本小節(jié)中session的含義為⑤和⑥的混合)

  1、session在何時(shí)被創(chuàng)建

  一個(gè)常見的誤解是以為session在有客戶端訪問時(shí)就被創(chuàng)建,然而事實(shí)是直到某server端程序調(diào)用HttpServletRequest.getSession(true)這樣的語句時(shí)才被創(chuàng)建,注意如果JSP沒有顯示的使用 <%@page session="false"%>關(guān)閉session,則JSP文件在編譯成Servlet時(shí)將會(huì)自動(dòng)加上這樣一條語句HttpSession session = HttpServletRequest.getSession(true);這也是JSP中隱含的session對象的來歷。

  由于session會(huì)消耗內(nèi)存資源,因此,如果不打算使用session,應(yīng)該在所有的JSP中關(guān)閉它。

  2、session何時(shí)被刪除

  綜合前面的討論,session在下列情況下被刪除a.程序調(diào)用HttpSession.invalidate();或b.距離上一次收到客戶端發(fā)送的session id時(shí)間間隔超過了session的超時(shí)設(shè)置;或c.服務(wù)器進(jìn)程被停止(非持久session)

  3、如何做到在瀏覽器關(guān)閉時(shí)刪除session

  嚴(yán)格的講,做不到這一點(diǎn)??梢宰鲆稽c(diǎn)努力的辦法是在所有的客戶端頁面里使用javascript代碼window.oncolose來監(jiān)視瀏覽器的關(guān)閉動(dòng)作,然后向服務(wù)器發(fā)送一個(gè)請求來刪除session。但是對于瀏覽器崩潰或者強(qiáng)行殺死進(jìn)程這些非常規(guī)手段仍然無能為力。

4、有個(gè)HttpSessionListener是怎么回事

  你可以創(chuàng)建這樣的listener去監(jiān)控session的創(chuàng)建和銷毀事件,使得在發(fā)生這樣的事件時(shí)你可以做一些相應(yīng)的工作。注意是session的創(chuàng)建和銷毀動(dòng)作觸發(fā)listener,而不是相反。類似的與HttpSession有關(guān)的listener還有HttpSessionBindingListener,HttpSessionActivationListener和HttpSessionAttributeListener。

5、存放在session中的對象必須是可序列化的嗎

  不是必需的。要求對象可序列化只是為了session能夠在集群中被復(fù)制或者能夠持久保存或者在必要時(shí)server能夠暫時(shí)把session交換出內(nèi)存。在Weblogic Server的session中放置一個(gè)不可序列化的對象在控制臺上會(huì)收到一個(gè)警告。我所用過的某個(gè)iPlanet版本如果session中有不可序列化的對象,在session銷毀時(shí)會(huì)有一個(gè)Exception,很奇怪。

  6、如何才能正確的應(yīng)付客戶端禁止cookie的可能性

  對所有的URL使用URL重寫,包括超鏈接,form的action,和重定向的URL,具體做法參見[6]
http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770

  7、開兩個(gè)瀏覽器窗口訪問應(yīng)用程序會(huì)使用同一個(gè)session還是不同的session

  參見第三小節(jié)對cookie的討論,對session來說是只認(rèn)id不認(rèn)人,因此不同的瀏覽器,不同的窗口打開方式以及不同的cookie存儲(chǔ)方式都會(huì)對這個(gè)問題的答案有影響。

  8、如何防止用戶打開兩個(gè)瀏覽器窗口操作導(dǎo)致的session混亂

  這個(gè)問題與防止表單多次提交是類似的,可以通過設(shè)置客戶端的令牌來解決。就是在服務(wù)器每次生成一個(gè)不同的id返回給客戶端,同時(shí)保存在session里,客戶端提交表單時(shí)必須把這個(gè)id也返回服務(wù)器,程序首先比較返回的id與保存在session里的值是否一致,如果不一致則說明本次操作已經(jīng)被提交過了??梢詤⒖础禞2EE核心模式》關(guān)于表示層模式的部分。需要注意的是對于使用javascript window.open打開的窗口,一般不設(shè)置這個(gè)id,或者使用單獨(dú)的id,以防主窗口無法操作,建議不要再window.open打開的窗口里做修改操作,這樣就可以不用設(shè)置。

  9、為什么在Weblogic Server中改變session的值后要重新調(diào)用一次session.setValue
做這個(gè)動(dòng)作主要是為了在集群環(huán)境中提示W(wǎng)eblogic Server session中的值發(fā)生了改變,需要向其他服務(wù)器進(jìn)程復(fù)制新的session值。

  10、為什么session不見了

  排除session正常失效的因素之外,服務(wù)器本身的可能性應(yīng)該是微乎其微的,雖然筆者在iPlanet6SP1加若干補(bǔ)丁的Solaris版本上倒也遇到過;瀏覽器插件的可能性次之,筆者也遇到過3721插件造成的問題;理論上防火墻或者代理服務(wù)器在cookie處理上也有可能會(huì)出現(xiàn)問題。

  出現(xiàn)這一問題的大部分原因都是程序的錯(cuò)誤,最常見的就是在一個(gè)應(yīng)用程序中去訪問另外一個(gè)應(yīng)用程序。我們在下一節(jié)討論這個(gè)問題。

  七、跨應(yīng)用程序的session共享

  常常有這樣的情況,一個(gè)大項(xiàng)目被分割成若干小項(xiàng)目開發(fā),為了能夠互不干擾,要求每個(gè)小項(xiàng)目作為一個(gè)單獨(dú)的web應(yīng)用程序開發(fā),可是到了最后突然發(fā)現(xiàn)某幾個(gè)小項(xiàng)目之間需要共享一些信息,或者想使用session來實(shí)現(xiàn)SSO(single sign on),在session中保存login的用戶信息,最自然的要求是應(yīng)用程序間能夠訪問彼此的session。

  然而按照Servlet規(guī)范,session的作用范圍應(yīng)該僅僅限于當(dāng)前應(yīng)用程序下,不同的應(yīng)用程序之間是不能夠互相訪問對方的session的。各個(gè)應(yīng)用服務(wù)器從實(shí)際效果上都遵守了這一規(guī)范,但是實(shí)現(xiàn)的細(xì)節(jié)卻可能各有不同,因此解決跨應(yīng)用程序session共享的方法也各不相同。

  首先來看一下Tomcat是如何實(shí)現(xiàn)web應(yīng)用程序之間session的隔離的,從Tomcat設(shè)置的cookie路徑來看,它對不同的應(yīng)用程序設(shè)置的cookie路徑是不同的,這樣不同的應(yīng)用程序所用的session id是不同的,因此即使在同一個(gè)瀏覽器窗口里訪問不同的應(yīng)用程序,發(fā)送給服務(wù)器的session id也可以是不同的。

 

  根據(jù)這個(gè)特性,我們可以推測Tomcat中session的內(nèi)存結(jié)構(gòu)大致如下。

 

  筆者以前用過的iPlanet也采用的是同樣的方式,估計(jì)SunONE與iPlanet之間不會(huì)有太大的差別。對于這種方式的服務(wù)器,解決的思路很簡單,實(shí)際實(shí)行起來也不難。要么讓所有的應(yīng)用程序共享一個(gè)session id,要么讓應(yīng)用程序能夠獲得其他應(yīng)用程序的session id。

  iPlanet中有一種很簡單的方法來實(shí)現(xiàn)共享一個(gè)session id,那就是把各個(gè)應(yīng)用程序的cookie路徑都設(shè)為/(實(shí)際上應(yīng)該是/NASApp,對于應(yīng)用程序來講它的作用相當(dāng)于根)。

/NASApp


  需要注意的是,操作共享的session應(yīng)該遵循一些編程約定,比如在session attribute名字的前面加上應(yīng)用程序的前綴,使得setAttribute("name", "neo")變成setAttribute("app1.name", "neo"),以防止命名空間沖突,導(dǎo)致互相覆蓋。


  在Tomcat中則沒有這么方便的選擇。在Tomcat版本3上,我們還可以有一些手段來共享session。對于版本4以上的Tomcat,目前筆者尚未發(fā)現(xiàn)簡單的辦法。只能借助于第三方的力量,比如使用文件、數(shù)據(jù)庫、JMS或者客戶端cookie,URL參數(shù)或者隱藏字段等手段。

  我們再看一下Weblogic Server是如何處理session的。

 


  從截屏畫面上可以看到Weblogic Server對所有的應(yīng)用程序設(shè)置的cookie的路徑都是/,這是不是意味著在Weblogic Server中默認(rèn)的就可以共享session了呢?然而一個(gè)小實(shí)驗(yàn)即可證明即使不同的應(yīng)用程序使用的是同一個(gè)session,各個(gè)應(yīng)用程序仍然只能訪問自己所設(shè)置的那些屬性。這說明Weblogic Server中的session的內(nèi)存結(jié)構(gòu)可能如下

 

  對于這樣一種結(jié)構(gòu),在session機(jī)制本身上來解決session共享的問題應(yīng)該是不可能的了。除了借助于第三方的力量,比如使用文件、數(shù)據(jù)庫、JMS或者客戶端cookie,URL參數(shù)或者隱藏字段等手段,還有一種較為方便的做法,就是把一個(gè)應(yīng)用程序的session放到ServletContext中,這樣另外一個(gè)應(yīng)用程序就可以從ServletContext中取得前一個(gè)應(yīng)用程序的引用。示例代碼如下,

  應(yīng)用程序A

context.setAttribute("appA", session);

  應(yīng)用程序B

contextA = context.getContext("/appA");
HttpSession sessionA = (HttpSession)contextA.getAttribute("appA");

  值得注意的是這種用法不可移植,因?yàn)楦鶕?jù)ServletContext的JavaDoc,應(yīng)用服務(wù)器可以處于安全的原因?qū)τ赾ontext.getContext("/appA");返回空值,以上做法在Weblogic Server 8.1中通過。

  那么Weblogic Server為什么要把所有的應(yīng)用程序的cookie路徑都設(shè)為/呢?原來是為了SSO,凡是共享這個(gè)session的應(yīng)用程序都可以共享認(rèn)證的信息。一個(gè)簡單的實(shí)驗(yàn)就可以證明這一點(diǎn),修改首先登錄的那個(gè)應(yīng)用程序的描述符weblogic.xml,把cookie路徑修改為/appA訪問另外一個(gè)應(yīng)用程序會(huì)重新要求登錄,即使是反過來,先訪問cookie路徑為/的應(yīng)用程序,再訪問修改過路徑的這個(gè),雖然不再提示登錄,但是登錄的用戶信息也會(huì)丟失。注意做這個(gè)實(shí)驗(yàn)時(shí)認(rèn)證方式應(yīng)該使用FORM,因?yàn)闉g覽器和web服務(wù)器對basic認(rèn)證方式有其他的處理方式,第二次請求的認(rèn)證不是通過session來實(shí)現(xiàn)的。具體請參看[7] secion 14.8 Authorization,你可以修改所附的示例程序來做這些試驗(yàn)。

  八、總結(jié)

  session機(jī)制本身并不復(fù)雜,然而其實(shí)現(xiàn)和配置上的靈活性卻使得具體情況復(fù)雜多變。這也要求我們不能把僅僅某一次的經(jīng)驗(yàn)或者某一個(gè)瀏覽器,服務(wù)器的經(jīng)驗(yàn)當(dāng)作普遍適用的經(jīng)驗(yàn),而是始終需要具體情況具體分析。

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 

WEB頁面工具語言XML(一)產(chǎn)生背景 10大城市2萬個(gè)熱門IT職位 注冊有獎(jiǎng)
  XML同HTML一樣,都來自tandard Generalized Markup Language, 即標(biāo)準(zhǔn)通用標(biāo)記語言,簡稱SGML.早在Web未發(fā)明之前,SGML就早已存在。正如它的名稱所言,SGML是一種用標(biāo)記來描述文檔資料的通用語言,它包含了一系列的文檔類型定義(簡稱DTD),DTD 中定義了標(biāo)記的含義,因而 SGML 的語法是可以擴(kuò)展的。SGML十分龐大,既不容易學(xué),又不容易使用,在計(jì)算機(jī)上實(shí)現(xiàn)也十分困難。鑒于這些因素,Web的發(fā)明者——歐洲核子物理研究中心的研究人員根據(jù)當(dāng)時(shí)(1989年)計(jì)算機(jī)技術(shù)的能力,提出了HTML語言。

  HTML只使用SGML中很小一部分標(biāo)記,例如HTML 3.2定義了70種標(biāo)記。為了便于在計(jì)算機(jī)上實(shí)現(xiàn),HTML規(guī)定的標(biāo)記是固定的,即HTML語法是不可擴(kuò)展的,它不需包含DTD.HTML這種固定的語法使它易學(xué)易用,在計(jì)算機(jī)上開發(fā) HTML的瀏覽器也十分容易。正是由于HTML的簡單性,使 Web 技術(shù)從計(jì)算機(jī)界走向全社會(huì),走向千家萬戶,Web的發(fā)展如日中天。

  近年來,隨著 Web的應(yīng)用越來越廣泛和深入,人們漸漸覺得HTML不夠用了,HTML過于簡單的語法嚴(yán)重地阻礙了用它來表現(xiàn)復(fù)雜的形式。盡管HTML推出了一個(gè)又一個(gè)新版本,已經(jīng)有了腳本、表格、幀等表達(dá)功能,但始終滿足不了不斷增長的需求。另一方面,這幾年來計(jì)算機(jī)技術(shù)的發(fā)展也十分迅速,已經(jīng)可以實(shí)現(xiàn)比當(dāng)初發(fā)明創(chuàng)造HTML時(shí)復(fù)雜得多的Web瀏覽器,所以開發(fā)一種新的Web頁面語言既是必要的,也是可能的。

  有人建議直接使用SGML 作為Web語言,這固然能解決HTML遇到的困難。但是SGML太龐大了,用戶學(xué)習(xí)和使用不方便尚且不說,要全面實(shí)現(xiàn)SGML的瀏覽器就非常困難,于是自然會(huì)想到僅使用SGML的子集,使新的語言既方便使用又實(shí)現(xiàn)容易。正是在這種形勢下,Web標(biāo)準(zhǔn)化組織W3C建議使用一種精簡的SGML版本——XML應(yīng)運(yùn)而生了

 

WEB頁面工具語言XML(二)定義
  XML是一個(gè)精簡的SGML,它將SGML的豐富功能與HTML的易用性結(jié)合到Web的應(yīng)用中。XML保留了SGML的可擴(kuò)展功能,TB這使XML從根本上有別于HTML.XML要比HTML強(qiáng)大得多,它不再是固定的標(biāo)記,而是允許定義數(shù)量不限的標(biāo)記來描述文檔中的資料,允許嵌套的信息結(jié)構(gòu)。HTML只是Web顯示數(shù)據(jù)的通用方法,而XML提供了一個(gè)直接處理 Web 數(shù)據(jù)的通用方法。HTML著重描述Web頁面的顯示格式,而XML著重描述的是Web頁面的內(nèi)容。

  XML中包括可擴(kuò)展格式語言XSL(Extensible Style Language) 和可擴(kuò)展鏈接語言XLL(Extensible Linking Language)。

  XSL用于將XML數(shù)據(jù)翻譯為HTML或其他格式的語言。XSL提供了一種疊式頁面CSS的功能,使開發(fā)者構(gòu)造出具有表達(dá)層結(jié)構(gòu)的Web頁面來,以有別于XML的數(shù)據(jù)結(jié)構(gòu)。XSL也能和HTML一起構(gòu)造疊式頁面。XSL可以解釋數(shù)量不限的標(biāo)記,它使Web的版面更豐富多彩,例如動(dòng)態(tài)的文本、跑馬式的文字。此外,XSL還處理多國文字、雙字節(jié)的漢字顯示、網(wǎng)格的各種各樣的處理等。

  XLL是XML的鏈接語言,它與HTML的鏈接相似,但功能更強(qiáng)大。XLL支持可擴(kuò)展的鏈接和多方向的鏈接。它打破了HTML只支持超級文本概念下最簡單的鏈接限制,能支持獨(dú)立于地址的域名、雙向鏈路、環(huán)路、多個(gè)源的集合鏈接等。XLL鏈接可不受文檔制約,完全按用戶要求來指定和管理。

  為了使XML易學(xué)易用,XML精簡了一大片SGML難得用一次的功能。正如幾十萬漢字中常用的只不過八千,SGML常用的部分只占20%,XML拋棄了SGML中不常用的部分,使它一下就精簡了80%。這樣一來,XML的語法說明書只有30頁,而SGML卻有500頁。

  XML設(shè)計(jì)中也考慮了它的易用性,易用性來自兩個(gè)方面:一方面用戶編寫Web頁面方便,另一方面設(shè)計(jì)人員實(shí)現(xiàn)XML瀏覽器也不太困難。

  總之,XML使用一個(gè)簡單而有靈活的標(biāo)準(zhǔn)格式,為基于Web的應(yīng)用提供了一個(gè)描述數(shù)據(jù)和交換數(shù)據(jù)的有效手段。HTML描述了顯示全球數(shù)據(jù)的通用方法,而XML提供了直接處理全球數(shù)據(jù)的通用方法

posted @ 2012-06-11 13:00 tbwshc 閱讀(286) | 評論 (0)編輯 收藏

僅列出標(biāo)題
共10頁: First 2 3 4 5 6 7 8 9 10 
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            一区二区欧美在线观看| 欧美激情一区二区三区在线| 免费在线一区二区| 乱码第一页成人| 久久精品理论片| 久久福利一区| 欧美在线一级va免费观看| 亚洲一区二区三区视频播放| 黄色成人av在线| 欧美日韩系列| 欧美视频精品一区| 欧美日本不卡视频| 欧美日韩一区二区视频在线观看| 免费av成人在线| 亚洲一区二区免费在线| 99国产精品国产精品久久| 亚洲人成人99网站| 久久精品国产2020观看福利| 99精品欧美一区二区三区综合在线| 日韩一区二区久久| 中文在线资源观看网站视频免费不卡 | 亚洲欧美电影在线观看| 老司机一区二区三区| 欧美一区二区在线| 欧美影院一区| 久久国产精品久久w女人spa| 欧美一区二区成人| 久久人人超碰| 亚洲国产精品嫩草影院| 亚洲无玛一区| 欧美激情综合五月色丁香小说| 久久国产欧美| 国产精品日韩在线| 亚洲精品1区2区| 久久久亚洲国产天美传媒修理工 | 在线免费不卡视频| 欧美一区二区三区的| 亚洲国产一区二区视频| 欧美一区二区在线免费播放| 欧美国产精品劲爆| 亚洲经典自拍| 亚洲国产美女精品久久久久∴| 欧美激情一区二区三区蜜桃视频| 亚洲影院污污.| 久久久噜噜噜久久中文字幕色伊伊| 国产一区二区三区的电影 | 欧美成人久久| 欧美亚洲在线视频| 国产主播精品在线| 免费视频最近日韩| 欧美激情91| 狠狠干成人综合网| 欧美国产日韩视频| 欧美日韩99| 欧美怡红院视频| 麻豆成人综合网| 一区二区三区高清在线观看| 在线视频精品| 激情亚洲网站| 一区二区三区久久网| 国产小视频国产精品| 亚洲大片av| 国产精品狠色婷| 久久精品一区二区三区四区| 免费不卡在线视频| 午夜精品美女自拍福到在线| 久久精品99无色码中文字幕| 亚洲精品久久久久| 亚洲神马久久| 亚洲第一久久影院| 亚洲欧美中文日韩在线| 在线中文字幕不卡| 亚洲欧美视频在线| 玖玖视频精品| 久久国产日本精品| 国产精品男人爽免费视频1| 亚洲激情在线播放| 亚洲国产日韩一区二区| 久久精品国产一区二区三区 | 免费在线日韩av| 欧美1区2区| 亚洲国产美女精品久久久久∴| 亚洲综合社区| 亚洲男人第一av网站| 女人天堂亚洲aⅴ在线观看| 欧美不卡高清| 一本高清dvd不卡在线观看| 欧美成人一区二区三区在线观看 | 国产精品久久久久久久午夜片| 亚洲黄页视频免费观看| 宅男精品视频| 国产一区在线看| 欧美成人一区二区三区在线观看| 亚洲国产精品成人综合色在线婷婷| 亚洲国产成人久久综合一区| 免费不卡在线视频| 亚洲永久精品大片| 欧美高清视频一区二区三区在线观看| 亚洲成人中文| 欧美午夜精品一区| 亚洲最新在线视频| 久久精品亚洲| 亚洲午夜电影网| 极品尤物一区二区三区| 欧美午夜精品久久久久久孕妇 | 亚洲精品一区在线观看| 夜夜嗨av色一区二区不卡| 久久人91精品久久久久久不卡| 免费在线观看日韩欧美| 亚洲午夜一区二区三区| 欧美精品久久一区二区| 亚洲欧美日韩国产中文| 欧美va亚洲va日韩∨a综合色| 亚洲精品欧美专区| 国产一区二区电影在线观看| 欧美极品影院| 欧美顶级艳妇交换群宴| 久久激五月天综合精品| 亚洲精品综合精品自拍| 久久蜜桃精品| 9人人澡人人爽人人精品| 蜜臀久久99精品久久久久久9| 性一交一乱一区二区洋洋av| 亚洲色图自拍| 亚洲免费在线视频一区 二区| 亚洲视频导航| 先锋影音网一区二区| 午夜精品剧场| 麻豆成人在线播放| 亚洲黄网站在线观看| 亚洲国产精品电影在线观看| 99re66热这里只有精品3直播| 亚洲精品在线观看免费| 亚洲香蕉成视频在线观看 | 午夜影院日韩| 久久久久久久久岛国免费| 久久一区二区三区四区| 亚洲激情在线激情| 亚洲一区二区成人在线观看| 亚洲国产精品一区二区www在线| 亚洲激情视频网| 小黄鸭精品密入口导航| 国产三级欧美三级| 亚洲精品乱码久久久久久黑人| 亚洲精品一区在线观看| 久久久99久久精品女同性| 亚洲区免费影片| 欧美在线视频日韩| 欧美色图五月天| 亚洲黄色尤物视频| 久久精品国产一区二区电影| 亚洲国产日韩一区| 久久久久成人精品| 国产主播一区二区三区四区| 亚洲字幕一区二区| 日韩网站在线观看| 欧美激情亚洲另类| 亚洲国产精品成人精品| 美女福利精品视频| 久久成人一区| 在线看视频不卡| 久热精品在线视频| 久久久久久午夜| 亚洲国产另类久久久精品极度| 久久久精彩视频| 久久久久天天天天| 亚洲欧洲精品一区| 蜜臀久久99精品久久久画质超高清| 亚洲黄色成人久久久| 亚洲电影免费观看高清完整版在线 | 亚洲国产精选| 欧美国产欧美亚州国产日韩mv天天看完整 | 久久精品三级| 欧美电影美腿模特1979在线看| 99视频热这里只有精品免费| aⅴ色国产欧美| 黄色成人在线网站| 亚洲最新合集| 欧美在线观看你懂的| 国语自产精品视频在线看一大j8| 久久综合色一综合色88| 欧美日本精品在线| 久久蜜桃资源一区二区老牛 | 欧美二区乱c少妇| 亚洲一区二区在线看| 麻豆91精品91久久久的内涵| 亚洲视频在线看| 久久久久一区二区| 欧美一区二区观看视频| 欧美精品亚洲| 欧美大胆成人| 在线欧美视频| 久久久999精品| 久久亚洲欧美国产精品乐播| 国产精品久久久久久久久免费| 亚洲精品123区| 亚洲人成77777在线观看网| 久久婷婷亚洲| 亚洲第一黄色网| 一区二区电影免费观看|