捕風(fēng)之巢

          統(tǒng)計(jì)

          留言簿(3)

          java友情鏈接

          閱讀排行榜

          評論排行榜

          j2ee小應(yīng)用

          附加功能 (目錄)
          實(shí)現(xiàn)圖片上傳 (目錄)
            用戶必須能夠上傳圖片,因此需要文件上傳的功能。比較常見的文件上傳組件有Commons FileUpload(http://jakarta.apache.org/commons/fileupload/a>)和COS FileUpload(http://www.servlets.com/cos),Spring已經(jīng)完全集成了這兩種組件,這里我們選擇Commons FileUpload。
            由于Post一個包含文件上傳的Form會以multipart/form-data請求發(fā)送給服務(wù)器,必須明確告訴 DispatcherServlet如何處理MultipartRequest。首先在dispatcher-servlet.xml中聲明一個 MultipartResolver:

          <bean?id="multipartResolver"
          ???????class
          ="org.springframework.web.multipart.commons.CommonsMultipartResolver">
          ????????
          <!--?設(shè)置上傳文件的最大尺寸為1MB?-->
          ????????
          <property?name="maxUploadSize">
          ????????
          <value>1048576</value>
          ????
          </property>
          </bean>


            這樣一旦某個Request是一個MultipartRequest,它就會首先被MultipartResolver處理,然后再轉(zhuǎn)發(fā)相應(yīng)的Controller。
            在UploadImageController中,將HttpServletRequest轉(zhuǎn)型為MultipartHttpServletRequest,就能非常方便地得到文件名和文件內(nèi)容:

          public?ModelAndView?handleRequest(HttpServletRequest?request,?HttpServletResponse?response)?throws?Exception?{
          ????
          //?轉(zhuǎn)型為MultipartHttpRequest:
          ????MultipartHttpServletRequest?multipartRequest?=?(MultipartHttpServletRequest)?request;
          ????
          //?獲得文件:
          ????MultipartFile?file?=?multipartRequest.getFile("file");
          ????
          //?獲得文件名:
          ????String?filename?=?file.getOriginalFilename();
          ????
          //?獲得輸入流:
          ????InputStream?input?=?file.getInputStream();
          ????
          //?寫入文件
          }


          生成縮略圖 (目錄)
            當(dāng)用戶上傳了圖片后,必須生成縮略圖以便用戶能快速瀏覽。我們不需借助第三方軟件,JDK標(biāo)準(zhǔn)庫就包含了圖像處理的API。我們把一張圖片按比例縮放到120X120大小,以下是關(guān)鍵代碼:

          public?static?void?createPreviewImage(String?srcFile,?String?destFile)?{
          ????
          try?{
          ????????File?fi?
          =?new?File(srcFile);?//?src
          ????????File?fo?=?new?File(destFile);?//?dest
          ????????BufferedImage?bis?=?ImageIO.read(fi);

          ????????
          int?w?=?bis.getWidth();
          ????????
          int?h?=?bis.getHeight();
          ????????
          double?scale?=?(double)w/h;
          ????????
          int?nw?=?IMAGE_SIZE;?//?final?int?IMAGE_SIZE?=?120;
          ????????int?nh?=?(nw?*?h)?/?w;
          ????????
          if(?nh>IMAGE_SIZE?)?{
          ????????????nh?
          =?IMAGE_SIZE;
          ????????????nw?
          =?(nh?*?w)?/?h;
          ????????}

          ????????
          double?sx?=?(double)nw?/?w;
          ????????
          double?sy?=?(double)nh?/?h;

          ????????transform.setToScale(sx,sy);
          ????????AffineTransformOp?ato?
          =?new?AffineTransformOp(transform,?null);
          ????????BufferedImage?bid?
          =?new?BufferedImage(nw,?nh,?BufferedImage.TYPE_3BYTE_BGR);
          ????????ato.filter(bis,bid);
          ????????ImageIO.write(bid,?
          "jpeg",?fo);
          ????}
          ?catch(Exception?e)?{
          ????????e.printStackTrace();
          ????????
          throw?new?RuntimeException("Failed?in?create?preview?image.?Error:?"?+?e.getMessage());
          ????}

          }

          實(shí)現(xiàn)RSS (目錄)
            RSS是一個標(biāo)準(zhǔn)的XML文件,Rss閱讀器可以讀取這個XML文件獲得文章的信息,使用戶可以通過Rss閱讀器而非瀏覽器閱讀Blog,我們只要動態(tài)生成這個XML文件便可以了。RSSLibJ是一個專門讀取和生成RSS的小巧實(shí)用的Java庫,大小僅25k,可以從http://sourceforge.net/projects/rsslibj/下載rsslibj-1_0RC2.jar和它需要的EXMLjar兩個文件,然后復(fù)制到web/WEB-INF/lib/下。
            使用RSSLibJ異常簡單,我們先設(shè)置好HttpServletResponse的Header,然后通過RSSLibJ輸出XML即可:

          Channel?channel?=?new?Channel();
          channel.setDescription(account.getDescription());
          baseUrl?
          =?baseUrl.substring(0,?n);
          channel.setLink(
          "http://server-name/home.c?accountId="?+?accountId);
          channel.setTitle(account.getTitle());
          List?articles?
          =?facade.getArticles(accountId,?account.getMaxPerPage(),?1);
          Iterator?it?
          =?articles.iterator();
          while(it.hasNext())?{
          ????Article?article?
          =?(Article)it.next();
          ????channel.addItem(
          "http://server-name/article.c?articleId="?+?article.getArticleId(),
          ????????article.getSummary(),?article.getTitle()
          ????);
          }

          //?輸出xml:
          response.setContentType("text/xml");
          PrintWriter?pw?
          =?response.getWriter();
          pw.print(channel.getFeed(
          "rss"));
          pw.close();

          實(shí)現(xiàn)全文搜索 (目錄)
            全文搜索能大大方便用戶快速找到他們希望的文章,為blog增加一個全文搜索功能是非常必要的。然而,全文搜索不等于SQL的LIKE語句,因?yàn)殛P(guān)系數(shù)據(jù)庫的設(shè)計(jì)并不是為全文搜索設(shè)計(jì)的,數(shù)據(jù)庫索引對全文搜索無效,在一個幾百萬條記錄中檢索LIKE '%A%'可能會耗時幾分鐘,這是不可接受的。幸運(yùn)的是,我們能使用免費(fèi)并且開源的純Java實(shí)現(xiàn)的Lucene全文搜索引擎,Lucene可以非常容易地集成到我們的blog中。
            Lucene不提供直接對文件,數(shù)據(jù)庫的索引,只提供一個高性能的引擎,但接口卻出人意料地簡單。我們只需要關(guān)心以下幾個簡單的接口:
            Document:代表Lucene數(shù)據(jù)庫的一條記錄,也代表搜索的一條結(jié)果。
            Field:一個Document包含一個或多個Field,類似關(guān)系數(shù)據(jù)庫的字段。
            IndexWriter:用于創(chuàng)建新的索引,也就是向數(shù)據(jù)庫添加新的可搜索的大段字符串。
            Analyzer:將字符串拆分成單詞(Token),不同的文本對應(yīng)不同的Analyzer,如HtmlAnalyzer,PDFAnalyzer。
            Query:封裝一個查詢,用于解析用戶輸入。例如,將“bea blog”解析為“同時包含bea和blog的文章”。
            Searcher:搜索一個Query,結(jié)果將以Hits返回。
            Hits:封裝一個搜索結(jié)果,包含Document集合,能非常容易地輸出結(jié)果。
            下一步,我們需要為Article表的content字段建立全文索引。首先為Lucene新建一個數(shù)據(jù)庫,請注意這個數(shù)據(jù)庫是Lucene專用的,我們不能也不必知道它的內(nèi)部結(jié)構(gòu)。Lucene的每個數(shù)據(jù)庫對應(yīng)一個目錄,只需要指定目錄即可:

          String?indexDir?=?"C:/search/blog";
          IndexWriter?indexWriter?
          =?new?IndexWriter(indexDir,?new?StandardAnalyzer(),?true);
          indexWriter.close();

            然后添加文章,讓Lucene對其索引:

          String?title?
          =?"文章標(biāo)題"?//?從數(shù)據(jù)庫讀取
          String?content?=?"文章內(nèi)容"?//?從數(shù)據(jù)庫讀取
          //?打開索引:
          IndexWriter?indexWriter?=?new?IndexWriter(indexDir,?new?StandardAnalyzer(),?false);
          //?添加一個新記錄:
          Document?doc?=?new?Document();
          doc.add(Field.Keyword(
          "title",?title));
          doc.add(Field.Text(
          "content",?content));
          //?建立索引:
          indexWriter.addDocument(doc);
          //?關(guān)閉:
          indexWriter.close();

           要搜索文章非常簡單:
           然后添加文章,讓對其索引:

          String?title?=?"文章標(biāo)題"?//?從數(shù)據(jù)庫讀取
          String?content?=?"文章內(nèi)容"?//?從數(shù)據(jù)庫讀取
          //?打開索引:
          IndexWriter?indexWriter?=?new?IndexWriter(indexDir,?new?StandardAnalyzer(),?false);
          //?添加一個新記錄:
          Document?doc?=?new?Document();
          doc.add(Field.Keyword(
          "title",?title));
          doc.add(Field.Text(
          "content",?content));
          //?建立索引:
          indexWriter.addDocument(doc);
          //?關(guān)閉:
          indexWriter.close();

            要搜索文章非常簡單:

          Searcher?searcher?=?new?IndexSearcher(dir);
          Query?query?
          =?QueryParser.parse(keyword,?"content",?new?StandardAnalyzer());
          Hits?hits?
          =?searcher.search(query);
          if(hits?!=?null){
          ????
          for(int?i?=?0;i?<?hits.length();?i++){
          ????????Document?doc?
          =?hits.doc(i);
          ????????System.out.println(
          "found?in?"?+?doc.get("title"));
          ????????System.out.println(doc.get(
          "content"));
          ????}

          }

          searcher.close();
            我們設(shè)計(jì)一個LuceneSearcher類封裝全文搜索功能,由于必須鎖定數(shù)據(jù)庫所在目錄,我們把數(shù)據(jù)庫設(shè)定在/WEB-INF/search/下,確保用戶不能訪問,并且在配置文件中初始化目錄:

          <bean?id="luceneSearcher"?class="org.crystalblog.search.LuceneSearcher">
          ????
          <property?name="directory">
          ???????
          <value>/WEB-INF/search/</value>
          ????
          </property>
          </bean>

          效果如下:


          (圖4:search)

          發(fā)送Email (目錄)
            Blog用戶可以讓系統(tǒng)將來訪用戶的留言發(fā)送到注冊的Email地址,為了避免使用SMTP發(fā)信服務(wù)器,我們自己手動編寫一個SendMail組件,直接通過SMTP協(xié)議將Email發(fā)送到用戶信箱。
            SendMail組件只需配置好DNS服務(wù)器的IP地址,即可向指定的Email信箱發(fā)送郵件。并且,SendMail使用緩沖隊(duì)列和多線程在后臺發(fā)送Email,不會中斷正常的Web服務(wù)。具體代碼請看SendMail.java。

          測試 (目錄)
            服務(wù)器配置為:P4 1.4G,512M DDR,100M Ethernet,Windows XP Professional SP2。
            測試服務(wù)器分別為WebLogic Server 8.1,Tomcat 4.1/5.0,Resin 2.1.1。
            測試數(shù)據(jù)庫為MS SQL Server 2000 SP3。如果你使用Oracle或者DB2,MySQL等其他數(shù)據(jù)庫并測試成功,請將SQL初始化腳本和詳細(xì)配置過程發(fā)一份給我,謝謝。
            由于時間有限,沒有作進(jìn)一步的調(diào)優(yōu)。WebLogic Server和iBatis有很多優(yōu)化選項(xiàng),詳細(xì)配置可以參考相關(guān)文檔。

          中文支持 (目錄)
            測試發(fā)現(xiàn),中文不能在頁面中正常顯示,為了支持中文,首先在web.xml加入Filter,用于將輸入編碼設(shè)置為gb2312:
          <filter>
          ????
          <filter-name>encodingFilter</filter-name>
          ????
          <filter-class>org.crystalblog.web.filter.EncodingFilter</filter-class>
          ????
          <init-param>
          ????????
          <param-name>encoding</param-name>
          ????????
          <param-value>gb2312</param-value>
          ????
          </init-param>
          </filter>
          <filter-mapping>
          ????
          <filter-name>encodingFilter</filter-name>
          ????
          <url-pattern>/*</url-pattern>
          </filter-mapping>

            然后用文本工具搜索所有的.htm,.html,.properties文件,將“iso-8859-1”替換為“gb2312”,現(xiàn)在頁面中文已經(jīng)能正常顯示,但是Lucene仍不能正常解析中文,原因是標(biāo)準(zhǔn)的StandardA?nalyzer只能解析英文,可以從網(wǎng)上下載一個支持中文的 Analyzer。

          posted on 2006-10-13 10:08 捕風(fēng) 閱讀(265) 評論(1)  編輯  收藏 所屬分類: java高級

          評論

          # re: j2ee小應(yīng)用 2008-01-19 08:41 touchsky88

          Dealing with Chinese, unicode I suppose is a pain on the neck.

          Add the following part solve the unicode problem.
          <bean id="multipartResolver"
          class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
          <!-- 設(shè)置上傳文件的最大尺寸為1MB -->
          <property name="maxUploadSize">
          <value>1048576</value>
          </property>
          <property name="defaultEncoding">
          <value>UTF-8</value>
          </property>
          </bean>  回復(fù)  更多評論   

          主站蜘蛛池模板: 鄂州市| 电白县| 泽库县| 康乐县| 腾冲县| 汤原县| 连州市| 松滋市| 卫辉市| 临沂市| 睢宁县| 道真| 天柱县| 崇州市| 柘荣县| 新竹市| 马龙县| 高密市| 交口县| 麻江县| 开封县| 都兰县| 定南县| 开江县| 鄂尔多斯市| 张家口市| 彭州市| 泾川县| 克山县| 平和县| 仪陇县| 会东县| 哈巴河县| 明溪县| 昌乐县| 杭州市| 九台市| 乌恰县| 商南县| 志丹县| 高青县|