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

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

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

    tory320

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      10 隨筆 :: 0 文章 :: 1 評論 :: 0 Trackbacks

    2006年12月18日 #

    Design Principle
    Identify the aspects of your application that vary and separate them from what stays the same.
    Here's another way to think about this principle: take the parts that vary and encapsulate them, so that later you can alter or extends the parts that vary without affecting those that don't.
    As simple as this concept is, it forms the basis for almost every design pattern. All patterns provide a way to let some part of a system vary independently of all other parts.

    Each set of class will hold all the implementations of their respective behavior. For instance, we might have one clss that implements quarking, another implements squaking, and another that implements silence.

    To separate thest behaviors from the Duck class, we'll pull both methods out of the duck class and create a new set of class to represent each behavior.

    This is in contrast to the way we were doing things before, where a behavior either came from a concrete implementation in the suprerclass Duck, or by providing a specialized implementation in the sub class itself. In both cases we were relying on an implementation. We were locked into using that specific implemetation and there was no room for changing out the behavior.

    And the same is true for the duck's flying behavior.

    Okay, now that we've done the deep dive on the duck simulator design, it's time to come back up for air and take a look at the big picture.

    Below is the entire reworked class structure. We have everything you'd expect: ducks extending Duck. fly behavior implementing FlyBehavior and quack behavior implementing QuackBehavior.

    Notice also that we've started to describe things a little differntly. Instead of thinking of the duck behaviors as a set of behaviors, we'll start thinking of them ad a family of algorithms. Think about it: in the SimUDuck design, the algorithms represent things a duck would do , but we could just as easily use the same techniques for a set of classes that implement the ways to compute state sales tax by different states.

    posted @ 2008-03-07 17:58 tory 閱讀(136) | 評論 (0)編輯 收藏

    /**
    ?* //FileOperate.java
    ?* 文件的各種操作
    ?* 楊彩 http://blog.sina.com.cn/m/yangcai
    ?* 文件操作 1.0
    ?*/
    ?
    //package common;
    ?
    import java.io.*;
    ?
    public class FileOperate
    {
    ?static boolean exitnow=false;
    ?static String aa,bb;
    ? public FileOperate() {
    ? }
    ?
    ? /**
    ?? * 新建目錄
    ?? */
    ? public void newFolder(String folderPath) {
    ??? try
    ??? {
    ????? String filePath = folderPath;
    ????? filePath = filePath.toString();
    ????? File myFilePath = new File(filePath);
    ????? if(!myFilePath.exists())
    ????? {
    ??????? myFilePath.mkdir();
    ????? }
    ????? System.out.println("新建目錄操作 成功執行");
    ??? }
    ??? catch(Exception e)
    ??? {
    ????? System.out.println("新建目錄操作出錯");
    ????? e.printStackTrace();
    ??? }
    ? }
    ?
    ? /**
    ?? * 新建文件
    ?? */
    ? public void newFile(String filePathAndName, String fileContent)
    ? {
    ?
    ??? try
    ??? {
    ????? String filePath = filePathAndName;
    ????? filePath = filePath.toString();
    ????? File myFilePath = new File(filePath);
    ????? if (!myFilePath.exists())
    ????? {
    ??????? myFilePath.createNewFile();
    ????? }
    ????? FileWriter resultFile = new FileWriter(myFilePath);
    ????? PrintWriter myFile = new PrintWriter(resultFile);
    ????? String strContent = fileContent;
    ????? myFile.println(strContent);
    ????? resultFile.close();
    ????? System.out.println("新建文件操作 成功執行");
    ??? }
    ??? catch (Exception e) {
    ????? System.out.println("新建目錄操作出錯");
    ????? e.printStackTrace();
    ?
    ??? }
    ?
    ? }
    ?
    ? /**
    ?? * 刪除文件
    ?? */
    ? public void delFile(String filePathAndName) {
    ??? try {
    ????? String filePath = filePathAndName;
    ????? filePath = filePath.toString();
    ????? File myDelFile = new File(filePath);
    ????? myDelFile.delete();
    ????? System.out.println("刪除文件操作 成功執行");
    ??? }
    ??? catch (Exception e) {
    ????? System.out.println("刪除文件操作出錯");
    ????? e.printStackTrace();
    ?
    ??? }
    ?
    ? }
    ?
    ? /**
    ?? * 刪除文件夾
    ?? */
    ? public void delFolder(String folderPath)
    ? {
    ??? try
    ??? {
    ????? delAllFile(folderPath); //刪除完里面所有內容
    ????? String filePath = folderPath;
    ????? filePath = filePath.toString();
    ????? File myFilePath = new File(filePath);
    ????? myFilePath.delete(); //刪除空文件夾
    ????? System.out.println("刪除文件夾操作 成功執行");
    ??? }
    ??? catch (Exception e)
    ??? {
    ????? System.out.println("刪除文件夾操作出錯");
    ????? e.printStackTrace();
    ?
    ??? }
    ?
    ? }
    ?
    ? /**
    ?? * 刪除文件夾里面的所有文件
    ?? * @param path String 文件夾路徑 如 c:/fqf
    ?? */
    ? public void delAllFile(String path)
    ? {
    ??? File file = new File(path);
    ??? if(!file.exists())
    ??? {
    ????? return;
    ??? }
    ??? if(!file.isDirectory())
    ??? {
    ????? return;
    ??? }
    ??? String[] tempList = file.list();
    ??? File temp = null;
    ??? for (int i = 0; i < tempList.length; i++)
    ??? {
    ????? if(path.endsWith(File.separator))
    ????? {
    ??????? temp = new File(path + tempList[i]);
    ????? }
    ????? else
    ????? {
    ??????? temp = new File(path + File.separator + tempList[i]);
    ????? }
    ????? if (temp.isFile())
    ????? {
    ??????? temp.delete();
    ????? }
    ????? if (temp.isDirectory())
    ????? {
    ??????? delAllFile(path+"/"+ tempList[i]);//先刪除文件夾里面的文件
    ??????? delFolder(path+"/"+ tempList[i]);//再刪除空文件夾
    ????? }
    ??? }
    ????????? System.out.println("刪除文件操作 成功執行");?
    ? }
    ?
    ? /**
    ?? * 復制單個文件
    ?? * @param oldPath String 原文件路徑 如:c:/fqf.txt
    ?? * @param newPath String 復制后路徑 如:f:/fqf.txt
    ?? */
    ? public void copyFile(String oldPath, String newPath) {
    ??? try {
    ????? int bytesum = 0;
    ????? int byteread = 0;
    ????? File oldfile = new File(oldPath);
    ????? if (oldfile.exists())
    ????? { //文件存在時
    ??????? InputStream inStream = new FileInputStream(oldPath); //讀入原文件
    ??????? FileOutputStream fs = new FileOutputStream(newPath);
    ??????? byte[] buffer = new byte[1444];
    ??????? int length;
    ??????? while ( (byteread = inStream.read(buffer)) != -1) {
    ????????? bytesum += byteread; //字節數 文件大小
    ????????? System.out.println(bytesum);
    ????????? fs.write(buffer, 0, byteread);
    ??????? }
    ??????? inStream.close();
    ????? }
    ??????????? System.out.println("刪除文件夾操作 成功執行");?
    ??? }
    ??? catch (Exception e) {
    ????? System.out.println("復制單個文件操作出錯");
    ????? e.printStackTrace();
    ?
    ??? }
    ?
    ? }
    ?
    ? /**
    ?? * 復制整個文件夾內容
    ?? * @param oldPath String 原文件路徑 如:c:/fqf
    ?? * @param newPath String 復制后路徑 如:f:/fqf/ff
    ?? */
    ? public void copyFolder(String oldPath, String newPath) {
    ?
    ??? try
    ??? {
    ????? (new File(newPath)).mkdirs(); //如果文件夾不存在 則建立新文件夾
    ????? File a=new File(oldPath);
    ????? String[] file=a.list();
    ????? File temp=null;
    ????? for (int i = 0; i < file.length; i++)
    ????? {
    ??????? if(oldPath.endsWith(File.separator))
    ??????? {
    ????????? temp=new File(oldPath+file[i]);
    ??????? }
    ??????? else{
    ????????? temp=new File(oldPath+File.separator+file[i]);
    ??????? }
    ?
    ??????? if(temp.isFile())
    ??????? {
    ????????? FileInputStream input = new FileInputStream(temp);
    ????????? FileOutputStream output = new FileOutputStream(newPath + "/" +
    ????????????? (temp.getName()).toString());
    ????????? byte[] b = new byte[1024 * 5];
    ????????? int len;
    ????????? while ( (len = input.read(b)) != -1)
    ????????? {
    ??????????? output.write(b, 0, len);
    ????????? }
    ????????? output.flush();
    ????????? output.close();
    ????????? input.close();
    ??????? }
    ??????? if(temp.isDirectory())
    ??????? {//如果是子文件夾
    ????????? copyFolder(oldPath+"/"+file[i],newPath+"/"+file[i]);
    ??????? }
    ????? }
    ??????????? System.out.println("復制文件夾操作 成功執行");?
    ??? }
    ??? catch (Exception e) {
    ????? System.out.println("復制整個文件夾內容操作出錯");
    ????? e.printStackTrace();
    ?
    ??? }
    ?
    ? }
    ?
    ? /**
    ?? * 移動文件到指定目錄
    ?? * @param oldPath String 如:c:/fqf.txt
    ?? * @param newPath String 如:d:/fqf.txt
    ?? */
    ? public void moveFile(String oldPath, String newPath) {
    ??? copyFile(oldPath, newPath);
    ??? delFile(oldPath);
    ?
    ? }
    ?
    ? /**
    ?? * 移動文件到指定目錄
    ?? * @param oldPath String 如:c:/fqf.txt
    ?? * @param newPath String 如:d:/fqf.txt
    ?? */
    ? public void moveFolder(String oldPath, String newPath) {
    ??? copyFolder(oldPath, newPath);
    ??? delFolder(oldPath);
    ?
    ? }
    ?
    ? public static void main(String args[])
    ? {
    ? ?System.out.println("使用此功能請按[1]? 功能一:新建目錄");
    ? ?System.out.println("使用此功能請按[2]? 功能二:新建文件");
    ? ?System.out.println("使用此功能請按[3]? 功能三:刪除文件");
    ? ?System.out.println("使用此功能請按[4]? 功能四:刪除文件夾");
    ? ?System.out.println("使用此功能請按[5]? 功能五:刪除文件夾里面的所有文件");
    ? ?System.out.println("使用此功能請按[6]? 功能六:復制文件");
    ? ?System.out.println("使用此功能請按[7]? 功能七:復制文件夾的所有內容");
    ? ?System.out.println("使用此功能請按[8]? 功能八:移動文件到指定目錄");
    ? ?System.out.println("使用此功能請按[9]? 功能九:移動文件夾到指定目錄");
    ? ?System.out.println("使用此功能請按[10] 退出程序");
    ? ?
    ?while(!exitnow)
    ?{
    ? ??FileOperate fo=new FileOperate();
    ? ??try
    ? ??{
    ? ??BufferedReader Bin=new BufferedReader(new InputStreamReader(System.in));
    ? ??String a=Bin.readLine();
    ? ??int b=Integer.parseInt(a);
    ? ??
    ? ??switch(b)
    ? ??{
    ? ???case 1:System.out.println("你選擇了功能一? 請輸入目錄名");??
    ? ????? aa=Bin.readLine();
    ? ????? fo.newFolder(aa);
    ? ????? break;
    ? ???case 2:System.out.println("你選擇了功能二? 請輸入文件名");??
    ? ????? aa=Bin.readLine();
    ? ????? System.out.println("請輸入在"+aa+"中的內容");
    ? ????? bb=Bin.readLine();
    ? ????? fo.newFile(aa,bb);
    ? ????? break;
    ? ???case 3:System.out.println("你選擇了功能三? 請輸入文件名");??
    ? ????? aa=Bin.readLine();
    ? ????? fo.delFile(aa);
    ? ????? break;
    ? ???case 4:System.out.println("你選擇了功能四? 請輸入文件名");??
    ? ????? aa=Bin.readLine();
    ? ????? fo.delFolder(aa);
    ? ????? break;
    ? ???case 5:System.out.println("你選擇了功能五? 請輸入文件名");??
    ? ????? aa=Bin.readLine();
    ? ????? fo.delAllFile(aa);
    ? ????? break;??
    ? ???case 6:System.out.println("你選擇了功能六? 請輸入文件名");??
    ? ????? aa=Bin.readLine();
    ? ????? System.out.println("請輸入目標文件名");?
    ? ????? bb=Bin.readLine();
    ? ????? fo.copyFile(aa,bb);
    ? ????? break;
    ? ???case 7:System.out.println("你選擇了功能七? 請輸入源文件名");??
    ? ????? aa=Bin.readLine();
    ? ????? System.out.println("請輸入目標文件名");?
    ? ????? bb=Bin.readLine();
    ? ????? fo.copyFolder(aa,bb);
    ? ????? break;? ?????
    ? ???case 8:System.out.println("你選擇了功能八? 請輸入源文件名");??
    ? ????? aa=Bin.readLine();
    ? ????? System.out.println("請輸入目標文件名");?
    ? ????? bb=Bin.readLine();
    ? ????? fo.moveFile(aa,bb);
    ? ????? break;
    ? ??? ?case 9:System.out.println("你選擇了功能九? 請輸入源文件名");??
    ? ????? aa=Bin.readLine();
    ? ????? System.out.println("請輸入目標文件名");?
    ? ????? bb=Bin.readLine();
    ? ????? fo.moveFolder(aa,bb);
    ? ????? break;? ?????
    ? ???case 10:exitnow=true;
    ? ?????? System.out.println("程序結束,請退出");
    ? ????? break;
    ? ???default:System.out.println("輸入錯誤.請輸入1-10之間的數");?? ???? ????? ?
    ? ?? }
    ? ??
    ? ??
    ? ??System.out.println("請重新選擇功能");
    ? ??
    ? ??
    ? ??}
    ? ??catch(Exception e)
    ? ??{
    ? ??System.out.println("輸入錯誤字符或程序出錯");
    ? ??}
    ? ??
    ?}? ?
    ?}
    }
    posted @ 2007-01-30 13:03 tory 閱讀(186) | 評論 (0)編輯 收藏

    本文是在參閱了http://ivanl.javaeye.com/blog/24739基礎上完成的
    在看JPetStore的代碼時,發現它的分頁處理主要是通過返回PaginatedList對象來完成的。如:在CatalogService類中
    public?PaginatedList?getProductListByCategory(String?categoryId)?{?
    ????
    return?productDao.getProductListByCategory(categoryId);?
    ??}
    ?

    分頁是操作數據庫型系統常遇到的問題。分頁實現方法很多,但效率的差異就很大了。iBatis是通過什么方式來實現這個分頁的了。查看它的實現部分:
    ?
    返回的PaginatedList實際上是個接口,實現這個接口的是PaginatedDataList類的對象,查看PaginatedDataList類發現,每次翻頁的時候最后都會調用下面這段函數
    private?List?getList(int?idx,?int?localPageSize)?throws?SQLException?{?
    ????
    return?sqlMapExecutor.queryForList(statementName,?parameterObject,?(idx)?*?pageSize,?localPageSize);?
    ??}
    ?
    由于
    public?interface?SqlMapClient?extends?SqlMapExecutor,?SqlMapTransactionManager?{……}?

    所以實際的調用次序如下:
    SqlMapClientImpl.queryForPaginatedList->SqlMapSessionImpl.queryForPaginatedList?
    ->SqlMapExecutorDelegate.queryForPaginatedList->GeneralStatement.executeQueryForList?
    ->GeneralStatment.executeQueryWithCallback->GeneralStatment.executeQueryWithCallback?
    ->SqlExecutor.executeQuery->SqlExecutor.handleMultipleResults()->SqlExecutor.executeQuery->?handleResults?
    分頁處理的函數如下
    private?void?handleResults(RequestScope?request,?ResultSet?rs,?int?skipResults,?int?maxResults,?RowHandlerCallback?callback)?throws?SQLException?{?
    ????
    try?{?
    ??????request.setResultSet(rs);?
    ??????ResultMap?resultMap?
    =?request.getResultMap();?
    ??????
    if?(resultMap?!=?null)?{?
    ????????
    //?Skip?Results?
    ????????if?(rs.getType()?!=?ResultSet.TYPE_FORWARD_ONLY)?{?
    ??????????
    if?(skipResults?>?0)?{?
    ????????????rs.absolute(skipResults);?
    ??????????}
    ?
    ????????}
    ?else?{?
    ??????????
    for?(int?i?=?0;?i?<?skipResults;?i++)?{?
    ????????????
    if?(!rs.next())?{?
    ??????????????
    return;?
    ????????????}
    ?
    ??????????}
    ?
    ????????}
    ?
    ??
    ????????
    //?Get?Results?
    ????????int?resultsFetched?=?0;?
    ????????
    while?((maxResults?==?SqlExecutor.NO_MAXIMUM_RESULTS?||?resultsFetched?<?maxResults)?&&?rs.next())?{?
    ??????????Object[]?columnValues?
    =?resultMap.resolveSubMap(request,?rs).getResults(request,?rs);?
    ??????????callback.handleResultObject(request,?columnValues,?rs);?
    ??????????resultsFetched
    ++;?
    ????????}
    ?
    ??????}
    ?
    ????}
    ?finally?{?
    ??????request.setResultSet(
    null);?
    ????}
    ?
    ??}
    ?

    由此可見,iBatis的分頁主要依賴于jdbcdriver的如何實現以及是否支持rs.absolute(skipResults)。它并不是一個好的分頁方式。它先要取出所有的符合條件的記錄存入ResultSet對象,然后用absolute方法進行定位,來實現分頁。當記錄數較大(比如十萬條)時,整體的查詢速度將會變得很慢。
    所以分頁還是要考慮采用直接操作sql語句來完成。當然小批量的可以采用iBatis的分頁模式。一般分頁的sql語句與數據庫的具體實現有關
    mysql:?
    select?*?from?A?limit?startRow,endRow?
    oracle:?
    select?b.*?from?(select?a.*,rownum?as?linenum?from?(select?*?from?A)?a?where?rownum?<=?endRow)?b?where?linenum?>=?startRow?

    Hibernate的Oracle分頁采用的就是是拼湊RowNum的Sql語句來完成的。參考代碼如下:?
    ?
    ????????public?String?createOraclePagingSql(String?sql,?int?pageIndex,?int?pageSize){?
    ????????????
    int?m?=?pageIndex?*?pageSize;?
    ????????????
    int?n?=?m?+?pageSize;?
    ????????????
    return?"select?*?from?(?select?row_.*,?rownum?rownum_?from?(?"?+?sql?
    ????????????????????
    +?"?)?row_?where?rownum?<=?"?+?n??
    ????????????????????
    +?")?where?rownum_?>?"?+?m;?
    ????????}
    ?
    綜上,小批量(<2w)可以采用ibatis自帶的分頁類,大批量的還是直接操縱sql,當然也可以將這些sql自己進行封裝,或在包中封裝都可以。包封裝的示例代碼如下:
    一個封裝了分頁功能的Oracle Package
    create?or?replace?package?body?FMW_FY_HELPER?is
    PROCEDURE?GET_DATA(pi_sql?in?varchar,pi_whichpage?in?integer,pi_rownum?in?integer,
    po_cur_data?out?cur_DATA,po_allrownum?out?
    integer,pio_succeed?in?out?integer)
    as?
    v_cur_data?cur_DATA;
    v_cur_temp?cur_TEMP;
    v_temp?
    integer;
    v_sql?
    varchar(5000);
    v_temp1?
    integer;
    v_temp2?
    integer;
    begin
    pio_succeed?:
    =?1;
    v_sql?:
    =?'select?count(''a'')?from?(?'?||?pi_sql?||?')';
    execute?immediate?v_sql?into?v_temp;

    po_allrownum:
    =ceil(v_temp/pi_rownum);

    v_sql?:
    =?'';
    v_temp?:
    =pi_whichpage*pi_rownum?+?1;
    v_temp1:
    =(pi_whichpage-1)*pi_rownum?+?1;
    v_temp2:
    =pi_whichpage*pi_rownum;
    v_sql:
    =?'select?*?from?(select?rownum?as?rn,t.*?from?('?||?pi_sql?||')?t?where?rownum<'?||?to_char(v_temp)?||?')??where?rn?between?'?||?to_char(v_temp1)?||?'?and?'?||?to_char(v_temp2);
    open?v_cur_data?for?v_sql;
    if?v_cur_data?%notfound
    then
    pio_succeed:
    =-1;
    return;
    end?if;
    po_cur_DATA?:
    =?v_cur_data;
    end;
    posted @ 2007-01-19 13:02 tory 閱讀(829) | 評論 (0)編輯 收藏

    使用JFreeChart生成熱點圖表
    2006-12-14 11:54
    <一>前言:

      JFreeChart是開放源代碼站點SourceForge.net上的一個JAVA項目。它的功能十分強大,能創建餅圖、柱狀圖(普通柱狀圖以及堆棧柱狀圖)、線圖、區域圖、分布圖、混合圖、甘特圖以及一些儀表盤等等,并可生成PNG或JPG圖片格式文件。
      本人在學習過程中發現,網上很多文章都是講一些JFreeChart的基本應用,而對JFreeChart生成熱點圖表這樣常用的功能雖有所提及卻沒有一個完整的例子,所以我就寫一個簡單示例供大家參考,希望對大家的學習有所幫助。?

     ?。级臼纠f明:

      假設有一個關于程序員北京,上海,廣洲三地程序員學歷,開發語言,薪金情況的調查。首先要以餅圖顯示程序員學歷的分布情況(index.jsp)。點擊餅圖的每一部分會以柱狀圖顯示該層次程序員所用開發語言和薪金的情況(barview.jsp)。重點演示怎樣在餅圖上添加鏈接。?

     ?。既緶蕚涔ぷ鳎?br />
      1.下載最新版本的JFreeChart,當前為jfreechart-1.0.0-rc1
    下載地址:http://www.jfree.org/jfreechart/index.html

      2.解壓文件,將jfreechart-1.0.0-rc1/lib下的jcommon-1.0.0-rc1.jar,jfreechart-1.0.0-rc1.jar復制到WEB應用的lib目錄下。

      3.在web.xml文件中增加以下內容:

    <servlet>?
    <servlet-name>DisplayChart</servlet-name>?
    <servlet-class>org.jfree.chart.servlet.DisplayChart</servlet-class>?
    </servlet>?
    <servlet-mapping>?
    <servlet-name>DisplayChart</servlet-name>?
    <url-pattern>/servletDisplayChart</url-pattern>?
    </servlet-mapping>?

     ?。妓模撅瀳D頁面代碼(index.jsp)?


    <%@?page?contentType="text/html;charset=GBK"%>?
    <%@?page?import="org.jfree.data.general.DefaultPieDataset"%>?
    <%@?page?import="org.jfree.chart.*"%>?
    <%@?page?import="org.jfree.chart.plot.*"%>?
    <%@?page?import="org.jfree.chart.servlet.ServletUtilities"%>?
    <%@?page?import="org.jfree.chart.labels.StandardPieItemLabelGenerator"%>?
    <%@?page?import="org.jfree.chart.urls.StandardPieURLGenerator"%>?
    <%@?page?import="org.jfree.chart.entity.StandardEntityCollection"%>?
    <%@?page?import="java.io.*"%>?
    <HTML>?
    <HEAD>?
    <META?http-equiv=Content-Type?content="text/html;?charset=GBK">?
    <TITLE>nacl_zhuang@hotmail.com</TITLE>?
    </HEAD>?
    <BODY>?
    <%?

    DefaultPieDataset?data?=?new?DefaultPieDataset();?
    data.setValue("高中以下",370);?
    data.setValue("高中",1530);?
    data.setValue("大專",5700);?
    data.setValue("本科",8280);?
    data.setValue("碩士",4420);?
    data.setValue("博士",80);?

    PiePlot3D?plot?=?new?PiePlot3D(data);//3D餅圖?
    plot.setURLGenerator(new?StandardPieURLGenerator("barview.jsp"));//設定鏈接?
    JFreeChart?chart?=?new?JFreeChart("",JFreeChart.DEFAULT_TITLE_FONT,?plot,?true);?
    chart.setBackgroundPaint(java.awt.Color.white);//可選,設置圖片背景色?
    chart.setTitle("程序員學歷情況調查表");//可選,設置圖片標題?
    plot.setToolTipGenerator(new?StandardPieItemLabelGenerator());?
    StandardEntityCollection?sec?=?new?StandardEntityCollection();?
    ChartRenderingInfo?info?=?new?ChartRenderingInfo(sec);?
    PrintWriter?w?=?new?PrintWriter(out);//輸出MAP信息?
    //500是圖片長度,300是圖片高度?
    String?filename?=?ServletUtilities.saveChartAsPNG(chart,?500,?300,?info,?session);?
    ChartUtilities.writeImageMap(w,?"map0",?info,?false);?

    String?graphURL?=?request.getContextPath()?+?"/servlet/DisplayChart?filename="?+?filename;?

    %>?

    <P?ALIGN="CENTER">?
    <img?src="<%=?graphURL?%>"?width=500?height=300?border=0?usemap="#map0">?
    </P>?
    </BODY>?
    </HTML>?

      生成的圖片如下


      在瀏覽器中點右鍵->查看源文件會發現有以下一段HTML代碼:?

    <map?id="map0"?name="map0">?
    <area?shape="poly"?coords="247,61,250,61,250,123,250,123"?title="博士?=?80"?alt=""?href="barview.jsp?category=博士&pieIndex=0"/>?
    <area?shape="poly"?coords="148,112,153,102,160,92,170,83,182,76,196,70,212,65,229,62,247,61,250,123,250,123"?title="碩士?=?4,420"?alt=""?href="barview.jsp?category=碩士&pieIndex=0"/>?
    <area?shape="poly"?coords="324,167,311,173,297,179,282,182,266,185,250,186,234,185,217,183,202,179,188,173,175,167,
     ?165,159,157,151,151,142,147,132,146,122,148,112,250,123,250,123"?title="本科?=?8,280"?alt=""?
     href="barview.jsp?category=本科&pieIndex=0"/>?
    <area?shape="poly"?coords="307,72,324,80,338,91,347,103,352,117,352,131,347,144,338,156,324,167,250,123,250,123"?title="大專?=?5,700"?alt=""?href="barview.jsp?category=大專&pieIndex=0"/>?
    <area?shape="poly"?coords="261,62,285,65,307,72,250,123,250,123"?title="高中?
     =?1,530"?alt=""?href="barview.jsp?category=高中&pieIndex=0"/>?
    <area?shape="poly"?coords="250,61,261,62,250,123,250,123"?title="高中以下?=?370"?alt=""?href="barview.jsp?category=高中以下&pieIndex=0"/>?
    </map>?


      這就是MAP信息,我們在IMG標簽中加入usemap="#map0"就可以為餅圖的每一部分加入鏈接。

     ?。嘉澹局鶢顖D頁面代碼:(barview.jsp)

    <HTML>?
    <HEAD>?
    <META?http-equiv=Content-Type?content="text/html;?charset=GBK">?
    <TITLE>nacl_zhuang@hotmail.com</TITLE>?
    </HEAD>?

    <body>?

    <%@?page?contentType="text/html;charset=GBK"%>?
    <%@?page?import="org.jfree.chart.ChartFactory,?
    org.jfree.chart.JFreeChart,?
    org.jfree.chart.plot.PlotOrientation,?
    org.jfree.chart.servlet.ServletUtilities,?
    org.jfree.data.category.*"%>?
    <%?
    CategoryDataset?dataset;?
    String?category=request.getParameter("category");?
    category=?new?String(category.getBytes("ISO8859_1"),?"GBK");?
    if(category.equals("本科")||category.equals("高中")||category.equals("大專"))?
    {?
     dataset=getDataSet();?
    }?
    else?if(category.equals("碩士")||category.equals("博士"))?
    {?
     dataset=getDataSet2();?
    }else?
    {?
     dataset=getDataSet3();?
    }?
    String?title=category+"程序員在各城市薪金情況統計";?
    JFreeChart?chart?=?ChartFactory.createBarChart3D(title,?
    "城市",?
    "薪金",?
    dataset,?
    PlotOrientation.VERTICAL,?
    true,?
    false,?
    false);?

    String?filename?=?ServletUtilities.saveChartAsPNG(chart,?500,?300,?null,?session);?
    String?graphURL?=?request.getContextPath()?+?"/servlet/DisplayChart?filename="?+?filename;?
    %>?
    <P?ALIGN="CENTER">?
    <img?src="<%=?graphURL?%>"?width=500?height=300?border=0?usemap="#<%=?filename?%>">?
    </P>?
    <%!?
    private?static?CategoryDataset?getDataSet()?{?
     DefaultCategoryDataset?dataset?=?new?DefaultCategoryDataset();?
     dataset.addValue(2000,?"北京",?"VB");?
     dataset.addValue(1800,?"上海",?"VB");?
     dataset.addValue(2200,?"廣州",?"VB");?
     dataset.addValue(3200,?"北京",?"JAVA");?
     dataset.addValue(3500,?"上海",?"JAVA");?
     dataset.addValue(3600,?"廣州",?"JAVA");?
     dataset.addValue(3300,?"北京",?"DOT?NET");?
     dataset.addValue(3400,?"上海",?"DOT?NET");?
     dataset.addValue(3700,?"廣州",?"DOT?NET");?
     dataset.addValue(2500,?"北京",?"DELPHI");?
     dataset.addValue(2800,?"上海",?"DELPHI");?
     dataset.addValue(3200,?"廣州",?"DELPHI");?
     dataset.addValue(5000,?"北京",?"VC");?
     dataset.addValue(3500,?"上海",?"VC");?
     dataset.addValue(4600,?"廣州",?"VC");?
     return?dataset;?
    }?
    private?static?CategoryDataset?getDataSet2()?{?
     DefaultCategoryDataset?dataset?=?new?DefaultCategoryDataset();?
     dataset.addValue(2000,?"上海",?"VB");?
     dataset.addValue(3000,?"北京",?"JAVA");?
     dataset.addValue(3330,?"上海",?"JAVA");?
     dataset.addValue(3500,?"廣州",?"JAVA");?
     dataset.addValue(3500,?"北京",?"DOT?NET");?
     dataset.addValue(4000,?"上海",?"DOT?NET");?
     dataset.addValue(4800,?"廣州",?"DOT?NET");?
     dataset.addValue(2600,?"北京",?"DELPHI");?
     dataset.addValue(2200,?"上海",?"DELPHI");?
     dataset.addValue(4000,?"北京",?"VC");?
     dataset.addValue(4000,?"上海",?"VC");?
     dataset.addValue(4200,?"廣州",?"VC");?
     return?dataset;?
    }?
    private?static?CategoryDataset?getDataSet3()?{?
     DefaultCategoryDataset?dataset?=?new?DefaultCategoryDataset();?
     dataset.addValue(2100,?"北京",?"VB");?
     dataset.addValue(2200,?"上海",?"VB");?
     dataset.addValue(2100,?"廣州",?"VB");?
     dataset.addValue(3000,?"北京",?"JAVA");?
     dataset.addValue(3200,?"上海",?"JAVA");?
     dataset.addValue(3600,?"廣州",?"JAVA");?
     dataset.addValue(4100,?"北京",?"DOT?NET");?
     dataset.addValue(4200,?"上海",?"DOT?NET");?
     dataset.addValue(4160,?"廣州",?"DOT?NET");?
     dataset.addValue(2400,?"北京",?"DELPHI");?
     dataset.addValue(2600,?"上海",?"DELPHI");?
     dataset.addValue(2500,?"廣州",?"DELPHI");?
     dataset.addValue(5400,?"北京",?"VC");?
     dataset.addValue(5000,?"上海",?"VC");?
     dataset.addValue(5500,?"廣州",?"VC");?
     return?dataset;?
    }?
    %>?
    </body>?
    </html>?

      生成圖片如下:?


    posted @ 2006-12-29 23:36 tory 閱讀(387) | 評論 (0)編輯 收藏

    ?
    在用 AJAX 開發的過程中, 不可避免的會遇到中文問題. 很多原來可以通過表單進行 POST 提交的字符, 到了用 AJAX 實現的時候, 就會出現煩人的亂碼和丟特殊字符的現象. 另外服務器端返回值如何解析, 也是一個很煩人的問題. 本文將就個人的一點實踐經驗作出總結, 并給出一個盡量簡單可行, 復用性高的方案. 目的不是替代你喜歡的 AJAX 框架, 而是希望幫助您理解和處理可能遇到的問題.

    開始之前: 首先一個問題就是通常 XMLHttpRequest 默認的編碼都是UTF-8的, 所以我們建議所有頁面, 客戶端和服務器端都使用 UTF-8 作為編碼.

    1. base64 encode 和 decode
    ??? 這個方案依賴于 JavaScript 實現的 base64 編碼/解碼方法, 在客戶端發送參數的時候用 base64 進行編碼, 服務器端通過 base64 進行解碼后還原出原來的字符, 這個解決方案可以滿足需要, 但是有個問題就是一是增加了客戶端代碼量, 還有個大問題就是編碼后的內容比原始內容會大很多, 另外如果找到的 base64 JS 算法不夠標準的話, 服務器端就無法還原原來的值了. 現在網上有很多種 base64 的 JS 實現代碼, 例如如下的一個算法實現:

    <HTML>
    <HEAD>
    <TITLE>Base64</TITLE>
    <script language=javascript>
    var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    var base64DecodeChars = new Array(
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
      52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
      -1,  0, 1, 2, 3,? 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
      15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
      -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
      41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1);
    function base64encode(str) {
      var out, i, len;
      var c1, c2, c3;
      len = str.length;
      i = 0;
      out = "";
      while (i < len) {
    ?c1 = str.charCodeAt(i++) & 0xff;
    ?if(i == len)
    ?{
       out += base64EncodeChars.charAt(c1 >> 2);
       out += base64EncodeChars.charAt((c1 & 0x3) << 4);
       out += "==";
       break;
    ?}
    ?c2 = str.charCodeAt(i++);
    ?if(i == len)
    ?{
       out += base64EncodeChars.charAt(c1 >> 2);
       out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
       out += base64EncodeChars.charAt((c2 & 0xF) << 2);
       out += "=";
       break;
    ?}
    ?c3 = str.charCodeAt(i++);
    ?out += base64EncodeChars.charAt(c1 >> 2);
    ?out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
    ?out += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6));
    ?out += base64EncodeChars.charAt(c3 & 0x3F);
      }
       return out;
    }
    function base64decode(str) {
      var c1, c2, c3, c4;
      var i, len, out;
      len = str.length;
      i = 0;
      out = "";
      while (i < len) {
    ?/* c1 */
    ?do {
       c1 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
    ?} while(i < len && c1 == -1);
    ?if(c1 == -1)
       break;
    ?/* c2 */
    ?do {
       c2 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
    ?} while(i < len && c2 == -1);
    ?if(c2 == -1)
       break;
    ?out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4));
    ?/* c3 */
    ?do {
       c3 = str.charCodeAt(i++) & 0xff;
       if(c3 == 61)
     return out;
       c3 = base64DecodeChars[c3];
    ?} while(i < len && c3 == -1);
    ?if(c3 == -1)
       break;
    ?out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2));
    ?/* c4 */
    ?do {
       c4 = str.charCodeAt(i++) & 0xff;
       if(c4 == 61)
     return out;
       c4 = base64DecodeChars[c4];
    ?} while(i < len && c4 == -1);
    ?if(c4 == -1)
       break;
    ?out += String.fromCharCode(((c3 & 0x03) << 6) | c4);
      }
       return out;
    }
    function utf16to8(str) {
      var out, i, len, c;
      out = "";
      len = str.length;
      for(i = 0; i < len; i++) {
    ?c = str.charCodeAt(i);
    ?if ((c >= 0x0001) && (c <= 0x007F)) {
       out += str.charAt(i);
    ?} else if (c > 0x07FF) {
       out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F));
       out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F));
       out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
    ?} else {
       out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F));
       out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
    ?}
      }
       return out;
    }
    function utf8to16(str) {
      var out, i, len, c;
      var char2, char3;
      out = "";
      len = str.length;
      i = 0;
      while (i < len) {
    ?c = str.charCodeAt(i++);
    ?switch(c >> 4)
    ?{
      case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
       // 0xxxxxxx
       out += str.charAt(i-1);
       break;
      case 12: case 13:
       // 110x xxxx  10xx xxxx
       char2 = str.charCodeAt(i++);
       out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
       break;
      case 14:
       // 1110 xxxx 10xx xxxx 10xx xxxx
       char2 = str.charCodeAt(i++);
       char3 = str.charCodeAt(i++);
       out += String.fromCharCode(((c & 0x0F) << 12) |
         ((char2 & 0x3F) << 6) |
         ((char3 & 0x3F) << 0));
       break;
    ?}
      }
       return out;
    }

    function doit() {
      var f = document.f
       f.output.value = base64encode(utf16to8(f.source.value))
       f.decode.value = utf8to16(base64decode(f.output.value))
    }
    </script>
    </HEAD>
    <BODY>
    <H1>Base64</H1>
    <FORM NAME="f">
    原碼& lt;BR>
    <TEXTAREA NAME="source" ROWS=4 COLS=60 WRAP="soft"></TEXTAREA><BR><BR>
    Base64 encode<BR>
    <TEXTAREA NAME="output" ROWS=4 COLS=60 WRAP="soft"></TEXTAREA><BR><BR>
    Base64 decode<BR>
    <TEXTAREA NAME="decode" ROWS=4 COLS=60 WRAP="soft"></TEXTAREA><BR><BR>
    <INPUT TYPE=BUTTON VALUE="轉換" ONCLICK="doit()">
    </FORM>
    </BODY>

    在每個表單值被提交之前調用 base64encode, 然后在服務器端調用 base64 解碼器即可.
    在 JSP 中可以通過這樣做來實現:
    ??? ??? sun.misc.BASE64Decoder base64decoder = new sun.misc.BASE64Decoder();
    ??? ??? byte[] data =?base64decoder.decodeBuffer(request.getParameter("input"));
    ??? ??? String result = new String(data, "UTF-8");// 注意建議這里制定字符集來歡迎到原來的字符串

    在這種情況下服務器端返回的字符也可以通過先 base64 編碼的方式傳遞到客戶端, 客戶端之后調用 JS 形式的解碼器即可還原到原來的字符串. 服務器端可以使用 sun.misc.BASE64Encoder (不要用 java.netURLEncoder).

    2.使用 JS 自帶的 escape() & encodeURI() & encodeURIComponent()

    escape() & encodeURI() & encodeURIComponent()這三個函數都可以用來對URI進行encode或過濾特殊字符(#/$&+=?/等)。我的經驗是最好用encodeURIComponent()(需要IE 5.5以上,FireFox當然沒問題),因為對UTF-8支持比較好,不會遇到中文亂碼問題,否則還需要進行編碼轉換,很麻煩的。使用其它兩個函數都會發生丟失特殊字符的問題,例如空格變+號或者空格,引號,&=?等丟失的問題, 至少使用 JSP 作為服務器端的話會發生這種情況, 有興趣的朋友可以將本文最后的例子代碼中的編碼部分修改后做個測試.

    下面是MSDN上對這三個函數的解釋:

    escape(charString)

    The escape method returns a string value (in Unicode format) that contains the contents of charstring. All spaces, punctuation, accented characters, and any other non-ASCII characters are replaced with %xx encoding, where xx is equivalent to the hexadecimal number representing the character. For example, a space is returned as "%20."

    Characters with a value greater than 255 are stored using the %uxxxx format.

    Note?? The escape method should not be used to encode Uniform Resource Identifiers (URI). Use encodeURI and encodeURIComponent methods instead.

    http://msdn.microsoft.com/library/en-us/script56/html/js56jsmthescape.asp

    ?encodeURI(URIString)

    The encodeURI method returns an encoded URI. If you pass the result to decodeURI, the original string is returned. The encodeURI method does not encode the following characters: ":", "/", ";", and "?". Use encodeURIComponent to encode these characters.

    http://msdn.microsoft.com/library/en-us/script56/html/js56jsmthfencodeuri.asp

    encodeURIComponent(encodedURIString)

    The encodeURIComponent method returns an encoded URI. If you pass the result to decodeURIComponent, the original string is returned. Because the encodeURIComponent method encodes all characters, be careful if the string represents a path such as /folder1/folder2/default.html. The slash characters will be encoded and will not be valid if sent as a request to a web server. Use the encodeURI method if the string contains more than a single URI component.

    http://msdn.microsoft.com/library/en-us/script56/html/js56jsmthencodeuricomponent.asp

    3. 使用一個簡便的客戶端數據解析方案

    最偷懶的辦法就是返回一段 HTML 顯示出來了. 至于如果是想帶一些數據, 解析處理的話, 方案很多, 利用 XML 啊, JSON 啊什么的不一而足. 我這里呢就給出一個相當簡便的方案: 使用 JS 內置的 eval 方法來解析. 這個方案是在幫助一個同事想最快的已最短的代碼解析返回的對象的多個變量的時候提出的.

    服務器端返回一個字符串:
    var _dataObject = {
    ?? username : "beansoft",
    ??????? age : 24
    };

    客戶端在得到這個字符串后可以通過下面一段代碼搞定:
    var responseText = xmlhttp.responseText;
    eval(responseText);
    alert("_dataObject.username=" + _dataObject.username);

    好了, 解析出來了!
    如果要傳遞多個變量呢, 就用 var _dataObject1, var _dataObject2...這樣就可以了, 客戶端就依次是 _dataObject1.username, _dataObject2.username...

    等等: 我的變量里寫了特殊字符怎么辦? 例如我用的字符串是 'abc"'', 這時候我不得不拋出殺手锏了, 這就是用 Java 實現的 escape(), unescape() 方法, 其實本例中只需要 escape() 的 Java 版本就可以了(這個方案也幫助另一個同事解決了從JSP端傳遞的變量含有'號結果導致客戶端沒法顯示的問題):

    ??? public static String escape(String src) {
    ??? ??? int i;
    ??? ??? char j;
    ??? ??? StringBuffer tmp = new StringBuffer();
    ??? ??? tmp.ensureCapacity(src.length() * 6);
    ??? ??? for (i = 0; i < src.length(); i++) {
    ??? ??? ??? j = src.charAt(i);
    ??? ??? ??? if (Character.isDigit(j) || Character.isLowerCase(j)
    ??? ??? ??? ??? ??? || Character.isUpperCase(j))
    ??? ??? ??? ??? tmp.append(j);
    ??? ??? ??? else if (j < 256) {
    ??? ??? ??? ??? tmp.append("%");
    ??? ??? ??? ??? if (j < 16)
    ??? ??? ??? ??? ??? tmp.append("0");
    ??? ??? ??? ??? tmp.append(Integer.toString(j, 16));
    ??? ??? ??? } else {
    ??? ??? ??? ??? tmp.append("%u");
    ??? ??? ??? ??? tmp.append(Integer.toString(j, 16));
    ??? ??? ??? }
    ??? ??? }
    ??? ??? return tmp.toString();
    ??? }

    ??? public static String unescape(String src) {
    ??? ??? StringBuffer tmp = new StringBuffer();
    ??? ??? tmp.ensureCapacity(src.length());
    ??? ??? int lastPos = 0, pos = 0;
    ??? ??? char ch;
    ??? ??? while (lastPos < src.length()) {
    ??? ??? ??? pos = src.indexOf("%", lastPos);
    ??? ??? ??? if (pos == lastPos) {
    ??? ??? ??? ??? if (src.charAt(pos + 1) == 'u') {
    ??? ??? ??? ??? ??? ch = (char) Integer.parseInt(src
    ??? ??? ??? ??? ??? ??? ??? .substring(pos + 2, pos + 6), 16);
    ??? ??? ??? ??? ??? tmp.append(ch);
    ??? ??? ??? ??? ??? lastPos = pos + 6;
    ??? ??? ??? ??? } else {
    ??? ??? ??? ??? ??? ch = (char) Integer.parseInt(src
    ??? ??? ??? ??? ??? ??? ??? .substring(pos + 1, pos + 3), 16);
    ??? ??? ??? ??? ??? tmp.append(ch);
    ??? ??? ??? ??? ??? lastPos = pos + 3;
    ??? ??? ??? ??? }
    ??? ??? ??? } else {
    ??? ??? ??? ??? if (pos == -1) {
    ??? ??? ??? ??? ??? tmp.append(src.substring(lastPos));
    ??? ??? ??? ??? ??? lastPos = src.length();
    ??? ??? ??? ??? } else {
    ??? ??? ??? ??? ??? tmp.append(src.substring(lastPos, pos));
    ??? ??? ??? ??? ??? lastPos = pos;
    ??? ??? ??? ??? }
    ??? ??? ??? }
    ??? ??? }
    ??? ??? return tmp.toString();
    ??? }

    這樣, 在服務器端的時候可以變成:
    <%
    String username = "'abc\"''";// 其實這個普通子串轉換成 Java 語言中的字符串也有工具可以用的, 例如本人開發的 Native2JavaString, 改日再講.
    %>
    var _dataObject = {
    ?? username : "<%=escape(username)%>",
    ??????? age : 24
    };
    客戶端呢, 就可以簡單的來JS自帶的 unescape() 函數來取出原來的字符串:
    var responseText = xmlhttp.responseText;
    eval(responseText);
    alert("_dataObject.username=" + unescape(_dataObject.username));
    就是服務器端用 Java 寫的 escape(), 客戶端呢就用 JS 自帶的 unescape().

    4.?實例代碼
    好了, 說了這么多, 就推出個人的解決方案吧. 簡單的講就是我寫了一個腳本對象 AjaxFormer, 使用的是 escape來自動的將原來的 POST/GET 方式的提交代碼自動的轉換成 AJAX 的方式.

    /**
    ?* @constructor
    ?* This is a ajax form helper class.
    ?*
    ?* @param form - the document form
    ?* @param resultDivId - the result div id
    ?*/
    function AjaxFormer (form, resultDivId);

    構造器的第一個參數是個 form 對象, 第二個是個可選的結果 DIV 對象, 也就是說你可以指定服務器端返回的 HTML 代碼顯示的地方, 如果保持為空的話, 那么返回的 HTML?會被附加到文檔的末尾. 本對象有一個名字為 ajaxSubmitForm() 的方法來自動的遍歷所有表單元素, 然后將結果拼成一個字符串, 最后根據原來的表單的提交方式(get/post)來自動再客戶端用 AJAX 模擬提交這個表單到原來的表單的 action 屬性所指定的頁面中去.

    用法示例:
    <html>

    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>AJAX Form Submit Test</title>
    <script src='ajax_common.js'></script>

    </head>

    <body>
    <h3>AJAX Form Submit Test</h3>
    Fill the form and then click submit
    <form method="POST" id="form1" name="form1"
    action="form_action.jsp"
    onSubmit="former.ajaxSubmitForm();return false;">
    ??? <p><input type="hidden" name="hidden1" value="hiddenValue">
    ??? text:<input type="text" name="textf&1" size="20" value="text1">
    ??? checkbox:<input type="checkbox" name="checkbox1" value="ON" checked>
    ??? radio:<input type="radio" value="V1" checked name="radio1">
    ??? select:<select size="1" name="select1">
    ??? <option selected value="option1">D1</option>
    ??? </select>
    ??? <br>
    ??? <br>
    ??? <input type="submit" name="B1" value="submit">
    ??? <input type="reset" name="B2" value="reset">
    ??? </p>
    </form>

    <script type="text/javascript">
    var former = new AjaxFormer($('form1'));
    </script>
    </body>

    </html>

    紅色的字體就是您從一個非 AJAX 的表單提交改變成一個 AJAX 的表單提交所需要做的工作, 看上去夠簡單吧?

    運行時的效果如圖所示:
    http://m.tkk7.com/images/blogjava_net/beansoft/18680/o_ajaxFormer.png

    下載本文的源碼:?

    AJAXFormer.zip4KB

    將源碼解壓縮到JSP服務器的任意目錄下即可, 例如 $TOMCAT_HOME\webapps\ROOT 下, 然后在瀏覽器里鍵入:
    http://localhost:8080/ajax_form_submit.htm

    作者: beansoft@126.com?2006.12.25

    posted @ 2006-12-25 21:01 tory 閱讀(764) | 評論 (1)編輯 收藏

    ? 在這篇 ASP.NET 中Session 實現原理淺析[2] 狀態管理器 Blog中, Flier 老大向大家推薦了Java中幾種Cache的實現,于是我就按圖索驥,首先是找到OSCache的老家: OpenSymphony 。哇,這里的資源真多啊,簡直就是一個寶藏。為什么原來就沒有發現呢?感謝Flier老大了!
    ??????? 在OpenSymphony的主頁上,我看到了兩個讓我覺得很親切的項目:WebWork和Quarts。WebWork作為一個實現了IOC的輕量級Web Application Framework一直備受開發者的青睞;而Quarts更是在異步信息處理上大展拳腳了??吹搅死吓笥眩揖椭缓脮簳r將新歡OSCache擺一邊,找出我很久沒有聯系的老貓(Tomcat)去跟WebWork聊嗑了。
    ??????? 做好了一切的準備工作之后[1],我嘗試著做一個登陸注冊的功能,以體驗一下WebWork。跟其他的Web應用一樣,我們首先要建立一個標準的WEB-INF目錄(所謂標準就是目錄下面包含lib和classes子目錄以及Web.xml文件),接著在WEB-INF/lib下面放上WebWork所需要的.jar文件并在WEB-INF目錄下建立Web.xml文件[2]。在完成了這些千篇一律的工作之后,我仔細的看了一下Web.xml中內容,它里面只定義了一個servlet:webwork,其對應的class為com.opensymphony.webwork.dispatcher.ServletDispatcher,然后由webwork這個servlet去處理所有.action的請求??吹竭@里,我暗自竊喜,這跟我熟悉的WAF框架是十分類似的,只不過MainServlet變成了ServletDispatcher,.do的請求變成了.action而已。
    ??????? 接下來,就是到classes目錄下建立xwork.xml文件,這個文件跟WAF中的mappings.xml很相似,因為對.action的處理都是在這里被定義的,而WAF中關于.do的處理則定義在mapping.xml中。但是也有一些我并不清楚的東西,如package和Interceptor。在classes目錄下還要建立一個validator.xml文件,但是這個并不是必需的。做好了這些準備工作之后,就真正開始WebWork的體驗之旅了。
    ?????? ?1、建立一個index.jsp(以下為主要部分):
    ?<form?action="Login.action"?method="post">
    ??
    < table? cellspacing =0? width ="100%" >
    ????
    < tr >
    ??????
    < td > Login?ID:
    ????????
    < input? type ="text" ?name ="loginId" ?width =100? /> &nbsp;&nbsp;

    ??????????Password:
    ????????
    < input? type ="password" ?name ="loginPassword" ?width =100? /> &nbsp;&nbsp;
    ????????
    < input? type ="submit" ?value ="Login" ? />
    ??????
    </ td >
    ??????
    < td? align =right>
    ?????????
    Hello,?<ww:property?value ="loginId" ? />

    ??????
    </ td >
    ????
    </ tr >
    ??
    </ table >
    </ form > < SPAN>

    ????????需要注意的地方就是form的action屬性的寫法了;
    ??????? 2、在xwork.xml中增加相應的處理action的節點

    ?<action?name="Login"?class="fantasysoft.webwork.Login">
    ???
    < result? name ="error" ?type ="dispatcher" > index.jsp </ result >
    ???
    < result? name ="success" ?type ="dispatcher" > index.jsp </ result >
    </ action >

    ????????這里需要注意的是action節點中name的值要與index.jsp中定義的action的名字要嚴格匹配,對于大小 寫是敏感的。在action節點中還包含了節點,以說明處理action之后會可能出現的不同結果(name)和相應的處理方式(type)。譬如說,如果Login的這個action處理success了,則使用dispatcher將結果分(dispatch)到相應的頁面。而在WAF框架中并沒有這樣的定義,因為在默認情況下如果不成功則會返回當前頁面,不過可以定義FlowHandler,并擁有類似的功能且更加靈活;
    ??????? 3、實現類Login的代碼:

    package?fantasysoft.webwork;

    import?com.opensymphony.xwork.ActionSupport;

    public ? class ?Login?extends?ActionSupport
    {
    ????
    private
    ?String?loginId;
    ????
    private
    ?String?loginPassword;

    ????
    public ?String?getLoginPassword()?
    {
    ????????
    return
    ?loginPassword;
    ????}

    ????
    public ? void ?setLoginPassword(String?loginPassword)? {
    ????????
    this .loginPassword? =
    ?loginPassword;
    ????}

    ????
    public ?String?getLoginId()? {
    ????????
    return
    ?loginId;
    ????}

    ????
    public ? void ?setLoginId(String?loginId)? {
    ????????
    this .loginId? =
    ?loginId;
    ????}

    ????
    public ?String?execute()?throws?Exception {?????????????
    ????????
    if ?(!checkUserId() )? return
    ?ERROR;? // checkUserId is the method that will be implemented
    ????????????
    else ? return
    ?SUCCESS;
    ????}

    }

    ????????在代碼中,你會發現有兩個繼承變量ERROR與SUCCESS。這兩個變量是定義在Action這個接口的,而ActionSupport則實現了Action接口。在接口Action的代碼中,我們可以看到ERROR = "error"、SUCCESS = "success"。我們可以發現這兩個變量的值與xwork.xml中result子節點中的name的值是相匹配。除此之外,在代碼中,我也找不到了原來在開發中經常要用到的一個API:getParameter。事實上,將表單中數據析取出來的工作是由webwork這個唯一定義的servlet去完成的,而這個類會調用Login類中set的方法將用戶輸入的數據賦給Login類的屬性:loginId和loginPassword。在這里,我們也要跟前面index.jsp中的包含的標簽聯系起來。當數據被dispatch回index.jsp的時候,在index.jsp頁面render的過程中是調用了get的方法去獲取相應的數據的。
    ??????? 最后,我們可以總結一下,整個Web應用程序的處理流程了:
    ??????? 首先,當用戶提交了表單(form)至Login.action后,由web.xml中定義的唯一的一個servlet:webwork去處理這個請求。webwork會以action的name:Login到xwork.xml中尋找相應的處理action的類,于是就找到了fantasysoft.webwork包中的Login類,由Login類中的execute方法來處理提交的form的數據了;
    ????????然后,根據execute方法的返回值,再到xwork.xml中對應的action節點中去找匹配的result子節點;
    ??????? 最后,根據result子節點的定義,將處理結果分發(dispatch)或者重定向(redirect)至下一個頁面[3]

    ????????
    ????????[1] 準備工作可以參考
    WebWork?Getting Started ;
    ??????? [2]?web.xml文件的具體內容,可以參考
    WebWork Tutorial Lesson 2 ? ;
    ??????? [3] 對于result的Type的更多介紹,可以參考
    WebWork Tutorial Lesson 3 ?????

    /SPAN>
    posted @ 2006-12-24 22:42 tory 閱讀(161) | 評論 (0)編輯 收藏

         摘要: 一 Ajax-- 整合的力量 2005 年,伴隨著 Web2.0 的東風, Ajax 逐漸進入國內開發人...  閱讀全文
    posted @ 2006-12-21 22:40 tory 閱讀(295) | 評論 (0)編輯 收藏

    重載overloading和覆寫overriding哪個更早執行-- visitor幫助篇

    重載overloading和覆寫overriding哪個更早執行--?? visitor幫助篇
    一:問題提出
    雖然我們經常寫程序用到重載和覆寫,但是很少會考慮他們的執行順序。下邊的內容就是關于,他們同時出現時
    哪個先起作用:
    二:問題分析
    Java是"動態單分派靜態多分派語言",這個定義已經多次提起,如果你不了解這些概念,看這里"visitor模式準備"
    所以就注定了重載(靜態多分派)要早于覆寫(動態單分派),因為靜態分派是編繹期實現的,動態分派是執行期實現的。
    三:驗證
    簡單驗證一下,順變提高記憶

    ?1 public ? class ?Parent? {
    ?2 ???? public ? void ?run(Object?o) {
    ?3 ????????System.out.println( " in?Parent?+param:object " );
    ?4 ????}

    ?5 ???? public ? void ?run( int ?i) {
    ?6 ????????System.out.println( " in?Parent?+?param:int " );
    ?7 ????}

    ?8 }

    ?9
    10 public ? class ?Child? extends ?Parent? {
    11
    12 ???? public ? void ?run(Object?o) {
    13 ????????System.out.println( " in?Child?+param:Object " );
    14 ????}

    15 ???? public ? void ?run(String?str) {
    16 ????????System.out.println( " in?Child?+?param:String " );
    17 ????}

    18 ???? public ? static ? void ?main(String[]?args)? {
    19 ????????Parent?p? = ? new ?Child();
    20 ????????String?str? = ? new ?String();
    21 ????????p.run(str);
    22 ????}

    23 }


    運行結果是什么?
    in Child +param:Object
    inChild是確認的,但是為什么是object,而不是String,我們放入的就是String啊。
    首先來分析執行過程。
    定義韋類型Parent p在執行run(Str)的時候,

    1,如果是先執行重載,然後是執行覆寫的過程
    重載時因為找不到對應的String參數的函數,所以定位到接受父類的run(Object o)函數,
    覆寫時因為傳入時父類告訴子類的對象類型是Object,所以執行run(Object o);
    正是我們看到的結果,所以在Java中執行的順序是這樣的。

    2,為了對比,說一下先覆寫后重載的過程
    如果是先覆寫,再重載
    覆寫時因為確定對象實際是子類,所以直接覆寫到Child,然後重載,發現有對應的String為參數的函數
    執行,run(String str);
    應該輸出的結果:in Child +param:String
    但我們看到結果顯然是1,所以驗證了Java是先重載后覆寫的。


    最后的部分:

    看完本文,如果你對visitor模式有更多的興趣,想了解更多請看如下幾篇文章。
    1,靜態分派,動態分派,多分派,單分派 --------------?? visitor模式準備
    2,訪問差異類型的集合類 ------------------------?? visitor模式入門
    3,visitor模式理論及學術概念-------------------?? visitor模式深入
    4,visitor模式和其它模式的比較和關系-------------?? visitor模式總結?
    5,重載overloading和覆寫overriding哪個更早執行--?? visitor幫助篇 (本文)
    雖然排列順序是1,2,3,4,5 但是我個人建議的學習方式是2,1,3,4,5因為這個順序更方便一般人理解

    posted @ 2006-12-18 22:38 tory 閱讀(245) | 評論 (0)編輯 收藏

    主站蜘蛛池模板: 亚洲国产专区一区| 动漫黄网站免费永久在线观看| 国产AV无码专区亚洲AV琪琪| 亚洲性无码AV中文字幕| 亚洲日本乱码卡2卡3卡新区| 亚洲乱码中文字幕小综合| 亚洲成av人片在线看片| 亚洲精品午夜在线观看| 亚洲色图黄色小说| 亚洲精品国产福利片| 亚洲综合校园春色| 亚洲国产午夜精品理论片在线播放| 亚洲偷自拍另类图片二区| 亚洲av成人一区二区三区观看在线| 国产成人精品久久亚洲高清不卡| 国产成人亚洲精品无码AV大片| 激情婷婷成人亚洲综合| 一级一看免费完整版毛片| 两个人看的www免费视频| 国产亚洲精aa成人网站| 青娱乐免费在线视频| 日本XXX黄区免费看| 日本一道一区二区免费看| 免费人成激情视频| 亚洲色偷偷综合亚洲AVYP| 亚洲成年轻人电影网站www| 亚洲国产精品成人精品软件| 亚洲综合国产成人丁香五月激情| 在线亚洲v日韩v| 在线观看片免费人成视频播放| 57pao国产成视频免费播放| 成人免费福利电影| 亚洲国产黄在线观看| 日日AV拍夜夜添久久免费| ZZIJZZIJ亚洲日本少妇JIZJIZ| 久久久久亚洲AV无码专区首| 亚洲人成在线中文字幕| 校园亚洲春色另类小说合集| 最近中文字幕大全免费版在线 | 久久亚洲精品成人无码网站| avtt天堂网手机版亚洲|