亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

基于J2EE的Blog平臺

2019-11-18 16:08:50
字體:
來源:轉載
供稿:網友

 Blog(WebLog)在Internet上越來越流行。許多網友都有了自己的Blog,通過Blog展示自己,結識更過的網友。比較著名的Blog平臺是基于asp.net的開源項目.Text。但是它的邏輯全部以存儲過程的形式放在數據庫中。雖然存儲過程能大大提高數據操作的效率,但是存儲過程本身是結構化的程序,無法發揮面向對象的威力,也不便于實現代碼復用。因此,我決定實現一個基于J2EE體系的多層結構的Blog平臺,功能和界面和.Text非常類似,暫命名為Crystal Blog。實現的功能有:發表和編輯文章;多用戶支持;全文檢索;rss支持;圖片管理;SMTP郵件發送等常見功能。界面如下:

基于J2EE的Blog平臺(圖一)

選擇平臺和框架 (目錄)
  由于使用J2EE平臺,我們準備采用WebLogic Server 8.1作為運行平臺,使用WebLogic Workshop8.1這個強大的集成化IDE作為開發工具。
  數據庫選擇MS SQL Server 2000 SP3,建立一個名為blog的數據庫存儲所有的用戶數據。由于我們并沒有針對特定數據庫編碼,稍后我們會使用其他數據庫測試。在系統設計之前,選擇一個優秀的框架能大大提高開發效率。SPRing是一個輕量級的J2EE框架。它覆蓋了從后臺數據庫的JDBC封裝到前臺Web框架的幾乎所有方?面。并且,Spring的各個模塊耦合非常松散,我們既可以用它作為整個應用程序的框架,也可以僅僅使用它的某一個模塊。此外,Spring非常強大的集成功能使我們可以輕易地集成Struts編寫的Web端,或者使用Hibernate作為后端的O/R Mapping方案。
  Spring的核心思想便是IoC和AOP,Spring本身是一個輕量級容器,和EJB容器不同,Spring的組件就是普通的java Bean,這使得單元測試可以不再依賴容器,編寫更加容易。Spring負責管理所有的Java Bean組件,同樣支持聲明式的事務管理。我們只需要編寫好Java Bean組件,然后將它們“裝配”起來就可以了,組件的初始化和管理均由Spring完成,只需在配置文件中聲明即可。這種方式最大的優點是各組件的耦合極為松散,并且無需我們自己實現Singleton模式。
  由于后臺要使用關系數據庫存儲數據,使用O/R Mapping必不可少。iBatis是又一個類似于Hibernate的O/R Mapping方案,特點是小巧,配置簡單,查詢靈活,完全符合我們的要求。
  除了Spring和iBatis,用到的第三方組件還有:用于全文搜索的LUCene引擎,用于文件上傳的common-file-upload 1.0,用于輸出RSS的RSSLibJ1.0 RC2。
  由于使用Spring這個輕量級框架,就無需EJB服務器,只需要Web服務器即可。因此,系統可以運行在WebLogic Server,Tomcat和Resin等支持Servlet和jsp的Web服務器上。

系統設計 (目錄)
  很顯然,多層結構的J2EE架構能保證系統的靈活性和可擴展性。我們仍然采用表示層/邏輯層/持久層三層設計。

基于J2EE的Blog平臺(圖二)

點擊查看大圖

  整個系統以Spring為基礎,持久層采用DAO模式和iBatis O/R Mapping,封裝所有數據庫操作;中間層是由Spring管理的普通的JavaBean,采用Fa?ade模式;表示層使用Spring提供的MVC框架。由于Spring對其他框架的良好集成,我們采用Velocity作為View。由于Velocity不能調用Java代碼,從而強制使用MVC模式而不是在View中嵌入邏輯代碼。

配置服務器 (目錄)
  在WebLogic中新建一個Configuration,命名為blog,添加一個數據源,命名為jdbc/blog:

基于J2EE的Blog平臺(圖三)

點擊查看大圖

  整個應用程序的目錄結構如下:

crystalblog/
+ doc/ (存放API文檔)
+ report/ (存放JUnit測試結果)
+ src/ (存放java源程序)
+ web/ (web目錄)
+ manage/ (存放blog管理頁)
+ SKIN/ (存放blog界面頁)
+ upload/ (存放用戶上傳的圖片)
+ WEB-INF/
   + classes/ (存放編譯的class文件)
   + lib/ (存放用到的所有jar文件)
   + search/ (存放Lucene的index)
   + c.tld (使用jstl必須的文件)
   + dispatcher-servlet.xml (Spring配置文件)
   + web.xml (標準web配置文件)
