莊周夢蝶

          生活、程序、未來
             :: 首頁 ::  ::  :: 聚合  :: 管理

          讀R4R,才讀完第2章,前兩章沒什么新內(nèi)容,算是復習吧

          rails的lifecycle:
          test3.jpg

          從瀏覽器發(fā)起一個請求的基本流程:

          A.server to dispatcher

          服務器通過你指定的路徑查找dispatcher,比如,你在apache配置:

          <VirtualHost www.r4rmusic.com>
          ServerName www.r4rmusic.com
          ServerAlias r4rmusic.com
          DocumentRoot "/usr/local/share/railsapps/r4rmusic/public/"
          </VirtualHost>

          服務器將在"/usr/local/share/railsapps/r4rmusic/public/下查找分發(fā)器,在rails應用下面有這么幾個文件就是:dispatch.cgi dispatch.fcgi dispatch.rb

          這幾個文件中的某個將被調(diào)用

          B.dispatcher to controller

          分發(fā)器將解析發(fā)起請求的URL,按照:

          1.controller的名稱

          2.action名稱

          3.請求id值

          來尋找相應的controller的action,并執(zhí)行.當然,你可以通過編輯config下面的routes.rb來定義自己的路由規(guī)則

          C.performance of a controller action

          當相應的controller以及相應的action被找到并且執(zhí)行,他們將可以訪問:

          1.CGI數(shù)據(jù),form提交的數(shù)據(jù)

          2.controller的session信息,內(nèi)建的session方法

          本質(zhì)上rails是把業(yè)務邏輯放在controller的action里面,也就是沒有我們在J2EE中所謂的業(yè)務邏輯層.當業(yè)務邏輯或者說action較多時,你的controller文件不可避免的變的很長...在維護性和可讀性也許會帶來問題,當然,細分controller是更好的方法

          posted @ 2007-02-06 13:37 dennis 閱讀(449) | 評論 (0)編輯 收藏

          來自railscn的討論:

          http://www.railscn.com/viewtopic.php?t=2289

          ?

          1 . eval ? " obj?=?#{str}.new " ??? # 只能在irb中使用
          2 . obj? = ? eval ? " obj?=?#{str}.new " ?
          3 . obj? = ? eval (str) . new
          4 . c? = ?Object . const_get( " Array " )?
          ??s?
          = ?c . new

          ?

          相比于java的class.forName,與javascript等腳本語言一致,更為簡單和輕量級?

          posted @ 2007-02-06 13:35 dennis 閱讀(267) | 評論 (0)編輯 收藏

          剛學ruby時寫的工具,我自己一直在用,放在桌面上,遇到不懂單詞就得問它。發(fā)在railscn上,ranchgirl修改的更為ruby way。

          ?受blogjava上的帖子啟發(fā),實在是個有趣的主意,寫了個ruby版本的,對俺這等英語一般的同學來說,google在線翻譯經(jīng)常使用吶,原貼之java版
          http://www.aygfsteel.com/ekinglong/archive/2006/11/12/80704.html?Pending=true#Post

          require?'net/http'
          def?translate
          ??txt
          =STDIN.gets
          ??break?
          if?txt.strip=='e'?or?txt.strip=='exit'
          ??temp
          =txt.split('?')
          ??
          if?temp[1]=='1'?or?temp.size==1
          ????langpair
          ='en|zh-CN'
          ??
          else
          ????langpair
          ='zh-CN|en'
          ??end
          ?
          #使用代理??
          ??$proxy_addr?=?'127.0.0.1'
          ??
          $proxy_port?=?80

          ??response?
          =?Net::HTTP.Proxy($proxy_addr,?$proxy_port).post_form(URI.parse("http://translate.google.com/translate_t"),{'text'=>temp[0],'langpair'=>langpair})

          ??response
          .body?=~?/<div?id=result_box?dir=ltr>(.*)<\/div>/
          ??result?
          =?$1?
          ??puts?'翻譯內(nèi)容:'+temp[0]
          ??puts?
          'google返回:'+result
          ??puts?
          '-------------------退出請打e或者exit---------------'
          ??translate
          end
          translate


          ranchgirl修改的版本,沒有使用遞歸:
          require?'net/http'
          def?usage
          ??
          "usage:?word?[lang2?[lang1]]\n"?+
          ??
          "Translate?word?from?lang1?(default?en,?English)?to?lang2?(default?es,?Spanish)\n"?+
          ??
          "ISO?language?code:?http://www.unicode.org/unicode/onlinedat/languages.html"?
          end
          def?translate
          ??arr?
          =?ARGV
          ??
          if?!arr[0]?then?puts?usage;?return?end
          ??arr[
          1]?=?"es"?unless?arr[1]
          ??arr[
          2]?=?"en"?unless?arr[2]?
          ??langpair?
          =?"#{arr[2]}|#{arr[1]}"???
          ??response?
          =?Net::HTTP.post_form(URI.parse("http://translate.google.com/translate_t"),
          ?????????????????????????????????{
          :text?=>?arr[0],?:langpair?=>?langpair})
          ??response
          .body?=~?/<div?id=result_box?dir=ltr>(.*)<\/div>/
          ??result?
          =?$1?
          ??result?
          =?"No?#{langpair}?translation?available?for?#{arr[0]}"?if?result.size?==?0
          ??puts?result
          end
          translate?

          posted @ 2007-02-06 13:33 dennis 閱讀(1641) | 評論 (3)編輯 收藏

          ?項目算完成了,等測試報告出來的時間里玩玩groovy,不玩不知道,一玩嚇一跳,groovy與ruby好象啊。
          看看下面的代碼:
          ruby:
          [
          1,2,3,4,5,6,7].inject(0){|sum,i|?sum+=i}

          groovy:

          [
          1,2,3,4,5,6,7].inject(0){sum,i?->?sum+=i}


          ruby的closures與groovy的closures機制幾乎完全一樣,除了符號改變之外。有興趣的話看看這個:
          http://groovy.codehaus.org/Tutorial+2+-+Code+as+data%2C+or+closures

          如果說groovy有什么優(yōu)點的話,就是它可以直接利用java豐富的類庫,實在爽:
          //readFile.groovy
          myFileName?
          =?"E://groovy//readFile.groovy"
          myFile?
          =?new?File(?myFileName)
          printFileLine?
          =?{?println?"File?line:?"?+?it?}
          myFile
          .eachLine(?printFileLine?)


          語法層面沒什么好談的,我更希望了解下groovy在實際應用中的表現(xiàn),IBM的develper works上面有個實戰(zhàn)groovy系列,值的好好讀讀

          補充下,在spring中調(diào)用groovy beans的方法:
          首先需要一個java接口,比如:

          package?com.sohu.blog.dennis_zane.springdemo.scripting;

          public?interface?Calculator?{
          ???
          int?add(int?x,int?y);
          }

          然后是Groovy?bean
          :
          //GroovyCalculator.groovy
          package?com.sohu.blog.dennis_zane.springdemo.scripting;
          class?GroovyCalculator?implements?Calculator{
          ??
          int?add(int?x,?int?y){
          ??????x
          +y????
          ??}
          }

          在spring配置文件中配置:

          <lang:groovy?id="calculator"?script-source="classpath:/com/sohu/blog/dennis_zane/springdemo/scripting/GroovyCalculator.groovy"/>


          調(diào)用的話跟使用一般的bean沒什么不同:

          Calculator?calculator=(Calculator)ctx.getBean("calculator");
          System.out.println(calculator.add(100,?20));

          也許隨著groovy性能的提升,將業(yè)務層完全由動態(tài)語言來實現(xiàn)不是沒有可能。

          ?

          posted @ 2007-02-06 13:11 dennis 閱讀(486) | 評論 (0)編輯 收藏

          ruby語言本身并沒有提供abstract class和abstract method機制。這是ruby的spirit所決定的。但如果我們真的需要定義一個公共抽象類(或者抽象方法)來讓子類來實現(xiàn),又該如何做呢?
          ??? 我們可以通過在調(diào)用方法時拋出NotImplementedError來防止方法被調(diào)用。如(來自《ruby cookbook》的例子):

          ?class?Shape2D
          ??def?area
          ????raise?NotImplementedError
          .new("#{self.class.name}#area是抽象方法")
          ??end
          end?
          class?Square?
          <?Shape2D
          ??def?initialize(
          length)
          ????
          @length?=?length
          ??end
          ??
          ??def?area
          ????
          @length?**?2
          ??end
          end


          ?? 父類
          Shape2D的方法area就是我們所需要的“抽象方法”了。你不能直接調(diào)用:

          s1=Shape2D.new
          s1
          .area

          這樣調(diào)用將拋出錯誤:Shape2D#area是抽象方法 (NotImplementedError)
          Shape2D的子類Square覆寫了此方法。由此我們模擬實現(xiàn)了抽象方法。那么抽象類該如何實現(xiàn)呢?自然而然,我們想到如果把類的initialize方法這樣處理,那么這樣的類將沒辦法被new生成,不正是我們所需要的抽象類?說干就干:

          ?class?Shape2D
          ??def?initialize
          ????raise?NotImplementedError
          .new("#{self.class.name}#area是抽象類")
          ??end
          ??def?area
          ????raise?NotImplementedError
          .new("#{self.class.name}#area是抽象方法")
          ??end
          end?


          當你調(diào)用Shape2D.new時,解釋器將提示你:Shape2D是抽象類(NotImplementedError)

          我們已經(jīng)實現(xiàn)了抽象方法和抽象類,感覺還是不夠好,對每一個需要實現(xiàn)抽象類的類來說,我們都需要去寫一句:raise NotImplementedError.new...實在不夠爽。ruby鼓勵我們?nèi)バ薷念惖男袨椋踔潦菢藴蕩欤呛茫覀冃薷腃lass類吧,提供類似attr_reader的聲明式服務:
          class?Class
          ??def??
          ????abstract(
          *args)
          ????args
          .each?do?|method_name|
          ??????
          ??????define_method(method_name)?
          do?|*args|
          ????????
          if?method_name?==?:initialize???
          ??????????msg?
          =?"#{self.class.name}是抽象類"
          ????????
          else
          ??????????msg?
          =?"#{self.class.name}##{method_name}是抽象方法"
          ????????end
          ????????raise?NotImplementedError
          .new(msg)
          ????????
          ??????end
          ????end
          ??end
          end


          OK,如此一來,我們的Shape2D可以寫成:
          ?class?Shape2D
          ????abstract
          :initialize,:area??#initialize和area是抽象方法
          ?end


          盡管在ruby中,抽象類和抽象方法是否有用存在懷疑,不過知道這樣的辦法總是不錯的主意

          posted @ 2007-02-06 13:07 dennis 閱讀(1453) | 評論 (1)編輯 收藏

          rails1.1已經(jīng)加入對json的全面支持,現(xiàn)在的Array,Hash,String,Object...等等都有一個to_json方法,生成 json字符串。反過來,我們該如何解析json呢?查了下http://www.json.org/上面ruby語言的鏈接,在rubyforge上找到了一個項目。解析json對ruby來說非常簡單,只要一行代碼:



          例子:
          json?=?'["a",?"B",?"C"]'
          ?
          puts?"Unsafe?#{unsafe_json(json).inspect}"???#輸出Unsafe?["a",?"B",?"C"]






          把上面的json字符串解析成Array。這樣的方法并不安全,比如:
          json?=?'puts?"Danger?Will?Robinson"'
          ? puts?"Unsafe?#{unsafe_json(json).inspect}"?







          又該輸出什么呢?很遺憾,解析不出什么東西,跳出一個警告:
          warning: character class has `[' without escape


          安全的方法如下:
          module?SafeJSON
          ??require?
          'monitor'
          ??def?SafeJSON.build_safe_json
          ????ret?
          =?nil
          ????waiter?
          =?''
          ????waiter.extend(MonitorMixin)
          ????wait_cond?
          =?waiter.new_cond
          ????
          ????Thread.start?
          do
          ??????$SAFE?
          =?4
          ??????ret?
          =?Proc.new?{|json|
          ????????eval(json.gsub(
          /(["'])/s*:/s*(['"0-9tfn/[{])/){"#{$1}=>#{$2}"})
          ??????}

          ??????waiter.synchronize?
          do
          ????????wait_cond.signal
          ??????end
          ????end
          ????waiter.synchronize?
          do
          ??????wait_cond.wait_while?
          {?ret.nil??}
          ????end
          ????
          return?ret
          ??end
          ??@@parser?
          =?SafeJSON.build_safe_json
          ??
          ??#?Safely?parse?the?JSON?input
          ??def?SafeJSON.parse(input)
          ????@@parser.call(input)
          ??rescue?SecurityError
          ????
          return?nil
          ??end
          end






          包含這個Module,你就可以這樣使用:
          peoples=SafeJSON.parse('{"peoples":[{"name":"site120","email":"site120@163.com","sex":"男"},{"name":"site120_2","email":"site120@163.com_2","sex":"男_2"}]}')

          puts?peoples[
          "peoples"][1]["name"]??#輸出site120_2







          rails通過RJS內(nèi)置了對AJAX的支持,也許用到json的機會并不多,不過作為一種數(shù)據(jù)交換的方便格式,還是值的注意。

          posted @ 2007-02-06 13:04 dennis 閱讀(4684) | 評論 (1)編輯 收藏

          ?雖然sohu不大可能倒閉,但是我也想導出我所有的文章,備份在自己的數(shù)據(jù)庫中。javaeye的blog系統(tǒng)提供了一個blog導入導出的功能,用起來很酷。其實你自己用ruby寫一下也很簡單,比如我要讀取我的blog的RSS源:

          require?
          'rss/2.0'
          require?
          'open-uri'
          url?
          =?'http://dennnis-zane.blog.sohu.com/rss'
          feed?
          =?RSS::Parser.parse(open(url).read,?false)?
          puts?
          "===?blog名稱:?#{feed.channel.title}?==="?
          feed.items.each?
          do?|item|?
          ????puts?item.title?
          ????puts?
          "?(#{item.link})"
          ????puts?puts?item.description?
          end?

          feed.items對應rss2.0的item元素,每個item元素描述了一篇文章的標題,鏈接,內(nèi)容等信息,你可以通過item.title,item.link等來讀取,并存入你自己的數(shù)據(jù)庫。

          再給一個使用代理的例子,因為我的機子是使用代理上網(wǎng)的:

          require?'rss/2.0'
          require?
          'net/http'
          url?
          =?'http://dennnis-zane.blog.sohu.com/rss'
          $proxy_addr?
          =?'172.16.51.10'
          $proxy_port?
          =?807

          response?
          =?Net::HTTP.Proxy($proxy_addr,?$proxy_port).get_response(URI.parse("http://dennnis-zane.blog.sohu.com/rss"))
          feed?
          =?RSS::Parser.parse(response.body,?false)
          puts?
          "===?Channel:?#{Iconv.conv('GBK','UTF-8',feed.channel.title)}?==="
          feed.items.each?
          do?|item|
          ??puts?Iconv.conv(
          'GBK','UTF-8',item.title)
          ??puts?
          "?(#{item.link})"
          ??puts
          ?#?puts?Iconv.conv(
          'GBK','UTF-8',item.description)
          end


          打印:

          === Channel: 花非花 ===
          websphere錯誤備忘錄
          ?(http://dennnis-zane.blog.sohu.com/29898836.html)

          感冒,寒冷的夜
          ?(http://dennnis-zane.blog.sohu.com/29859082.html)

          ECMAScript對象基礎
          ?(http://dennnis-zane.blog.sohu.com/29499101.html)

          用ruby創(chuàng)建領域特定語言(DSL)——轉(zhuǎn)載
          ?(http://dennnis-zane.blog.sohu.com/29350052.html)

          使用ruby解析json
          ?(http://dennnis-zane.blog.sohu.com/29200192.html)

          ruby實現(xiàn)抽象類和抽象方法
          ?(http://dennnis-zane.blog.sohu.com/29145303.html)

          看了《父子》,看了《綠帽子》
          ?(http://dennnis-zane.blog.sohu.com/29047444.html)

          ECMAScript基礎
          ?(http://dennnis-zane.blog.sohu.com/28876856.html)

          假期結束,專心工作
          ?(http://dennnis-zane.blog.sohu.com/28604494.html)

          不解
          ?(http://dennnis-zane.blog.sohu.com/27564529.html)

          posted @ 2007-02-06 12:57 dennis 閱讀(323) | 評論 (0)編輯 收藏

          呵呵,在《develope J2EE without EJB》中,DTO被狠很地批判了一把,rod說這完全是反模式。可實際項目當中,我們還是不得不在使用。VO,PO,一牽扯到概念總是多么復雜。。。把一個PO從頭傳到尾??從頁面到數(shù)據(jù)庫,一捅到底?NO,NO,萬一你要顯示給用戶的是幾個PO的結合怎么辦?萬一我們只是需要某幾個屬性組合在一起顯示怎么辦?一捅到底的策略是多么丑陋,而且你完全把你的數(shù)據(jù)庫設計模型暴露給用戶。所以我們需要一些map工具來轉(zhuǎn)換,在這方面,過去我只知道有個 BeanUtils,不夠靈活,而今天,接觸了下dozer,啊,跟spring一樣的理念!靈活多變,你想怎么映射,想怎么換都可以。看看它支持的轉(zhuǎn)換類型:

          ? Primitive to Primitive Wrapper
          ? Primitive to Custom Wrapper
          ? Primitive Wrapper to Primitive Wrapper

          ? Primitive to Primitive
          ? Complex Type to Complex Type
          ? String to Primitive
          ? String to Primitive Wrapper
          ? String to Complex Type if the Complex Type contains a String constructor
          ? Each of these can be mapped to one another: java.util.Date, java.sql.Date, java.sql.Time,
          java.sql.Timestamp, java.util.Calendar, java.util.GregorianCalendar
          ? String to any of the supported Date/Calendar Objects if an explicit date format mapping attribute is
          specified.
          ? Objects containing a toString() method that produces a long representing time in (ms) to any
          supported Date/Calendar object.

          幾乎我們能想到的,它都提供了方法來做到。而且dozer可以很容易地跟spring集成。下面舉個簡單例子:

          定義一個Book對象:

          package com.denny_blue.dozerdemo;
          public class Book {
          ?private String name;
          ?private String author;
          ?
          ?
          ?public Book(){
          ??
          ?}?
          ?public void setAuthor(String author) {
          ??this.author = author;
          ?}

          ?public String getAuthor() {
          ??return (this.author);
          ?}
          ?public void setName(String name){
          ??this.name=name;
          ?}?
          ?public String getName(){
          ??return this.name;
          ?}
          }
          簡單的,我們要實例化一個對象,然后clone此對象,注意,是clone!

          package com.denny_blue.dozerdemo;
          import net.sf.dozer.util.mapping.DozerBeanMapper;
          import java.util.List;
          import java.util.ArrayList;


          public class MyFirstDozerDemo {
          ?public static void main(String args[]){
          ??Book book1=new Book();
          ??book1.setAuthor("dennis");
          ??book1.setName("dozer demo");
          ??DozerBeanMapper mapper=new DozerBeanMapper();
          ??Book book2=new Book();
          ??mapper.map(book1,book2);
          ? book2=(Book)mapper.map(book1,com.denny_blue.dozerdemo.Book.class);
          ??System.out.println("book2's name:"+book2.getName());
          ?????}
          }?

          OK,如此簡單,我們把book1的屬性完全復制給了book2,兩者現(xiàn)在是完全獨立的對象。可如果僅僅是這樣,我們用BeanUtils不是也很容易辦到? book2=(Book)BeanUtils.cloneBean(book1);可如果我要把book1映射給一個完全不同的類的對象怎么辦?而且他們的屬性名也不相同,怎么辦?比如,一個CookBook類:

          package com.denny_blue.dozerdemo;
          public class CookBook {
          ?private String bookName;
          ?private String author;


          ?public CookBook(){}
          ?public String getBookName() {
          ??return (this.bookName);
          ?}

          ?public void setBookName(String bookName) {
          ??this.bookName = bookName;
          ?}

          ?public String getAuthor() {
          ??return (this.author);
          ?}

          ?public void setAuthor(String author) {
          ??this.author = author;
          ?}


          }
          它的bookName屬性與Book的name屬性名不一樣,我們該如何復制?dozer通過xml文件的配置來靈活地達到這個目的。我們配置一個dozerBeanMapping.xml:

          <?xml version="1.0" encoding="UTF-8"?>
          <!DOCTYPE mappings PUBLIC "-//DOZER//DTD MAPPINGS//EN"
          "<mappings>
          <configuration>
          <stop-on-errors>false</stop-on-errors>
          <date-format>MM/dd/yyyy HH:mm</date-format>
          <wildcard>true</wildcard>
          </configuration>
          <mapping>
          <class-a>com.denny_blue.dozerdemo.Book</class-a>
          <class-b>com.denny_blue.dozerdemo.CookBook</class-b>
          <field>
          <a>name</a>
          <b>bookName</b>
          </field>
          <field>
          <a>author</a>
          <b>author</b>
          </field>
          </mapping>
          </mappings>

          如上所示,<class-a>指定所要復制的源對象,<class-b>復制的目標對象,<a>源對象的屬性名, <b>目標對象的屬性名。wildcard默認為true,在此時默認對所有屬性進行map,如果為false,則只對在xml文件中配置的屬性進行map。此時的demo 看起來像這樣:

          package com.denny_blue.dozerdemo;
          import net.sf.dozer.util.mapping.DozerBeanMapper;
          import java.util.List;
          import java.util.ArrayList;


          public class MyFirstDozerDemo {
          ?public static void main(String args[]){
          ??Book book1=new Book();
          ??book1.setAuthor("dennis");
          ??book1.setName("dozer demo");
          ??DozerBeanMapper mapper=new DozerBeanMapper();
          ? book2=(Book)mapper.map(book1,com.denny_blue.dozerdemo.Book.class);
          ? CookBook cookBook=new CookBook();
          ? List myMappingFiles = new ArrayList();
          ? myMappingFiles.add("dozerBeanMapping.xml");
          ? mapper.setMappingFiles(myMappingFiles);
          ? cookBook=(CookBook)mapper.map(book1,CookBook.class);
          ? System.out.println("cookBook's name:"+?? cookBook.getBookName()+"???? cookBook's author:"+
          ????????????????????? cookBook.getAuthor());
          ?}
          }

          通過mapper.setMappingFiles()設置映射文件,可以添加多個配置文件,也可以把所有的映射寫在一個配置文件里面。??更多復雜例子請見它自帶的doc。

          posted @ 2007-02-06 12:45 dennis 閱讀(2535) | 評論 (0)編輯 收藏

          最近重新再看<Inside JVM>,對JAVA編譯成的字節(jié)碼結構很感興趣,希望找個工具能夠?qū)?class文件進行的解析和查看。沒找到,倒發(fā)現(xiàn)javaassist可以對字節(jié)碼進行操作和修改。此工具是JBOSS項目的一部分,JBOSS實現(xiàn)AOP的基礎。呵呵,開眼界了,原來我們可以直接對字節(jié)碼文件進行修改,哪怕不知道源文件(跟反編譯完全不同)。一個簡單例子:

          import javassist.*;
          class Hello {
          ??? public void say() {
          ??????? System.out.println("Hello");
          ??? }
          }

          public class Test {
          ??? public static void main(String[] args) throws Exception {
          ??????? ClassPool cp = ClassPool.getDefault();
          ??????? CtClass cc = cp.get("Hello");
          ??????? CtMethod m = cc.getDeclaredMethod("say");
          ??????? m.setBody("{System.out.println(/"shit/");}");
          ??????? m.insertBefore("System.out.println(/"fuck/");");
          ??????? Class c = cc.toClass();
          ??????? Hello h = (Hello)c.newInstance();
          ??????? h.say();
          ??? }
          }

          編譯運行此文件,輸出:

          fuck

          shit

          我們在

          ?CtMethod m = cc.getDeclaredMethod("say");
          ? m.setBody("{System.out.println(/"shit/");}");

          ? m.insertBefore("System.out.println(/"fuck/");");

          修改了say()方法,改成了

          System.out.println("fuck");

          System.out.println("shit");

          這里的ClassPool是CtClass的容器,它讀取class文件,并根據(jù)要求保存CtClass的結構以便日后使用,默認狀態(tài)下是從當前的類裝載器獲得,當然你可以指定:

          pool.insertClassPath("/usr/local/javalib");

          當然,不僅僅是修改方法,你還可以新建一個class,利用makeClass()方法,如:

          ClassPool pool = ClassPool.getDefault();
          CtClass cc = pool.makeClass("Point");

          還可以新增方法,下面是sample里的一個例子,同樣的:

          package sample;

          import javassist.*;
          import java.lang.reflect.*;

          /*
          ?? A very simple sample program

          ?? This program overwrites sample/Test.class (the class file of this
          ?? class itself) for adding a method g().? If the method g() is not
          ?? defined in class Test, then this program adds a copy of
          ?? f() to the class Test with name g().? Otherwise, this program does
          ?? not modify sample/Test.class at all.

          ?? To see the modified class definition, execute:

          ?? % javap sample.Test

          ?? after running this program.
          */
          public class Test {
          ??? public int f(int i) {
          ??? ?i++;
          ?? ?return i;
          ??? }

          ??? public static void main(String[] args) throws Exception {
          ?ClassPool pool = ClassPool.getDefault();

          ?CtClass cc = pool.get("sample.Test");
          ?Test test=new Test();
          ?Class c=test.getClass();
          ?Method []method=c.getDeclaredMethods();
          ?for(int i=0;i<method.length;i++){
          ??System.out.println(method[i]);
          ?}
          ?try {
          ???? cc.getDeclaredMethod("g");
          ???? System.out.println("g() is already defined in sample.Test.");
          ?}
          ?catch (NotFoundException e) {
          ???? /* getDeclaredMethod() throws an exception if g()
          ????? * is not defined in sample.Test.
          ????? */
          ???? CtMethod fMethod = cc.getDeclaredMethod("f");
          ???? CtMethod gMethod = CtNewMethod.copy(fMethod, "g", cc, null);
          ???? cc.addMethod(gMethod);
          ???? cc.writeFile();?// update the class file
          ???? System.out.println("g() was added.");
          ?}
          ??? }
          }
          第一次運行時,因為Test里并沒有g()方法,所以執(zhí)行

          ?CtMethod fMethod = cc.getDeclaredMethod("f");
          ???? CtMethod gMethod = CtNewMethod.copy(fMethod, "g", cc, null);? //把f方法復制給g
          ???? cc.addMethod(gMethod);
          ???? cc.writeFile();?//更新class文件

          ???? System.out.println("g() was added.");
          打印:g() was added

          第2次運行時,因為以上步驟已經(jīng)在class文件中增加了一個g方法,所以

          ?System.out.println("g() is already defined in sample.Test.");
          打印:g() is already defined in sample.Test

          ?

          Javassist不僅能修改你自己的class文件,而且可以同樣修改JDK自帶的類庫(廢話,類庫也是人寫的^_^)具體請看它的tutorial。

          posted @ 2007-02-06 12:44 dennis 閱讀(806) | 評論 (0)編輯 收藏

          一般網(wǎng)站在處理用戶上傳圖片時通常采用兩種策略:一是直接把圖片存入數(shù)據(jù)庫中的Blob字段;二是數(shù)據(jù)庫中只存儲圖片的在服務器上的路徑信息?,圖片存放在分門別類的文件中,使用的時候從數(shù)據(jù)庫讀取路徑信息到頁面img元素即可.在此不討論兩種方案的優(yōu)劣,我只是寫了個hibernate的例子來實現(xiàn)第一種策略.例子很簡單,t_user表主要兩個字段,name和photo,其中photo字段類型為Blob.在此例中數(shù)據(jù)庫我采用mysql, oracle的Blob字段比較特殊,你必須自定義類型,具體的請自行搜索,這方面的資料很多.

          //User.java  

          package com.denny_blue.hibernate;

          import java.io.Serializable;
          import java.sql.Blob;

          public class User implements Serializable{
          ?private Integer id;
          ?private String name;
          ?private Blob photo;
          ?/**
          ? * @return the id
          ? */
          ?public User(){
          ?}
          ?public Integer getId() {
          ??return id;
          ?}
          ?/**
          ? * @param id the id to set
          ? */
          ?public void setId(Integer id) {
          ??this.id = id;
          ?}
          ?/**
          ? * @return the name
          ? */
          ?public String getName() {
          ??return name;
          ?}
          ?/**
          ? * @param name the name to set
          ? */
          ?public void setName(String name) {
          ??this.name = name;
          ?}
          ?/**
          ? * @return the photo
          ? */
          ?public Blob getPhoto() {
          ??return photo;
          ?}
          ?/**
          ? * @param photo the photo to set
          ? */
          ?public void setPhoto(Blob photo) {
          ??this.photo = photo;
          ?}
          ?
          }

          類User有3個屬性,id,name,photo,相應的getter和setter方法以及一個無參構造函數(shù).應該注意的是photo的類型java.sql.Blob

          相應的user.hbm.xml應該如下:

          <?xml version="1.0"?>
          <!DOCTYPE hibernate-mapping PUBLIC
          ?"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
          ?"<hibernate-mapping
          ?package="com.denny_blue.hibernate">

          ?<class name="com.denny_blue.hibernate.User"
          ??????? table="t_user"
          ??????? dynamic-update="true"
          ??????? dynamic-insert="true"
          ??????? batch-size="3">
          ??<id name="id"
          ????? column="id"
          ????? type="java.lang.Integer">
          ???<generator class="native"/>
          ??</id>
          ??<property name="name" column="name" type="java.lang.String" lazy="true"/>
          ??<property name="photo" column="photo" type="java.sql.Blob"/>

          ?</class>

          </hibernate-mapping>

          對應的hibernate.cfg.xml配置文件,不再列出,請參照hibernate文檔自行設定.

          OK,做了這一步,我們寫個測試類來進行單元測試:

          package com.denny_blue.test;

          import java.io.FileInputStream;
          import java.io.FileNotFoundException;
          import java.io.FileOutputStream;
          import java.io.IOException;
          import java.io.InputStream;
          import java.sql.Blob;

          import org.hibernate.Hibernate;
          import org.hibernate.HibernateException;
          import org.hibernate.Session;
          import org.hibernate.SessionFactory;
          import org.hibernate.Transaction;
          import org.hibernate.cfg.Configuration;

          import com.denny_blue.hibernate.User;

          import junit.framework.TestCase;

          public class HibernateTest extends TestCase {
          ??????? private Session session;
          ?protected void setUp() throws Exception {
          ??try{
          ???Configuration config=new Configuration().configure();
          ???SessionFactory sf=config.buildSessionFactory();
          ???session=sf.openSession();
          ??}catch(HibernateException e){
          ???e.printStackTrace();
          ??}
          ?}

          ?protected void tearDown() throws Exception {
          ??try{
          ???session.close();
          ??}catch(HibernateException e){
          ???e.printStackTrace();
          ??}
          ?}
          ?
          ?public void testSave()throws FileNotFoundException,IOException{
          ??User user=new User();
          ??user.setName("jordan");
          ??FileInputStream in=new FileInputStream("C://test.gif");
          ??Blob photo=Hibernate.createBlob(in);
          ??user.setPhoto(photo);
          ??Transaction tx=null;
          ??try{
          ??tx=session.beginTransaction();
          ??session.saveOrUpdate(user);
          ??tx.commit();
          ??}catch(HibernateException e){
          ???if(tx!=null)
          ????tx.rollback();
          ???e.printStackTrace();
          ??}finally{
          ???in.close();
          ??}
          ?}
          ?public void testLoad()throws Exception{
          ??try{
          ???User user=(User)session.load(User.class, new Integer(1));
          ???Blob photo=user.getPhoto();
          ???InputStream in=photo.getBinaryStream();
          ???FileOutputStream out=new FileOutputStream("C://out//test2.gif");
          ???byte [] buf=new byte[1024];
          ???int len;
          ???while((len=in.read(buf))!=-1){
          ????out.write(buf, 0, len);
          ???}
          ???in.close();
          ???out.close();
          ??}catch(HibernateException e){
          ???e.printStackTrace();
          ??}
          ?}

          }
          我們讀取C盤目錄下的test.gif并存儲到數(shù)據(jù)庫中,然后再取出來寫入C:/out目錄,此時你可以查看下數(shù)據(jù)表中photo顯示為blob,表示已經(jīng)成功存入.值的注意的代碼片段就是:

          FileInputStream in=new FileInputStream("C://test.gif");
          ??Blob photo=Hibernate.createBlob(in);
          我們這里是從磁盤中讀取圖片,實際應用中你可以利用上傳組件得到圖片的2進制數(shù)據(jù)流,并利用Hibernate.createBlob方法來構造相應的Blob對象.而取圖片則使用

          InputStream in=photo.getBinaryStream();

          這只是個簡單的測試類,如果我想從數(shù)據(jù)庫中取出圖片并現(xiàn)實在頁面上該如何做呢?其實也很簡單,我們先要寫一個servlet,在它的service方法中取出圖片,并"畫"到指定頁面上.

          package com.easyjf.asp.action;

          import java.io.InputStream;
          import java.io.OutputStream;
          import java.sql.Blob;

          import javax.servlet.ServletException;
          import javax.servlet.http.HttpServlet;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;

          import org.hibernate.HibernateException;
          import org.hibernate.Session;
          import org.hibernate.SessionFactory;
          import org.hibernate.cfg.Configuration;
          import com.denny)blue.hibernate.User;


          public class Test extends HttpServlet {

          ?/**
          ? * Destruction of the servlet. <br>
          ? */
          ?private Session session;
          ?public void destroy() {
          ??try{
          ???session.close();
          ??}catch(HibernateException e){
          ???e.printStackTrace();
          ??}
          ?}

          ?/**
          ? * Initialization of the servlet. <br>
          ? *
          ? * @throws ServletException if an error occure
          ? */
          ?public void init() throws ServletException {
          ??try{
          ???Configuration config=new Configuration().configure();
          ???SessionFactory sf=config.buildSessionFactory();
          ???session=sf.openSession();
          ??}catch(HibernateException e){
          ???e.printStackTrace();
          ??}
          ?}
          ??? public void doGet(HttpServletRequest request,HttpServletResponse response)
          ??? {
          ??? ?try{
          ???User user=(User)session.load(User.class, new Integer(1));
          ???Blob photo=user.getPhoto();
          ???InputStream in=photo.getBinaryStream();
          ???OutputStream out=response.getOutputStream();
          ???byte [] buf=new byte[1024];
          ???int len;
          ???while((len=in.read(buf))!=-1){
          ????out.write(buf, 0, len);
          ???}
          ???in.close();
          ???out.close();
          ??}catch(Exception e){
          ???e.printStackTrace();
          ??}
          ??? }

          }

          通過response.getOutputStream取得輸出流,其他就與上段代碼一致.servlet寫好了,怎么在頁面調(diào)用呢?那就更簡單啦,直接在頁面的img標簽的src屬性上調(diào)用該servlet即可,如:

          <img id="test" src="/servlet/Test"/>

          ?

          簡單的例子,希望對初學者有幫助.

          附記:如果不希望在servlet(或者action之類)中進行保存操作,希望在DAO進行此操作,那么InputStream的關閉問題可以通過hibernate的interceptor機制解決

          posted @ 2007-02-06 12:43 dennis 閱讀(489) | 評論 (0)編輯 收藏

          僅列出標題
          共56頁: First 上一頁 48 49 50 51 52 53 54 55 56 下一頁 
          主站蜘蛛池模板: 那曲县| 墨竹工卡县| 新建县| 天台县| 开鲁县| 剑川县| 郸城县| 息烽县| 汉沽区| 蒙阴县| 德兴市| 武陟县| 遵义市| 云安县| 日照市| 巢湖市| 万荣县| 达拉特旗| 泽州县| 西丰县| 平罗县| 横山县| 德安县| 云霄县| 家居| 阳江市| 鸡西市| 威信县| 邵武市| 尖扎县| 葫芦岛市| 龙山县| 吕梁市| 潢川县| 嘉义县| 安达市| 木兰县| 平顶山市| 合阳县| 阜城县| 大名县|