2008年4月4日

          J2EE程序員之路之武功修為片

                                                                   作者:EasyJF開源團隊(www.easyjf.com) 大峽

            經常會跟一些朋友討論怎么樣才能學好Java,學到什么程度才算撐握了Java的問題。其中有一個J2EE程序員層次及武功修為的問題,有點意思。這里就把討論的內容大致整理一下發出來,大家繼續討論。  縱觀國內的軟件行業,靠Java吃飯的程序員還真不是少,而且Java程序員是有很大優越感的,畢竟對于很多用b/s搞開發的業內朋友來說,Java技術意味著難度大、門檻高,因此相對來說Java程序員比其它的程序員(如php、.net)收入高就理所當然。然而J2EE所涉及到的范疇是很廣的,不能一個Java程序員就概括了事,而應該具有層次及水平之分,很多時候經常需要進行分類或評級,有時他評、有時自評。  談到國內J2EE領域的程序員層次水平,當前流行的稱謂及評級不外乎就下面幾種:  第一種是精通掌握記事本、Dreamweaver等工具來寫JSP+JavaBean數據庫應用的是J2EE程序員;
            第二種是用JBuilder、Eclipse等專用Java開發工具寫著一堆一堆過程式Java Bean,而且還能精通Struts+Spring+Hibernate等應用框架的高級J2EE程序員;
            第三種是用Together建模,然后生成一堆Java接口或代碼,開口閉口都是設計模式的資深Java程序同及高級系統分析、構架師;
            最后還有一種是整天在BlogJava或JavaEye上談經論道的大師們,這些大師技術水平難以觸摸,武功門派也各具特色,不好歸類,有時不好稱為程序員(因為有的時候他們甚至不寫或者寫不出程序),但又做著與J2EE程序員密切相關的事情,我們暫且就歸為“牛牛”或“大師”。  稱謂畢竟只是稱謂,帶有點主觀或者功利色彩,有時很難鑒定一個人應該屬于什么,因此,我們再從純技術的角度,也即武功修為的角度,作了一個簡單的分析及歸類,把2EE領域程序員大致分成以下幾個層次,可以作為大家自評的一個參考標準:  第一個層次:精通掌握Java語法、能調試基本的程序錯誤,精通掌握JSP+Java Bean寫一些N年前ASP、PHP翻版的Java Web應用程序(如論壇、網站新聞發布系統、OA、網上商城等),精通JDBC使用、精通SQL語句、精通XML等。  第二個層次:掌握設計模式原理及應用,掌握基于OO的分析及設計方法,并能精通熟練使用幾種Java專業設計及開發工具,精通掌握流行的J2EE框架如Hibernate、EJB、Webwork、Spring的原理及應用,精通J2EE中一兩個組成部分(如Servlet、EJB等)的工作原理及細節。  第三個層次:少林的高僧有兩種,禪僧及武僧。J2EE程序員的第三個層次也同樣有禪、武兩個分支,這里我們重點分析一下:  第一個分支屬于走的禪僧線路。在練完第二個層次中的各種武功基礎上,結合實際項目中的千奇百怪的用戶需求,游刃有余的選擇適合的技術方案為客戶解決問題,并形成自己的一套解決方案。達到這一個層次的J2EE程序員已經不在乎使用任何工具、任何框架了,而是根據不同的對手,使用不同的武器或招式來應對。好比 小李飛刀一樣,只有達到了“手中無刀、心中有刀”的境界,才能達到“出手一刀,例不虛發”的效果。這一層次的武功屬于一個熟練度問題,刀練得多了、遇到的對手多了,再加上前面的武功修為,就算做不到例不虛發,也可達到十發九中。  第二個分支屬于走的武僧線路,在撐握熟悉第一二個層次中涉及到的內容后,進一步專研并撐握J2EE底層開發,J2EE規范制訂、規范實現、Java虛擬機的工作原理、各種常見的J2EE服務器內核工作機制、內存管理、進程機制、源代碼等。因為涉及的很多東西都比較抽象,代碼也很多,練這一層的武功需要有很好的資質及耐性、并具還得有一定的環境及條件。好比神雕大俠楊過拿起“玄鐵劍”,并練成“暗然銷魂掌”的成長過程,需要前面的武功修為作基礎,更需那只威力神武神雕的幫助指點及他處處為民、懲奸除惡的俠之心態。
            
            胡侃了這么多,現在來根據自己情況測算一下自己的份量,結果如下:  第一層 練到8成;
            第二層 練到5成;
            第三層 準備走禪僧線路,當前算是練到1成;
            
            唉,后面的武功提升越來越難,真不知道要到何年何月才能達到10成啊。你的武功練到哪一個層次了,不防亮出來大家切磋切磋。嘿嘿,要是有一天,咱們中國的Java程序員人手一把“玄鐵劍”、人人會使“暗然銷魂掌”,那還了得!汗...,寫著寫著居然做起白日夢了,不好意思,就此打住。
            
            手中雞蛋先別扔,還要打個廣告:本人剛開始涉足Java開源,目前在EasyJF開源團隊中負責EasyJWeb(官網www.easyjf.com)項目,歡迎大家前來指導。
                 很牛的一個人物啊!

          posted @ 2008-05-16 00:47 伍興佳 閱讀(230) | 評論 (0)編輯 收藏

          純JAVA技術驗證碼生成器(服務器端servlet實現)(不是javascript哦~)

          java驗證碼生成器,自認為還算經典import java.awt.Color;
          import java.awt.Font;
          import java.awt.Graphics;
          import java.awt.image.BufferedImage;
          import java.io.IOException;
          import java.util.Random;
          import javax.servlet.ServletOutputStream;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          import com.sun.image.codec.jpeg.JPEGCodec;
          import com.sun.image.codec.jpeg.JPEGImageEncoder;
          /**
          * @(#)VerifyCodeServlet.java Dec 9, 2007 8:14:14 PM
          *
          * @author Yuan
          * 驗證碼生成器,使用此類需要將表單里的驗證碼輸入框的name屬性設為"verifycode"
          */
          public class VerifyCodeGenerator {
              
              private static final VerifyCodeGenerator generator = new VerifyCodeGenerator();
              
              private final String ATTRIBUTE_NAME = "verifycode";
              //圖片的寬度
              private final int WIDTH = 15;
              //圖片的高度
              private final int HEIGHT = 22;
              //字符串長度
              private final int CODE_LENGTH = 4;
              //隨機字符串范圍
              private final String RAND_RANGE = "abcdefghijklmnopqrstuvwxyz"
                  + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                  + "1234567890"
                  + "@#quot;;
              
              private final char[] CHARS = RAND_RANGE.toCharArray();
              
              private Random random = new Random();
              
              private VerifyCodeGenerator(){
                  //
              }
              
              public static VerifyCodeGenerator getInstance(){
                  return generator;
              } 
               

              /**
               * 生成隨機字符串
               * @return 隨機字符串
               */
              private String getRandString(){
                  StringBuilder sb = new StringBuilder();
                  for (int i = 0; i < CODE_LENGTH; i++)
                      sb.append(CHARS[random.nextInt(CHARS.length)]);
                  return sb.toString();
              }
              
              /**
               * 生成隨機顏色
               * @param ll 產生顏色值下限(lower limit)
               * @param ul 產生顏色值上限(upper limit)
               * @return 生成的隨機顏色對象
               */
              private Color getRandColor(int ll, int ul){
                  if (ll > 255) ll = 255;
                  if (ll < 1) ll = 1;
                  if (ul > 255) ul = 255;
                  if (ul < 1) ul = 1;
                  if (ul == ll) ul = ll + 1;
                  int r = random.nextInt(ul - ll) + ll;
                  int g = random.nextInt(ul - ll) + ll;
                  int b = random.nextInt(ul - ll) + ll;
                  Color color = new Color(r,g,b);
                  return color;
              }
              
              /**
               * 生成指定字符串的圖像數據
               * @param verifyCode 即將被打印的隨機字符串
               * @return 生成的圖像數據
               * */
              private BufferedImage getImage(String verifyCode){
                  
                  BufferedImage image = new BufferedImage(WIDTH * CODE_LENGTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
                  
                  //獲取圖形上下文
                  Graphics graphics = image.getGraphics();
                  
                  //設置背景色
                  graphics.setColor(getRandColor(1,50));
                  //填充背景色
                  graphics.fillRect(0, 0, WIDTH * 4, HEIGHT);
                  
                  //設置邊框顏色
                  graphics.setColor(new Color(0,255,0));
                  //畫邊框
                  for (int i=0; i<2; i++)
                      graphics.drawRect(i, i, WIDTH * CODE_LENGTH - i * 2 - 1, HEIGHT - i * 2 - 1);
                  
                  //設置隨機干擾線條顏色
                  graphics.setColor(getRandColor(50,100));
                  //產生50條干擾線條
                  for (int i=0; i<50; i++){
                      int x1 = random.nextInt(WIDTH * CODE_LENGTH - 4) + 2;
                      int y1 = random.nextInt(HEIGHT - 4) + 2;
                      int x2 = random.nextInt(WIDTH * CODE_LENGTH - 2 - x1) + x1;
                      int y2 = y1;
                      graphics.drawLine(x1, y1, x2, y2);
                  }
                  
                  //設置字體
                  graphics.setFont(new Font("Times New Roman", Font.PLAIN, 18));
                  //畫字符串
                  for (int i=0; i<this.CODE_LENGTH; i++){
                      String temp = verifyCode.substring(i, i+1);
                      graphics.setColor(getRandColor(100,255));
                      graphics.drawString(temp, 13 * i + 6, 16);
                  } 
                   
                  //圖像生效
                  graphics.dispose();
                  
                  return image;
              }
              
              /**
               * 將驗證碼的圖像輸出
               * @param request 用戶的請求對象
               * @param response 用戶的響應對象
               * */
              public void printImage(HttpServletRequest request,
                      HttpServletResponse response){
                  //將ContentType設為"image/jpeg",讓瀏覽器識別圖像格式。
                  response.setContentType("image/jpeg");
                  //設置頁面不緩存
                  response.setHeader("Pragma", "No-cache");
                  response.setHeader("Cache-Control", "no-cache");
                  response.setDateHeader("Expires", 2000);
                  
                  //獲得隨機驗證碼
                  String verifyCode = this.getRandString();
                  String str = "ssss";
                  for(int i=0; i<10; i++)
                      str = str + str;
                  //獲得驗證碼的圖像數據
                  BufferedImage bi = this.getImage(verifyCode);
                  //把驗證碼存入session
                  request.getSession().setAttribute(ATTRIBUTE_NAME, verifyCode);
                  try{
                      //獲得Servlet輸出流
                      ServletOutputStream outStream = response.getOutputStream();
                      //創建可用來將圖像數據編碼為JPEG數據流的編碼器
                      JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(outStream);
                      //將圖像數據進行編碼
                      encoder.encode(bi);
                      //強行將緩沖區的內容輸入到頁面
                      outStream.flush();
                      //關閉輸出流
                      outStream.close();
                  }catch(IOException ex){
                      ex.printStackTrace();
                  }
              }
              
              /**
               * 檢查輸入的驗證碼是否正確,若用戶輸入的驗證碼與生成的驗證碼相符則返回true,否則返回false。
               * @param request 用戶的請求對象
               * @return 驗證結果
               * */
              public boolean check(HttpServletRequest request){
                  if (((String)request.getParameter(ATTRIBUTE_NAME))
                          .equalsIgnoreCase((String)request.getSession().getAttribute(ATTRIBUTE_NAME))){
                      request.getSession().removeAttribute(ATTRIBUTE_NAME);
                      return true;
                  }
                  return false;
              }
          }
          /**此代碼為我們群老大深秋小雨
          所編寫,真的比較實用,來自qq群J道
          **/

          posted @ 2008-04-05 12:40 伍興佳 閱讀(5464) | 評論 (10)編輯 收藏

          一個小腳本測試

          為什么我寫的一個顯示系統時間的小腳本不能在這里顯示出來?
          還有就是如何使用DOM的getelementbyid方法顯示系統時間?
          <SCRIPT LANGUAGE="JavaScript">
          <!--
          var timerID = null
          var timerRunning = false
          function showtime(){
            var today,hour,second,minute,year,month,date;
          var strDate ;
          today=new Date();
          var n_day = today.getDay();
          switch (n_day)
           {
          case 0:{
          strDate = "星期日"
                 }break;
          case 1:{
          strDate = "星期一"
                 }break;
          case 2:{
          strDate ="星期二"
                 }break;
          case 3:{
          strDate = "星期三"
                 }break;
          case 4:{
          strDate = "星期四"
                 }break;
          case 5:{
          strDate = "星期五"
                 }break;
          case 6:{
          strDate = "星期六"
                 }break;
          case 7:{
          strDate = "星期日"
                 }break;
          }
          year = today.getYear();
          month = today.getMonth()+1;
          date = today.getDate();
          hour = today.getHours();
          minute =today.getMinutes();
          second = today.getSeconds();
          if(month<10) month="0"+month;
          if(date<10) date="0"+date;
          if(hour<10) hour="0"+hour;
          if(minute<10) minute="0"+minute;
          if(second<10) second="0"+second;
           timeValue =year + " 年 " + month + " 月 " + date + " 日 " + strDate +" " + hour + ":" + minute + ":" + second
             document.GG.MM.value = timeValue
             wuxingjia= setTimeout("showtime()",1000)
           
          }

          //-->
          </SCRIPT>
          </HEAD> <BODY onLoad="showtime()">
          <FORM NAME="GG" onSubmit="0">
             <INPUT TYPE="text" NAME="MM" SIZE=40 >
          </FORM>

          posted @ 2008-04-05 01:18 伍興佳 閱讀(859) | 評論 (3)編輯 收藏

          sqlserver中,sql編程的幾個小常識 呵呵,容易出錯的~

          sqlserver中,sql編程的幾個小常識

          1、取出剛剛插入(刪除)的數據SELECT 字段名 FROM INSERTED(DELETED)
          2、對于UPDATE實際上是先DELETE然后再INSERT所以如果想得到UPDATE前后的數據值,應該先從DELETED取出,然后從INSERTED取出;
          3、IF UPDATE(列名)可以判斷更新或插入哪一個字段的值;
          4、@@ROWCOUNT可以判斷上一行查詢操作得到的列數;
          5、給變量賦值用SET @ZQB = 13;
          6、察看是否有符合條件的記錄IF EXISTS (SELECT name FROM sysobjects WHERE name = 'reminder' AND type = 'TR');
          7、定義游標,如下:
          DECLARE c1 CURSOR FOR
          SELECT emp_mgr.emp
          FROM emp_mgr, inserted
          WHERE emp_mgr.emp = inserted.mgr

          OPEN c1
          FETCH NEXT FROM c1 INTO @e--從游標中取出數據
          WHILE @@fetch_status = 0--判斷是否到最后
          BEGIN
          UPDATE emp_mgr
          SET emp_mgr.NoOfReports = emp_mgr.NoOfReports + 1 -- Add 1 for newly
          WHERE emp_mgr.emp = @e -- added employee.

          FETCH NEXT FROM c1 INTO @e
          END
          CLOSE c1
          DEALLOCATE c1--刪除游標引用

          posted @ 2008-04-05 00:38 伍興佳 閱讀(1004) | 評論 (2)編輯 收藏

          關于隱式挖掘網站用戶行為的分析

          關于隱式挖掘網站用戶行為的分析如何了解用戶和需求

            如何了解用戶需求?根據用戶是否主動參與分為顯式與隱式兩種挖掘模式,因為顯式的動靜比較大,有很大局限性,所以為了保證結果準確性以及提高用戶接受度,一般都采用隱式。

            用戶的日常交互行為會產生四類關鍵數據:鼠標移動軌跡、鏈接點擊分布、頁面瀏覽流、頁面停留時間。通過用戶的行為能反映用戶的觀點,同時利用訪問的網頁次序可以找出網頁之間的隱性關系。

            收集數據

            Web服務器的日志(用戶會話記錄)

            Web trends或類似的第三方共享軟件(客戶端分析,流量分析,可用性分析)

            自己開發的第三方軟件/插件(需求自定義)


            大型網站通常會把以上三種方法組合應用,大致原理就是給進入網站的用戶賦予身份識別,每次產生交互動作就向服務器發回請求,通過時間和頁面判斷連接各個請求點并且記錄下來。(算法不討論)

            過濾數據

            明確目標,定義核心數據。

            界定用戶行為,利用多數人的行為來消除個人行為的主觀性。

            對用戶進行歸類,確定數據類別。

            大型網站每天所產生的數據量是驚人的,所以常規需求一般都是定時或定量的分析。另外,額外的數據處理會減慢網站的速度,搜集的數據越多,潛在的負面影響越大。

            習慣分析

            對用戶瀏覽過的頁面進行內容分析,根據信息主題對頁面進行聚類。

            聚類過程中除了考慮頁面內容相近程度,還應該考慮頁面路徑。

            把用戶瀏覽行為對其興趣的作用列入聚類結果,得到綜合評估模型。

            用戶興趣分偶然和穩定兩種情況,其中偶然可以認為是隨機變化的,穩定的挖掘又有基于內容和行為兩種方式,在內容上表現有重復度、相似度等,在行為上表現有停留時長、點此次數、拉動滾動條次數等。

            實際案例

            類似系統、瀏覽器、分辨率的客戶端分析,常見而且簡單,略過。

            關于鼠標軌跡、點擊分布的可用性例子:

            跟蹤用戶在進行檢索時的鼠標移動軌跡,可以獲取用戶操作的先后順序、熱點功能、動作曲線等一手數據,這些都是改善或簡化表單的重要參考。
          在重要的頁面進行詳細的點擊分布監控統計,主要檢查信息呈現的易用性,看看有沒有偏離設計初衷,經常更新,找到規律。

            處理特定用戶行為、用戶群、用戶來路的任務流例子:

            監控分布式注冊流程,能夠看到有多少用戶填了表單、填完了表單,或者在某個步驟有異常流失。


            監控不同模塊入口過來的注冊用戶,能夠統計出各模塊導入的有效注冊量、百分比、成功率,以便合理調配資源。

            監控投放廣告過來的注冊量、注冊成功率、轉換付費用戶成功率,以便明確廣告的投入產出比。

            監控用戶的縱深瀏覽行為,是測試導航可用性很好的辦法,也就是說用戶會不會在你的網站內迷路。

          posted @ 2008-04-05 00:06 伍興佳 閱讀(1153) | 評論 (7)編輯 收藏

          通過一個簡單的登錄過程了解Struts的業務流程(Struts初學的請進)

          一個簡單的登錄過程描述了一下Struts的業務流程,感覺挺容易懂的,摘出來大家分享:(1)用戶的請求以HTTP方式傳輸到服務器上,接收請求的是ActionServlet。
          (2)ActionServlet接收到請求后,會查找struts-config.xml文件來確定服務器上是否有用戶請求的操作,此處用戶請求的操作應為登錄操作。如果沒有,則返回一個用戶請求無效的出錯信息。
          (3)當ActionServlet找到用戶請求的Action后,首先將用戶輸入的表單參數打包成一個ActionForm對象,這個ActionForm對象其實也就是一個JavaBean,里面包含兩個字段,分別是用戶名和密碼。接著ActionServlet再根據struts-config.xml中的配置信息決定是否要執行ActionForm對象中的Validate方法。若Validate方法執行有錯,則返回;否則,繼續下一步。
          (4)系統生成一個用戶所請求的Action的實例對象,將前面的ActionForm對象傳遞給它,運行它的execute()方法。這一步其實就是用戶登錄的控制器,在執行execute()方法時,可以調用后臺模型驗證登錄名和密碼是否正確等信息。
          (5)execute()執行結束前會生成一個ActionForward類型的對象并將之返回給ActionServlet,該對象的作用是告訴ActionServlet下一步應該跳轉到哪里,假如后臺模型檢驗用戶名和密碼正確,則ActionForward就代表跳轉到一個登錄成功的界面。ActionServlet將對之進行分析,其實就相當于接收到一個新的請求,重復(2)~(5)的過程,直到將某個界面返回用戶為止。
          以上就是Struts的基本工作流程,可以看出struts-config.xml在整個流程中起到了一個類似站點地圖的作用,它記錄了所有可能的請求跳轉。其實,在Web容器加載Struts應用程序后,struts-config.xml就被首先讀入內存成為一個ActionMapping對象,前面所說的查找struts-config.xml文件,實際上是查找ActionMapping對象。對于初學者來說可以不必深究其中的細節……
          摘自清華大學出版社出版的《Struts-Web設計與開發大全》

          posted @ 2008-04-04 23:27 伍興佳 閱讀(453) | 評論 (1)編輯 收藏

          <2008年4月>
          303112345
          6789101112
          13141516171819
          20212223242526
          27282930123
          45678910

          導航

          統計

          公告

          這是伍嗲的純JAVA技術博客

          常用鏈接

          留言簿(1)

          隨筆檔案

          文章分類

          相冊

          技術鏈接

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 张家川| 二连浩特市| 镇宁| 平和县| 民县| 常德市| 布尔津县| 金湖县| 嘉荫县| 汉寿县| 资中县| 攀枝花市| 盐池县| 旬邑县| 眉山市| 日土县| 库尔勒市| 邯郸县| 清涧县| 呈贡县| 永福县| 新沂市| 子长县| 湖北省| 平山县| 绵阳市| 吕梁市| 贞丰县| 昆山市| 贡觉县| 葫芦岛市| 从江县| 读书| 石门县| 盐源县| 深州市| 曲靖市| 巩留县| 长治市| 壶关县| 望都县|