+ blog.war (打包的可部署應用)
+ build.xml (ant腳本)

編寫Ant?腳本 (目錄)
  Ant是一個非常棒的執行批處理任務的工具。使用Ant能使編譯、測試、打包、部署和生成文檔等一系列任務全自動化,從而大大節省開發時間。
  首先我們把用到的所有.jar文件放到/web/WEB-INF/lib中,然后編寫compile任務,生成的class文件直接放到web/WEB-INF/classes目錄下。如果編譯成功,就進行單元測試,單元測試的結果以文本文件存放在report目錄中。如果測試通過,下一步便是打包成blog.war文件。接著把應用部署到服務器上,直接將web目錄的內容復制到%BEA_HOME%/user_projects/domains/blogdomain/applications/blog/目錄下即可。如果要在Tomcat上部署,直接將整個web目錄復制到%TOMCAT%/webapps/blog/下。
  最后,如果需要,可以用javadoc生成api文檔。


系統設計 (目錄)
  Crystal Blog共分成三層結構:后臺數據持久層,采用DAO模式;中間邏輯層,采用Facade模式;前端Web層,采用MVC結構,使用JSP作為視圖。以下是Rational Rose的UML圖:

設計Domain對象 (目錄)

  設計Domain對象
  Domain層是抽象出的實體。根據我們要實現的功能,設計以下實體,它們都是普通的Java Bean:
  Account:封裝一個用戶,包括用戶ID,用戶名,口令,用戶設置等等。
  Category:封裝一個分類,一共有3種Category,分別用來管理Article,Image和Link,一個Account對應多個Category。
  Article:封裝一篇文章,包括Title,Summary,Content等等,一個Category對應多個Article。
  Feedback:封裝一個回復,包括Title,Username,Url和Content,一個Article對應多個Feedback。
  Image:封裝一個圖片,Image只包含圖片信息(ImageId,Type),具體的圖片是以用戶上傳到服務器的文件的形式存儲的。一個Category對應多個Image。
  Link:封裝一個鏈接,和Category是多對一的關系。有Title,Url,Rss等屬性。
  Message:封裝一個消息,使其他用戶在不知道Email地址的情況下能夠通過系統發送郵件給某個用戶。

  最后,為了唯一標識每條數據庫記錄,我們需要一個主鍵。在MS SQL Server和Oracle中可以使用自動遞增的主鍵生成方式。但是很多數據庫不支持自動遞增的主鍵,考慮到移植性,我們自己定義一個Sequence表,用于生成遞增的主鍵。Sequence表有且僅有7條記錄,分別記錄Account到Message對象的當前最大主鍵值。系統啟動時,由SqlConfig負責初始化Sequence表。
  SequenceDao負責提供下一個主鍵,為了提高效率,一次緩存10個主鍵。

配置iBatis (目錄)
  接下來,使用iBatis實現O/R Mapping。首先從http://www.ibatis.com下載iBatis 2.0,將所需的jar文件復制到web/WEB-INF/lib/目錄下。iBatis使用XML配置數據庫表到Java對象的映射,先編寫一個sql-map-config.xml:

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE sqlMapConfig
  PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"
  "http://www.ibatis.com/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
  <settings cacheModelsEnabled="false" enhancementEnabled="true"
    lazyLoadingEnabled="true" maxRequests="32"
    maxsessions="10" maxTransactions="5"
    useStatementNamespaces="false"
  />
  <transactionManager type="JDBC">
    <dataSource type="JNDI">
      <property name="DataSource" value="jdbc/blog" />
    </dataSource>
  </transactionManager>
  <!-- 如果有其他xml配置文件,可以包含進來 -->
  <sqlMap resource="Account.xml" />
</sqlMapConfig>

  將sql-map-config.xml放到web/WEB-INF/classes/目錄下,iBatis就能搜索到這個配置文件,然后編寫一個初始化類:

public class SqlConfig {
    private SqlConfig() {}
    private static final SqlMapClient sqlMap;
    static {
        try {
            java.io.Reader reader = Resources.getResourceAsReader ("sql-map-config.xml");
            sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("Error initializing SqlConfig. Cause: " + e);
        }
    }
    public static SqlMapClient getSqlMapInstance () {
        return sqlMap;
    }
}

  SqlMapClient封裝了訪問數據庫的大部分操作,可以直接使用SqlConfig.getSqlMapInstance()獲得這個唯一實例。


