隨筆 - 10, 文章 - 0, 評論 - 7, 引用 - 0
          數據加載中……

          2007年6月7日

          關于appfuse的探討

                項目在緊張的生活中很快就要結束了,一直以來,都是由于工作的繁忙,沒有時間去寫自己的blog.這段時間終于可以稍微閑下來了,覺得應該把這一階段的工作總結一下了,但是拿起鍵盤,思緒卻有些散亂,想寫的很多,卻也不知道怎么來寫,還是慢慢來吧.
             首先說一下整體框架appfuse,它是集成了當今最流行的web應用框架的更高層次的web開發框架.也可以說是一個web開發的基本平臺,它將當前最流行的一些技術,比如hibernate,spring,struts,DBUnit,ant,log4j,xdoclet,sitemesh,velocity,jstl,webwork,等等都集成了進來,在國內能夠將這些都應用進來的并不多見.

          待續....

          posted @ 2007-06-07 23:56 LiuTing 閱讀(251) | 評論 (0)編輯 收藏

          2007年5月29日

          JS常見函數

          1.常規函數  
            javascript常規函數包括以下9個函數:  
            (1)alert函數:顯示一個警告對話框,包括一個OK按鈕。  
            (2)confirm函數:顯示一個確認對話框,包括OK、Cancel按鈕。  
            (3)escape函數:將字符轉換成Unicode碼。  
            (4)eval函數:計算表達式的結果。  
            (5)isNaN函數:測試是(true)否(false)不是一個數字。  
            (6)parseFloat函數:將字符串轉換成符點數字形式。  
            (7)parseInt函數:將符串轉換成整數數字形式(可指定幾進制)。  
            (8)prompt函數:顯示一個輸入對話框,提示等待用戶輸入。例如:  
            (9)unescape函數:解碼由escape函數編碼的字符。  
            2.數組函數  
            javascript數組函數包括以下4個函數:  
            (1)join函數:轉換并連接數組中的所有元素為一個字符串。例:  
           
           程序代碼  
              function JoinDemo()  
              {  
               var a, b;  
               a = new Array(0,1,2,3,4);  
               b = a.join("-");//分隔符  
               return(b);//返回的b=="0-1-2-3-4"  
              }   
             
           (2)langth函數:返回數組的長度。例:  
                 
           程序代碼  
          function LengthDemo()  
              {  
               var a, l;  
               a = new Array(0,1,2,3,4);  
               l = a.length;  
               return(l);//l==5  
              }   
           
            (3)reverse函數:將數組元素順序顛倒。例:  
                
           程序代碼  
          function ReverseDemo()  
             {  
              var a, l;  
              a = new Array(0,1,2,3,4);  
              l = a.reverse();  
              return(l);  
             }   
            (4)sort函數:將數組元素重新排序。例:  
                 
           程序代碼  
          function SortDemo()  
              {  
               var a, l;  
               a = new Array("X" ,"y" ,"d", "Z", "v","m","r");  
               l = a.sort();  
               return(l);  
              }   
            3.日期函數  
            javascript日期函數包括以下20個函數:  
            (1)getDate函數:返回日期的“日”部分,值為1~31。例:  
                
           程序代碼  
          function DateDemo()  
             {  
              var d, s = "Today's date is: ";  
              d = new Date();  
              s += (d.getMonth() + 1) + "/";  
              s += d.getDate() + "/";  
              s += d.getYear();  
              return(s);  
             }   
            (2)getDay函數:返回星期幾,值為0~6,其中0表示星期日,1表示星期一,...,6表示星期六。例:  
                
           程序代碼  
          function DateDemo()  
             {  
              var d, day, x, s = "Today is: ";  
              var x = new Array("Sunday", "Monday", "Tuesday");  
              var x = x.concat("Wednesday","Thursday", "Friday");  
              var x = x.concat("Saturday");  
              d = new Date();  
              day = d.getDay();  
              return(s += x[day]);  
             }   
            (3)getHouse函數:返回日期的“小時”部分,值為0~23。例。  
                
           程序代碼  
          function TimeDemo()  
             {  
              var d, s = "The current local time is: ";  
              var c = ":";  
              d = new Date();  
              s += d.getHours() + c;  
              s += d.getMinutes() + c;  
              s += d.getSeconds() + c;  
              s += d.getMilliseconds();  
              return(s);  
             }   
            (4)getMinutes函數:返回日期的“分鐘”部分,值為0~59。見上例。  
            (5)getMonth函數:返回日期的“月”部分,值為0~11。其中0表示1月,2表示3月,...,11表示12月。見前面的例子。  
            (6)getSeconds函數:返回日期的“秒”部分,值為0~59。見前面的例子。  
            (7)getTime函數:返回系統時間。  
                
           程序代碼  
          function GetTimeTest()  
             {  
              var d, s, t;  
              var MinMilli = 1000 * 60;  
              var HrMilli = MinMilli * 60;  
              var DyMilli = HrMilli * 24;  
              d = new Date();  
              t = d.getTime();  
              s = "It's been " 
              s += Math.round(t / DyMilli) + " days since 1/1/70";  
              return(s);  
             }   
            (8)getTimezoneOffset函數:返回此地區的時差(當地時間與GMT格林威治標準時間的地區時差),單位為分鐘。  
                
           程序代碼  
          function TZDemo()  
             {  
              var d, tz, s = "The current local time is ";  
              d = new Date();  
              tz = d.getTimezoneOffset();  
           
              if (tz 的鏈接點的名稱,另一個函數link設定的URL地址。  
            (2)big函數:將字體加到一號,與...標簽結果相同。  
            (3)blink函數:使字符串閃爍,與...標簽結果相同。  
            (4)bold函數:使字體加粗,與...標簽結果相同。  
            (5)charAt函數:返回字符串中指定的某個字符。  
            (6)fixed函數:將字體設定為固定寬度字體,與...標簽結果相同。  
            (7)fontcolor函數:設定字體顏色,與標簽結果相同。  
            (8)fontsize函數:設定字體大小,與標簽結果相同。  
            (9)indexOf函數:返回字符串中第一個查找到的下標index,從左邊開始查找。  
            (10)italics函數:使字體成為斜體字,與...標簽結果相同。  
            (11)lastIndexOf函數:返回字符串中第一個查找到的下標index,從右邊開始查找。  
            (12)length函數:返回字符串的長度。(不用帶括號)  
            (13)link函數:產生一個超級鏈接,相當于設定的URL地址。  
            (14)small函數:將字體減小一號,與...標簽結果相同。  
            (15)strike函數:在文本的中間加一條橫線,與...標簽結果相同。  
            (16)sub函數:顯示字符串為下標字(subscript)。  
            (17)substring函數:返回字符串中指定的幾個字符。  
            (18)sup函數:顯示字符串為上標字(superscript)。  
            (19)toLowerCase函數:將字符串轉換為小寫。  
            (20)toUpperCase函數:將字符串轉換為大寫。  
           
          //校驗是否全由數字組成  
           
           程序代碼  
          function isDigit(s)  
          {  
          var patrn=/^[0-9]{1,20}$/;  
          if (!patrn.exec(s)) return false 
          return true 
          }  
           
          //校驗登錄名:只能輸入5-20個以字母開頭、可帶數字、“_”、“.”的字串  
           
           程序代碼  
          function isRegisterUserName(s)  
          {  
          var patrn=/^[a-zA-Z]{1}([a-zA-Z0-9]|[._]){4,19}$/;  
          if (!patrn.exec(s)) return false 
          return true 
          }  
           
          //校驗用戶姓名:只能輸入1-30個以字母開頭的字串  
           
           程序代碼  
          function isTrueName(s)  
          {  
          var patrn=/^[a-zA-Z]{1,30}$/;  
          if (!patrn.exec(s)) return false 
          return true 
          }  
           
          //校驗密碼:只能輸入6-20個字母、數字、下劃線  
           
           程序代碼  
          function isPasswd(s)  
          {  
          var patrn=/^(\w){6,20}$/;  
          if (!patrn.exec(s)) return false 
          return true 
          }  
           
          //校驗普通電話、傳真號碼:可以“+”開頭,除數字外,可含有“-”  
           
           程序代碼  
          function isTel(s)  
          {  
          //var patrn=/^[+]{0,1}(\d){1,3}[ ]?([-]?(\d){1,12})+$/;  
          var patrn=/^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$/;  
          if (!patrn.exec(s)) return false 
          return true 
          }  
           
          //校驗手機號碼:必須以數字開頭,除數字外,可含有“-”  
           
           程序代碼  
          function isMobil(s)  
          {  
          var patrn=/^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$/;  
          if (!patrn.exec(s)) return false 
          return true 
          }  
           
          //校驗郵政編碼  
           
           程序代碼  
          function isPostalCode(s)  
          {  
          //var patrn=/^[a-zA-Z0-9]{3,12}$/;  
          var patrn=/^[a-zA-Z0-9 ]{3,12}$/;  
          if (!patrn.exec(s)) return false 
          return true 
          }  
           
          //校驗搜索關鍵字  
           
           程序代碼  
          function isSearch(s)  
          {  
          var patrn=/^[^`~!@#$%^&*()+=|\\\][\]\{\}:;\'\,.<>/?]{1}[^`~!@$%^&()+=|\\\][\]\{\}:;\'\,.<>?]{0,19}$/;  
          if (!patrn.exec(s)) return false 
          return true 
          }  
           
           程序代碼  
          function isIP(s) //by zergling  
          {  
          var patrn=/^[0-9.]{1,20}$/;  
          if (!patrn.exec(s)) return false 
          return true 
          }  

          posted @ 2007-05-29 18:03 LiuTing 閱讀(300) | 評論 (0)編輯 收藏

          2007年5月25日

          DISPALYTAG的用法

          1) Caption指標題
          2) name:數據源
          3) defaultsort:排序列,一般不需要
          4) defaultorder:排序方式
          5) class:表格顯示的樣式
          6) varTotals:需要統計(總計)
          7) decorator="totals":表示使用指定的decorator。現在僅在同時使用小計、合計時用到,自己也可以定制。
          8) <display:column 部分:
            property指數據中的列名
            title指顯示的標題
            format指數據的格式化樣式,
            total表示該字段是否需要作統計。
            style="width:20%"可以設置寬度。
            也可以用
            <display:column title="請假時間">
            <fmt:formatDate value="${currentRowObject.QJSJ}" pattern="yyyy-MM-dd"/>
            </display:column>表現。
            group="1"表示進行group的字段。
          9) 在表格中建立一個連接:
            <display:column title="部別">
            <a href="<c:out value="${pageContext.request.contextPath}"/>
            /holidayDefaultSearchStatView.do?type=
            <c:out value="${currentRowObject.CJDM}"/>&SYD=
            <c:out value="${currentRowObject.DWDM}"/>" target="_blank">
            <c:out value="${currentRowObject.DWMC}"/>
            </a>
            </display:column>
          10) 由于該tag只有合計時,沒有合計那一列,所以實現的時候以<display:footer>實現。
            可以通過totalMap對象獲取合計的數據,如totalMap.colomn1獲取合計的第一列數值。
          11) 標題頭不顯示<display:setProperty name="basic.show.header" value="false" />
          12) 自己定制表頭:<display:caption>
             使用decorator:
             <jsp:scriptlet>
             org.displaytag.decorator.TotalTableDecorator totals =
             new org.displaytag.decorator.TotalTableDecorator();
                 totals.setTotalLabel("合計");
                 totals.setSubtotalLabel("小計");
                 pageContext.setAttribute("totals", totals);
             </jsp:scriptlet>
          實例:
          <display:caption>這是表標題</display:caption>
           <display:table
            name="${model.rowToColumnStatResult}" defaultsort="1"
            class="simple" defaultorder="ascending" varTotals="totalMap">
            <display:column property="GCWZ" title="部門"/>
             <c:forEach items="${model.YList.YList}" var="yColumn">
             <c:forEach items="${model.rowToColumnStatResult[0]}"
                var="mapEntry">
              <c:if test="${mapEntry.key == yColumn}">
               <th>
                 <display:column property="${mapEntry.key}"
                 title="${mapEntry.key}"
                 format="{0,number,####.##}" total="true"/>
               </th>
              </c:if>
             </c:forEach>
             </c:forEach>
            <display:column property="小計"
                title="小計"
                format="{0,number,####.##}" total="true"/>
           <display:footer>
           <tr>
            <td>總計</td>
            <c:forEach items="${model.YList.YColumn}" var="yColumn">
            <td><fmt:formatNumber value="${totalMap[yColumn]}"
                  pattern="####.##"/>
            </td>
            </c:forEach>
           </tr>
           </display:footer>
          </display:table>
           

          另外一個例子:
          <display:table name="${model.statResult}" class="simple"
           varTotals="totalMap">
           <display:column property="XMMC" title="項目名稱" />
           <display:column property="KSRQ" title="開始日期" />
           <display:column property="FZRXM" title="負責人姓名" />
           <display:column property="GKDW" title="掛靠單位" />
           <display:column property="JFLY" title="經費來源" />
           <display:column property="XMZJF" title="項目總經費" total="true" />
           <display:column property="DNDKJF" title="當年到款經費" total="true"/>
           <display:footer>
            <tr><td colspan="5">總計</td>
             <td>
              <fmt:formatNumber value="${totalMap.column6}"
               pattern="####.####" />
             </td>
             <td>
              <fmt:formatNumber value="${totalMap.column7}"
               pattern="####.####" />
             </td>
            </tr>
           </display:footer>
          </display:table>
          總計某一列的方法:
          ${totalMap.column?}    ?為該列號
          colspan="5":表示這個單元格占5個單元格
          項目名稱 開始日期  負責人姓名 掛靠單位 經費來源 項目總經費 當年到款經費
                                                             531      400
                                                             151       10
          -------------------------------------
          總計                              682     500 

          posted @ 2007-05-25 10:42 LiuTing 閱讀(760) | 評論 (0)編輯 收藏

          2007年5月20日

          DWRUtils API 使用方法

          $("precloneNode1suf") 取得該對象;

          DWRUtil.selectRange("selectRangeBasic", 5, 15) 選中selectRangeBasic文本框里面從第五個字符到第15個字符之間的字符.

          DWRUtil._getSelection("selectRangeBasic") 得到selectRangeBasic文本框里選中的字符.

          var arrayFive = [ 'One', 'Two', 'Three', 'Four', 'Five' ];
          DWRUtil.addOptions('addOptionsBasic', arrayFive); 將數組添加到下拉菜單里面去;

          DWRUtil.getValue('addOptionsBasic') 得到 addOptionsBasic 對象的值;
          DWRUtil.getValue("precloneNode1Inner1suf", { textContent:true }); 后面加個參數,在 precloneNode1Inner1suf元素為"UL" 時,它返回了元素里面得值,也就是說去掉了HTML標簽部分.

          DWRUtil.getText('addOptionsBasic') 得到下拉框 addOptionsBasic 顯示的文本;

          var arrayObject = [
          { name:'One', value:'1' },
          { name:'Two', value:'2' },
          { name:'Three', value:'3' },
          { name:'Four', value:'4' },
          { name:'Five', value:'5' }
          ];
          DWRUtil.addOptions('addOptionsObject1', arrayObject, "name"); 將數組添加到下拉菜單里面去;后面的參數是確定那個是給用戶顯示的文本,同時也是值;

          DWRUtil.addOptions('addOptionsObject1', arrayObject, "name","value"); 同上,不過后面參數是: 3=文本;4=值;

          var map = { one:1, two:2, three:3, four:4, five:5 };
          DWRUtil.addOptions('addOptionsMap1', map); 同上, one 是值;1 是文本;
          DWRUtil.addOptions('addOptionsMap1', map,true); 同上, 1 是值;one 是文本;

          -------------------------------------------------------------------------------------
          <ul id="removeItems">
          <li>One</li><li>Two</li><li>Three</li><li>Four</li><li>Five</li>
          </ul>

          如果是列表顯示,如上;則上面所有方法和select 下拉框使用一樣;
          -------------------------------------------------------------------------------------
          DWRUtil.cloneNode('cloneNode1', { idPrefix:'pre', idSuffix:'suf' });克隆一個節點,參數一為要克隆的節點的id,第二個參數是在克隆的節點id前面加pre,后面加suf.(注意:如果該節點有子節點的話,子節點的名字也一樣加)

          DWRUtil.addRows(id, array, cellfuncs, [options]);
          原理:

          for each member in array
          for each function in cellfuncs
          create cell from cellfunc(array[i])
          循環數組,循環函數,建立單元調用函數;(順序決定)

          例如:
          DWRUtil.addRows('addRowsBasic', arrayFive, [
          function(data) { return data; },
          function(data) { return data.toUpperCase(); },
          function(data) {
          var input = document.createElement("input");
          input.setAttribute("type", "button");
          input.setAttribute("value", "DOM Test");
          input.setAttribute("onclick", "alert('" + data + "');");
          return input;
          },
          function(data) { return "<input type='button' value='innerHTML Test' onclick='alert(\"" + data + "\");'>"; }
          ]);

          高級部分:
          第四個參數為對單元的高級操作,主要下面的兩個方法;
          function defaultRowCreator(options) {
          return document.createElement("tr");
          };

          function defaultCellCreator(options) {
          return document.createElement("td");
          };

          例子:
          DWRUtil.addRows( "demo2",[ 'Africa', 'America', 'Asia', 'Australasia', 'Europe' ] , cellFuncs, {
          rowCreator:function(options) {
          var row = document.createElement("tr");
          var index = options.rowIndex * 50;
          row.style.color = "rgb(" + index + ",0,0)";
          return row;
          },
          cellCreator:function(options) {
          var td = document.createElement("td");
          var index = 255 - (options.rowIndex * 50);
          td.style.backgroundColor = "rgb(" + index + ",255,255)";
          td.style.fontWeight = "bold";
          return td;
          }
          });

          其中 options 參數的屬性可用的為:(沒試過,自己試試吧)

          rowData: the element value from the array (the same for all cells in a row)
          rowIndex: the key (if map) or index (if array) from the collection
          rowNum: The row number counting from 0 in this section (so if you are using tbody, it counts rows in the tbody and not the whole table)
          data: The 'computed' data value for the cell (cellCreators only)
          cellNum: The cell number that we are altering counting from 0 (cellCreators only)


          DWRUtil.setValues(); 批量設置值;
          var settings = {
          setValuesDiv:"setValuesDiv",
          setValuesSpan:"setValuesSpan",
          setValuesSelect:"two",
          setValuesText:"setValuesText",
          setValuesPassword:"AB",
          setValuesTextarea:"setValuesTextarea",
          setValuesButton1:"B1-Two",
          setValuesButton2:"B2-Two",
          setValuesRadio1:true,
          setValuesRadio2:false,
          setValuesRadio3:"one",
          setValuesRadio4:"two",
          setValuesCheckbox1:true,
          setValuesCheckbox2:false
          };
          DWRUtil.setValues(settings);

          DWRUtil.getValues(empty);批量獲取值;
          var empty = {
          setValuesDiv:null,
          setValuesSpan:null,
          setValuesSelect:null,
          setValuesText:null,
          setValuesPassword:null,
          setValuesTextarea:null,
          setValuesButton1:null,
          setValuesButton2:null,
          setValuesRadio1:null,
          setValuesRadio2:null,
          setValuesRadio3:null,
          setValuesRadio4:null,
          setValuesCheckbox1:null,
          setValuesCheckbox2:null
          };
          DWRUtil.getValues(empty);

          DWRUtil.useLoadingMessage("Ping");//類似gmail那個樣子,在右上角顯示加載"ping";可用自定樣式,具體查詢;
          http://getahead.ltd.uk/dwr/browser/util/useloadingmessage

          DWRUtil.toDescriptiveString("id",數字);彈出調試信息,數字為0,1,2.一級比一級高.

          DWRUtil.onReturn(event, submitFunction);一般在form表單里面,防止在文本框上按回車就提交表單.
          例如:
          <input type="text"
          onkeypress="DWRUtil.onReturn(event, submitFunction)"/>
          <input type="button" onclick="submitFunction()"/>

          posted @ 2007-05-20 12:46 LiuTing 閱讀(616) | 評論 (1)編輯 收藏

          DWR框架實現Ajax

                Ajax是時下比較流行的一種web界面設計新思路,其核心思想是從瀏覽器獲取XMLHttp對象與服務器端進行交互. DWR(Direct Web Remoting)就是實現了這種Ajax技術的一種web框架. 最近做的項目中我也將它用上了,感覺很是方便,比如動態生成javascript代碼,隱藏的http協議,java代碼和javascript交互的是javascript的對象(或字符串).  下面是我整理的文檔.
            DWR主要由兩部門組成。javascript與web服務器通信并更新web頁;運行在web服務器的Servlet處理請求并把響應發回瀏覽器。

             1  .  配置web.xml
          <servlet>
            <servlet-name>dwr-invoker</servlet-name>
            <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
          </servlet>
          <servlet-mapping>
            <servlet-name>dwr-invoker</servlet-name>
            <url-pattern>/dwr/*</url-pattern>
          </servlet-mapping>

            2    當我們想看dwr自動生成的測試頁時,可在java代碼
          servlet中加
          <init-param>
            <param-name>debug</param-name>
            <param-value>true</param-value>
          </init-param>

          這個參數DWR默認是false.如果選擇true.我們可以通過url http://localhost:port/app/dwr ,你就可以看到你部署的每個DWR class。并且可以測試java代碼的每個方法是否運行正常。為了安全考慮,在正式環境下你一定把這個參數設為false.

          3  log信息配置

          我喜歡用log4j輸出日志,那么在log4j.properties下加,log4j.logger.uk.ltd.getahead.dwr = debug。這樣可以看DWR的調試日志。

          4  配置dwr.xml (和web.xml同目錄)
           
          <create creator="new" javascript="JDate">
          <param name="class" value="java.util.Date"/>
          </create>

          這里的多數元素都是可選的 - 你真正必須知道的是指定一個creator和一個javascript名字。

          creator屬性 是必須的 - 它用來指定使用那種創造器。

          默認情況下DWR1.1有8種創造器。它們是:

          • new: 用Java的new關鍵字創造對象。
          • none: 它不創建對象,看下面的原因。 (v1.1+)
          • scripted: 通過BSF使用腳本語言創建對象,例如BeanShell或Groovy。
          • spring: 通過Spring框架訪問Bean。
          • jsf: 使用JSF的Bean。 (v1.1+)
          • struts: 使用Struts的FormBean。 (v1.1+)
          • pageflow: 訪問Beehive或Weblogic的PageFlow。 (v1.1+)

          javascript屬性 用于指定瀏覽器中這個被創造出來的對象的名字。你不能使用Javascript的關鍵字。

          scope屬性 非常類似servlet規范中的scope。 它允許你指定這個bean在什么生命范圍。選項有"application", "session", "request" 和"page"。這些值對于Servlet和JSP開發者來說應該相當熟悉了。

          scope屬性是可選的。默認是"page"。如果要使用"session"需要cookies。當前的DWR不支持ULR重寫。

          param元素 被用來指定創造器的其他參數,每種構造器各有不同。例如,"new"創造器需要知道要創建的對象類型是什么。每一個創造器的參數在各自的文檔中能找到。請查看上面的鏈接。

          include和exclude元素 允許創造器來限制類中方法的訪問。一個創造器必須指定include列表或exclude列表之一。如果是include列表則暗示默認的訪問策略是"拒絕";如果是exclude列表則暗示默認的訪問策略是"允許"。


          5 dwr.jar下載后放lib下

          源碼淺析

          dwr的設計很象webwork2的設計,隱藏http協議,擴展性,兼容性及強。

          通過研究uk.ltd.getahead.dwr.DWRServlet這個servlet來研究下dwr到底是如何工作的。

          <servlet>
            <servlet-name>dwr-invoker</servlet-name>
            <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
          </servlet>
          <servlet-mapping>
            <servlet-name>dwr-invoker</servlet-name>
            <url-pattern>/dwr/*</url-pattern>
          </servlet-mapping>

          這樣/dwr/*下的所有的請求都是由這個servlet來處理,到底生理了什么呢,我們還是以例子來說明吧.

          1 web服務器啟動,DWRServlet init()方法調用,init主要做了以下工作。
          設置日志級別、實例化DWR用到的單例類(這些類在jvm中只有一個實例對象)、讀去配置文件(包括dwr.jar包中的dwr.xml,WEB-INF/dwr.xml. config*.xml)。
          2 請求處理
          DWRServlet.doGet, doPost方法都調用processor.handle(req, resp)方法處理。Processor對象在init()方法中已經初始化了。 

          代碼
          public void handle(HttpServletRequest req, HttpServletResponse resp)  
                  throws IOException  
              {  
                  String pathinfo = req.getPathInfo();  
                  if(pathinfo == null || pathinfo.length() == 0 || pathinfo.equals("/"))  
                  {  
                      resp.sendRedirect(req.getContextPath() + req.getServletPath() + '/' + "index.html");  
                  } else 
                  if(pathinfo != null && pathinfo.equalsIgnoreCase("/index.html"))  
                  {  
                      doIndex(req, resp);  
                  } else 
                  if(pathinfo != null && pathinfo.startsWith("/test/"))  
                  {  
                      doTest(req, resp);  
                  } else 
                  if(pathinfo != null && pathinfo.equalsIgnoreCase("/engine.js"))  
                  {  
                      doFile(resp, "engine.js", "text/javascript");  
                  } else 
                  if(pathinfo != null && pathinfo.equalsIgnoreCase("/util.js"))  
                  {  
                      doFile(resp, "util.js", "text/javascript");  
                  } else 
                  if(pathinfo != null && pathinfo.equalsIgnoreCase("/deprecated.js"))  
                  {  
                      doFile(resp, "deprecated.js", "text/javascript");  
                  } else 
                  if(pathinfo != null && pathinfo.startsWith("/interface/"))  
                  {  
                      doInterface(req, resp);  
                  } else 
                  if(pathinfo != null && pathinfo.startsWith("/exec"))  
                  {  
                      doExec(req, resp);  
                  } else 
                  {  
                      log.warn("Page not found. In debug/test mode try viewing /[WEB-APP]/dwr/");  
                      resp.sendError(404);  
                  }  
              } 

          dwr/*處理的請求也就這幾種。

          (1)dwr/index.html,dwr/test/這種只能在debug模式下使用,調試用。
          dwr/engine.js,dwr/util.js,dwr/deprecated.js當這個請求到達,從dwr.jar包中讀取文件流,響應回去。(重復請求有緩存)
          (2)當dwr/interface/這種請求到來,(例如我們在index.html中的 <script type='text/javascript' src='dwr/interface/JDate.js'></script>)DWR做一件偉大的事。把我們在WEB-INF/dwr.xml中的
          <create creator="new" javascript="JDate">
          <param name="class" value="java.util.Date"/>
          </create>
          java.util.Date轉化為javascript函數。
          http://localhost:port/simpledwr/dwr/interface/JDate.js看看吧。
          細節也比較簡單,通過java反射,把方法都寫成javascript特定的方法。(我覺得這些轉換可以放到緩存里,下次調用沒必要再生成一遍,不知道作者為什么沒這樣做)。
          (3)dwr/exec
          javascript調用方法時發送這種請求,可能是XMLHttpRequest或IFrame發送。
          當然,javascript調用的方法簽名與java代碼一致,包括參數,還有javascript的回調方法也傳到了服務器端,在服務器端很容易實現。回調方法的java的執行結果 返回類似 <script>callMethod(結果)<script>的javascript字符串,在瀏覽器執行。哈,一切就這么簡單,巧妙。

          我這里還有DWR中文文檔. http://www.aygfsteel.com/Files/LiuTing/DWR中文文檔.rar





          posted @ 2007-05-20 12:45 LiuTing 閱讀(4340) | 評論 (4)編輯 收藏

          Acegi工作流程

          任何一個安全系統都包括authentication和authorization兩部分,Acegi相同。

          第一部分:authentication

          1、acegi通過AuthenticationProcessingFilter攔截login請求獲取Principal和Credential信息(通俗一點就是用戶名和密碼);

          2、驗證用戶名密碼,由這個Filter調用認證管理器AuthenticatiomManager進行驗證。

          AuthenticatiomManager本身并不具備驗證的功能,它相當與是一個驗證控制器,由它來管理驗證的過程及方式。AuthenticatiomManager是通過調用provider來進行驗證的,一個manager中可以具有多個provider,但只要有一個provider驗證通過,manager就認為驗證成功。

          這部分要明白三點:一,provider是可以配置進去的,因為acegi是基于spring的;二是AuthenticatiomManager是可以被重寫的,你可以將manager改成你自己希望的控制器;三,好好利用event,這是標準的observer模式。acegi中的設計模式研究將在以后的貼子中討論。

          3、provider進行驗證。

          provider是真正的驗證模塊,并且決定了驗證的模式。provider目前acegi提供了dao、jaas,cas,x509,ldap等幾種驗證方式,這些驗證方式的具體內容可以查閱acegi的文檔。provider驗證通過后將Authentication對象返回。

          4、AuthenticationProcessingFilter將對象保存到ContextHolder中。Authentication部分結束。

          第二部分:authorization

          1、用戶提交請求,攔截器FilterSecurityInterceptor攔截請求,攔截器是一個Filter.

          2 、鑒權,攔截器調用AccessDecisionManager進行鑒權。

          AccessDecisionManager是通過投票的方式來決定是否有權限訪問資源。所謂投票就要包括投票的參與者和投票的策略。

          投票的參與者decisionVoters,這是AccessDecisionManager的一個屬性。decisionVoter能從某一個角度決定用戶是否能訪問資源,例如RoleVoter來判斷用戶的角色是否有權限訪問資源,MaxuserVoter來決定某個資源的訪問用戶數是否已經達到了最大值等。

          投票策略。投票的策略是通過不同的AccessDecisionManager來實現的,例如acegi提供的AffirmativeBased對象,這個對象的策略就是只要有一個投票通過就全體通過。UnanimousBased對象的策略是必須全體投票通過才能通過。但在大多數情況下acegi提供的AccessDecisionManager不能滿足我們的要求,這就需要我們去實現AccessDecisionManager接口,去定制適合自己項目的策略。

          3、投票。投票對象必須實現AccessDecisionVoter接口。投票對象關注的是某一方面的決定權,如果投票通過則Vote方法來完成的。vote方法必須返回一個int型的數據代表投票結果,它們是AccessDecisionVoter的三個靜態成員屬性:ACCESS_ABSTAIN,,ACCESS_DENIED和ACCESS_GRANTED,它們分別是棄權,否決和贊成。
           

          安全攔截器

            攔截器如何工作
            MethodInvocation攔截器
            FilterInvocation攔截器

          認證

            認證請求
            認證管理器
            Authentication Provider

          授權

            Access Decision Manager
            Voting Decision Manager
            授權管理推薦

          ContextHolder的用戶接口

            用戶接口目標
            HTTP會話認證
            HTTP Basic認證

          posted @ 2007-05-20 12:44 LiuTing 閱讀(650) | 評論 (1)編輯 收藏

          使用Acegi時獲取用戶信息的幾個函數

          1 /**
           2    * 取得當前用戶名
           3    *  @return
           4     */

           5    public   static  String getUsername() {
           6     Context context = ContextHolder.getContext();
           7      if (context != null ) {
           8        if (context  instanceof  SecureContext) {
           9         SecureContext sc = (SecureContext)context;
          10         Authentication auth = sc.getAuthentication();
          11          if (auth != null ) {
          12           Object principal = auth.getPrincipal();
          13            if (principal  instanceof  UserDetails)  {
          14              return  ((UserDetails)principal).getUsername();
          15           }
          else {
          16              return  principal.toString();
          17           }

          18         }

          19       }

          20     }

          21      return   null ;
          22   }

          23    /**
          24    * 取得當前用戶密碼
          25    *  @return
          26     */

          27    public   static  String getPassword() {
          28     Context context = ContextHolder.getContext();
          29      if (context != null ) {
          30        if (context  instanceof  SecureContext) {
          31         SecureContext sc = (SecureContext)context;
          32         Authentication auth = sc.getAuthentication();
          33          if (auth != null ) {
          34           Object principal = auth.getPrincipal();
          35            if (principal  instanceof  UserDetails)  {
          36              return  ((UserDetails)principal).getPassword();
          37           }
          else {
          38              return   null ;
          39           }

          40         }

          41       }

          42     }

          43      return   null ;
          44   }

          45    /**   */ /**
          46    * 取得當前用戶session id
          47    *  @return  sessionid or null
          48     */

          49    public   static  String getSessionID() {
          50     Context context = ContextHolder.getContext();
          51      if (context != null ) {
          52        if (context  instanceof  SecureContext) {
          53         SecureContext sc = (SecureContext)context;
          54         Authentication auth = sc.getAuthentication();
          55          if (auth != null ) {
          56           Object details = auth.getDetails();
          57            if (details  instanceof  WebAuthenticationDetails)  {
          58              return  ((WebAuthenticationDetails)details).getSessionId();
          59           }
          else {
          60              return   null ;
          61           }

          62         }

          63       }

          64     }

          65      return   null ;
          66   }

          posted @ 2007-05-20 12:43 LiuTing 閱讀(368) | 評論 (0)編輯 收藏

          Acegi使用2

          流程說完了,接下對上面提到的問題解釋一下:

          引用

          先使用URL攔截的方式去對付大多數的情況,然后少數URL搞不定的再加一個接口,讓Action自己去判別。這樣用兩個攔截器對Action進行攔截,如果Action實現了hasPermission接口,那么就交給Action自己判斷,如果Action沒有該接口,就查找內部的URL和權限的對照表來判斷。

           

          這個情況比較復雜,因為是要對Action進行調用,所以要看使用的web框架來定奪。是用不同Web框架要是用不同的Web框架攔截器。所以恐怕acegi力不從心,挺多在filter里面配置一下是否要是用Action自身校驗。但是想法很好,贊。

           

          引用

          你怎么把信息有效的傳遞給Web層和其他的Facade層進行用戶友好性的提示處理?

           

          acegi校驗失敗的時候會拋出AuthenticationException異常,然后放在session里面,
          在錯誤轉向頁面可以這樣是用

          代碼
          <%= ((AuthenticationException) session.getAttribute(AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY)).getMessage() %>    
          <%= session.getAttribute(AuthenticationProcessingFilter.ACEGI_SECURITY_LAST_USERNAME_KEY) %>    
          <%= session.getAttribute(SecurityEnforcementFilter.ACEGI_SECURITY_ACCESS_DENIED_EXCEPTION_KEY) %> 

          不過這么用實在太難看了,暈了。可以自己用tag來搞定

           

           

          引用

          很多系統需要根據權限不同,生成不同的UI組件(例如管理員的菜單和普通用戶菜單就肯定不一樣),這也需要在Web層的View進行控制。

          acegi對View的處理就是使用tag,原來的acegi好像沒有什么tag,簡直是爛,現在有了tag,說一下是用的方法,但是說實話他的tag實在是不夠強。

           

          老版的web.xml

          代碼
          1<taglib>   
          2  <taglib-uri>http://acegisecurity.sf.net/authz</taglib-uri>   
          3  <taglib-location>/WEB-INF/authz.tld</taglib-location>   
          4</taglib>  

          在頁面中使用
          代碼
          1<authz:authorize ifAllGranted="ROLE_SUPERVISOR">   
          2<td>   
          3<HREF="del.htm?id=<c:out value="/${contact.id}"/>">Del</A>   
          4</td>   
          5</authz:authorize>  

          ifAllGranted是說所有的權限都有,用','分割權限
          可以替換成ifAnyGranted: ifNotGranted:

           

           

          代碼
          1<authz:authentication operation="username"/>   

           

          這個是用來顯示你的權限信息的。

           

          代碼
          1<authz:acl domainObject="${contact}" hasPermission="16,1">   
          2<td><HREF="<c:url value="del.htm"><c:param name="contactId"   
          3value="${contact.id}"/></c:url>">Del</A></td>   
          4</authz:acl>  

          posted @ 2007-05-20 12:42 LiuTing 閱讀(496) | 評論 (0)編輯 收藏

          Acegi使用1

          首先要配置一個filter,這個filter用一個代理bean寫在了spring里面,其實根正常的filter沒有任何區別。

          代碼
          1<bean id="securityEnforcementFilter"   
          2    class="org.acegisecurity.intercept.web.SecurityEnforcementFilter">   
          3    <property name="filterSecurityInterceptor">   
          4        <ref local="filterInvocationInterceptor" />   
          5    </property>   
          6    <property name="authenticationEntryPoint">   
          7        <ref local="authenticationProcessingFilterEntryPoint" />   
          8    </property>   
          9</bean>  

           

          "filterInvocationInterceptor" 是一個攔截器,說是攔截器,其實就是在filter里面執行一下他的攔截方法,這里可沒有什么aop.
          authenticationEntryPoint 交驗失敗的時候轉到的地方,為什么說是地方,因為通過配置可以轉到其它的url甚至其它的協議下(http 轉到 https等等)
           
          代碼
           1<bean id="authenticationProcessingFilterEntryPoint"   
           2    class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">   
           3    <property name="loginFormUrl">   
           4        <value>/error.security</value>   
           5    </property>   
           6    <property name="forceHttps">   
           7        <value>false</value>   
           8    </property>   
           9</bean>  
          10

           

          這個就是失敗的時候轉到的地方,我們可以配置url和是否使用https

           

          代碼
           1<bean id="filterInvocationInterceptor"   
           2    class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">   
           3    <property name="authenticationManager">   
           4        <ref bean="authenticationManager" />   
           5    </property>   
           6    <property name="accessDecisionManager">   
           7        <ref local="httpRequestAccessDecisionManager" />   
           8    </property>   
           9    <property name="objectDefinitionSource">   
          10        <value>   
          11            CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON    
          12            PATTERN_TYPE_APACHE_ANT    
          13            /index.jsp=ROLE_ANONYMOUS,ROLE_USER    
          14            /j_acegi_switch_user=ROLE_SUPERVISOR   
          15            /login.security=ROLE_ANONYMOUS,ROLE_USER                /test.do=ROLE_CODER   
          16            /**.do*=ROLE_USER    
          17        </value>   
          18    </property>   
          19</bean>  

           

          這個就是前面提到的攔截器。簡單解釋一下:
          authenticationManager 在acegi里面的主要作用就是管理維護用戶的權限角色等信息,比方說想要用戶的ROLE就要在這里面拿了。里面配置了多種全縣的來源,可以從DAO里面來(就是數據庫里面),可以是cookies里面的,也可以是匿名的權限,每種權限都以一種Provider的形式提供:

          代碼
           1<bean id="authenticationManager"   
           2    class="org.acegisecurity.providers.ProviderManager">   
           3    <property name="providers">   
           4        <list>   
           5            <ref local="daoAuthenticationProvider" />   
           6            <ref local="anonymousAuthenticationProvider" />   
           7            <ref local="rememberMeAuthenticationProvider" />   
           8        </list>   
           9    </property>   
          10</bean>

           

          objectDefinitionSource在acegi里面就是配置權限信息,說明哪一個url需要什么權限才能訪問,acegi默認用<value>來表示,其實這正是acegi的不足之處,還好能夠補救。我來說明一下:
          我們知道在spring里面<value>標簽比較特殊,spring首先找到這個屬性的類型,然后把value里面的內容以String的類型取出來(Spring做了一下包裝,為TypedString)。然后根據這個屬性的類型找他的Editer,然后用Editer來處理String為需要的類型。但是我們不希望用String來表達url,很明顯url里面有=就不會玩了。我們可以把這個信息寫到數據庫里面,然后讀取,這里面不說了以前有一位高手已經解釋過了。

          接下來就是httpRequestAccessDecisionManager了,AccessDecisionManager在acegi里面是決策者,就是根據你所擁有的權限和訪問URL需要的權限來決定你到底能不能訪問。

           

          代碼
           1<bean id="httpRequestAccessDecisionManager"   
           2    class="org.acegisecurity.vote.AffirmativeBased">   
           3    <property name="allowIfAllAbstainDecisions">   
           4        <value>false</value>   
           5    </property>   
           6    <property name="decisionVoters">   
           7        <list>   
           8            <ref bean="roleVoter" />   
           9        </list>   
          10    </property>   
          11</bean>  

           

          決策者里面是投票者,這個上面已經解釋過了,一個投票者校驗一種權限。整個流程已經說完了。

          posted @ 2007-05-20 12:41 LiuTing 閱讀(408) | 評論 (0)編輯 收藏

          Eclipse報表插件birt

           

          1. BIRT 概述

          BIRT是一個Eclipse-based開放源代碼報表系統。它主要是用在基于JavaJ2EEWeb應用程序上。BIRT主要由兩部分組成:一個是基于Eclipse的報表設計和一個可以加到你應用服務的運行期組件。BIRT同時也提供一個圖形報表制作引擎。

              使用BIRT,能制作出多樣化的報表到你的應用中。比如:列表 lists ,圖表 charts,混合報表 Compound Reports,交叉表(二維表)Crosstabs(二維報表目前在BIRT 2.1.1 還未實現,但在以后的版本中將會實現此功能)。

          2. BIRT的安裝

          2.1>birt的安裝

          Eclipse 3.1
          支持 BIRT 2.0

          Eclipse 3.2 支持 BIRT 2.1

           

          目前我使用的版本是BIRT 2.1.1BIRT的安裝有很多的方法。

          方法一:

          Eclipse的官方網站http://download.eclipse.org/birt/downloads去下載 BIRT 插件(birt-report-designer-all-in-one-2_1_1),解壓后,它就是一個擁有 BIRT插件的Eclipse。如果你已經安裝了Eclipse,那么把下載的文件夾的內容拷到所對應的 Eclipse 的文件夾里(pluginsfeatures兩個目錄),之后的第一次啟動是通過DOS進入到Eclipse目錄,啟動 Eclipse -clean 命令,此命令是清除 Eclipse 緩存里的記錄并啟動Eclipse。這也是最簡單的安裝BIRT方法。

           

          方法二:

              BIRT 2.1開始,可以在 Eclipse 里直接下載。[幫助]à[軟件更新]à[查找并安裝]

           

          方法三:

              如果你的 Eclipse 已經安裝或者不想使用方法一安裝,可以進行分別安裝的方法。EMF, GEF BIRT 都是需要通過 Eclipse download page下載的。請注意以下的配置要求:

          • BIRT 2.0.2
          • Eclipse 3.1
          • GEF 3.1.
          • EMF 2.1.
          • JRE 1.4.2/JRE 1.5.
          • BIRT 2.1/2.1.1
          • Eclipse 3.2.
          • GEF 3.2.
          • EMF 2.2.
          • JRE 1.4.2/JRE 1.5.
          • BIRT 2.2M4 and higher
          • Eclipse 3.3.
          • GEF 3.3.
          • EMF 2.3.
          • JRE 1.5.

          GEF:圖形編輯框架,是一個通過 BIRT UI 使用的Eclipse 插件

          EMF:用來制作圖表的框架

          具體的安裝和配置請參考 Eclipse官方網站 這里我還推薦一個BIRT 2.0.1的安裝視頻 希望對大家有所幫助。

          注意:iTextAsian.jar 是為了支持用PDF輸出時亞洲人的字體。prototype.js 是安裝 BIRT 2.0.2 或者更早的版本使用的,目前版本不需要了。

          提示:我個人使用的是方法一,首先安裝比較方便,其次如果使用方法二,在Eclipse [幫助]à[幫助內容] 里沒有關于 BIRT 的幫助文檔,這樣對學習不是很方便。

           2.2    birt版本升級

          1.刪除在 plugins 目錄下的所有以 org.eclipse.birt 開頭的文件。

          2.
          按照上面的方法一進行安裝。

          3.重新啟動 Eclipse -clean

           2.3  語言包安裝

              目前 BIRT2.1.1 已經有中文語言包。下載完畢以后把對應的目錄 copy 到對應的 Eclipse 目錄下,然后 Eclipse -clean 啟動。

            

          3. BIRT應用

              在這里我提供了一個 “BIRT中文教程”,在Eclipse官方網站也有它的演示視頻,Customers.rptdesign 是做好的報表。

           

          JDBC Drivers

              以上例子介紹的是使用“示例數據庫”的數據源,在大多數情況下我們使用的是自己的JDBC driver,下面介紹連接 Oracle 數據庫。

              打開 Eclipse 后進入 [窗口]à[打開透視圖]à[報表設計],新建項目 [文件]à[新建]à[項目],選擇“業務智能和報表工具”à“報表項目”,起項目名。新建的項目上,右鍵 新建報表,給報表起名字,報表的后綴名是 .rptdesign

              [數據源]à[新建數據源],選擇“JDBC數據源”(別忘了給數據源起名字),“管理驅動程序”à“添加”,把所需要的數據庫 jar 包添加進來。選擇oracle.jdbc.driver.OracleDriver ( v1.0),寫上正確的數據庫 URL,用戶名,密碼,點擊“測試連接”,顯示 連接成功。

           

          報表的種類有很多,具體的制作過程參考[幫助]à[幫助內容]

           

          提示:交叉表即二維報表在目前BIRT 2.1.1 還未實現,但在以后的版本中正在計劃實現此功能。

           

          4. BIRT部署

          BIRT 2.1.1所對應使用的部署工具是birt-runtime-2_1_1,可以到 Eclipse 官方網站下載。

           
          4.1. tomcat 部署

          我使用的版本是 tomcat 5.5,步驟如下:

          1)      mail.jar activation.jar拷到Tomcat 5.5\common\lib

          2)      iTextAsian.jar itext-1.3.jar拷到

          WebViewerExample\WEB-INF\platform\plugins\com.lowagie.itext\lib

          3)      連接數據庫的包拷到

          WebViewerExample\WEB-INF\platform\plugins\org.eclipse.birt.report.data.oda.jdbc_2.1.1.v20060922-1058\drivers

          4)      WebViewerExample整個目錄copy Tomcat 5.5\webapps,可以更改文件夾名。

          5)      完成的報表可以直接復制到根目錄下,也可以新建文件夾目錄。

           

          現在BIRT支持兩種瀏覽報表模式,frameset是支持顯示分頁的,采用Ajax技術。run暫不支持顯示分頁,直接輸出HTML流。比較一下它們的區別,如下:

          http://localhost:8080/WebViewerExample/frameset?__report=Customers.rptdesign

          http://localhost:8080/WebViewerExample/run?__report=Customers.rptdesign

          注意:

          a)      問號后面的是雙下劃線

          b)      以上報表是放在根目錄下,如果是放在自己新建的目錄比如 myreport URL應是:

          http://localhost:8080/WebViewerExample/run?__report=myreport/Customers.rptdesign

           
          4.2. Weblogic Server 部署

          我使用的版本是 Weblogic Server 9.2,它是 BEA WebLogic 產品的一部分。BEA WebLogic Server 是一個功能豐富、基于標準的現成的企業 J2EE應用服務器。

          Weblogic Server 有很多的域組成,medrec wl_server 是其中自帶的域,也可以自己創建新的域。域中可以包含許多服務器,在服務器中可以部署許多的應用程序。域有一個默認的服務器,它是管理服務器。每個域中的管理服務器是唯一的,其他創建的服務器叫受管服務器。

          Weblogic Server 的安裝就不多做介紹了,主要介紹它的配置和部署。下面介紹一下新建域和部署的步驟:

          1)      運行開始 -> 程序 -> BEA Products -> Tools -> Configuration Wizard

          2)      選擇 Create a new WebLogic domainNext

          3)      Select Domain Source 界面保持默認,Next

          4)      User name 處輸入用戶名,如 userpassword 輸入密碼,如12345678(密碼要求 8 位),Next

          5)      Configure Server Start Mode and JDK 界面中保持默認,即 JDK 選擇的是“Sun SDK 1.5.0_04 @ C:\BEA\jdk150_04,注意這里若選擇“Other JDK”配置比 SDK 1.5.0_04 更高的版本,服務器啟動時將會出現異常,所以最好保持默認,然后 Next

          6)      Customize Environment and Services Settings 界面中默認為 NoNext

          7)      Domain name 處輸入 mydomain,點擊 Create

          8)      完成后點擊 Done 關閉 Configuration Wizard 對話框。

          9)      運行開始 -> 程序 -> BEA Products -> User Projects -> mydomain -> Start Admin Server for Weblogic Server Domain,啟動創建域的服務器。如果最后顯示 <Server started in RUNNING mode> 則說明服務器啟動成功。

          10) 在地址欄輸入 http://localhost:7001/console 進入管理控制臺,輸入剛才的用戶名和密碼。點擊 更改中心 的[鎖定并編輯],域結構 中的[部署],點擊[安裝]。找到你要部署的應用程序,之后都為默認,最后點完成。在更改頁面上點擊[保存]完成所需的更改后,單擊 更改中心 中的[激活更改]注意:只有點擊了[激活更改]后才真正保存了更改。某些在管理控制臺中所做的更改在激活后立即生效。有些更改需要重新啟動此更改影響到的服務器或模塊。后面的這些更改稱為非動態更改。非動態更改在管理控制臺中由此警告圖標表示: 如果對非動態配置設置進行了編輯,則只有在重新啟動服務器之后,所有對動態配置設置所進行的編輯才會生效。

          11) 點擊 域結構 中的[部署],啟動剛才部署的應用程序。

          12) 在地址欄中輸入 http://localhost:7001/部署程序名在web中顯示應用程序。

           

              BIRT的部署方法基本和上面步驟相同,注意一點,在部署前將

          commons-logging.jar 拷入 WebViewerExample 中的 lib 包中,否則最后顯示會報錯。

           

              Weblogic Server 的部署方法有很多,weblogic.Deployer、管理控制臺、WLST 等等。剛才介紹的管理控制臺的部署,它是一個可視化的界面,用起來比較方便。

           

          推薦:在這里推薦使用一種應用程序的目錄管理方法,新建目錄結構如下:

          C:myApplication

          app

          plan

          將你的應用程序放入此目錄

          部署完后將會再此目錄下自動產生plan.xml文件

          用此目錄有利于很好的管理配置文件。

           

          關于 Weblogic 的更多詳細資料,我這里推薦幾個比較好的官方學習網站:

          www.bea.com.cn          bea的產品網站

          edocs.bea.com.cn       bea的比較系統的學習網站

          dev2dev.bea.com.cn      一般介紹bea的最新技術,動態等的網站
           
          4.3. web外觀顯示

              部署好的報表頁面顯示樣式是固定的,在多數情況下我們都希望修改外觀,下面將對此做簡單介紹。

          Webcontent是主要文件夾:

          1)      Webcontent中的ajax目錄,完成了在web上顯示的報表分頁的功能。

          2)      Styles目錄中的style.css是整個報表在web上顯示的外觀,包括工具條顏色,字體。文件注釋很清楚,具體修改可以參見注釋。

          3)      pages目錄pages/control/ NavigationbarFragment.jsp 分頁那一條工具欄的 JSP pages/control/ ToolbarFragment.jsp 工具按紐JSP,可以修改以保留自己想要使用的功能按紐。pages/control/ ProgressBarFragment.jsp 它是顯示剛開始讀取報表時,顯示條的樣式。

          4)      Layout目錄 FramesetFragment.jsp 可以修改報表標題。

           

          WEB-INF/web.xml文件中,BIRT_VIEW_REPORT_ROOT 是配置報表路徑的屬性,如果沒有配置則是默認路徑:$tomcat$\webapps\birt

              目前在web上顯示的所有的都是英文。項目有一個資源文件,打包在lib/viewservlets.jar中,…/…/resource/messages.properties文件中。顯示中文的解決方法是,用unicode轉換器把要顯示的中文事先轉換好,然后替換資源文件中的英文。

           

          5. BIRT總結

          BIRT是目前比較常用也是比較方便,效率較高的報表制作工具。當然其發展時間不長,所以還有很多的缺陷和未完善的地方,之后的版本也在不斷改進,因此我也將會一直跟蹤它的技術發展,不斷更新我的文檔。

          posted @ 2007-05-20 12:40 LiuTing 閱讀(4586) | 評論 (1)編輯 收藏

          主站蜘蛛池模板: 东台市| 富蕴县| 肇庆市| 资中县| 邹平县| 潮州市| 舒兰市| 太原市| 军事| 武平县| 驻马店市| 九龙城区| 福清市| 文昌市| 英山县| 金乡县| 桃江县| 长顺县| 湘乡市| 桓台县| 合肥市| 濮阳市| 蚌埠市| 大城县| 隆子县| 利川市| 阿拉善左旗| 蕲春县| 历史| 孟州市| 涿鹿县| 梁山县| 昆明市| 乌兰浩特市| 宝坻区| 永靖县| 缙云县| 东莞市| 泾阳县| 买车| 集贤县|