<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    小方的Java博客

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      27 隨筆 :: 17 文章 :: 115 評論 :: 0 Trackbacks

    置頂隨筆 #

    Let my heart hibernate and I'm waiting for spring!
    posted @ 2006-07-20 16:34 方佳瑋 閱讀(274) | 評論 (0)編輯 收藏

    2006年6月17日 #

    Struts的Token(令牌)機制能夠很好的解決表單重復(fù)提交的問題,基本原理是:服務(wù)器端在處理到達的請求之前,會將請求中包含的令牌值與保存在當前用戶會話中的令牌值進行比較,看是否匹配。在處理完該請求后,且在答復(fù)發(fā)送給客戶端之前,將會產(chǎn)生一個新的令牌,該令牌除傳給客戶端以外,也會將用戶會話中保存的舊的令牌進行替換。這樣如果用戶回退到剛才的提交頁面并再次提交的話,客戶端傳過來的令牌就和服務(wù)器端的令牌不一致,從而有效地防止了重復(fù)提交的發(fā)生。
      
      這時其實也就是兩點,第一:你需要在請求中有這個令牌值,請求中的令牌值如何保存,其實就和我們平時在頁面中保存一些信息是一樣的,通過隱藏字段來保存,保存的形式如: 〈input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="6aa35341f25184fd996c4c918255c3ae"〉,這個value是TokenProcessor類中的generateToken()獲得的,是根據(jù)當前用戶的session id和當前時間的long值來計算的。第二:在客戶端提交后,我們要根據(jù)判斷在請求中包含的值是否和服務(wù)器的令牌一致,因為服務(wù)器每次提交都會生成新的Token,所以,如果是重復(fù)提交,客戶端的Token值和服務(wù)器端的Token值就會不一致。下面就以在數(shù)據(jù)庫中插入一條數(shù)據(jù)來說明如何防止重復(fù)提交。
      
      在Action中的add方法中,我們需要將Token值明確的要求保存在頁面中,只需增加一條語句:saveToken(request);,如下所示:
    public?ActionForward?add(ActionMapping?mapping,?ActionForm?form,
      
      HttpServletRequest?request,?HttpServletResponse?response)
      
      
    //前面的處理省略
      
      saveToken(request);
      
      
    return?mapping.findForward("add");
      
      }在Action的insert方法中,我們根據(jù)表單中的Token值與服務(wù)器端的Token值比較,如下所示:
      
      
    public?ActionForward?insert(ActionMapping?mapping,?ActionForm?form,
      
      HttpServletRequest?request,?HttpServletResponse?response)
      
      
    if?(isTokenValid(request,?true))?{
      
      
    //?表單不是重復(fù)提交
      
      
    //這里是保存數(shù)據(jù)的代碼
      
      }
    ?else?{
      
      
    //表單重復(fù)提交
      
      saveToken(request);
      
      
    //其它的處理代碼
      
      }

      
      }
    其實使用起來很簡單,舉個最簡單、最需要使用這個的例子:
      
      一般控制重復(fù)提交主要是用在對數(shù)據(jù)庫操作的控制上,比如插入、更新、刪除等,由于更新、刪除一般都是通過id來操作(例如:updateXXXById, removeXXXById),所以這類操作控制的意義不是很大(不排除個別現(xiàn)象),重復(fù)提交的控制也就主要是在插入時的控制了。
      
      先說一下,我們目前所做項目的情況:
      
      目前的項目是用Struts+Spring+Ibatis,頁面用jstl,Struts復(fù)雜View層,Spring在Service層提供事務(wù)控制,Ibatis是用來代替JDBC,所有頁面的訪問都不是直接訪問jsp,而是訪問Structs的Action,再由Action來Forward到一個Jsp,所有針對數(shù)據(jù)庫的操作,比如取數(shù)據(jù)或修改數(shù)據(jù),都是在Action里面完成,所有的Action一般都繼承BaseDispatchAction,這個是自己建立的類,目的是為所有的Action做一些統(tǒng)一的控制,在Struts層,對于一個功能,我們一般分為兩個Action,一個Action里的功能是不需要調(diào)用Struts的驗證功能的(常見的方法名稱有add,edit,remove,view,list),另一個是需要調(diào)用Struts的驗證功能的(常見的方法名稱有insert,update)。
      
      就拿論壇發(fā)貼來說吧,論壇發(fā)貼首先需要跳轉(zhuǎn)到一個頁面,你可以填寫帖子的主題和內(nèi)容,填寫完后,單擊“提交”,貼子就發(fā)表了,所以這里經(jīng)過兩個步驟:
      
      1、轉(zhuǎn)到一個新增的頁面,在Action里我們一般稱為add,例如:
    public?ActionForward?add(ActionMapping?mapping,?ActionForm?form,
      
      HttpServletRequest?request,?HttpServletResponse?response)
      
      
    throws?Exception?{
      
      
    //這一句是輸出調(diào)試信息,表示代碼執(zhí)行到這一段了
      
      log.debug(
    "::?action?-?subject?add");
      
      
    //your?code?here
      
      
    //這里保存Token值
      
      saveToken(request);
      
      
    //跳轉(zhuǎn)到add頁面,在Structs-config.xml里面定義,例如,跳轉(zhuǎn)到subjectAdd.jsp
      
      
    return?mapping.findForward("add");
      
      }

    2、在填寫標題和內(nèi)容后,選擇 提交 ,會提交到insert方法,在insert方法里判斷,是否重復(fù)提交了。
    public?ActionForward?insert(ActionMapping?mapping,?ActionForm?form,
      
      HttpServletRequest?request,?HttpServletResponse?response)
    {
      
      
    if?(isTokenValid(request,?true))?{
      
      
    //?表單不是重復(fù)提交
      
      
    //這里是保存數(shù)據(jù)的代碼
      
      }
    ?else?{
      
      
    //表單重復(fù)提交
      
      saveToken(request);
      
      
    //其它的處理代碼
      
      }

      
      }

    下面更詳細一點(注意,下面所有的代碼使用全角括號):
      
      1、你想發(fā)貼時,點擊“我要發(fā)貼”鏈接的代碼可以里這樣的:
      
      〈html:link action="subject.do?method=add"〉我要發(fā)貼〈/html:link〉
      
      subject.do 和 method 這些在struct-config.xml如何定義我就不說了,點擊鏈接后,會執(zhí)行subject.do的add方法,代碼如上面說的,跳轉(zhuǎn)到subjectAdd.jsp頁面。頁面的代碼大概如下:
      〈html:form?action="subjectForm.do?method=insert"〉
      
      〈html:text?property="title"?/〉
      
      〈html:textarea?property="content"?/〉
      
      〈html:submit?property="發(fā)表"?/〉
      
      〈html:reset?property="重填"?/〉
      
      〈html:form〉
    如果你在add方法里加了“saveToken(request);”這一句,那在subjectAdd.jsp生成的頁面上,會多一個隱藏字段,類似于這樣〈input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="6aa35341f25184fd996c4c918255c3ae"〉,
      
      2、點擊發(fā)表后,表單提交到subjectForm.do里的insert方法后,你在insert方法里要將表單的數(shù)據(jù)插入到數(shù)據(jù)庫中,如果沒有進行重復(fù)提交的控制,那么每點擊一次瀏覽器的刷新按鈕,都會在數(shù)據(jù)庫中插入一條相同的記錄,增加下面的代碼,你就可以控制用戶的重復(fù)提交了。
    if?(isTokenValid(request,?true))?{
      
      
    //?表單不是重復(fù)提交
      
      
    //這里是保存數(shù)據(jù)的代碼
      
      }
    ?else?{
      
      
    //表單重復(fù)提交
      
      saveToken(request);
      
      
    //其它的處理代碼
      
      }

    注意,你必須在add方法里使用了saveToken(request),你才能在insert里判斷,否則,你每次保存操作都是重復(fù)提交。
      
      記住一點,Struts在你每次訪問Action的時候,都會產(chǎn)生一個令牌,保存在你的Session里面,如果你在Action里的函數(shù)里面,使用了saveToken(request);,那么這個令牌也會保存在這個Action所Forward到的jsp所生成的靜態(tài)頁面里。
      
      如果你在你Action的方法里使用了isTokenValid,那么Struts會將你從你的request里面去獲取這個令牌值,然后和Session里的令牌值做比較,如果兩者相等,就不是重復(fù)提交,如果不相等,就是重復(fù)提交了。
      
      由于我們項目的所有Action都是繼承自BaseDispatchAction這個類,所以我們基本上都是在這個類里面做了表單重復(fù)提交的控制,默認是控制add方法和insert方法,如果需要控制其它的方法,就自己手動寫上面這些代碼,否則是不需要手寫的,控制的代碼如下:
    public?abstract?class?BaseDispatchAction?extends?BaseAction?{
      
      
    protected?ActionForward?perform(ActionMapping?mapping,?ActionForm?form,
      
      HttpServletRequest?request,?HttpServletResponse?response)
      
      
    throws?Exception?{
      
      String?parameter?
    =?mapping.getParameter();
      
      String?name?
    =?request.getParameter(parameter);
      
      
    if?(null?==?name)?{?//如果沒有指定?method?,則默認為?list
      
      name?
    =?"list";
      
      }

      
      
    if?("add".equals(name))?{
      
      
    if?("add".equals(name))?{
      
      saveToken(request);
      
      }

      
      }
    ?else?if?("insert".equals(name))?{
      
      
    if?(!isTokenValid(request,?true))?{
      
      resetToken(request);
      
      saveError(request,?
    new?ActionMessage("error.repeatSubmit"));
      
      log.error(
    "重復(fù)提交!");
      
      
    return?mapping.findForward("error");
      
      }

      
      }

      
      
    return?dispatchMethod2(mapping,?form,?request,?response,?name);
      
      }

      
      }
    posted @ 2006-06-17 21:23 方佳瑋 閱讀(374) | 評論 (0)編輯 收藏

    2006年2月1日 #

    前兩天給朋友寫的一段代碼,特此總結(jié)在此。除Oracle以外的數(shù)據(jù)庫應(yīng)當都可以使用以下代碼,Oracle的操作方法Hibernate.org的站長roobin有一篇文章有講。


    首先建立實體類。二進制的字段是一個java.sql.Blob類型
    private java.sql.Blob image;

    xdoclet要用的注釋:
    @hibernate.property
    column="image"


    接下來就是保存文件的代碼了,以下僅給出偽碼,也很簡單
    String fname = "c:\\javalogo.gif";//要入庫的文件
    File f = new File(fname);
    fin = new FileInputStream(f);

    要保存的實體類 jtdsBlob = new 要保存的實體類();
    jtdsBlob.setTitle("Test1");
    jtdsBlob.setImage(Hibernate.createBlob(fin));

    /*
    * 保存實體的代碼可以換成你自己的方式,當然,如果你要了解ParadiseSDK請訪問
    * http://paradisesdk.dev.java.net/
    */
    IParadiseDAO dao = DAOFactory.getInstance();
    dao.save(jtdsBlob);
    dao.execute();

    posted @ 2006-02-01 12:51 方佳瑋 閱讀(1332) | 評論 (0)編輯 收藏

         摘要: 一、安裝篇   jspSmartUpload是由www.jspsmart.com網(wǎng)站開發(fā)的一個可免費使用的全功能的文件上傳下載組件,適于嵌入執(zhí)行上傳下載操作的JSP文件中。該組件有以下幾個特點: 1、使用簡單。在JSP文件中僅僅書寫三五行JAVA代碼就可以搞定文件的上傳或下載,方便。 2、能全程控制上傳。利用jspSmartUpload組件提供的對象及其操作方法,可以獲得全部上傳文件的信息(包括文...  閱讀全文
    posted @ 2006-02-01 12:48 方佳瑋 閱讀(1155) | 評論 (0)編輯 收藏

    在一個Web應(yīng)用中經(jīng)常需要向服務(wù)器傳遞一些參數(shù),一般通過form向服務(wù)器發(fā)送一個POST請求。在參數(shù)中有可能包含中文信息,如用戶信息登記、購物定單中的地址信息等等。參數(shù)字符串一般用本地字符集進行編碼,如中文采用GB2312或GBK字符集,英文或西歐文字采用ISO8859_1字符集,但在Java程序中一律采用Unicode處理字符串,這就需要有一個編碼轉(zhuǎn)換的過程。不幸的是,現(xiàn)有的大部分Java應(yīng)用服務(wù)器都是在英語國家開發(fā)出來的,由于缺乏大字符集(中文、日文、韓文等)的應(yīng)用環(huán)境,這些應(yīng)用服務(wù)器在處理HTTP請求參數(shù)時都存在一些中文處理的問題,也是最為困擾JSP和Servlet開發(fā)者的問題。 

    產(chǎn)生這一問題的根本原因是在HTTP請求中缺乏足夠的信息來指明客戶端所使用的字符集。在一個JSP頁面中我們可以通過下面的偽指令來指明輸出頁面所使用的字符集: 



    JSP引擎會將上面的偽指令轉(zhuǎn)換為HTTP應(yīng)答的頭部: 

    Content-Type: text/html; charset=GB2312 

    樣輸出的就是采用GB2312編碼的中文頁面,瀏覽器會正確地顯示出中文。但瀏覽器在將form的內(nèi)容POST到服務(wù)器時卻沒有包含charset,而且將中文內(nèi)容用%xx的形式(xx是十六進制數(shù))進行編碼,例如漢字"中"的GB2312內(nèi)碼為0xD6D0,在HTTP請求中就變成了%D6%D0,根據(jù)RFC2616的規(guī)定,如果在HTTP請求中未指明字符集,就使用ISO8859_1編碼,這樣"中"字在處理時變成了兩個字符,分別為'u00D6'和'u00D0',而返回到客戶端時變成了兩個不可顯示的字符,瀏覽器一般顯示成'??'。 

    解決這一問題的傳統(tǒng)做法是編寫額外的代碼來完成字符集的轉(zhuǎn)換: 

    strOut = new String(strIn.getBytes("8859_1"), "GB2312"); 

    strIn是未經(jīng)過轉(zhuǎn)換的字符串,其編碼為ISO8859_1,strOut是經(jīng)過轉(zhuǎn)換的字符串,其編碼為GB2312。 

    在Apusic 0.9.5版中實現(xiàn)了Java Servlets 2.3規(guī)范草案,其中在ServletRequest接口中新增了一個方法setCharacterEncoding(String enc),可以補上在HTTP請求中缺少的charset信息,而上面這一煩瑣的轉(zhuǎn)換過程就在Servlet引擎中自動完成了,而且Servlet引擎還對轉(zhuǎn)換過程做了優(yōu)化,提高了運行效率。下面給出一個簡單的例子,大家可以做一下比較。 

    // 傳統(tǒng)方式 
    <%@ page contentType="text/html; charset=gb2312" %> 
    <html> 
    <body> 
    <form method=post action=test.jsp> 
    <input type=text name=your_name> 
    </form> 
    <%= new String(request.getParameter("your_name").getBytes("8859_1"), "GB2312"%> 
    </body> 
    </html> 

    // 新的方式 
    <%@ page contentType="text/html; charset=gb2312" %> 
    <% request.setCharacterEncoding("GB2312"); %> 
    <html> 
    <body> 
    <form method=post action=test.jsp> 
    <input type=text name=your_name> 
    </form> 
    <%= request.getParameter("your_name"%> 
    </body> 
    </html> 
    posted @ 2006-02-01 12:46 方佳瑋 閱讀(301) | 評論 (0)編輯 收藏

    1.   在業(yè)務(wù)層使用JDBC直接操作數(shù)據(jù)庫-最簡單,最直接的操作
     
    1)數(shù)據(jù)庫url,username,password寫死在代碼中
        Class.forName("oracle.jdbc.driver.OracleDriver").newInstance(); 
        String url="jdbc:oracle:thin:@localhost:1521:orcl"; 
        String user="scott"; 
        String password="tiger"; 
        Connection conn= DriverManager.getConnection(url,user,password); 
        Statement stmt=conn.createStatement(
    ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE); 
        String sql="select * from test"; 
        ResultSet rs=stmt.executeQuery(sql);
     
    2)采用Facade和Command模式,使用DBUtil類封裝JDBC操作;
          數(shù)據(jù)庫url,username,password可以放在配置文件中(如xml,properties,ini等)。
          這種方法在小程序中應(yīng)用較多。
     
    2.DAO(Data Accessor Object)模式-松耦合的開始
    DAO = data + accessor + domain object
     
     例如User類-domain object (javabean)
    UserDAO類-accessor ,提供的方法getUser(int id),save(User user)內(nèi)包含了JDBC操作
    在業(yè)務(wù)邏輯中使用這兩個類來完成數(shù)據(jù)操作。
     
    使用Factory模式可以方便不同數(shù)據(jù)庫連接之間的移植。
     
    3.數(shù)據(jù)庫資源管理模式
    3.1 數(shù)據(jù)庫連接池技術(shù)
    資源重用,避免頻繁創(chuàng)建,釋放連接引起大大量性能開銷;
    更快的系統(tǒng)響應(yīng)速度;
     
    通過實現(xiàn)JDBC的部分資源對象接口( Connection, Statement, ResultSet ),可以使用Decorator設(shè)計模式分別產(chǎn)生三種邏輯資源對象: PooledConnection, PooledStatement和 PooledResultSet。
     
     
    一個最簡單地數(shù)據(jù)庫連接池實現(xiàn)
    public class ConnectionPool {
     
           private static Vector pools;
           private final int POOL_MAXSIZE = 25;
           /**
            * 獲取數(shù)據(jù)庫連接
            * 如果當前池中有可用連接,則將池中最后一個返回;若沒有,則創(chuàng)建一個新的返回
            */
           public synchronized Connection getConnection() {
                  Connection conn = null;
                  if (pools == null) {
                         pools = new Vector();
                  }
     
                  if (pools.isEmpty()) {
                         conn = createConnection();
                  } else {
                         int last_idx = pools.size() - 1;
                         conn = (Connection) pools.get(last_idx);
                         pools.remove(last_idx);
                  }
     
                  return conn;
           }
     
           /**
            * 將使用完畢的數(shù)據(jù)庫連接放回池中
            * 若池中連接已經(jīng)超過閾值,則關(guān)閉該連接;否則放回池中下次再使用
            */
           public synchronized void releaseConnection(Connection conn) {
                  if (pools.size() >= POOL_MAXSIZE)
                         try {
                                conn.close();
                         } catch (SQLException e) {
                                // TODO自動生成 catch
                                e.printStackTrace();
                         } else
                         pools.add(conn);
           }
     
           public static Connection createConnection() {
                  Connection conn = null;
                  try {
                         Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
                         String url = "jdbc:oracle:thin:@localhost:1521:orcl";
                         String user = "scott";
                         String password = "tiger";
                         conn = DriverManager.getConnection(url, user, password);
                  } catch (InstantiationException e) {
                         // TODO自動生成 catch
                         e.printStackTrace();
                  } catch (IllegalAccessException e) {
                         // TODO自動生成 catch
                         e.printStackTrace();
                  } catch (ClassNotFoundException e) {
                         // TODO自動生成 catch
                         e.printStackTrace();
                  } catch (SQLException e) {
                         // TODO自動生成 catch
                         e.printStackTrace();
                  }
                  return conn;
           }
    }
     
    注意:利用getConnection()方法得到的Connection,程序員很習(xí)慣地調(diào)用conn.close()方法關(guān)閉了數(shù)據(jù)庫連接,那么上述的數(shù)據(jù)庫連接機制便形同虛設(shè)。在調(diào)用conn.close()方法方法時如何調(diào)用releaseConnection()方法?這是關(guān)鍵。這里,我們使用Proxy模式和java反射機制。
     
    public synchronized Connection getConnection() {
                  Connection conn = null;
                  if (pools == null) {
                         pools = new Vector();
                  }
     
                  if (pools.isEmpty()) {
                         conn = createConnection();
                  } else {
                         int last_idx = pools.size() - 1;
                         conn = (Connection) pools.get(last_idx);
                         pools.remove(last_idx);
                  }
           
            ConnectionHandler handler=new ConnectionHandler(this);
                  return handler.bind(con);
           }
     
    public class ConnectionHandler implements InvocationHandler {
         private Connection conn;
         private ConnectionPool pool;
        
         public ConnectionHandler(ConnectionPool pool){
                this.pool=pool;
         }
        
         /**
          * 將動態(tài)代理綁定到指定Connection
          * @param conn
          * @return
          */
         public Connection bind(Connection conn){
                this.conn=conn;
    Connection proxyConn=(Connection)Proxy.newProxyInstance(
    conn.getClass().getClassLoader(), conn.getClass().getInterfaces(),this);
              return proxyConn;
         }
        
           /* (非 Javadoc
            * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
            */
           public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                  // TODO自動生成方法存根
                  Object obj=null;
                  if("close".equals(method.getName())){
                         this.pool.releaseConnection(this.conn);
                  }
                  else{
                         obj=method.invoke(this.conn, args);
                  }
                 
                  return obj;
           }
    }
     
          在實際項目中,并不需要你來從頭開始來設(shè)計數(shù)據(jù)庫連接池機制,現(xiàn)在成熟的開源項目,如C3P0,dbcp,Proxool等提供了良好的實現(xiàn)。一般推薦使用Apache dbcp,基本使用實例:
    DataSource ds = null;
       try{
         Context initCtx = new InitialContext();
         Context envCtx = (Context) initCtx.lookup("java:comp/env");
         ds = (DataSource)envCtx.lookup("jdbc/myoracle");
            if(ds!=null){
                    out.println("Connection is OK!");
                    Connection cn=ds.getConnection();
                    if(cn!=null){
                            out.println("cn is Ok!");
                    Statement stmt = cn.createStatement();
                     ResultSet rst = stmt.executeQuery("select * from BOOK");
                    out.println("<p>rst is Ok!" + rst.next());
                    while(rst.next()){
                            out.println("<P>BOOK_CODE:" + rst.getString(1));
                      }
                            cn.close();
                    }else{
                            out.println("rst Fail!");
                    }
            }
            else
                    out.println("Fail!");
               }catch(Exception ne){ out.println(ne);
             }

    3.2 Statement Pool
    普通預(yù)編譯代碼:
    String strSQL=”select name from items where id=?”;
    PreparedStatement ps=conn.prepareStatement(strSQL);
    ps.setString(1, “2”);
    ResultSet rs=ps.executeQuery();
     
    但是PreparedStatement 是與特定的Connection關(guān)聯(lián)的,一旦Connection關(guān)閉,則相關(guān)的PreparedStatement 也會關(guān)閉。
    為了創(chuàng)建PreparedStatement 緩沖池,可以在invoke方法中通過sql語句判斷池中還有沒有可用實例。
     
    4. 持久層設(shè)計與O/R mapping 技術(shù)
    1) Hernate:適合對新產(chǎn)品的開發(fā),進行封閉化的設(shè)計
    Hibernate 2003年被Jboss接管,通過把java pojo對象映射到數(shù)據(jù)庫的table中,采用了xml/javareflection技術(shù)等。3.0提供了對存儲過程和手寫sql的支持,本身提供了hql語言。
    開發(fā)所需要的文件:
    hibernate配置文件: hibernate.cfg.xml hibernate.properties
    hibernate 映射文件: a.hbm.xml
    pojo類源文件: a.java  
     
    導(dǎo)出表與表之間的關(guān)系:
    a. java對象到hbm文件:xdoclet
    b. hbm文件到java對象:hibernate extension
    c. 從數(shù)據(jù)庫到hbm文件:middlegen
    d. hbm文件到數(shù)據(jù)庫:SchemaExport
     
    2)Iatis :適合對遺留系統(tǒng)的改造和對既有數(shù)據(jù)庫的復(fù)用,有很強的靈活性 3) Apache OJB:優(yōu)勢在于對標準的全面支持 4)EJB:適合集群服務(wù)器,其性能也不象某些人所詬病的那么差勁 5) JDO (java data object)
    設(shè)置一個Properties對象,從而獲取一個JDO的PersistenceManagerFactory(相當于JDBC連接池中的DataSource),進而獲得一個PersistenceManager對象(相當于JDBC中的Connection對象),之后,你可以用這個PersistenceManager對象來增加、更新、刪除、查詢對象。
    JDOQL是JDO的查詢語言;它有點象SQL,但卻是依照Java的語法的。
     
    5. 基于開源框架的Struts+Spring+Hibernate實現(xiàn)方案
    示例:這是一個3層架構(gòu)的web 程序,通過一個Action 來調(diào)用業(yè)務(wù)代理,再通過它來回調(diào) DAO類。下面的流程圖表示了MyUsers是如何工作的。數(shù)字表明了流程的先后順序,從web(UserAction)到中間層(UserManager),再到數(shù)據(jù)層(UserDAO),然后返回。
    SpringAOP, UserManagerUserDAO都是接口.
    1)       web(UserAction) :調(diào)用中間層的接口方法,將UserManager作為屬性注入。
                 采用流行的Struts框架,雖然有很多人不屑一顧,但是這項技術(shù)在業(yè)界用的比較普遍,能滿足基本的功能,可以減少培訓(xùn)學(xué)習(xí)成本。
    2)       中間層(UserManager):將UserDAO作為屬性注入,其實現(xiàn)主要是調(diào)用數(shù)據(jù)層接口的一些方法;它處于事務(wù)控制中。
                采用Spring框架實現(xiàn),IOC與AOP是它的代名詞,功能齊全,非常棒的一個架構(gòu)。
    3)       數(shù)據(jù)層(UserDAO):實現(xiàn)類繼承HibernateDaoSupport類,在該類中可以調(diào)用getHibernateTemplate()的一些方法執(zhí)行具體的數(shù)據(jù)操作。
                采用Hibernate做O/R mapping,從種種跡象可以看出,Hibernate就是EJB3.0的beta版。
    posted @ 2006-02-01 12:44 方佳瑋 閱讀(487) | 評論 (0)編輯 收藏

    FACTORY—人才市場:以往是要哪個人才,就找哪個人才,效率低,現(xiàn)在有了人才市場,我們只需
    直接去人才市場挑一個好了;

    BUILDER—生產(chǎn)流水線:以前是手工業(yè)作坊式的人工單個單個的生產(chǎn)零件然后一步一步組裝做,好
    比有了工業(yè)革命,現(xiàn)在都由生產(chǎn)流水線代替了。如要造豐田汽車,先制定汽車的構(gòu)造如由車胎、方
    向盤、發(fā)動機組成。再以此構(gòu)造標準生產(chǎn)豐田汽車的車胎、方向盤、發(fā)動機。然后進行組裝。最后
    得到豐田汽車;

    PROTOTYPE—印刷術(shù)的發(fā)明:以前只能臨貼才能保持和別人的字跡基本相同,直從印刷技術(shù)發(fā)明,
    從而保證了復(fù)制得和原物一模一樣;

    SINGLETON—唯一:以前是商標滿天飛,相同的商標難免造成侵權(quán),直從有商標保護法后,就保證
    了不會再產(chǎn)生第家企業(yè)使用相同的商標;
    結(jié)構(gòu)型模式

    ADAPTER—集眾人之私,成一己之公:武當派張三豐會太極拳,少林派智空大師會金剛般若掌,如
    果他們兩個都成為我的師傅,我就既會太極拳,又會金剛般若掌了;

    DECORATOR—青出于藍而勝于藍:武當派張三豐會太極拳,是我?guī)煾担虝宋姨珮O拳,但我自
    己還會點蒙古式摔交,張三豐卻不會。于是我就成了DECORATOR模式的實現(xiàn);

    BRIDGE—白馬非馬:馬之顏色有黑白,馬之性別有公母。我們說”這是馬”太抽象,說”這是黑色
    的公馬”又太死板,只有將顏色與性別和馬動態(tài)組合,”這是(黑色的或白色的)(公或母)馬”
    才顯得靈活而飄逸,如此bridge模式精髓得矣。

    COMPOSITE—大家族:子又生孫,孫又生子,子子孫孫,無窮盡也,將眾多紛雜的人口組織成一個
    按輩分排列的大家族即是此模式的實現(xiàn);

    FACADE—求同存異:高中畢業(yè)需讀初中和高中,博士也需讀初中和高中,因此國家將初中和高中普
    及成九年制義務(wù)教育;

    FLYWEIGHT—一勞永逸:認識三千漢字,可以應(yīng)付日常讀書與寫字,可見頭腦中存在這個漢字庫的
    重要;

    PROXY—垂簾聽政:猶如清朝康熙年間的四大府臣,很多權(quán)利不在皇帝手里,必須通過輔佐大臣去
    辦;


    行為模式

    CHAIN OF RESPONSIBLEITY—租房:以前為了找房到處打聽,效率低且找不到好的房源。現(xiàn)在有了
    房屋中介,于是向房屋中介提出租房請求,中介提供一個合適的房源,滿意則不再請求,不滿意
    繼續(xù)看房,直到滿意為止;

    COMMAND—借刀殺人:以前是想殺誰就殺,但一段時間后領(lǐng)悟到,長此以往必將結(jié)仇太多,于是假
    手他人,挑撥他人之間的關(guān)系從而達到自己的目的;

    INTERPRETER—文言文注釋:一段文言文,將它翻譯成白話文;

    ITERATOR—趕盡殺絕:一個一個的搜索,絕不放掉一個;

    MEDIATOR—三角債:本來千頭萬緒的債務(wù)關(guān)系,忽出來一中介,包攬其一切,于是三角關(guān)系變成了
    獨立的三方找第四方中介的關(guān)系;

    MEMENTO—有福同享:我有多少,你就有多少;

    OBSERVER—看守者:一旦被看守者有什么異常情況,定會及時做出反應(yīng);

    STATE—進出自由:如一扇門,能進能出,如果有很多人隨時進進出出必定顯得雜亂而安全,如今
    設(shè)一保安限制其進出,如此各人進出才顯得規(guī)范;

    STRATEGY—久病成良醫(yī):如人生病可以有各種癥狀,但經(jīng)過長期摸索,就可以總結(jié)出感冒、肺病、
    肝炎等幾種;


    TEMPLATE METHOD——理論不一定要實踐:教練的學(xué)生會游泳就行了,至于教練會不會則無關(guān)緊要;

    VISITOR—依法治罪:因張三殺人要被處死,李四偷竊要被罰款。由此勢必制定處罰制度,故制定
    法律寫明殺人、放火、偷竊等罪要受什么處罰,經(jīng)通過后須變動要小。今后有人犯罪不管是誰,按
    共條例處罰即是,這就是訪問者模式誕生的全過程;
    posted @ 2006-02-01 12:42 方佳瑋 閱讀(424) | 評論 (2)編輯 收藏

    跳槽是一門學(xué)問,也是一種策略。“人往高處走”,這固然沒有錯。但是,說來輕巧的一句話,它卻包含了為什么“走”、什么是“高”、怎么“走”、什么時候“走”,以及“走”了以后怎么辦等一系列問題。 
      那么當面臨跳槽時,如何才能順利地完成跳槽,從而取得職業(yè)的成功呢? 
      首先,要確定你跳槽的動機是什么和自己是不是需要跳槽。大致來說,一個人跳槽的動機一般有如下兩種:一是被動的跳槽,即個人對自己目前的工作不滿意,不得不跳槽,這里又具體包括對人際關(guān)系(包括上、下級關(guān)系)、工作內(nèi)容、工作崗位、工作待遇、工作環(huán)境或工作條件、發(fā)展機會的不滿意等方面。比如,如果你與上司關(guān)系不融洽,覺得得不到發(fā)展,你自己也感覺無法適應(yīng)目前的環(huán)境,那么恐怕就要考慮換個環(huán)境試試了;第二,是主動的跳槽,即面對著更好的工作條件,如待遇、工作環(huán)境、發(fā)展機會,自己經(jīng)不住“誘惑”而促使自己跳槽;或者尋求更高的挑戰(zhàn)與報酬,比如你發(fā)現(xiàn)自己的能力應(yīng)付目前的工作綽綽有余,并且發(fā)現(xiàn)了自己真正感興趣的工作的時候,你就不妨考慮換個工作試試。 
      無論如何,當你具備了跳槽動機的時候,就是你跳槽行動的開始。但是,為了跳得更“高”,你在跳槽前不妨先問自己下面的問題: 
      1、是什么讓你不滿意現(xiàn)在的工作了? 
      2、你想跳槽經(jīng)過慎重考慮了嗎?還是一時的情緒?嘗試做自我調(diào)整了嗎? 
      3、跳槽會使你失去什么,又得到什么呢? 
      4、適應(yīng)新的工作或環(huán)境、建立新的人際關(guān)系需要你付出更多的精力,你有信心嗎? 
      5、你的背景和能力能適應(yīng)新的工作嗎? 
      6、你是為了生活而工作,還是為了工作而生活? 
      7、你有沒有職業(yè)目標?新的工作是不是為你提供了一個清晰的職業(yè)方向? 
      8、征求過專家的意見嗎?有沒有咨詢過職業(yè)顧問? 
      如果對上面的問題回答是“是”,那么你可以接著考慮下面的問題: 
      1、你要跳過去的公司的職位是什么?如果比你現(xiàn)在的職位還低你能接受嗎? 
      2、新的工作要求你從頭做起,你有這個心理準備嗎? 
      3、你在目前的公司里工作有多久??一般來說,在一個公司的工作至少應(yīng)該滿1年,否則它不會為你提供非常有價值的職業(yè)發(fā)展依據(jù); 
      4、你應(yīng)何時跳槽???最好的狀態(tài)是在目前工作進展順利時跳槽,那么你的職業(yè)含金量會大大提升。 
      5、你實事求是地估價自己的能力了嗎?你的優(yōu)點或特長是什么?你有哪些不足???這里要求你既不要好高騖遠,也不要自甘弱小。 
      一旦決定跳槽,你就要大膽地付諸實施了。這時你需要選擇恰當?shù)奶蹠r機,以下是職業(yè)咨詢顧問提醒你跳槽時應(yīng)當注意的事項和建議你的比較妥當?shù)淖龇ǎ?nbsp;
      1、知己知彼:查閱與目前公司簽訂的勞動合同,明確自己是否受到違約金或競業(yè)壁止等條款影響、離職手續(xù)辦理難易程度等,做到心中有數(shù); 
      2、盡可能收集新公司的信息以及可能要求自己提供的項目,做到有備無患; 
      3、設(shè)計簡歷:準備一份職業(yè)化的簡歷,你可以尋求職業(yè)顧問的幫助; 
      4、有時候根據(jù)自己的工作經(jīng)歷和能力,使用獵頭公司應(yīng)聘也不失為一種有效的策略; 
      5、遞交辭呈:向原公司遞交辭職信,做好離職過渡期的安排。記住千萬在拿到“O ffe r Le tte r”以后再遞交辭職信; 
      6、與人為善:雖然你應(yīng)聘成功了,雖然你可能“痛恨”原來的公司,但是也不要在背后惡言冷語,你哪天還會“用”到原來的公司,這誰也說不準。 
      你也在準備跳槽嗎?你知道跳槽之前應(yīng)該做什么嗎?當你開始認真思考這些問題的時候,說明你開始關(guān)注自己的職業(yè)發(fā)展了。但是,你必須明白:跳槽并不意味著你就能夠取得職業(yè)的成功,這個時候,尋求職業(yè)顧問的幫助才是理性的做法,因為職業(yè)顧問會告訴你什么是正確的跳槽、什么是你應(yīng)該選擇的職業(yè)方向。一句話:職業(yè)顧問會幫助你取得職業(yè)生涯的成功!
    posted @ 2006-02-01 12:41 方佳瑋 閱讀(289) | 評論 (0)編輯 收藏

    JAVA學(xué)習(xí)之路:不走彎路,就是捷徑
    ChinaITLab劉曉濤原創(chuàng)     2005-8-22
    備注:本文選自ChinaITLab網(wǎng)校課程《劉曉濤Java就業(yè)直通班V2.0》之預(yù)備知識!
      0.引言
      在ChinaITLAB導(dǎo)師制輔導(dǎo)中,筆者發(fā)現(xiàn)問得最多的問題莫過于"如何學(xué)習(xí)編程?JAVA該如何學(xué)習(xí)?"。類似的問題回答多了,難免會感覺厭煩,就萌生了寫下本文的想法。到時候再有人問起類似的問題,我可以告訴他(她),請你去看看《JAVA學(xué)習(xí)之路》。拜讀過臺灣蔡學(xué)鏞先生的《JAVA夜未眠》,有些文章如《JAVA學(xué)習(xí)之道》等讓我們確實有共鳴,本文題目也由此而來。
      軟件開發(fā)之路是充滿荊棘與挑戰(zhàn)之路,也是充滿希望之路。JAVA學(xué)習(xí)也是如此,沒有捷徑可走。夢想像《天龍八部》中虛竹一樣被無崖子醍醐灌頂而輕松獲得一甲子功力,是很不現(xiàn)實的。每天仰天大叫"天神啊,請賜給我一本葵花寶典吧",殊不知即使你獲得了葵花寶典,除了受自宮其身之苦外,你也不一定成得了"東方不敗",倒是成"西方失敗"的幾率高一點。
      "不走彎路,就是捷徑",佛經(jīng)說的不無道理。
      1.如何學(xué)習(xí)程序設(shè)計?
      JAVA是一種平臺,也是一種程序設(shè)計語言,如何學(xué)好程序設(shè)計不僅僅適用于JAVA,對C++等其他程序設(shè)計語言也一樣管用。有編程高手認為,JAVA也好C也好沒什么分別,拿來就用。為什么他們能達到如此境界?我想是因為編程語言之間有共通之處,領(lǐng)會了編程的精髓,自然能夠做到一通百通。如何學(xué)習(xí)程序設(shè)計理所當然也有許多共通的地方。
      1.1 培養(yǎng)興趣
      興趣是能夠讓你堅持下去的動力。如果只是把寫程序作為謀生的手段的話,你會活的很累,也太對不起自己了。多關(guān)心一些行業(yè)趣事,多想想蓋茨。不是提倡天天做白日夢,但人要是沒有了夢想,你覺得有味道嗎?可能像許多深圳本地農(nóng)民一樣,打打麻將,喝喝功夫茶,拜拜財神爺;每個月就有幾萬十幾萬甚至更多的進帳,憑空多出個"食利階層"。你認為,這樣有味道嗎?有空多到一些程序員論壇轉(zhuǎn)轉(zhuǎn),你會發(fā)現(xiàn),他們其實很樂觀幽默,時不時會冒出智慧的火花。
      1.2 慎選程序設(shè)計語言
      男怕入錯行,女怕嫁錯郎。初學(xué)者選擇程序設(shè)計語言需要謹慎對待。軟件開發(fā)不僅僅是掌握一門編程語言了事,它還需要其他很多方面的背景知識。軟件開發(fā)也不僅僅局限于某幾個領(lǐng)域,而是已經(jīng)滲透到了各行各業(yè)幾乎每一個角落。
      如果你對硬件比較感興趣,你可以學(xué)習(xí)C語言/匯編語言,進入硬件開發(fā)領(lǐng)域。如果你對電信的行業(yè)知識及網(wǎng)絡(luò)比較熟悉,你可以在C/C++等之上多花時間,以期進入電信軟件開發(fā)領(lǐng)域。如果你對操作系統(tǒng)比較熟悉,你可以學(xué)習(xí)C/Linux等等,為Linux內(nèi)核開發(fā)/驅(qū)動程序開發(fā)/嵌入式開發(fā)打基礎(chǔ)。如果你想介入到應(yīng)用范圍最廣泛的應(yīng)用軟件開發(fā)(包括電子商務(wù)電子政務(wù)系統(tǒng))的話,你可以選擇J2EE或.NET,甚至LAMP組合。每個領(lǐng)域要求的背景知識不一樣。做應(yīng)用軟件需要對數(shù)據(jù)庫等很熟悉。總之,你需要根據(jù)自己的特點來選擇合適你的編程語言。
      1.3 要腳踏實地,快餐式的學(xué)習(xí)不可取
      先分享一個故事。
      有一個小朋友,他很喜歡研究生物學(xué),很想知道那些蝴蝶如何從蛹殼里出來,變成蝴蝶便會飛。 有一次,他走到草原上面看見一個蛹,便取了回家,然后看著,過了幾天以后,這個蛹出了一條裂痕,看見里面的蝴蝶開始掙扎,想抓破蛹殼飛出來。 這個過程達數(shù)小時之久,蝴蝶在蛹里面很辛苦地拼命掙扎,怎么也沒法子走出來。這個小孩看著看著不忍心,就想不如讓我?guī)蛶退桑汶S手拿起剪刀在蛹上剪開,使蝴蝶破蛹而出。 但蝴蝶出來以后,因為翅膀不夠力,變得很臃腫,飛不起來。
      這個故事給我們的啟示是:欲速則不達。
      浮躁是現(xiàn)代人最普遍的心態(tài),能怪誰?也許是貧窮落后了這么多年的緣故,就像當年的大躍進一樣,都想大步跨入共產(chǎn)主義社會。現(xiàn)在的軟件公司、客戶、政府、學(xué)校、培訓(xùn)機構(gòu)等等到處彌漫著浮躁之氣。就拿筆者比較熟悉的深圳IT培訓(xùn)行業(yè)來說吧,居然有的打廣告宣稱"參加培訓(xùn),100%就業(yè)",居然報名的學(xué)生不少,簡直是藐視天下程序員。社會環(huán)境如是,我們不能改變,只能改變自己,鬧市中的安寧,彌足珍貴。許多初學(xué)者C++/JAVA沒開始學(xué),立馬使用VC/JBuilder,會使用VC/JBuilder開發(fā)一個Hello World程序,就忙不迭的向世界宣告,"我會軟件開發(fā)了",簡歷上也大言不慚地寫上"精通VC/JAVA"。結(jié)果到軟件公司面試時要么被三兩下打發(fā)走了,要么被駁的體無完膚,無地自容。到處碰壁之后才知道捧起《C++編程思想》《JAVA編程思想》仔細鉆研,早知如此何必當初呀。
      "你現(xiàn)在講究簡單方便,你以后的路就長了",好象也是佛經(jīng)中的勸戒。
      1.4 多實踐,快實踐
      彭端淑的《為學(xué)一首示子侄》中有窮和尚與富和尚的故事。
      從前,四川邊境有兩個和尚,一個貧窮,一個有錢。一天,窮和尚對富和尚說:"我打算去南海朝圣,你看怎么樣?"富和尚說:"這里離南海有幾千里遠,你靠什么去呢?"窮和尚說:"我只要一個水缽,一個飯碗就夠了。"富和尚為難地說:"幾年前我就打算買條船去南海,可至今沒去成,你還是別去吧!" 一年以后,富和尚還在為租賃船只籌錢,窮和尚卻已經(jīng)從南海朝圣回來了。
      這個故事可解讀為:任何事情,一旦考慮好了,就要馬上上路,不要等到準備周全之后,再去干事情。假如事情準備考慮周全了再上路的話,別人恐怕捷足先登了。軟件開發(fā)是一門工程學(xué)科,注重的就是實踐,"君子動口不動手"對軟件開發(fā)人員來講根本就是錯誤的,他們提倡"動手至上",但別害怕,他們大多溫文爾雅,沒有暴力傾向,雖然有時候蓬頭垢面的一副"比爾蓋茨"樣。有前輩高人認為,學(xué)習(xí)編程的秘訣是:編程、編程、再編程,筆者深表贊同。不僅要多實踐,而且要快實踐。我們在看書的時候,不要等到你完全理解了才動手敲代碼,而是應(yīng)該在看書的同時敲代碼,程序運行的各種情況可以讓你更快更牢固的掌握知識點。
      1.5 多參考程序代碼
      程序代碼是軟件開發(fā)最重要的成果之一,其中滲透了程序員的思想與靈魂。許多人被《仙劍奇?zhèn)b傳》中凄美的愛情故事感動,悲劇的結(jié)局更有一種缺憾美。為什么要以悲劇結(jié)尾?據(jù)說是因為寫《仙劍奇?zhèn)b傳》的程序員失戀而安排了這樣的結(jié)局,他把自己的感覺融入到游戲中,卻讓眾多的仙劍迷扼腕嘆息。
      多多參考代碼例子,對JAVA而言有參考文獻[4.3],有API類的源代碼(JDK安裝目錄下的src.zip文件),也可以研究一些開源的軟件或框架。
      1.6 加強英文閱讀能力
      對學(xué)習(xí)編程來說,不要求英語, 但不能一點不會,。最起碼像JAVA API文檔(參考文獻[4.4])這些東西還是要能看懂的,連猜帶懵都可以;旁邊再開啟一個"金山詞霸"。看多了就會越來越熟練。在學(xué)JAVA的同時學(xué)習(xí)英文,一箭雙雕多好。另外好多軟件需要到英文網(wǎng)站下載,你要能夠找到它們,這些是最基本的要求。英語好對你學(xué)習(xí)有很大的幫助。口語好的話更有機會進入管理層,進而可以成為剝削程序員的"周扒皮"。
      1.7 萬不得已才請教別人
      筆者在ChinaITLab網(wǎng)校的在線輔導(dǎo)系統(tǒng)中解決學(xué)生問題時發(fā)現(xiàn),大部分的問題學(xué)生稍做思考就可以解決。請教別人之前,你應(yīng)該先回答如下幾個問題。
      你是否在google中搜索了問題的解決辦法?
      你是否查看了JAVA API文檔?
      你是否查找過相關(guān)書籍?
      你是否寫代碼測試過?
      如果回答都是"是"的話,而且還沒有找到解決辦法,再問別人不遲。要知道獨立思考的能力對你很重要。要知道程序員的時間是很寶貴的。
      1.8 多讀好書
      書中自有顏如玉。比爾?蓋茨是一個飽讀群書的人。雖然沒有讀完大學(xué),但九歲的時候比爾?蓋茨就已經(jīng)讀完了所有的百科全書,所以他精通天文、歷史、地理等等各類學(xué)科,可以說比爾?蓋茨不僅是當今世界上金錢的首富,而且也可以稱得上是知識的巨富。
      筆者在給學(xué)生上課的時候經(jīng)常會給他們推薦書籍,到后來學(xué)生實在忍無可忍開始抱怨,"天吶,這么多書到什么時候才能看完了","學(xué)軟件開發(fā),感覺上了賊船"。這時候,我的回答一般是,"別著急,什么時候帶你們?nèi)タ纯次业臅浚浆F(xiàn)在每月花在技術(shù)書籍上的錢400元,這在軟件開發(fā)人員之中還只能夠算是中等的",學(xué)生當場暈倒。(注:這一部分學(xué)生是剛學(xué)軟件開發(fā)的)
      對于在JAVA開發(fā)領(lǐng)域的好書在筆者另外一篇文章中會專門點評。該文章可作為本文的姊妹篇。
      1.9 使用合適的工具
      工欲善其事必先利其器。軟件開發(fā)包含各種各樣的活動,需求收集分析、建立用例模型、建立分析設(shè)計模型、編程實現(xiàn)、調(diào)試程序、自動化測試、持續(xù)集成等等,沒有工具幫忙可以說是寸步難行。工具可以提高開發(fā)效率,使軟件的質(zhì)量更高BUG更少。組合稱手的武器。到飛花摘葉皆可傷人的境界就很高了,無招勝有招,手中無劍心中有劍這樣的境界幾乎不可企及。在筆者另外一篇文章中會專門闡述如何選擇合適的工具(該文章也可作為本文的姊妹篇)。
      2.軟件開發(fā)學(xué)習(xí)路線
      兩千多年的儒家思想孔孟之道,中庸的思想透入骨髓,既不冒進也不保守并非中庸之道,而是找尋學(xué)習(xí)軟件開發(fā)的正確路線與規(guī)律。
      從軟件開發(fā)人員的生涯規(guī)劃來講,我們可以大致分為三個階段,軟件工程師→軟件設(shè)計師→架構(gòu)設(shè)計師或項目管理師。不想當元帥的士兵不是好士兵,不想當架構(gòu)設(shè)計師或項目管理師的程序員也不是好的程序員。我們應(yīng)該努力往上走。讓我們先整理一下開發(fā)應(yīng)用軟件需要學(xué)習(xí)的主要技術(shù)。
      A.基礎(chǔ)理論知識,如操作系統(tǒng)、編譯原理、數(shù)據(jù)結(jié)構(gòu)與算法、計算機原理等,它們并非不重要。如不想成為計算機科學(xué)家的話,可以采取"用到的時候再來學(xué)"的原則。
      B.一門編程語言,現(xiàn)在基本上都是面向?qū)ο蟮恼Z言,JAVA/C++/C#等等。如果做WEB開發(fā)的話還要學(xué)習(xí)HTML/JavaScript等等。
      C.一種方法學(xué)或者說思想,現(xiàn)在基本都是面向?qū)ο笏枷耄∣OA/OOD/設(shè)計模式)。由此而衍生的基于組件開發(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/鋼筆進行建模。
      G.一種軟件過程,RUP/XP/CMM等等,通過軟件過程來組織軟件開發(fā)的眾多活動,使開發(fā)流程專業(yè)化規(guī)范化。當然還有其他的一些軟件工程知識。
      H.項目管理、體系結(jié)構(gòu)、框架知識。
      正確的路線應(yīng)該是:B→C→E→F→G→H。
      還需要補充幾點:
      1).對于A與C要補充的是,我們應(yīng)該在實踐中逐步領(lǐng)悟編程理論與編程思想。新技術(shù)雖然不斷涌現(xiàn),更新速度令人眼花燎亂霧里看花;但萬變不離其宗,編程理論與編程思想的變化卻很慢。掌握了編程理論與編程思想你就會有撥云見日之感。面向?qū)ο蟮乃枷朐谀壳皝碇v是相當關(guān)鍵的,是強勢技術(shù)之一,在上面需要多投入時間,給你的回報也會讓你驚喜。
      2).對于數(shù)據(jù)庫來說是獨立學(xué)習(xí)的,這個時機就由你來決定吧。
      3).編程語言作為學(xué)習(xí)軟件開發(fā)的主線,而其余的作為輔線。
      4).軟件工程師著重于B、C、E、 D;軟件設(shè)計師著重于B、C、E、 D、F;架構(gòu)設(shè)計師著重于C、F、H。
      3.如何學(xué)習(xí)JAVA?
      3.1 JAVA學(xué)習(xí)路線
      3.1.1 基礎(chǔ)語法及JAVA原理
      基礎(chǔ)語法和JAVA原理是地基,地基不牢靠,猶如沙地上建摩天大廈,是相當危險的。學(xué)習(xí)JAVA也是如此,必須要有扎實的基礎(chǔ),你才能在J2EE、J2ME領(lǐng)域游刃有余。參加SCJP(SUN公司認證的JAVA程序員)考試不失為一個好方法,原因之一是為了對得起你交的1200大洋考試費,你會更努力學(xué)習(xí),原因之二是SCJP考試能夠讓你把基礎(chǔ)打得很牢靠,它要求你跟JDK一樣熟悉JAVA基礎(chǔ)知識;但是你千萬不要認為考過了SCJP就有多了不起,就能夠獲得軟件公司的青睞,就能夠獲取高薪,這樣的想法也是很危險的。獲得"真正"的SCJP只能證明你的基礎(chǔ)還過得去,但離實際開發(fā)還有很長的一段路要走。
      3.1.2 OO思想的領(lǐng)悟
      掌握了基礎(chǔ)語法和JAVA程序運行原理后,我們就可以用JAVA語言實現(xiàn)面向?qū)ο蟮乃枷肓恕C嫦驅(qū)ο螅且环N方法學(xué);是獨立于語言之外的編程思想;是CBD基于組件開發(fā)的基礎(chǔ);屬于強勢技術(shù)之一。當以后因工作需要轉(zhuǎn)到別的面向?qū)ο笳Z言的時候,你會感到特別的熟悉親切,學(xué)起來像喝涼水這么簡單。
      使用面向?qū)ο蟮乃枷脒M行開發(fā)的基本過程是:
      ●調(diào)查收集需求。
      ●建立用例模型。
      ●從用例模型中識別分析類及類與類之間的靜態(tài)動態(tài)關(guān)系,從而建立分析模型。
      ●細化分析模型到設(shè)計模型。
      ●用具體的技術(shù)去實現(xiàn)。
      ●測試、部署、總結(jié)。
      3.1.3 基本API的學(xué)習(xí)
      進行軟件開發(fā)的時候,并不是什么功能都需要我們?nèi)崿F(xiàn),也就是經(jīng)典名言所說的"不需要重新發(fā)明輪子"。我們可以利用現(xiàn)成的類、組件、框架來搭建我們的應(yīng)用,如SUN公司編寫好了眾多類實現(xiàn)一些底層功能,以及我們下載過來的JAR文件中包含的類,我們可以調(diào)用類中的方法來完成某些功能或繼承它。那么這些類中究竟提供了哪些方法給我們使用?方法的參數(shù)個數(shù)及類型是?類的構(gòu)造器需不需要參數(shù)?總不可能SUN公司的工程師打國際長途甚至飄洋過海來告訴你他編寫的類該如何使用吧。他們只能提供文檔給我們查看,JAVA DOC文檔(參考文獻4.4)就是這樣的文檔,它可以說是程序員與程序員交流的文檔。
      基本API指的是實現(xiàn)了一些底層功能的類,通用性較強的API,如字符串處理/輸入輸出等等。我們又把它成為類庫。熟悉API的方法一是多查JAVA DOC文檔(參考文獻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;如果你進行網(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,從鍛煉語言熟練程度的角度考慮,我們推薦使用的工具是Editplus/JCreator+JDK,這時候不要急于上手JBuilder/Eclipse等集成開發(fā)環(huán)境,以免過于關(guān)注IDE的強大功能而分散對JAVA技術(shù)本身的注意力。過了這一階段你就可以開始熟悉IDE了。
      程序員日常工作包括很多活動,編輯、編譯及構(gòu)建、調(diào)試、單元測試、版本控制、維持模型與代碼同步、文檔的更新等等,幾乎每一項活動都有專門的工具,如果獨立使用這些工具的話,你將會很痛苦,你需要在堆滿工具的任務(wù)欄上不斷的切換,效率很低下,也很容易出錯。在JBuilder、Eclipse等IDE中已經(jīng)自動集成編輯器、編譯器、調(diào)試器、單元測試工具JUnit、自動構(gòu)建工具ANT、版本控制工具CVS、DOC文檔生成與更新等等,甚至可以把UML建模工具也集成進去,又提供了豐富的向?qū)椭煽蚣艽a,讓我們的開發(fā)變得更輕松。應(yīng)該說IDE發(fā)展的趨勢就是集成軟件開發(fā)中要用到的幾乎所有工具。
      從開發(fā)效率的角度考慮,使用IDE是必經(jīng)之路,也是從一個學(xué)生到一個職業(yè)程序員轉(zhuǎn)變的里程碑。
      JAVA開發(fā)使用的IDE主要有Eclipse、JBuilder、JDeveloper、NetBeans等幾種;而Eclipse、JBuilder占有的市場份額是最大的。JBuilder在近幾年來一直是JAVA集成開發(fā)環(huán)境中的霸主,它是由備受程序員尊敬的Borland公司開發(fā),在硝煙彌漫的JAVA IDE大戰(zhàn)中,以其快速的版本更新?lián)魯BM的Visual Age for JAVA等而成就一番偉業(yè)。IBM在Visual Age for JAVA上已經(jīng)無利可圖之下,干脆將之貢獻給開源社區(qū),成為Eclipse的前身,真所謂"柳暗花明又一村"。浴火重生的Eclipse以其開放式的插件擴展機制、免費開源獲得廣大程序員(包括幾乎所有的骨灰級程序員)的青睞,極具發(fā)展?jié)摿Α?BR>  3.1.6 學(xué)習(xí)軟件工程
      對小型項目而言,你可能認為軟件工程沒太大的必要。隨著項目的復(fù)雜性越來越高,軟件工程的必要性才會體現(xiàn)出來。參見"軟件開發(fā)學(xué)習(xí)路線"小節(jié)。
      3.2學(xué)習(xí)要點
      確立的學(xué)習(xí)路線之后,我們還需要總結(jié)一下JAVA的學(xué)習(xí)要點,這些要點在前文多多少少提到過,只是筆者覺得這些地方特別要注意才對它們進行匯總,不要嫌我婆婆媽媽啊。
      3.2.1勤查API文檔
      當程序員編寫好某些類,覺得很有成就感,想把它貢獻給各位苦難的同行。這時候你要使用"javadoc"工具(包含在JDK中)生成標準的JAVA DOC文檔,供同行使用。J2SE/J2EE/J2ME的DOC文檔是程序員與程序員交流的工具,幾乎人手一份,除了菜鳥之外。J2SE DOC文檔官方下載地址:http://java.sun.com/j2se/1.5.0/download.jsp,你可以到google搜索CHM版本下載。也可以在線查看:  3.2.3學(xué)習(xí)開源軟件的設(shè)計思想
      JAVA領(lǐng)域有許多源代碼開放的工具、組件、框架,JUnit、ANT、Tomcat、Struts、Spring、Jive論壇、PetStore寵物店等等多如牛毛。這些可是前輩給我們留下的瑰寶呀。入寶山而空手歸,你心甘嗎?對這些工具、框架進行分析,領(lǐng)會其中的設(shè)計思想,有朝一日說不定你也能寫一個XXX框架什么的,風(fēng)光一把。分析開源軟件其實是你提高技術(shù)、提高實戰(zhàn)能力的便捷方法。
      3.2.4 規(guī)范的重要性
      沒有規(guī)矩,不成方圓。這里的規(guī)范有兩層含義。第一層含義是技術(shù)規(guī)范,多到
    http://www.jcp.org/下載JSRXXX規(guī)范,多讀規(guī)范,這是最權(quán)威準確最新的教材。第二層含義是編程規(guī)范,如果你使用了大量的獨特算法,富有個性的變量及方法的命名方式;同時,沒給程序作注釋,以顯示你的編程功底是多么的深厚。這樣的代碼別人看起來像天書,要理解談何容易,更不用說維護了,必然會被無情地掃入垃圾堆。JAVA編碼規(guī)范到此查看或下載  4.結(jié)束語
      需要強調(diào)的是,學(xué)習(xí)軟件開發(fā)確實有一定的難度,也很辛苦,需要付出很多努力,但千萬不要半途而廢。本文如果能對一直徘徊在JAVA神殿之外的朋友有所幫助的話,筆者也欣慰了。哈哈,怎么聽起來老氣橫秋呀?沒辦法,在電腦的長期輻射之下,都快變成小老頭了。最后奉勸各位程序員尤其是MM程序員,完成工作后趕快遠離電腦,據(jù)《胡播亂報》報道,電腦輻射會在白皙的皮膚上面點綴一些小黑點,看起來鮮艷無比……
    posted @ 2006-02-01 12:38 方佳瑋 閱讀(409) | 評論 (0)編輯 收藏

    六種異常處理的陋習(xí)

    你覺得自己是一個Java專家嗎?是否肯定自己已經(jīng)全面掌握了Java的異常處理機制?在下面這段代碼中,你能夠迅速找出異常處理的六個問題嗎?

    1 OutputStreamWriter out =  
    2 java.sql.Connection conn =  
    3 try // ⑸ 
    4  Statement stat = conn.createStatement(); 
    5  ResultSet rs = stat.executeQuery( 
    6   "select uid, name from user"); 
    7  while (rs.next()) 
    8  
    9   out.println("ID:" + rs.getString("uid"// ⑹ 
    10    ",姓名:" + rs.getString("name")); 
    11  }
     
    12  conn.close(); // ⑶ 
    13  out.close(); 
    14 }
     
    15 catch(Exception ex) // ⑵ 
    16 
    17  ex.printStackTrace(); //⑴,⑷ 
    18 }

    作為一個Java程序員,你至少應(yīng)該能夠找出兩個問題。但是,如果你不能找出全部六個問題,請繼續(xù)閱讀本文。

      本文討論的不是Java異常處理的一般性原則,因為這些原則已經(jīng)被大多數(shù)人熟知。我們要做的是分析各種可稱為“反例”(anti-pattern)的違背優(yōu)秀編碼規(guī)范的常見壞習(xí)慣,幫助讀者熟悉這些典型的反面例子,從而能夠在實際工作中敏銳地察覺和避免這些問題。

      反例之一:丟棄異常

      代碼:15行-18行。

      這段代碼捕獲了異常卻不作任何處理,可以算得上Java編程中的殺手。從問題出現(xiàn)的頻繁程度和禍害程度來看,它也許可以和C/C++程序的一個惡名遠播的問題相提并論??不檢查緩沖區(qū)是否已滿。如果你看到了這種丟棄(而不是拋出)異常的情況,可以百分之九十九地肯定代碼存在問題(在極少數(shù)情況下,這段代碼有存在的理由,但最好加上完整的注釋,以免引起別人誤解)。

      這段代碼的錯誤在于,異常(幾乎)總是意味著某些事情不對勁了,或者說至少發(fā)生了某些不尋常的事情,我們不應(yīng)該對程序發(fā)出的求救信號保持沉默和無動于衷。調(diào)用一下printStackTrace算不上“處理異常”。不錯,調(diào)用printStackTrace對調(diào)試程序有幫助,但程序調(diào)試階段結(jié)束之后,printStackTrace就不應(yīng)再在異常處理模塊中擔(dān)負主要責(zé)任了。

      丟棄異常的情形非常普遍。打開JDK的ThreadDeath類的文檔,可以看到下面這段說明:“特別地,雖然出現(xiàn)ThreadDeath是一種‘正常的情形’,但ThreadDeath類是Error而不是Exception的子類,因為許多應(yīng)用會捕獲所有的Exception然后丟棄它不再理睬。”這段話的意思是,雖然ThreadDeath代表的是一種普通的問題,但鑒于許多應(yīng)用會試圖捕獲所有異常然后不予以適當?shù)奶幚恚訨DK把ThreadDeath定義成了Error的子類,因為Error類代表的是一般的應(yīng)用不應(yīng)該去捕獲的嚴重問題。可見,丟棄異常這一壞習(xí)慣是如此常見,它甚至已經(jīng)影響到了Java本身的設(shè)計。

      那么,應(yīng)該怎樣改正呢?主要有四個選擇:

      1、處理異常。針對該異常采取一些行動,例如修正問題、提醒某個人或進行其他一些處理,要根據(jù)具體的情形確定應(yīng)該采取的動作。再次說明,調(diào)用printStackTrace算不上已經(jīng)“處理好了異常”。

      2、重新拋出異常。處理異常的代碼在分析異常之后,認為自己不能處理它,重新拋出異常也不失為一種選擇。

      3、把該異常轉(zhuǎn)換成另一種異常。大多數(shù)情況下,這是指把一個低級的異常轉(zhuǎn)換成應(yīng)用級的異常(其含義更容易被用戶了解的異常)。

      4、不要捕獲異常。

      結(jié)論一:既然捕獲了異常,就要對它進行適當?shù)奶幚怼2灰东@異常之后又把它丟棄,不予理睬。

      反例之二:不指定具體的異常

      代碼:15行。

      許多時候人們會被這樣一種“美妙的”想法吸引:用一個catch語句捕獲所有的異常。最常見的情形就是使用catch(Exception ex)語句。但實際上,在絕大多數(shù)情況下,這種做法不值得提倡。為什么呢?

      要理解其原因,我們必須回顧一下catch語句的用途。catch語句表示我們預(yù)期會出現(xiàn)某種異常,而且希望能夠處理該異常。異常類的作用就是告訴Java編譯器我們想要處理的是哪一種異常。由于絕大多數(shù)異常都直接或間接從java.lang.Exception派生,catch(Exception ex)就相當于說我們想要處理幾乎所有的異常。

      再來看看前面的代碼例子。我們真正想要捕獲的異常是什么呢?最明顯的一個是SQLException,這是JDBC操作中常見的異常。另一個可能的異常是IOException,因為它要操作OutputStreamWriter。顯然,在同一個catch塊中處理這兩種截然不同的異常是不合適的。如果用兩個catch塊分別捕獲SQLException和IOException就要好多了。這就是說,catch語句應(yīng)當盡量指定具體的異常類型,而不應(yīng)該指定涵蓋范圍太廣的Exception類。

      另一方面,除了這兩個特定的異常,還有其他許多異常也可能出現(xiàn)。例如,如果由于某種原因,executeQuery返回了null,該怎么辦?答案是讓它們繼續(xù)拋出,即不必捕獲也不必處理。實際上,我們不能也不應(yīng)該去捕獲可能出現(xiàn)的所有異常,程序的其他地方還有捕獲異常的機會??直至最后由JVM處理。

      結(jié)論二:在catch語句中盡可能指定具體的異常類型,必要時使用多個catch。不要試圖處理所有可能出現(xiàn)的異常。

      反例之三:占用資源不釋放

      代碼:3行-14行。

      異常改變了程序正常的執(zhí)行流程。這個道理雖然簡單,卻常常被人們忽視。如果程序用到了文件、Socket、JDBC連接之類的資源,即使遇到了異常,也要正確釋放占用的資源。為此,Java提供了一個簡化這類操作的關(guān)鍵詞finally。

      finally是樣好東西:不管是否出現(xiàn)了異常,F(xiàn)inally保證在try/catch/finally塊結(jié)束之前,執(zhí)行清理任務(wù)的代碼總是有機會執(zhí)行。遺憾的是有些人卻不習(xí)慣使用finally。

      當然,編寫finally塊應(yīng)當多加小心,特別是要注意在finally塊之內(nèi)拋出的異常??這是執(zhí)行清理任務(wù)的最后機會,盡量不要再有難以處理的錯誤。

      結(jié)論三:保證所有資源都被正確釋放。充分運用finally關(guān)鍵詞。

    反例之四:不說明異常的詳細信息

      代碼:3行-18行。

      仔細觀察這段代碼:如果循環(huán)內(nèi)部出現(xiàn)了異常,會發(fā)生什么事情?我們可以得到足夠的信息判斷循環(huán)內(nèi)部出錯的原因嗎?不能。我們只能知道當前正在處理的類發(fā)生了某種錯誤,但卻不能獲得任何信息判斷導(dǎo)致當前錯誤的原因。

      printStackTrace的堆棧跟蹤功能顯示出程序運行到當前類的執(zhí)行流程,但只提供了一些最基本的信息,未能說明實際導(dǎo)致錯誤的原因,同時也不易解讀。

      因此,在出現(xiàn)異常時,最好能夠提供一些文字信息,例如當前正在執(zhí)行的類、方法和其他狀態(tài)信息,包括以一種更適合閱讀的方式整理和組織printStackTrace提供的信息。

      結(jié)論四:在異常處理模塊中提供適量的錯誤原因信息,組織錯誤信息使其易于理解和閱讀。

      反例之五:過于龐大的try塊

      代碼:3行-14行。

      經(jīng)常可以看到有人把大量的代碼放入單個try塊,實際上這不是好習(xí)慣。這種現(xiàn)象之所以常見,原因就在于有些人圖省事,不愿花時間分析一大塊代碼中哪幾行代碼會拋出異常、異常的具體類型是什么。把大量的語句裝入單個巨大的try塊就象是出門旅游時把所有日常用品塞入一個大箱子,雖然東西是帶上了,但要找出來可不容易。

      一些新手常常把大量的代碼放入單個try塊,然后再在catch語句中聲明Exception,而不是分離各個可能出現(xiàn)異常的段落并分別捕獲其異常。這種做法為分析程序拋出異常的原因帶來了困難,因為一大段代碼中有太多的地方可能拋出Exception。

      結(jié)論五:盡量減小try塊的體積。

      反例之六:輸出數(shù)據(jù)不完整

      代碼:7行-11行。

      不完整的數(shù)據(jù)是Java程序的隱形殺手。仔細觀察這段代碼,考慮一下如果循環(huán)的中間拋出了異常,會發(fā)生什么事情。循環(huán)的執(zhí)行當然是要被打斷的,其次,catch塊會執(zhí)行??就這些,再也沒有其他動作了。已經(jīng)輸出的數(shù)據(jù)怎么辦?使用這些數(shù)據(jù)的人或設(shè)備將收到一份不完整的(因而也是錯誤的)數(shù)據(jù),卻得不到任何有關(guān)這份數(shù)據(jù)是否完整的提示。對于有些系統(tǒng)來說,數(shù)據(jù)不完整可能比系統(tǒng)停止運行帶來更大的損失。

      較為理想的處置辦法是向輸出設(shè)備寫一些信息,聲明數(shù)據(jù)的不完整性;另一種可能有效的辦法是,先緩沖要輸出的數(shù)據(jù),準備好全部數(shù)據(jù)之后再一次性輸出。

      結(jié)論六:全面考慮可能出現(xiàn)的異常以及這些異常對執(zhí)行流程的影響。

      改寫后的代碼

      根據(jù)上面的討論,下面給出改寫后的代碼。也許有人會說它稍微有點?嗦,但是它有了比較完備的異常處理機制。

     1OutputStreamWriter out =  
     2java.sql.Connection conn =  
     3try 
     4 Statement stat = conn.createStatement(); 
     5 ResultSet rs = stat.executeQuery( 
     6  "select uid, name from user"); 
     7 while (rs.next()) 
     8 
     9  out.println("ID:" + rs.getString("uid"+ ",姓名: " + rs.getString("name")); 
    10 }
     
    11}
     
    12catch(SQLException sqlex) 
    13
    14 out.println("警告:數(shù)據(jù)不完整"); 
    15 throw new ApplicationException("讀取數(shù)據(jù)時出現(xiàn)SQL錯誤", sqlex); 
    16}
     
    17catch(IOException ioex) 
    18
    19 throw new ApplicationException("寫入數(shù)據(jù)時出現(xiàn)IO錯誤", ioex); 
    20}
     
    21finally 
    22
    23 if (conn != null
    24  try 
    25   conn.close(); 
    26  }
     
    27  catch(SQLException sqlex2) 
    28  
    29   System.err(this.getClass().getName() + ".mymethod - 不能關(guān)閉數(shù)據(jù)庫連接: " + sqlex2.toString()); 
    30  }
     
    31 }
     
    32
    33 if (out != null
    34  try 
    35   out.close(); 
    36  }
     
    37  catch(IOException ioex2) 
    38  
    39   System.err(this.getClass().getName() + ".mymethod - 不能關(guān)閉輸出文件" + ioex2.toString()); 
    40  }
     
    41 }
     
    42}
     

    本文的結(jié)論不是放之四海皆準的教條,有時常識和經(jīng)驗才是最好的老師。如果你對自己的做法沒有百分之百的信心,務(wù)必加上詳細、全面的注釋。

      另一方面,不要笑話這些錯誤,不妨問問你自己是否真地徹底擺脫了這些壞習(xí)慣。即使最有經(jīng)驗的程序員偶爾也會誤入歧途,原因很簡單,因為它們確確實實帶來了“方便”。所有這些反例都可以看作Java編程世界的惡魔,它們美麗動人,無孔不入,時刻誘惑著你。也許有人會認為這些都屬于雞皮蒜毛的小事,不足掛齒,但請記住:勿以惡小而為之,勿以善小而不為。

    posted @ 2006-02-01 12:36 方佳瑋 閱讀(331) | 評論 (0)編輯 收藏

         摘要: java語言已經(jīng)內(nèi)置了多線程支持,所有實現(xiàn)Runnable接口的類都可被啟動一個新線程,新線程會執(zhí)行該實例的run()方法,當run()方法執(zhí)行完畢后,線程就結(jié)束了。一旦一個線程執(zhí)行完畢,這個實例就不能再重新啟動,只能重新生成一個新實例,再啟動一個新線程。Thread類是實現(xiàn)了Runnable接口的一個實例,它代表一個線程的實例,并且,啟動線程的唯一方法就是通過Thread類的start()實例方...  閱讀全文
    posted @ 2006-02-01 12:34 方佳瑋 閱讀(2685) | 評論 (1)編輯 收藏

    僅列出標題  下一頁
    主站蜘蛛池模板: 免费一级全黄少妇性色生活片 | 精品国产污污免费网站aⅴ| 嫩草影院在线免费观看| 久久精品国产亚洲一区二区三区| 亚洲网站免费观看| 黄色毛片免费网站| 2019中文字幕在线电影免费| 又粗又硬又黄又爽的免费视频 | 亚洲区视频在线观看| 高潮内射免费看片| 久久不见久久见免费视频7| 四虎免费影院4hu永久免费| 精品亚洲A∨无码一区二区三区| 美女视频黄频a免费| 日本最新免费网站| 亚洲视频在线一区二区| 亚洲成年网站在线观看| 免费人成毛片动漫在线播放| 日本免费一区尤物| 亚洲熟妇av一区| 男女一边桶一边摸一边脱视频免费| 成人AV免费网址在线观看| 亚洲综合日韩久久成人AV| 亚洲а∨天堂久久精品9966| 久久精品免费一区二区三区| 四虎永久成人免费| 亚洲人成电影在线观看青青| 免费无码又爽又刺激高潮软件 | 全亚洲最新黄色特级网站 | 四虎影视www四虎免费| 久久久久亚洲AV无码专区首| 特级无码毛片免费视频| 在线视频免费观看高清| 亚洲AV无码乱码在线观看富二代| 日韩免费码中文在线观看| 成年在线观看免费人视频草莓| 图图资源网亚洲综合网站| ssswww日本免费网站片| 国产免费一区二区三区VR| 亚洲国产激情在线一区| 一区二区三区在线免费看|