使用DAO模1 式 (目錄)
  為了分離邏輯層和數據庫持久層,定義一系列DAO接口:AccountDao,CategoryDao,ArticleDao……其實現類對應為SqlMapAccountDao,SqlMapCategoryDao,SqlMapArticleDao……這樣就使得邏輯層完全脫離了數據庫訪問代碼。如果將來需要使用其它的O/R Mapping方案,直接實現新的DAO接口替代現有的SqlMapXxxDao即可。
  以SqlMapAccountDao為例,實現一個login()方法是非常簡單的:

public int login(String username, String passWord) throws AuthorizationException {
    try {
        Map map = new HashMap();
        map.put("username", username);
        map.put("password", password);
        Integer I = (Integer)sqlMap.queryForObject("login", map);
        if(I==null)
            throw new RuntimeException("Failed: Invalid username or password.");
        return I.intValue();
    }
    catch(SQLException sqle) {
        throw new RuntimeException("Sql Exception: " + sqle);
    }
}

  在Account.xml配置文件中定義login查詢:

<select id="login" parameterClass="java.util.Map" resultClass="int">
  select [accountId] from [Account] where
  [username] = #username# and password = #password#
</select>

邏輯層設計 (目錄)
  由于DAO模式已經實現了所有的數據庫操作,業務邏輯主要是檢查輸入,調用DAO接口,因此業務邏輯就是一個簡單的Facade接口:

public class FacadeImpl implements Facade {
    private AccountDao  accountDao;
    private ArticleDao  articleDao;
    private CategoryDao categoryDao;
    private FeedbackDao feedbackDao;
    private ImageDao    imageDao;
    private LinkDao     linkDao;
    private SequenceDao sequenceDao;
}

  對于普通的getArticle()等方法,Facade僅僅簡單地調用對應的DAO接口:

public Article getArticle(int articleId) throws QueryException {
    return articleDao.getArticle(articleId);
}

  對于需要身份驗證的操作,如deleteArticle()方法,Facade需要首先驗證用戶身份:

public void deleteArticle(Identity id, int articleId) throws DeleteException {
    Article article = getArticleInfo(articleId);
    if(article.getAccountId()!=id.getAccountId())
        throw new AuthorizationException("Permission denied.");
    articleDao.deleteArticle(articleId);
}

  要分離用戶驗證邏輯,可以使用Proxy模式,或者使用Spring的AOP,利用MethodInterceptor實現,不過,由于邏輯很簡單,完全可以直接寫在一塊,不必使用過于復雜的設計。
  至此,我們的Blog已經實現了所有的后臺業務邏輯,并且提供統一的Facade接口。前臺Web層僅僅依賴這個Facade接口,這樣,Web層和后臺耦合非常松散,即使替換整個Web層也非常容易。


Web層設計 (目錄)
使用MVC模式 (目錄)
  對于復雜的Web層,使用MVC模式是必不可少的。雖然Spring能輕易集成Struts,WebWorks等Web框架,但Spring本身就提供了一個非常好的Web框架,能完全實現MVC模式。
  Spring使用一個DispatcherServlet,所有的特定請求都被轉發到DispatcherServlet,然后由相應的Controller處理,Controller返回一個ModelAndView對象(因為Java語言的方法調用只能返回一個結果,而且不支持ref參數,所以將Model和View對象合在一起返回),Model是一個Java對象,通常是Map,View是視圖的邏輯名字,通常是JSP文件名,但也可以使用Velocity等作為視圖。返回的View通過viewResolver得到真正的文件名。
  首先配置Spring的MVC,在web.xml中聲明DispatcherServlet,處理所有以.c結尾的請求:

<web-app>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>*.c</url-pattern>
    </servlet-mapping>
</web-app>

  Spring會在WEB-INF下查找一個名為dispatcher-servlet.xml的文件,我們需要創建這個文件:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
 "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
</beans>

 用到的所有的Java Bean組件都要在這個文件中聲明和配置,以下是配置URL映射的Bean:

<bean id="urlMapping"
 class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
        <props>
            <prop key="/article.c">articleController</prop>
        </props>
    </property>
</bean>

  凡是匹配/article.c的Request都會被名為articleController的Bean處理,同樣需要聲明這個articleController:

<bean id="articleController" class="example.ViewArticleController">
</bean>

 ViewArticleController處理請求,然后生成Model,并選擇一個View:

public class ViewArticleController implements Controller {
    private Facade facade;
    public void setFacade(Facade facade) { this.facade = facade; }
public ModelAndView handleRequest(HttpServletRequest request,
    HttpServletResponse response) throws Exception {
        // 獲得參數:
        int articleId = Integer.parseInt(request.getParameter("articleId"));
        // 使用facade處理請求:
        Article article = facade.getArticle(articleId);
        // 生成Model:
        Map map = new HashMap();
        map.put("article", article);
        // 返回Model和視圖名“skin/blueskysimple/article”:
        return new ModelAndView("skin/blueskysimple/article", map);
    }
}

  最后,skin/bluesky/article視圖會將結果顯示給用戶。
  我們注意到,ViewArticleController并不自己查找或者創建Facade,而是由容器通過setFacade(Facade)方法設置的,這就是所謂的IoC(Inversion of Control)或者Dependency Injection。容器通過配置文件完成所有組件的初始化工作:

<!-- 聲明一個Facade -->
<bean id="facade" class="example.Facade" />
<!-- 聲明一個Controller -->
<bean id="articleController" class="example.ViewArticleController">
    <!-- 為articleController設置facade屬性 -->
<property name="facade">
        <!-- 將名為facade的Bean的引用傳進去 -->
        <ref bean="facade" />
    </property>
</bean>

  以上配置文件實現的功能大致為:

Facade facade = new Facade();
ViewArticleController articleController = new ViewArticleController();
articleController.setFacade(facade);

  但是我們不必編寫以上代碼,只需在xml文件中裝配好我們的組件就可以了。所有組件由Spring管理,并且,缺省的創建模式是Singleton,確保了一個組件只有一個實例。
  此外,所有自定義異常都是RuntimeException,Spring提供的AOP使我們能非常方便地實現異常處理。在Web層定義ExceptionHandler,處理所有異常并以統一的error頁面把出錯信息顯示給用戶,因此,在代碼中只需拋出異常,完全不必在Controller中處理異常:

<bean id="handlerExceptionResolver" class="org.crystalblog.web.ExceptionHandler" />


使用Velocity作為View
  采用Velocity作為View的最大的優點是簡潔,能通過簡單明了的語法直接在Html中輸出Java變量。Velocity本身是一個模板引擎,通過它來渲染Model輸出Html非常簡單,比如顯示用戶名:

<b>${account.username}</b>
  換成JSP不得不寫成:
<b><%=account.getUsername()%></b>
而<%...%>標記在Dreamwaver中無法直接看到其含義。如果需要在標簽中嵌入JSP就更晦澀了:
<a href="somelink?id=<%=id %>">Link</a>

  這種嵌套的標簽往往使得可視化Html編輯器難以正常顯示,而Velocity用直接嵌入的語法解決了“ <%...%>”的問題。
  在Spring中集成Velocity是非常簡單的事情,甚至比單獨使用Velocity更簡單,只需在dispatcher-servlet.xml中申明:

<bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
</bean>
<bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
    <property name="resourceLoaderPath"><value>/</value></property>
    <property name="configLocation"><value>/WEB-INF/velocity.properties</value></property>
</bean>

  雖然標準的Velocity模板以.vm命名,但我們的所有Velocity模板頁均以.html作為擴展名,不但用Dreamwaver編輯極為方便,甚至可以直接用IE觀看頁面效果。

實現Skin (目錄)
  許多Blog系統都允許用戶選擇自己喜歡的界面風格。要實現Skin功能非常簡單,為每個Skin編寫Velocity模板,存放在web/skin/目錄下,然后在Controller中返回對應的視圖:

String viewpath = skin.getSkin(account.getSkinId()) + "viewArticle";

  由于使用了MVC模式,我們已經為每個頁面定義好了Model,添加一個新的skin非常容易,只需要編寫幾個必須的.html文件即可,可以參考現有的skin。
  SkinManager的作用是在啟動時自動搜索/skin/目錄下的所有子目錄并管理這些skin,將用戶設定的skinId映射到對應的目錄。目前只有一個skin,您可以直接用可視化Html編輯器如Dreamwaver改造這個skin。

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

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

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

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


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

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());
    }
}

實現RSS (目錄)
  RSS是一個標準的XML文件,Rss閱讀器可以讀取這個XML文件獲得文章的信息,使用戶可以通過Rss閱讀器而非瀏覽器閱讀Blog,我們只要動態生成這個XML文件便可以了。RSSLibJ是一個專門讀取和生成RSS的小巧實用的Java庫,大小僅25k,可以從http://sourceforge.net/projects/rsslibj/下載rsslibj-1_0RC2.jar和它需要的EXMLjar兩個文件,然后復制到web/WEB-INF/lib/下。
  使用RSSLibJ異常簡單,我們先設置好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();

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

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

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

String title = "文章標題" // 從數據庫讀取
String content = "文章內容" // 從數據庫讀取
// 打開索引:
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);
// 關閉:
indexWriter.close();

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

String title = "文章標題" // 從數據庫讀取
String content = "文章內容" // 從數據庫讀取
// 打開索引:
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);
// 關閉:
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();


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

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

效果如下:

基于J2EE的Blog平臺(圖四)

點擊查看大圖

(圖4:search)

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

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

中文支持 (目錄)
  測試發現,中文不能在頁面中正常顯示,為了支持中文,首先在web.xml加入Filter,用于將輸入編碼設置為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”,現在頁面中文已經能正常顯示,但是Lucene仍不能正常解析中文,原因是標準的StandardA?nalyzer只能解析英文,可以從網上下載一個支持中文的Analyzer。

總結 (目錄)
  Spring的確是一個優秀的J2EE框架,通過Spring強大的集成和配置能力,我們能輕松設計出靈活的多層J2EE應用而無需復雜的EJB組件支持。由于時間倉促,水平有限,文中難免有不少錯誤,懇請讀者指正。

源代碼下載 (目錄)
  源代碼可以從http://www.javASPrite.com/crystal/index.htm下載。

相關資源下載 (目錄)
JDK 1.4.2可以從http://java.sun.com下載。
Spring framework 1.1可以從http://www.springframework.org下載。
iBatis 2.0可以從http://www.ibatis.com下載。
Tomcat 4.1/5.0、Ant 1.6可以從http://www.apache.org下載。
Resin 2.1.1可以從http://www.caucho.com下載。
WebLogic Server / Workshop 8.1可以從http://commerce.bea.com下載。
JUnit 3.8可以從http://www.junit.org下載。
MySQL 4及其JDBC驅動可以從http://www.mysql.com下載。
MS SQL Server 2000 JDBC驅動可以從http://www.microsoft.com/downloads/details.aspx?FamilyID=07287b11-0502-461a-b138-2aa54bfdc03a&DisplayLang=en下載。
RSSLibJ 1.0可以從http://sourceforge.net/projects/rsslibj/下載。


參考 (目錄)
“Spring Reference”,Rod Johnson等。
“iBatis SQL Maps Guide”。
“Apache Ant 1.6.2 Manual”。
“Lucene Getting Started”。
Springframework的JPetStore示例是非常棒的設計,本文參考了JPetStore的許多設計模式。

關于作者
廖雪峰,北京郵電大學本科畢業,對J2EE/J2ME有濃厚興趣,歡迎交流:asklxf@163.com。
個人網站:http://www.javasprite.com,歡迎訪問。
個人Blog站點:http://blog.csdn.net/asklxf/,歡迎訪問。

(出處:http://www.49028c.com)



發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
色多多国产成人永久免费网站| 波霸ol色综合久久| 国产精品午夜视频| 欧美极品少妇xxxxx| 91美女福利视频高清| 日韩亚洲精品电影| 国产主播在线一区| 不卡在线观看电视剧完整版| 亚洲免费人成在线视频观看| 91精品国产777在线观看| 日韩欧美成人免费视频| 国产精品高潮呻吟久久av黑人| 欧美精品video| 亚洲男人天堂手机在线| 热久久99这里有精品| 久久久久久久久91| 米奇精品一区二区三区在线观看| 宅男66日本亚洲欧美视频| 国产精品狼人色视频一区| 欧美激情视频三区| 日韩成人激情影院| 久久国产精彩视频| 国内精品中文字幕| 亚洲精品成人久久久| 中文国产亚洲喷潮| 精品国产老师黑色丝袜高跟鞋| 国产福利精品av综合导导航| 中文字幕亚洲无线码a| 亚洲欧美综合图区| 亚洲女人初尝黑人巨大| 97国产精品免费视频| 九九久久久久99精品| 日韩久久免费视频| 国产精品久久久久久五月尺| 日韩在线视频国产| 91免费在线视频网站| 欧美精品手机在线| 高清欧美性猛交xxxx| 裸体女人亚洲精品一区| 亚洲男人天堂网站| 国产精品爽黄69天堂a| 欧美极品少妇xxxxⅹ免费视频| 成人午夜小视频| 日韩欧美a级成人黄色| 国产亚洲在线播放| 国产欧美亚洲视频| 97视频在线观看免费高清完整版在线观看| 午夜精品久久久久久久99热浪潮| 欧美国产日韩一区二区三区| 亚洲欧美日韩久久久久久| 亚洲网在线观看| 神马国产精品影院av| 亚洲第一免费网站| 国产网站欧美日韩免费精品在线观看| 亚洲国产高清福利视频| 日韩欧美国产中文字幕| 亚洲精品国产精品乱码不99按摩| 久久频这里精品99香蕉| 日日噜噜噜夜夜爽亚洲精品| 91亚洲精品久久久| 国产精品永久免费在线| 亚洲bt欧美bt日本bt| 国产欧洲精品视频| 国产ts人妖一区二区三区| 亚洲精品美女在线观看播放| 性金发美女69hd大尺寸| 亚洲欧美一区二区三区在线| 亚洲一区中文字幕在线观看| 亚洲精品久久久久中文字幕欢迎你| 亚洲第一视频在线观看| 国产成人免费av电影| 国产视频自拍一区| 狠狠躁18三区二区一区| 久久色免费在线视频| 91牛牛免费视频| 国产精品欧美风情| 亚洲嫩模很污视频| 久99久在线视频| 久久久国产一区二区三区| 国产成人拍精品视频午夜网站| 国产亚洲精品久久久久动| 日本高清视频一区| 国产有码在线一区二区视频| 亚洲人成亚洲人成在线观看| 美女少妇精品视频| 亚洲美女在线观看| 久久久久久久久亚洲| 国产精品极品美女粉嫩高清在线| 色樱桃影院亚洲精品影院| 色偷偷噜噜噜亚洲男人| 午夜精品久久久99热福利| 国产精品视频白浆免费视频| 久久在线观看视频| 91香蕉嫩草影院入口| 亚洲欧美国产视频| 国产伦精品一区二区三区精品视频| 欧美成人性色生活仑片| 中文字幕不卡av| 久久精品国产一区二区电影| 91精品91久久久久久| 亚洲欧美日韩精品久久奇米色影视| 欧美精品videos性欧美| 欧美黑人又粗大| 日韩在线视频网站| 国产91精品视频在线观看| 亚洲欧美自拍一区| 热re99久久精品国产66热| 亚洲天堂开心观看| 欧美丝袜一区二区三区| 色诱女教师一区二区三区| 久久这里有精品| 日韩va亚洲va欧洲va国产| 国产男女猛烈无遮挡91| 欧洲美女免费图片一区| 日韩久久免费视频| 2020欧美日韩在线视频| 久久久久久久久久亚洲| 成人免费视频在线观看超级碰| 国产精品久久久久久av| 成人免费网站在线观看| 精品久久香蕉国产线看观看亚洲| 亚洲在线视频福利| 久久视频在线视频| 亚洲视屏在线播放| 色综合男人天堂| 中文字幕日韩高清| 久操成人在线视频| 亚洲人成电影在线观看天堂色| 国产精品久久久久久久久久小说| 中文字幕欧美精品日韩中文字幕| 亚洲最新中文字幕| 国产aⅴ夜夜欢一区二区三区| 青草青草久热精品视频在线网站| 国产日韩专区在线| 精品视频—区二区三区免费| 久久精品男人天堂| 亚洲精品第一国产综合精品| 亚洲欧美国产日韩天堂区| 日本成人黄色片| 欧美亚洲激情在线| 视频在线观看99| 美女扒开尿口让男人操亚洲视频网站| 性欧美暴力猛交69hd| 日本在线精品视频| 91中文字幕在线观看| 日本久久久久久久久久久| 色吧影院999| 欧美色图在线视频| 欧美综合激情网| 少妇高潮 亚洲精品| 中文字幕日韩专区| 色噜噜狠狠狠综合曰曰曰88av| 亚洲成人激情小说| 久久国产精品电影| 国自在线精品视频| 久久九九精品99国产精品| 久久久国产精品一区| 国产欧美在线播放| 亚洲在线免费视频| 精品日韩中文字幕| 亚洲黄色www| 亚洲最大成人免费视频| 国产不卡av在线| 亚洲欧美日韩一区二区三区在线|