现在的位置: 首页 > 搜索技术 > 正文

SSH + Lucene + 分页 + 排序 + 高亮 模拟简单新闻网站搜索引擎

2017年11月02日 搜索技术 ⁄ 共 77386字 ⁄ 字号 评论关闭

http://shuaigg-babysky.iteye.com/blog/414477

前两天看到了一个中国新闻网,这个网站的搜索form的action是

http://search.chinanews.com/search.do

便知道是struts1的产物,现在都用struts2了,所以给自己的任务是实现Struts2 SSH分页浏览新闻、Lucene分页高亮排序搜索新闻这个两个功能。

 

    IDE使用的MyEclipse6.5,数据库使用MySQL 5.0.37 , 另装了Navicat for MySQL , jdk版本是6.0

    工程做完的效果图如下,com.zly.indexManager中两个类,分别创建索引和搜索索引,

    com.zly.test.entity中是使用的实体类,分别是NewsType(新闻类型),NewsItem(新闻具体条目),PageControl(分页实体bean) , SearchResultBean(保存搜索结果的bean).

  

    

 

        浏览和搜索的前提是有据可查,没有数据什么都实现不了 , 我使用了Htmlparser通过抓取页面信息的形式将新闻添加进数据库 , 添加数据库数据使用了hibernate3

        使用了Annotation的方式完成数据库的映射。

         //NewsType(新闻类型)

Java代码  收藏代码
  1. package com.zly.test.entity;  
  2.   
  3. import java.io.Serializable;  
  4.   
  5. import javax.persistence.Column;  
  6. import javax.persistence.Entity;  
  7. import javax.persistence.GeneratedValue;  
  8. import javax.persistence.GenerationType;  
  9. import javax.persistence.Id;  
  10. import javax.persistence.Table;  
  11. @Entity  
  12. @Table(name = "t_newsType")  
  13. public class NewsType implements Serializable {  
  14.   
  15.       
  16.     private static final long serialVersionUID = -5092622762025999122L;  
  17.       
  18.     private Integer id;  
  19.       
  20.     private String newsTypeName;  
  21.     @Column  
  22.     public String getNewsTypeName() {  
  23.         return newsTypeName;  
  24.     }  
  25.   
  26.     public void setNewsTypeName(String newsTypeName) {  
  27.         this.newsTypeName = newsTypeName;  
  28.     }  
  29.     @Id  
  30.     @GeneratedValue(strategy = GenerationType.AUTO)  
  31.     public Integer getId() {  
  32.         return id;  
  33.     }  
  34.   
  35.     public void setId(Integer id) {  
  36.         this.id = id;  
  37.     }  
  38.       
  39.       
  40. }  

 

   //NewsItem(新闻具体条目)

  

Java代码  收藏代码
  1. package com.zly.test.entity;  
  2.   
  3. import java.io.Serializable;  
  4. import java.util.Date;  
  5.   
  6. import javax.persistence.Column;  
  7. import javax.persistence.Entity;  
  8. import javax.persistence.GeneratedValue;  
  9. import javax.persistence.GenerationType;  
  10. import javax.persistence.Id;  
  11. import javax.persistence.JoinColumn;  
  12. import javax.persistence.ManyToOne;  
  13. import javax.persistence.Table;  
  14. import javax.persistence.Temporal;  
  15. import javax.persistence.TemporalType;  
  16. @Entity  
  17. @Table(name = "t_newsItem")  
  18. public class NewsItem implements Serializable {  
  19.   
  20.       
  21.     private static final long serialVersionUID = -7532888546907495633L;  
  22.       
  23.     private Integer id ;   
  24.       
  25.     private String newsTitle ;  
  26.       
  27.     private String newsContent;  
  28.       
  29.     private Date publishTime;  
  30.       
  31.     private String resource;  
  32.       
  33.     private NewsType type;  
  34.       
  35.     private String editor;  
  36.     @Column  
  37.     public String getEditor() {  
  38.         return editor;  
  39.     }  
  40.   
  41.     public void setEditor(String editor) {  
  42.         this.editor = editor;  
  43.     }  
  44.     @ManyToOne  
  45.     @JoinColumn(name = "t_newsType_id")  
  46.     public NewsType getType() {  
  47.         return type;  
  48.     }  
  49.   
  50.     public void setType(NewsType type) {  
  51.         this.type = type;  
  52.     }  
  53.     @Id  
  54.     @GeneratedValue(strategy = GenerationType.AUTO)  
  55.     public Integer getId() {  
  56.         return id;  
  57.     }  
  58.   
  59.     public void setId(Integer id) {  
  60.         this.id = id;  
  61.     }  
  62.     @Column  
  63.     public String getNewsTitle() {  
  64.         return newsTitle;  
  65.     }  
  66.   
  67.     public void setNewsTitle(String newsTitle) {  
  68.         this.newsTitle = newsTitle;  
  69.     }  
  70.       
  71.       
  72.     @Temporal(value = TemporalType.TIMESTAMP)  
  73.     public Date getPublishTime() {  
  74.         return publishTime;  
  75.     }  
  76.   
  77.     public void setPublishTime(Date publishTime) {  
  78.         this.publishTime = publishTime;  
  79.     }  
  80.   
  81.     public String getResource() {  
  82.         return resource;  
  83.     }  
  84.   
  85.     public void setResource(String resource) {  
  86.         this.resource = resource;  
  87.     }  
  88.   
  89.     public String getNewsContent() {  
  90.         return newsContent;  
  91.     }  
  92.   
  93.     public void setNewsContent(String newsContent) {  
  94.         this.newsContent = newsContent;  
  95.     }  
  96.       
  97.       
  98. }  

 

    添加所有新闻类型的类放在了com.zly.test.newsFetch包下 , 具体代码:

 

 

Java代码  收藏代码
  1. package com.zly.test.newsfetch;  
  2.   
  3.   
  4. import java.text.DateFormat;  
  5. import java.text.SimpleDateFormat;  
  6. import java.util.Date;  
  7. import java.util.LinkedHashSet;  
  8. import java.util.Set;  
  9. import java.util.regex.Matcher;  
  10. import java.util.regex.Pattern;  
  11.   
  12. import org.hibernate.Session;  
  13. import org.hibernate.SessionFactory;  
  14. import org.hibernate.cfg.AnnotationConfiguration;  
  15. import org.hibernate.cfg.Configuration;  
  16. import org.htmlparser.Parser;  
  17. import org.htmlparser.Tag;  
  18. import org.htmlparser.filters.NodeClassFilter;  
  19. import org.htmlparser.tags.Div;  
  20. import org.htmlparser.tags.LinkTag;  
  21. import org.htmlparser.util.NodeList;  
  22. import org.htmlparser.visitors.NodeVisitor;  
  23.   
  24. import com.zly.test.entity.NewsItem;  
  25. import com.zly.test.entity.NewsType;  
  26.   
  27. public class GetNews {  
  28.     public static void main(String[] args) throws Exception {  
  29.         //插入数据新闻类型  
  30.         //insertAllTypes();  
  31.           
  32.         //插入所有新闻数据  
  33.           
  34.         //国内新闻  
  35.         //insertNewsItems("http://www.chinanews.com.cn/scroll-news/gn/2009/05" ,"/news.shtml" ,1);  
  36.         //国际新闻  
  37.         //insertNewsItems("http://www.chinanews.com.cn/scroll-news/gj/2009/05" ,"/news.shtml" ,2);  
  38.         //社会新闻  
  39.         //insertNewsItems("http://www.chinanews.com.cn/scroll-news/sh/2009/05" ,"/news.shtml" ,3);  
  40.         //港澳新闻  
  41.         //insertNewsItems("http://www.chinanews.com.cn/scroll-news/ga/2009/05" ,"/news.shtml" ,4);        
  42.         //台湾新闻  
  43.         //insertNewsItems("http://www.chinanews.com.cn/scroll-news/tw/2009/05" ,"/news.shtml" ,5);        
  44.         //华人新闻  
  45.         //insertNewsItems("http://www.chinanews.com.cn/scroll-news/hr/2009/05" ,"/news.shtml" ,6);        
  46.         //经济新闻  
  47.         //insertNewsItems("http://www.chinanews.com.cn/scroll-news/cj/2009/05" ,"/news.shtml" ,7);        
  48.         //文化新闻  
  49.         //insertNewsItems("http://www.chinanews.com.cn/scroll-news/wh/2009/05" ,"/news.shtml" ,8);        
  50.         //娱乐新闻  
  51.         //insertNewsItems("http://www.chinanews.com.cn/scroll-news/yl/2009/05" ,"/news.shtml" ,9);        
  52.         //体育新闻  
  53.         //insertNewsItems("http://www.chinanews.com.cn/scroll-news/ty/2009/05" ,"/news.shtml" ,10);       
  54.         //教育新闻  
  55.         //insertNewsItems("http://www.chinanews.com.cn/scroll-news/edu/2009/05" ,"/news.shtml" ,11);          
  56.         //健康新闻  
  57.         //insertNewsItems("http://www.chinanews.com.cn/scroll-news/jk/2009/05" ,"/news.shtml" ,12);       
  58.         //生活新闻  
  59.         //insertNewsItems("http://www.chinanews.com.cn/scroll-news/life/2009/05" ,"/news.shtml" ,13);         
  60.         //IT新闻  
  61.         //insertNewsItems("http://www.chinanews.com.cn/scroll-news/it/2009/05" ,"/news.shtml" ,14);       
  62.     }  
  63.     public static void insertAllTypes() {  
  64.         Configuration cfg = new AnnotationConfiguration().configure();  
  65.         SessionFactory factory = cfg.buildSessionFactory();  
  66.         Session session = factory.openSession();  
  67.         String str = new String("国内 国际 社会 港澳 台湾 华人 经济 文化 娱乐 体育 教育 健康 生活 IT");  
  68.         String[] typesStr = str.split(" ");  
  69.         NewsType[] types = new NewsType[typesStr.length];  
  70.         session.beginTransaction();  
  71.         for (int i = 0; i < typesStr.length; i++) {  
  72.             types[i] = new NewsType();  
  73.             types[i].setNewsTypeName(typesStr[i]);  
  74.             session.save(types[i]);  
  75.         }  
  76.         session.getTransaction().commit();  
  77.         session.close();  
  78.     }  
  79.       
  80.     //处理5.1 - 5.5 所有的具体类型的新闻  
  81.       
  82.     public static void insertNewsItems(String before , String after , int type) throws Exception {  
  83.         Configuration cfg = new AnnotationConfiguration().configure();  
  84.         SessionFactory factory = cfg.buildSessionFactory();  
  85.         Session session = factory.openSession();  
  86.         //得到当前新闻所属类别  
  87.         NewsType newsType = (NewsType) session.get(NewsType.class, type);  
  88.         final Set<NewsItem> set = new LinkedHashSet<NewsItem>();  
  89.         //获取5月1日-5月5日的新闻  
  90.         for (int i = 1; i <= 5; i++) {  
  91.             String src = before;  
  92.             if(i < 10) {  
  93.                 src = src + "0" + i;  
  94.             }else {  
  95.                 src = src + i ;   
  96.             }  
  97.             src = src + after;  
  98.             //使用htmlParser获取每一条新闻的超链接  
  99.             Parser parser = new Parser(src);  
  100.             parser.setEncoding("gb2312");  
  101.             NodeList divList = parser.parse(new NodeClassFilter(Div.class));  
  102.             for (int j = 0; j < divList.size(); j++) {  
  103.                 Div div = (Div) divList.elementAt(j);  
  104.                 String divClass = div.getAttribute("id");  
  105.                 //取得id为news_list的div  
  106.                 if(divClass != null && divClass.equals("news_list")) {  
  107.                     div.accept(new NodeVisitor() {  
  108.                         //遍历news_list里面的所有超链接  
  109.                         public void visitTag(Tag tag) {  
  110.                             if(tag instanceof LinkTag) {  
  111.                                 String href = ((LinkTag)tag).getLink();  
  112.                                 if(!href.startsWith("http")) {  
  113.                                     href = "http://www.chinanews.com.cn" + href;  
  114.                                 }  
  115.                                 System.out.println(href);  
  116.                                 //找到超链接,将这个超链接所在的页面进行处理,抓取新闻数据,并将其保存在Set中。  
  117.                                 try{  
  118.                                     insertOneNews(href , set);  
  119.                                 }catch(Exception e) {  
  120.                                     e.printStackTrace();  
  121.                                 }  
  122.                                   
  123.                             }  
  124.                         }  
  125.                     });  
  126.                 }  
  127.             }  
  128.         }  
  129.         //获取新闻完成后,将所有NewsItem添加到数据库  
  130.         session.beginTransaction();  
  131.         for (NewsItem newsItem : set) {  
  132.             newsItem.setType(newsType);  
  133.             session.save(newsItem);  
  134.         }  
  135.         session.getTransaction().commit();  
  136.         session.close();  
  137.     }  
  138.     //处理每一个具体的新闻超链接,得到NewsItem类  
  139.     public static void insertOneNews(String src , Set<NewsItem> set) throws Exception {  
  140.         Parser parser = new Parser(src);  
  141.         parser.setEncoding("gb2312");  
  142.         NodeList divList = parser.extractAllNodesThatMatch(new NodeClassFilter(Div.class));  
  143.         NewsItem newsItem = new NewsItem();  
  144.         String title = "";  
  145.         Date parse = null;  
  146.         String content = "";  
  147.         String editor = "";  
  148.         //遍历网页的div。将制定div里面的信息设置到NewsItem实体类中  
  149.         for (int i = 0; i < divList.size(); i++) {  
  150.             Div div = (Div) divList.elementAt(i);  
  151.             String divString = div.getAttribute("class");  
  152.             if(divString != null) {  
  153.                 //设置标题  
  154.                 if(divString.equals("left_bt")) {  
  155.                     title = div.toPlainTextString();  
  156.                 }  
  157.                 //设置发布时间  
  158.                 if(divString.equals("left_time")) {  
  159.                     String publishStr = "";  
  160.                     Pattern pattern = Pattern.compile("[\\d]{4}年[\\d]{2}月[\\d]{2}日 [\\d]{2}:[\\d]{2}");  
  161.                     Matcher matcher = pattern.matcher(div.toPlainTextString()) ;  
  162.                     if(matcher.find()) {  
  163.                         publishStr = matcher.group();  
  164.                     }  
  165.                     DateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH:mm");  
  166.                     parse = format.parse(publishStr);  
  167.                 }  
  168.                 //设置正文内容  
  169.                 if(divString.equals("left_zw")) {  
  170.                     content = div.toHtml();  
  171.                 }  
  172.                 //设置记者名称  
  173.                 if(divString.equals("left_name")) {  
  174.                     editor = div.toPlainTextString().trim();  
  175.                     editor = editor.substring(editor.indexOf(":") + 1, editor.lastIndexOf("】"));  
  176.                 }  
  177.             }  
  178.               
  179.         }  
  180.         newsItem.setEditor(editor);  
  181.         newsItem.setNewsContent(content);  
  182.         newsItem.setNewsTitle(title);  
  183.         newsItem.setPublishTime(parse);  
  184.         //设置新闻来源  
  185.         newsItem.setResource("最快新闻网");  
  186.         //将新闻添加到set中  
  187.         set.add(newsItem);  
  188.     }  
  189. }  

 

 通过上面的代码完成了所有的数据添加工作。

 

下面根据ssh的流程分别定制dao , manager , action

 

com.zly.test.dao包中是所有操作dao的抽象类和接口

 

我们直接看这些接口的实现

 

//NewsItemDaoHibernate  新闻实体类dao

 

 

 

Java代码  收藏代码
  1. @SuppressWarnings("unchecked")  
  2.     //根据分页得到具体页的内容  
  3.     public List<com.zly.test.entity.NewsItem> getNewsItemByFirstResultAndMaxResult(  
  4.             final int firstResult, final int maxResult , final int type) {  
  5.         return (List<NewsItem>) this.getHibernateTemplate().execute(new HibernateCallback() {  
  6.             public Object doInHibernate(Session session)  
  7.                     throws HibernateException, SQLException {  
  8.                 return session.createQuery(" from NewsItem where type.id = '" + type + "'").setFirstResult(firstResult).setMaxResults(maxResult).list();  
  9.             }  
  10.         });  
  11.     }  
  12.     //得到数据总条数 , 以便计算总页数  
  13.     public Long getItemCount(final int id) {  
  14.         return (Long) this.getHibernateTemplate().execute(new HibernateCallback(){  
  15.             public Object doInHibernate(Session session)  
  16.                     throws HibernateException, SQLException {  
  17.                 return session.createQuery("select count(*) from NewsItem where type.id = '" + id + "'").uniqueResult();  
  18.             }  
  19.         });  
  20.     }  
  21.     //显示新闻数据页面用到, 查询具体新闻属于哪个新闻类别  
  22.     public int getNewsType(final int id) {  
  23.         return (Integer) this.getHibernateTemplate().execute(new HibernateCallback() {  
  24.             public Object doInHibernate(Session session)  
  25.                     throws HibernateException, SQLException {  
  26.                 NewsItem newsItem = get(id);  
  27.                 NewsType type = newsItem.getType();  
  28.                 return type.getId();  
  29.             }  
  30.         });  
  31.     }  

 

   只用到了一个   NewsManagerImpl 

 

 

Java代码  收藏代码
  1. package com.zly.test.service.impl;  
  2.   
  3. import java.util.List;  
  4.   
  5. import com.zly.test.dao.NewsItemDao;  
  6. import com.zly.test.entity.NewsItem;  
  7. import com.zly.test.service.NewsManager;  
  8.   
  9. public class NewsManagerImpl implements NewsManager {  
  10.     //新闻条目dao  
  11.     private NewsItemDao newsItemDao;  
  12.       
  13.     public NewsItemDao getNewsItemDao() {  
  14.         return newsItemDao;  
  15.     }  
  16.   
  17.     public void setNewsItemDao(NewsItemDao newsItemDao) {  
  18.         this.newsItemDao = newsItemDao;  
  19.     }  
  20.     //根据分页得到内容  
  21.     public List<NewsItem> getNewsItemByFirstResultAndMaxResult(int firstResult,  
  22.             int maxResult , int type) {  
  23.         return newsItemDao.getNewsItemByFirstResultAndMaxResult(firstResult, maxResult ,  type);  
  24.     }  
  25.     //得到总记录数,以便计算总页数  
  26.     public Long getItemCounts(int id) {  
  27.         return newsItemDao.getItemCount(id);  
  28.     }  
  29.     //通过id得到具体新闻  
  30.     public NewsItem getNewsById(int id) {  
  31.         return newsItemDao.get(id);  
  32.     }  
  33.     //通过id得到所属新闻类别的id  
  34.     public int getNewsType(int id) {  
  35.         return newsItemDao.getNewsType(id);   
  36.     }  
  37.   
  38. }  

 

 

在applicationContext-action.xml中配置action类别

Java代码  收藏代码
  1. <bean class="com.zly.test.action.NewsAction" id="newsAction" scope="request">  
  2.         <property name="newsManager" ref="newsManager"></property>  
  3.         <property name="map" ref="map"></property>  
  4.         <property name="map1" ref="map1"></property>  
  5. </bean>  

 

其中定一个两个map , 因为主页的查看分类新闻的url是采用的这种形式<a href="newsAction.action?category=china" target="_blank">国内</a>   名字为map的Map中保存信息如下

 

Java代码  收藏代码
  1. <bean id="map" class="java.util.HashMap">  
  2.    <constructor-arg>  
  3.     <map>  
  4.     <entry key="china" value="1###国内新闻" />  
  5.         <entry key="world" value="2###国际新闻" />  
  6.         <entry key="society" value="3###社会新闻" />  
  7.         <entry key="compatriot" value="4###港台新闻" />  
  8.         <entry key="taiwan" value="5###台湾新闻" />  
  9.         <entry key="huaren" value="6###华人新闻" />  
  10.         <entry key="economic" value="7###经济新闻" />  
  11.         <entry key="wenhua" value="8###文化新闻" />  
  12.         <entry key="entertainment" value="9###娱乐新闻" />  
  13.         <entry key="sports" value="10###体育新闻" />  
  14.         <entry key="jiaoyu" value="11###教育新闻" />  
  15.         <entry key="jiankang" value="12###健康新闻" />  
  16.         <entry key="life" value="13###生活新闻" />  
  17.         <entry key="keji" value="14###科技新闻" />  
  18.     </map>  
  19.    </constructor-arg>  
  20. </bean>  

 

  key是?category后面的值 , value是两部分 , 被###分割开 , 前面的数值是所属新闻类别的id值, 后面的文字是其类别的文字。将其保存在map中,避免不停地查询数据库。

 

  分页类PageControl的代码如下:

 

Java代码  收藏代码
  1. package com.zly.test.entity;  
  2.   
  3. import java.util.List;  
  4.   
  5.   
  6.   
  7.   
  8. public class PageControl {  
  9.       
  10.     private int curPage ; //当前是第几页   
  11.       
  12.     private int maxPage ; //一共有多少页   
  13.       
  14.     private Long maxRowCount ; //一共有多少行   
  15.       
  16.     private int rowsPerPage = 8 ; //每页有多少行   
  17.   
  18.     private List<?> data;//每页的User  
  19.       
  20.     public int getCurPage() {  
  21.         return curPage;  
  22.     }  
  23.   
  24.     public void setCurPage(int curPage) {  
  25.         this.curPage = curPage;  
  26.     }  
  27.   
  28.     public int getMaxPage() {  
  29.         return maxPage;  
  30.     }  
  31.   
  32.     public void setMaxPage(int maxPage) {  
  33.         this.maxPage = maxPage;  
  34.     }  
  35.   
  36.     public List<?> getUserList() {  
  37.         return data;  
  38.     }  
  39.   
  40.     public void setUserList(List<?> data) {  
  41.         this.data = data;  
  42.     }  
  43.   
  44.     public Long getMaxRowCount() {  
  45.         return maxRowCount;  
  46.     }  
  47.   
  48.     public void setMaxRowCount(Long amaxRowCountxRowCount) {  
  49.         this.maxRowCount = amaxRowCountxRowCount;  
  50.     }  
  51.   
  52.     public int getRowsPerPage() {  
  53.         return rowsPerPage;  
  54.     }  
  55.   
  56.     public void setRowsPerPage(int rowsPerPage) {  
  57.         this.rowsPerPage = rowsPerPage;  
  58.     }  
  59.       
  60.     public void countMaxPage() {   //根据总行数计算总页数    
  61.         if (this.maxRowCount % this.rowsPerPage ==0){  
  62.            this.maxPage = (int) (this.maxRowCount/this.rowsPerPage);  
  63.         }else{  
  64.            this.maxPage = (int) (this.maxRowCount/this.rowsPerPage + 1);          
  65.         }  
  66.     }  
  67.       
  68. }  

 

  被许多页所包含的page.jsp代码如下:

 

 

Java代码  收藏代码
  1. <%@ page language="java"  contentType="text/html;charset=utf-8"  
  2.     pageEncoding="utf-8"%>  
  3. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>  
  4. <html>  
  5. <head>  
  6.     <script language="javascript">  
  7.         function jumping() {  
  8.             document.pageForm.submit();  
  9.             return true;  
  10.         }  
  11.         function gotoPage(pageNum) {  
  12.             document.pageForm.jumpPage.value = pageNum ;  
  13.             document.pageForm.submit();  
  14.             return true;  
  15.         }  
  16.     </script>  
  17. </head>  
  18. <body>  
  19.     <c:if test="${pageControl.maxPage != 1}">  
  20.         <form method="post" action="pageAction.action" name="pageForm">  
  21.   
  22.         <table>  
  23.             <tr>  
  24.                 <td>  
  25.                     每页${pageControl.rowsPerPage}行  
  26.                 </td>  
  27.                 <td>  
  28.                     共${pageControl.maxRowCount }行  
  29.                 </td>  
  30.                 <td>  
  31.                     第${pageControl.curPage }页  
  32.                 </td>  
  33.                 <td>  
  34.                     共${pageControl.maxPage }页  
  35.                 </td>  
  36.                 <td>  
  37.                     <c:choose>  
  38.                         <c:when test="${pageControl.curPage == 1}">  
  39.                             首页 上一页  
  40.                         </c:when>  
  41.                           
  42.                         <c:otherwise>  
  43.                             <A HREF="javascript:gotoPage(1)">首页</A>  
  44.                             <A HREF="javascript:gotoPage(${pageControl.curPage - 1} )">上一页</A>    
  45.                         </c:otherwise>  
  46.                     </c:choose>  
  47.                       
  48.                       
  49.                     <c:choose>  
  50.                         <c:when test="${pageControl.curPage == pageControl.maxPage}">  
  51.                             下一页 尾页  
  52.                         </c:when>  
  53.                           
  54.                         <c:otherwise>  
  55.                             <A HREF="javascript:gotoPage(${pageControl.curPage + 1})">下一页</A>  
  56.                             <A HREF="javascript:gotoPage(${pageControl.maxPage })">尾页</A>  
  57.                         </c:otherwise>  
  58.                     </c:choose>  
  59.                     转到第  
  60.                     <SELECT name="jumpPage" onchange="jumping()">  
  61.                                 <c:forEach var="i" begin="1" end="${pageControl.maxPage}" step="1">  
  62.                                     <c:choose>  
  63.                                         <c:when test="${i == pageControl.curPage}">  
  64.                                             <OPTION selected value="${i}">${i }</OPTION>  
  65.                                         </c:when>  
  66.                                         <c:otherwise>  
  67.                                             <OPTION value="${i}">${i}</OPTION>                    
  68.                                         </c:otherwise>  
  69.                                     </c:choose>  
  70.                                 </c:forEach>  
  71.                     </SELECT>  
  72.                     页  
  73.                 </td>  
  74.             </tr>  
  75.         </table>  
  76.   
  77.     </form>  
  78.     </c:if>  
  79.       
  80. </body>  
  81. </html>  

 

   下面是struts.xml中关于页面展示新闻的配置

 

  

Java代码  收藏代码
  1. <action name="newsAction" class="newsAction" >  
  2.     <result type="redirect">pageAction.action</result>                    
  3. </action>  
  4.   
  5. <action name="pageAction" class="newsAction" method="pageAction">  
  6.     <result>/result.jsp</result>  
  7. </action>  
  8.   
  9. <action name="detailAction" class="newsAction" method="showDetail">  
  10.     <result>/detail.jsp</result>  
  11. </action>  

  

   NewsAction代码如下:

  

Java代码  收藏代码
  1. package com.zly.test.action;  
  2.   
  3. import java.util.List;  
  4. import java.util.Map;  
  5.   
  6. import com.zly.test.entity.NewsItem;  
  7. import com.zly.test.entity.PageControl;  
  8. import com.zly.test.service.NewsManager;  
  9.   
  10. public class NewsAction extends BaseAction {  
  11.   
  12.     private static final long serialVersionUID = 7780804627621048756L;  
  13.   
  14.     //对应分页jsp中的跳转到第几页  
  15.     private String jumpPage;  
  16.     //对应url?category的值  
  17.     private String category;  
  18.     //对新闻数据进行处理  
  19.     private NewsManager newsManager;  
  20.     //保存<entry key="china" value="1###国内新闻" />这样的信息  
  21.     private Map<String , String> map;  
  22.     //保存<entry key="1" value="china###国内新闻" />这样的信息  
  23.     private Map<String , String> map1;  
  24.       
  25.     public Map<String, String> getMap1() {  
  26.         return map1;  
  27.     }  
  28.   
  29.   
  30.     public void setMap1(Map<String, String> map1) {  
  31.         this.map1 = map1;  
  32.     }  
  33.   
  34.   
  35.     public Map<String, String> getMap() {  
  36.         return map;  
  37.     }  
  38.   
  39.   
  40.     public void setMap(Map<String, String> map) {  
  41.         this.map = map;  
  42.     }  
  43.   
  44.   
  45.     public String getJumpPage() {  
  46.         return jumpPage;  
  47.     }  
  48.   
  49.   
  50.     public void setJumpPage(String jumpPage) {  
  51.         this.jumpPage = jumpPage;  
  52.     }  
  53.   
  54.   
  55.       
  56.     public NewsManager getNewsManager() {  
  57.         return newsManager;  
  58.     }  
  59.   
  60.   
  61.     public void setNewsManager(NewsManager newsManager) {  
  62.         this.newsManager = newsManager;  
  63.     }  
  64.   
  65.     //处理newsAction.action?category=xxx  
  66.     public String execute() {  
  67.         //得到相应的    1###国内新闻  
  68.         String typeIdInfo = map.get(category);  
  69.         //这里得到的是新闻类别id  
  70.         Integer typeId = Integer.parseInt(typeIdInfo.split("###")[0]);  
  71.         //这里得到的是新闻类别字符串  
  72.         String typeString = typeIdInfo.split("###")[1];  
  73.         //将上面三个变量保存在session中,在jsp页面中显示  
  74.         this.getSession().setAttribute("category", category);  
  75.         this.getSession().setAttribute("typeString" , typeString);  
  76.         this.getSession().setAttribute("id", typeId);  
  77.         //跳转到pageAction中,处理分页  
  78.         return SUCCESS;  
  79.     }  
  80.       
  81.     public String pageAction() {  
  82.         //取出新闻类别id  
  83.         Integer id = (Integer) this.getSession().getAttribute("id");  
  84.         //查看是不是第一次来分页,如果是,当前页设置成第一个  
  85.         if(jumpPage == null) {  
  86.             jumpPage = "1";  
  87.         }  
  88.         //从request范围内取出PageControl , 如为空,则第一次分页,创建pageControl对象  
  89.         PageControl pageControl  = (PageControl) this.getRequest().getAttribute("pageControl");  
  90.         if(pageControl == null) {  
  91.             pageControl = new PageControl();  
  92.             //第一次的时候得到相应新闻类别所对应的记录的总数  
  93.             pageControl.setMaxRowCount(newsManager.getItemCounts(id));  
  94.             //计算一共多少页  
  95.             pageControl.countMaxPage();  
  96.         }  
  97.         //设置jumpPage的值为当前页  
  98.         pageControl.setCurPage(Integer.parseInt(jumpPage));  
  99.         //计算出hibernate中firstResult的值  
  100.         int firstResult = (pageControl.getCurPage() - 1) * pageControl.getRowsPerPage() + 1;  
  101.         //设置hibernate中maxResult的值  
  102.         int maxResult = pageControl.getRowsPerPage();  
  103.         //利用hibernate得到当前页的数据,并保存在pageControl分页实体类中  
  104.         List<NewsItem> userList = newsManager.getNewsItemByFirstResultAndMaxResult(firstResult, maxResult , id);  
  105.         pageControl.setData(userList);  
  106.         //将分页实体类保存在request范围内。  
  107.         this.getRequest().setAttribute("pageControl", pageControl);  
  108.         //将页面视图跳转到result.jsp  
  109.         return SUCCESS;  
  110.     }  
  111.       
  112.     public String showDetail() {  
  113.         //得到url中的?id=xxx  
  114.         String newsId = this.getRequest().getParameter("id");  
  115.         int id = Integer.parseInt(newsId);  
  116.         //使用hibernate得到具体id的新闻记录  
  117.         NewsItem item = newsManager.getNewsById(id);  
  118.         //得到id记录所对应的新闻类型的值   map1这种形式<entry key="1" value="china###国内新闻" />  
  119.         int typeId = newsManager.getNewsType(id);  
  120.         //得到china,添加到jsp页面的<a href="newsAction?category=">里面  
  121.         String category = map1.get("" + typeId).split("###")[0];  
  122.         //得到国内新闻,显示在jsp页面的多个位置  
  123.         String typeString = map1.get("" + typeId).split("###")[1];  
  124.         //将以上多个数据添加到request范围内,以便显示。  
  125.         this.getRequest().setAttribute("news", item);  
  126.         this.getRequest().setAttribute("category", category);  
  127.         this.getRequest().setAttribute("typeString", typeString);  
  128.         return SUCCESS;  
  129.     }  
  130.   
  131.   
  132.     public String getCategory() {  
  133.         return category;  
  134.     }  
  135.   
  136.   
  137.     public void setCategory(String category) {  
  138.         this.category = category;  
  139.     }  
  140.       
  141. }  

 

 

首页页面index.jsp,里面有几个分类超链接和搜索对话框

 

Java代码  收藏代码
  1. <%@ page language="java"  pageEncoding="utf-8"%>  
  2.   
  3. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
  4. <html>  
  5.     
  6.   <head>  
  7.     <title>最快新闻网</title>  
  8.     <link href="css/main.css" rel="stylesheet" type="text/css" />  
  9.   </head>  
  10.     
  11.   <body>  
  12.          <div id="mainlink">  
  13.                 <span><a href="index.jsp">最快新闻网</a></span><br /><br />  
  14.                 <a href="newsAction.action?category=china" target="_blank">国内</a> | <a href="newsAction.action?category=world" target="_blank">国际</a> | <a href="newsAction.action?category=society" target="_blank">社会</a> | <a href="newsAction.action?category=compatriot" target="_blank">港澳</a> | <a href="newsAction.action?category=taiwan" target="_blank">台湾</a> | <a href="newsAction.action?category=huaren" target="_blank">华人</a> | <a href="newsAction.action?category=economic" target="_blank">经济</a> | <a href="newsAction.action?category=wenhua" target="_blank">文化</a> | <a href="newsAction.action?category=entertainment" target="_blank">娱乐</a> | <a href="newsAction.action?category=sports" target="_blank">体育</a> | <a href="newsAction.action?category=jiaoyu" target="_blank">教育</a> | <a href="newsAction.action?category=jiankang" target="_blank">健康</a> | <a href="newsAction.action?category=life" target="_blank">生活</a> | <a href="newsAction.action?category=keji" target="_blank">IT</a><br />  
  15.                 <form action="searchAction.action" method="post" target="_blank">  
  16.                     本站搜索:  
  17.                     <input type="text" name="searchParam" style="height:20px"/>  
  18.                     <select name="searchWhich">  
  19.                         <option value="title"/>标题  
  20.                         <option value="content"/>内容  
  21.                     </select>  
  22.                     <input type="submit" value="搜索" style="height:23px"/>  
  23.                 </form>              
  24.          </div>  
  25.   </body>  
  26. </html>  

 

 

 

  其表现形式如下:

新闻分页展示页面result.jsp代码如下:

Html代码  收藏代码
  1. <%@ page language="java" contentType="text/html;charset=utf-8"  
  2.     pageEncoding="utf-8"%>  
  3. <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>  
  4. <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>  
  5. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
  6. <html>  
  7. <head>  
  8. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">  
  9. <title>${typeString} -- 最快新闻网</title>  
  10. </head>  
  11. <body>  
  12.     <jsp:include page="index.jsp"></jsp:include>  
  13.     <div id="content">  
  14.         <font color="red" size="5">${typeString}</font>  
  15.         <br /><br /><br /><br />  
  16.         <div id="newsListTitle" style="float:left;">  
  17.             <c:forEach items="${pageControl.data}" var="news">  
  18.                 <div style="margin-top: 20px;">  
  19.                     <span>  
  20.                         <a href="detailAction.action?id=${news.id }">${news.newsTitle }</a>  
  21.                     </span>  
  22.                     <br />  
  23.                 </div>  
  24.             </c:forEach>        
  25.         </div>  
  26.           
  27.         <div id="newsListTime">  
  28.             <c:forEach items="${pageControl.data}" var="news">  
  29.                 <div style="margin-top: 20px;">  
  30.                     <span>  
  31.                         <fmt:formatDate value="${news.publishTime}" pattern="MM-dd HH:mm"/>  
  32.                     </span>  
  33.                     <br />  
  34.                 </div>  
  35.             </c:forEach>  
  36.         </div>  
  37.         <br /><br /><br /><br />  
  38.         <%@ include file="page.jsp" %>  
  39.     </div>  
  40. </body>  
  41. </html>  

  显示效果如下:

 

 

 

其中点击具体超链接的效果图如下:

 

 

 

任务1 到此完成,新闻显示工作结束。下面是搜索引擎部分。

 

搜索的工具类放置在com.zly.indexManager包下面

 

说明,本程序使用了庖丁解牛中文分词,用户使用时需要中文字典,我的字典放在了c:\dic下面,使用庖丁还需要配置环境变量PAODING_DIC_HOME , 其值为c:\dic , (就是你的字典文件所在的目录)

 

代码如下:

 

创建索引类IndexCreateUtil

 

Java代码  收藏代码
  1. package com.zly.indexManager;  
  2.   
  3. import java.io.File;  
  4. import java.text.DateFormat;  
  5. import java.text.SimpleDateFormat;  
  6. import java.util.List;  
  7.   
  8. import net.paoding.analysis.analyzer.PaodingAnalyzer;  
  9.   
  10. import org.apache.lucene.analysis.Analyzer;  
  11. import org.apache.lucene.document.Document;  
  12. import org.apache.lucene.document.Field;  
  13. import org.apache.lucene.index.IndexWriter;  
  14. import org.hibernate.SessionFactory;  
  15. import org.hibernate.cfg.AnnotationConfiguration;  
  16. import org.hibernate.cfg.Configuration;  
  17. import org.hibernate.Session;  
  18. import org.htmlparser.Parser;  
  19.   
  20. import com.zly.test.entity.NewsItem;  
  21.   
  22. public class IndexCreateUtil {  
  23.       
  24.     @SuppressWarnings("unchecked")  
  25.     public void createIndexForNews() throws Exception {  
  26.         //存放索引的文件夹  
  27.         File indexFile = new File("c:/index/news");  
  28.         //使用了庖丁解牛分词器  
  29.         Analyzer analyzer = new PaodingAnalyzer();  
  30.         //使用索引文件夹,庖丁解牛分词器创建IndexWriter  
  31.         IndexWriter indexWriter = new IndexWriter(indexFile , analyzer , true);  
  32.         //从数据库中读取出所有的新闻记录以便进行索引的创建  
  33.         Configuration cfg = new AnnotationConfiguration().configure();  
  34.         SessionFactory factory = cfg.buildSessionFactory();  
  35.         Session session = factory.openSession();  
  36.         List<NewsItem> list = session.createQuery(" from NewsItem").list();  
  37.         DateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");  
  38.         //对所有的新闻实体进行索引创建  
  39.         for (NewsItem newsItem : list) {  
  40.             //建立一个lucene文档  
  41.             Document doc = new Document();  
  42.             //得到新闻标题  
  43.             String newsTitle = newsItem.getNewsTitle();  
  44.             //得到新闻内容  
  45.             String newsContent = newsItem.getNewsContent();  
  46.             //得到新闻事件  
  47.             String publishDate = format.format(newsItem.getPublishTime());  
  48.             //得到新闻主键id  
  49.             String id = newsItem.getId() + "";  
  50.             //将新闻标题加入文档,因为要搜索和高亮,所以index是tokennized,TermVector是WITH_POSITIONS_OFFSETS  
  51.             doc.add(new Field("title" , newsTitle , Field.Store.YES , Field.Index.TOKENIZED , Field.TermVector.WITH_POSITIONS_OFFSETS));  
  52.             //利用htmlparser得到新闻内容html的纯文本  
  53.             Parser parser = new Parser();  
  54.             parser.setInputHTML(newsContent);  
  55.             String strings = parser.parse(null).elementAt(0).toPlainTextString().trim();  
  56.             //添加新闻内容至文档,与标题相似  
  57.             doc.add(new Field("content" , strings , Field.Store.COMPRESS , Field.Index.TOKENIZED , Field.TermVector.WITH_POSITIONS_OFFSETS));  
  58.             //添加时间至文档,因为要按照此字段降序排列排序,所以tokenzied,不用高亮所以TermVector是no就行了  
  59.             doc.add(new Field("date" , publishDate , Field.Store.YES , Field.Index.TOKENIZED , Field.TermVector.NO));  
  60.             //添加主键至文档,不分词,不高亮。  
  61.             doc.add(new Field("id" , id , Field.Store.YES , Field.Index.NO , Field.TermVector.NO));  
  62.             indexWriter.addDocument(doc);  
  63.         }  
  64.         //创建索引  
  65.         indexWriter.optimize();  
  66.         indexWriter.close();  
  67.         //关闭session  
  68.         session.close();  
  69.     }  
  70.     public static void main(String[] args) throws Exception {  
  71.         IndexCreateUtil util  = new IndexCreateUtil();  
  72.         util.createIndexForNews();  
  73.     }  
  74. }  

 

对索引进行搜索的代码如下:

 

  

Java代码  收藏代码
  1. package com.zly.indexManager;  
  2.   
  3. import java.io.File;  
  4. import java.util.ArrayList;  
  5. import java.util.List;  
  6.   
  7. import net.paoding.analysis.analyzer.PaodingAnalyzer;  
  8.   
  9. import org.apache.lucene.analysis.Analyzer;  
  10. import org.apache.lucene.document.Document;  
  11. import org.apache.lucene.index.IndexReader;  
  12. import org.apache.lucene.queryParser.QueryParser;  
  13. import org.apache.lucene.search.Hits;  
  14. import org.apache.lucene.search.IndexSearcher;  
  15. import org.apache.lucene.search.Query;  
  16. import org.apache.lucene.search.Sort;  
  17. import org.apache.lucene.search.highlight.Highlighter;  
  18. import org.apache.lucene.search.highlight.QueryScorer;  
  19. import org.apache.lucene.search.highlight.SimpleFragmenter;  
  20. import org.apache.lucene.search.highlight.SimpleHTMLFormatter;  
  21.   
  22. import com.zly.test.entity.SearchResultBean;  
  23.   
  24. public class IndexSearchUtil {  
  25.       
  26.     public List<SearchResultBean> getSearchResult(String searchWhich , String searchParam , int firstResult , int maxResult) throws Exception{  
  27.         //索引所在文件夹  
  28.         File indexFile = new File("c:/index/news");  
  29.         //读取索引的indexReader  
  30.         IndexReader reader = IndexReader.open(indexFile);  
  31.         //庖丁解牛分词器  
  32.         Analyzer analyzer = new PaodingAnalyzer();  
  33.         //指定对content还是title进行查询  
  34.         QueryParser parser = new QueryParser(searchWhich , analyzer);  
  35.         //创建indexSearcher  
  36.         IndexSearcher searcher  = new IndexSearcher(reader);  
  37.         //对用户的输入进行查询  
  38.         Query query = parser.parse(searchParam);  
  39.         //根据date字段进行排序,得到查询结果  
  40.         Hits hits = searcher.search(query , new Sort("date" , true));  
  41.         //创建list,将结果保存其中,以便在jsp页面中进行显示  
  42.         List<SearchResultBean> list = new ArrayList<SearchResultBean>();  
  43.         //模拟hibernate的serFirstResult和setMaxResult以便返回指定条目的结果  
  44.         for (int i = firstResult - 1; i < firstResult + maxResult - 1; i++) {  
  45.             Document doc = hits.doc(i);  
  46.             //取得该条索引文档  
  47.             SearchResultBean srb = new SearchResultBean();  
  48.             //从中取出标题  
  49.             String title = doc.get("title");  
  50.             //从中取出内容  
  51.             String content = doc.get("content");  
  52.             //从中取出主键id  
  53.             String id = doc.get("id");  
  54.             //从中取出发布时间  
  55.             String date = doc.get("date");  
  56.             //高亮htmlFormatter对象  
  57.             SimpleHTMLFormatter sHtmlF = new SimpleHTMLFormatter("<b><font color='red'>""</font></b>");  
  58.             //高亮对象  
  59.             Highlighter highlighter = new Highlighter(sHtmlF,new QueryScorer(query));  
  60.             //设置高亮附近的字数  
  61.             highlighter.setTextFragmenter(new SimpleFragmenter(100));  
  62.             //如果查询的是标题,进行处理  
  63.             if(searchWhich.equals("title")) {  
  64.                 String bestFragment = highlighter.getBestFragment(analyzer,searchWhich,title);  
  65.                 //获得高亮后的标题内容  
  66.                 srb.setTitle(bestFragment);  
  67.                 //如果内容不足150个字,全部设置  
  68.                 if(content.length() < 150) {  
  69.                     srb.setContent(content);  
  70.                 }else {  
  71.                     //如果内容多于150个字,只取出前面150个字  
  72.                     srb.setContent(content.substring(0 , 150));  
  73.                 }  
  74.             } else {  
  75.                 //如果查询的是内容字段  
  76.                 String bestFragment = highlighter.getBestFragment(analyzer,searchWhich,content);  
  77.                 //取得高亮内容并设置  
  78.                 srb.setContent(bestFragment);  
  79.                 //设置标题,全部设置  
  80.                 srb.setTitle(title);  
  81.             }  
  82.             //设置日期  
  83.             srb.setDate(date);  
  84.             //设置主键  
  85.             srb.setId(id);  
  86.             //添加到list中,以便在jsp页面上显示  
  87.             list.add(srb);  
  88.         }  
  89.         return list;  
  90.     }  
  91.     //取得符合搜索条件的所有记录总数,以便分页 , 与上面方法类似  
  92.     public int getResultCount(String searchWhich , String searchParam) throws Exception {  
  93.         File indexFile = new File("c:/index/news");  
  94.         IndexReader reader = IndexReader.open(indexFile);  
  95.         Analyzer analyzer = new PaodingAnalyzer();  
  96.         QueryParser parser = new QueryParser(searchWhich , analyzer);  
  97.         IndexSearcher searcher  = new IndexSearcher(reader);  
  98.         Query query = parser.parse(searchParam);  
  99.         Hits hits = searcher.search(query);  
  100.         return hits.length();  
  101.     }  
  102. }  

 

 

分页action代码如下:

Java代码  收藏代码
  1. package com.zly.test.action;  
  2.   
  3. import java.util.List;  
  4.   
  5. import com.zly.indexManager.IndexSearchUtil;  
  6. import com.zly.test.entity.PageControl;  
  7. import com.zly.test.entity.SearchResultBean;  
  8.   
  9. public class SearchAction extends BaseAction {  
  10.   
  11.       
  12.     private static final long serialVersionUID = -2387037924517370511L;  
  13.     //查询索引实体类  
  14.     private IndexSearchUtil indexSearcher;  
  15.     //对应搜索字段是标题还是内容  
  16.     private String searchWhich;  
  17.     //对应用户输入的搜索内容  
  18.     private String searchParam;  
  19.     //对应分页跳转到的页面  
  20.     private String jumpPage;  
  21.       
  22.     public String getJumpPage() {  
  23.         return jumpPage;  
  24.     }  
  25.   
  26.     public void setJumpPage(String jumpPage) {  
  27.         this.jumpPage = jumpPage;  
  28.     }  
  29.   
  30.     public String getSearchWhich() {  
  31.         return searchWhich;  
  32.     }  
  33.   
  34.     public void setSearchWhich(String searchWhich) {  
  35.         this.searchWhich = searchWhich;  
  36.     }  
  37.   
  38.     public String getSearchParam() {  
  39.         return searchParam;  
  40.     }  
  41.   
  42.     public void setSearchParam(String searchParam) {  
  43.         this.searchParam = searchParam;  
  44.     }  
  45.   
  46.     public String search() throws Exception {  
  47.         //如果为空,说明第一次进入分页  
  48.         if(jumpPage == null) {  
  49.             jumpPage = "1";  
  50.         }  
  51.         //从request范围内取得pageControl对象  
  52.         PageControl pageControl  = (PageControl) this.getRequest().getAttribute("pageControl");  
  53.         //如果为空,则是第一次分页,创建分页对象,并且设置总的记录条数,以便设置最大页数   
  54.         if(pageControl == null) {  
  55.             pageControl = new PageControl();  
  56.             pageControl.setMaxRowCount((long)indexSearcher.getResultCount(searchWhich, searchParam));  
  57.             pageControl.countMaxPage();  
  58.         }  
  59.         //设置当前页  
  60.         pageControl.setCurPage(Integer.parseInt(jumpPage));  
  61.         //计算firstResult  
  62.         int firstResult = (pageControl.getCurPage() - 1) * pageControl.getRowsPerPage() + 1;  
  63.         //计算从当前条数算还有多少条记录  
  64.         long left = pageControl.getMaxRowCount() - firstResult;  
  65.         int maxResult = -1;  
  66.         //如果剩余的记录数不如每页显示数,就设置maxResult为剩余条数  
  67.         if(left < pageControl.getRowsPerPage()) {  
  68.             maxResult = Integer.valueOf(left + "");  
  69.         //如果剩余记录数大于每页显示页数,就设置maxResult为每页条数  
  70.         }else {  
  71.             maxResult = pageControl.getRowsPerPage();   
  72.         }  
  73.         //取得查询结果集  
  74.         List<SearchResultBean> userList = indexSearcher.getSearchResult(searchWhich, searchParam, firstResult, maxResult);  
  75.         //设置为pageControl  
  76.         pageControl.setData(userList);  
  77.         //将pageControl设置到request范围,以便在jsp现实结果  
  78.         this.getRequest().setAttribute("pageControl", pageControl);  
  79.         //将searchWhich和searchParam设置到request范围,以便添加到分页jsp的form里面的hidden表单域,以便下次分页时,能够将值提交过来  
  80.         this.getRequest().setAttribute("searchWhich", searchWhich);  
  81.         this.getRequest().setAttribute("searchParam", searchParam);  
  82.         //跳转到分页视图  
  83.         return SUCCESS;  
  84.           
  85.     }  
  86.   
  87.     public IndexSearchUtil getIndexSearcher() {  
  88.         return indexSearcher;  
  89.     }  
  90.   
  91.     public void setIndexSearcher(IndexSearchUtil indexSearcher) {  
  92.         this.indexSearcher = indexSearcher;  
  93.     }  
  94.       
  95. }  

 

 

搜索的action在struts.xml中设置如下:

 

Xml代码  收藏代码
  1. <action name="searchAction" class="searchAction" method="search">  
  2.     <result>/searchResult.jsp</result>  
  3. </action>  

 

//searchResult.jsp代码如下:

 

Html代码  收藏代码
  1. <%@ page language="java" contentType="text/html;charset=utf-8"  
  2.     pageEncoding="utf-8"%>  
  3. <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>  
  4. <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>  
  5. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
  6. <html>  
  7. <head>  
  8. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">  
  9. <title>${searchParam} 的搜查结果 -- 最快新闻网</title>  
  10. </head>  
  11. <body>  
  12.     <jsp:include page="index.jsp"></jsp:include>  
  13.     <div id="content">  
  14.           
  15.         <div id="searchResults" >  
  16.             <c:forEach items="${pageControl.data}" var="result">  
  17.                 <div style="margin-top: 20px;">  
  18.                     <span>  
  19.                         <a href="detailAction.action?id=${result.id }">${result.title}</a><br />  
  20.                         ${result.content }  
  21.                         <font color="green">http://localhost:8080/NewsWithSearch/detailAction.action?id=${result.id } ${result.date }</font>  
  22.                     </span>  
  23.                     <br />  
  24.                 </div>  
  25.             </c:forEach>        
  26.         </div>  
  27.           
  28.         <br /><br /><br /><br />  
  29.           
  30.         <%@ include file="searchPage.jsp" %>  
  31.     </div>  
  32. </body>  
  33. </html>  

    其运行结果如图所示(按标题搜索):

 

 

 

 

 

按内容搜索的运行结果如下:

 

 

 

至此,本小项目的所有功能完成,虽然没有多少难度,也不是什么高科技, 俺还是在google和javaeye上查了不少资料,总算是做完了,贴出来,与大家分享,也给新手学习提供资料。

 

所有的资源我都添加到了附件中,学过ssh的同学应该能够成功部署项目并运行。

 

其中NewsWithSearch.rar是工程文件夹,包含了所有的代码文件和jar包,加压完直接引到MyEclipse里就行,data.rar是所有的sql语句,插入到MySQL之前应先建立数据库mynews  ,     dic.rar是庖丁解牛用到的字典文件,

解压成一个文件夹,并配置环境变量PAODING_DIC_HOME,其值就是你把它解压成的文件夹(例如c:\dic),最后如果你不想创建索引的话,可以把news.rar解压成一个文件夹,拷贝到c:\index\news下面。

 

  • dic.rar (1.4 MB)
  • 下载次数: 2704
分享到:
评论

30 楼
rentianchou
2010-06-05  
xuyao 写道
晕,刚看第二行就看不下去了,谁告诉您有.do就是struts1?

29 楼
wulinshishen
2010-05-24  
真该向楼主学习了啊
28 楼
wangxyong2001
2010-01-28  
不管怎么样 还是要感谢 lz的分享
27 楼
foxlish
2009-11-01  
我感觉写的挺好,挺适合我们新手研究和学习的!
我仔细看了一遍了,觉得代码和注释写的都不错!
26 楼
hudejunhit
2009-09-15  
好厉害,相比之下,我真是太初级了
25 楼
pricecome
2009-09-14  
现在可以考虑用solr了,不用这么费劲lucene了

http://www.pricecome.com

24 楼
phenom
2009-09-14  
SessionFactory factory = cfg.buildSessionFactory();
Session session = factory.openSession();
List<NewsItem> list = session.createQuery(" from NewsItem").list();

这句应该是查询所有的吧.如果数据量大的话呢?然后载入内存?再用FOR循环出来?

23 楼
great-coffee
2009-09-11  
注释很要,很详细、易懂也很清晰
做这个的与版本没关系吧应该

谢谢提供 ^_^

22 楼
shuaigg.babysky
2009-08-17  
其实我很菜,这篇文章当时写的时候漏洞漏洞百出,以后不得赛了。
21 楼
myclover
2009-08-15  
dic.rar是庖丁解牛用到的字典文件,

解压成一个文件夹,并配置环境变量PAODING_DIC_HOME,其值就是你把它解压成的文件夹(例如c:\dic)

这个东西究竟怎么配置才行呢?我也是解压到C:盘下面的,但是我运行IndexCreateUtil.java的时候总是报这个错误,应该怎么解决呢?谢谢哈!

Exception in thread "main" net.paoding.analysis.exception.PaodingAnalysisException: please set a system env PAODING_DIC_HOME or Config paoding.dic.home in paoding-dic-home.properties point to the dictionaries!
at net.paoding.analysis.knife.PaodingMaker.setDicHomeProperties(PaodingMaker.java:308)
at net.paoding.analysis.knife.PaodingMaker.getDicHome(PaodingMaker.java:255)
at net.paoding.analysis.knife.PaodingMaker.loadProperties(PaodingMaker.java:187)
at net.paoding.analysis.knife.PaodingMaker.loadProperties(PaodingMaker.java:223)
at net.paoding.analysis.knife.PaodingMaker.loadProperties(PaodingMaker.java:223)
at net.paoding.analysis.knife.PaodingMaker.getProperties(PaodingMaker.java:129)
at net.paoding.analysis.analyzer.PaodingAnalyzer.init(PaodingAnalyzer.java:70)
at net.paoding.analysis.analyzer.PaodingAnalyzer.<init>(PaodingAnalyzer.java:59)
at net.paoding.analysis.analyzer.PaodingAnalyzer.<init>(PaodingAnalyzer.java:52)
at com.zly.indexManager.IndexCreateUtil.createIndexForNews(IndexCreateUtil.java:29)
at com.zly.indexManager.IndexCreateUtil.main(IndexCreateUtil.java:73)

20 楼
wangpx
2009-08-14  
<div class="quote_title">shuaigg.babysky 写道</div>
<div class="quote_div">
<p>    前两天看到了一个中国新闻网,这个网站的搜索form的action是</p>
<pre><span class="attribute-value">http://search.chinanews.com/search.do</span></pre>
<p>便知道是struts1的产物,现在都用struts2了,所以给自己的任务是实现Struts2 SSH分页浏览新闻、Lucene分页高亮排序搜索新闻这个两个功能。</p>
<p> </p>
<p>    IDE使用的MyEclipse6.5,数据库使用MySQL 5.0.37 , 另装了Navicat for MySQL , jdk版本是6.0</p>
<p>    工程做完的效果图如下,com.zly.indexManager中两个类,分别创建索引和搜索索引,</p>
<p>    com.zly.test.entity中是使用的实体类,分别是NewsType(新闻类型),NewsItem(新闻具体条目),PageControl(分页实体bean) , SearchResultBean(保存搜索结果的bean).</p>
<p> </p>
<p> </p>
<p><img src="http://p13.freep.cn/p.aspx?u=v20_p13_p_0906241936572679_0.jpg" alt="" width="286" height="497"></p>
<p> </p>
<p>        浏览和搜索的前提是有据可查,没有数据什么都实现不了 , 我使用了Htmlparser通过抓取页面信息的形式将新闻添加进数据库 , 添加数据库数据使用了hibernate3</p>
<p>        使用了Annotation的方式完成数据库的映射。</p>
<p>         //NewsType(新闻类型)</p>
<pre name="code" class="java">package com.zly.test.entity;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "t_newsType")
public class NewsType implements Serializable {

private static final long serialVersionUID = -5092622762025999122L;

private Integer id;

private String newsTypeName;
@Column
public String getNewsTypeName() {
return newsTypeName;
}

public void setNewsTypeName(String newsTypeName) {
this.newsTypeName = newsTypeName;
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

}
</pre>
<p> </p>
<p>   //NewsItem(新闻具体条目)</p>
<p> </p>
<pre name="code" class="java">package com.zly.test.entity;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
@Entity
@Table(name = "t_newsItem")
public class NewsItem implements Serializable {

private static final long serialVersionUID = -7532888546907495633L;

private Integer id ;

private String newsTitle ;

private String newsContent;

private Date publishTime;

private String resource;

private NewsType type;

private String editor;
@Column
public String getEditor() {
return editor;
}

public void setEditor(String editor) {
this.editor = editor;
}
@ManyToOne
@JoinColumn(name = "t_newsType_id")
public NewsType getType() {
return type;
}

public void setType(NewsType type) {
this.type = type;
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}
@Column
public String getNewsTitle() {
return newsTitle;
}

public void setNewsTitle(String newsTitle) {
this.newsTitle = newsTitle;
}

@Temporal(value = TemporalType.TIMESTAMP)
public Date getPublishTime() {
return publishTime;
}

public void setPublishTime(Date publishTime) {
this.publishTime = publishTime;
}

public String getResource() {
return resource;
}

public void setResource(String resource) {
this.resource = resource;
}

public String getNewsContent() {
return newsContent;
}

public void setNewsContent(String newsContent) {
this.newsContent = newsContent;
}

}
</pre>
<p> </p>
<p>    添加所有新闻类型的类放在了com.zly.test.newsFetch包下 , 具体代码:</p>
<p> </p>
<p> </p>
<pre name="code" class="java">package com.zly.test.newsfetch;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;
import org.htmlparser.Parser;
import org.htmlparser.Tag;
import org.htmlparser.filters.NodeClassFilter;
import org.htmlparser.tags.Div;
import org.htmlparser.tags.LinkTag;
import org.htmlparser.util.NodeList;
import org.htmlparser.visitors.NodeVisitor;

import com.zly.test.entity.NewsItem;
import com.zly.test.entity.NewsType;

public class GetNews {
public static void main(String[] args) throws Exception {
//插入数据新闻类型
//insertAllTypes();

//插入所有新闻数据

//国内新闻
//insertNewsItems("http://www.chinanews.com.cn/scroll-news/gn/2009/05" ,"/news.shtml" ,1);
//国际新闻
//insertNewsItems("http://www.chinanews.com.cn/scroll-news/gj/2009/05" ,"/news.shtml" ,2);
//社会新闻
//insertNewsItems("http://www.chinanews.com.cn/scroll-news/sh/2009/05" ,"/news.shtml" ,3);
//港澳新闻
//insertNewsItems("http://www.chinanews.com.cn/scroll-news/ga/2009/05" ,"/news.shtml" ,4);
//台湾新闻
//insertNewsItems("http://www.chinanews.com.cn/scroll-news/tw/2009/05" ,"/news.shtml" ,5);
//华人新闻
//insertNewsItems("http://www.chinanews.com.cn/scroll-news/hr/2009/05" ,"/news.shtml" ,6);
//经济新闻
//insertNewsItems("http://www.chinanews.com.cn/scroll-news/cj/2009/05" ,"/news.shtml" ,7);
//文化新闻
//insertNewsItems("http://www.chinanews.com.cn/scroll-news/wh/2009/05" ,"/news.shtml" ,8);
//娱乐新闻
//insertNewsItems("http://www.chinanews.com.cn/scroll-news/yl/2009/05" ,"/news.shtml" ,9);
//体育新闻
//insertNewsItems("http://www.chinanews.com.cn/scroll-news/ty/2009/05" ,"/news.shtml" ,10);
//教育新闻
//insertNewsItems("http://www.chinanews.com.cn/scroll-news/edu/2009/05" ,"/news.shtml" ,11);
//健康新闻
//insertNewsItems("http://www.chinanews.com.cn/scroll-news/jk/2009/05" ,"/news.shtml" ,12);
//生活新闻
//insertNewsItems("http://www.chinanews.com.cn/scroll-news/life/2009/05" ,"/news.shtml" ,13);
//IT新闻
//insertNewsItems("http://www.chinanews.com.cn/scroll-news/it/2009/05" ,"/news.shtml" ,14);
}
public static void insertAllTypes() {
Configuration cfg = new AnnotationConfiguration().configure();
SessionFactory factory = cfg.buildSessionFactory();
Session session = factory.openSession();
String str = new String("国内 国际 社会 港澳 台湾 华人 经济 文化 娱乐 体育 教育 健康 生活 IT");
String[] typesStr = str.split(" ");
NewsType[] types = new NewsType[typesStr.length];
session.beginTransaction();
for (int i = 0; i &lt; typesStr.length; i++) {
types[i] = new NewsType();
types[i].setNewsTypeName(typesStr[i]);
session.save(types[i]);
}
session.getTransaction().commit();
session.close();
}

//处理5.1 - 5.5 所有的具体类型的新闻

public static void insertNewsItems(String before , String after , int type) throws Exception {
Configuration cfg = new AnnotationConfiguration().configure();
SessionFactory factory = cfg.buildSessionFactory();
Session session = factory.openSession();
//得到当前新闻所属类别
NewsType newsType = (NewsType) session.get(NewsType.class, type);
final Set&lt;NewsItem&gt; set = new LinkedHashSet&lt;NewsItem&gt;();
//获取5月1日-5月5日的新闻
for (int i = 1; i &lt;= 5; i++) {
String src = before;
if(i &lt; 10) {
src = src + "0" + i;
}else {
src = src + i ;
}
src = src + after;
//使用htmlParser获取每一条新闻的超链接
Parser parser = new Parser(src);
parser.setEncoding("gb2312");
NodeList divList = parser.parse(new NodeClassFilter(Div.class));
for (int j = 0; j &lt; divList.size(); j++) {
Div div = (Div) divList.elementAt(j);
String divClass = div.getAttribute("id");
//取得id为news_list的div
if(divClass != null &amp;&amp; divClass.equals("news_list")) {
div.accept(new NodeVisitor() {
//遍历news_list里面的所有超链接
public void visitTag(Tag tag) {
if(tag instanceof LinkTag) {
String href = ((LinkTag)tag).getLink();
if(!href.startsWith("http")) {
href = "http://www.chinanews.com.cn" + href;
}
System.out.println(href);
//找到超链接,将这个超链接所在的页面进行处理,抓取新闻数据,并将其保存在Set中。
try{
insertOneNews(href , set);
}catch(Exception e) {
e.printStackTrace();
}

}
}
});
}
}
}
//获取新闻完成后,将所有NewsItem添加到数据库
session.beginTransaction();
for (NewsItem newsItem : set) {
newsItem.setType(newsType);
session.save(newsItem);
}
session.getTransaction().commit();
session.close();
}
//处理每一个具体的新闻超链接,得到NewsItem类
public static void insertOneNews(String src , Set&lt;NewsItem&gt; set) throws Exception {
Parser parser = new Parser(src);
parser.setEncoding("gb2312");
NodeList divList = parser.extractAllNodesThatMatch(new NodeClassFilter(Div.class));
NewsItem newsItem = new NewsItem();
String title = "";
Date parse = null;
String content = "";
String editor = "";
//遍历网页的div。将制定div里面的信息设置到NewsItem实体类中
for (int i = 0; i &lt; divList.size(); i++) {
Div div = (Div) divList.elementAt(i);
String divString = div.getAttribute("class");
if(divString != null) {
//设置标题
if(divString.equals("left_bt")) {
title = div.toPlainTextString();
}
//设置发布时间
if(divString.equals("left_time")) {
String publishStr = "";
Pattern pattern = Pattern.compile("[\\d]{4}年[\\d]{2}月[\\d]{2}日 [\\d]{2}:[\\d]{2}");
Matcher matcher = pattern.matcher(div.toPlainTextString()) ;
if(matcher.find()) {
publishStr = matcher.group();
}
DateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH:mm");
parse = format.parse(publishStr);
}
//设置正文内容
if(divString.equals("left_zw")) {
content = div.toHtml();
}
//设置记者名称
if(divString.equals("left_name")) {
editor = div.toPlainTextString().trim();
editor = editor.substring(editor.indexOf(":") + 1, editor.lastIndexOf("】"));
}
}

}
newsItem.setEditor(editor);
newsItem.setNewsContent(content);
newsItem.setNewsTitle(title);
newsItem.setPublishTime(parse);
//设置新闻来源
newsItem.setResource("最快新闻网");
//将新闻添加到set中
set.add(newsItem);
}
}
</pre>
<p> </p>
<p> 通过上面的代码完成了所有的数据添加工作。</p>
<p> </p>
<p>下面根据ssh的流程分别定制dao , manager , action</p>
<p> </p>
<p>com.zly.test.dao包中是所有操作dao的抽象类和接口</p>
<p> </p>
<p>我们直接看这些接口的实现</p>
<p> </p>
<p>//NewsItemDaoHibernate  新闻实体类dao</p>
<p> </p>
<p> </p>
<p> </p>
<pre name="code" class="java">@SuppressWarnings("unchecked")
//根据分页得到具体页的内容
public List&lt;com.zly.test.entity.NewsItem&gt; getNewsItemByFirstResultAndMaxResult(
final int firstResult, final int maxResult , final int type) {
return (List&lt;NewsItem&gt;) this.getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session)
throws HibernateException, SQLException {
return session.createQuery(" from NewsItem where type.id = '" + type + "'").setFirstResult(firstResult).setMaxResults(maxResult).list();
}
});
}
//得到数据总条数 , 以便计算总页数
public Long getItemCount(final int id) {
return (Long) this.getHibernateTemplate().execute(new HibernateCallback(){
public Object doInHibernate(Session session)
throws HibernateException, SQLException {
return session.createQuery("select count(*) from NewsItem where type.id = '" + id + "'").uniqueResult();
}
});
}
//显示新闻数据页面用到, 查询具体新闻属于哪个新闻类别
public int getNewsType(final int id) {
return (Integer) this.getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session)
throws HibernateException, SQLException {
NewsItem newsItem = get(id);
NewsType type = newsItem.getType();
return type.getId();
}
});
}</pre>
<p> </p>
<p>   只用到了一个   NewsManagerImpl </p>
<p> </p>
<p> </p>
<pre name="code" class="java">package com.zly.test.service.impl;

import java.util.List;

import com.zly.test.dao.NewsItemDao;
import com.zly.test.entity.NewsItem;
import com.zly.test.service.NewsManager;

public class NewsManagerImpl implements NewsManager {
//新闻条目dao
private NewsItemDao newsItemDao;

public NewsItemDao getNewsItemDao() {
return newsItemDao;
}

public void setNewsItemDao(NewsItemDao newsItemDao) {
this.newsItemDao = newsItemDao;
}
//根据分页得到内容
public List&lt;NewsItem&gt; getNewsItemByFirstResultAndMaxResult(int firstResult,
int maxResult , int type) {
return newsItemDao.getNewsItemByFirstResultAndMaxResult(firstResult, maxResult ,  type);
}
//得到总记录数,以便计算总页数
public Long getItemCounts(int id) {
return newsItemDao.getItemCount(id);
}
//通过id得到具体新闻
public NewsItem getNewsById(int id) {
return newsItemDao.get(id);
}
//通过id得到所属新闻类别的id
public int getNewsType(int id) {
return newsItemDao.getNewsType(id);
}

}
</pre>
<p> </p>
<p> </p>
<p>在applicationContext-action.xml中配置action类别</p>
<pre name="code" class="java"> &lt;bean class="com.zly.test.action.NewsAction" id="newsAction" scope="request"&gt;
&lt;property name="newsManager" ref="newsManager"&gt;&lt;/property&gt;
&lt;property name="map" ref="map"&gt;&lt;/property&gt;
&lt;property name="map1" ref="map1"&gt;&lt;/property&gt;
&lt;/bean&gt;</pre>
<p> </p>
<p>其中定一个两个map , 因为主页的查看分类新闻的url是采用的这种形式&lt;a href="newsAction.action?category=china" target="_blank"&gt;国内&lt;/a&gt;   名字为map的Map中保存信息如下</p>
<p> </p>
<pre name="code" class="java"> &lt;bean id="map" class="java.util.HashMap"&gt;
   &lt;constructor-arg&gt;
    &lt;map&gt;
   &lt;entry key="china" value="1###国内新闻" /&gt;
      &lt;entry key="world" value="2###国际新闻" /&gt;
      &lt;entry key="society" value="3###社会新闻" /&gt;
      &lt;entry key="compatriot" value="4###港台新闻" /&gt;
      &lt;entry key="taiwan" value="5###台湾新闻" /&gt;
      &lt;entry key="huaren" value="6###华人新闻" /&gt;
      &lt;entry key="economic" value="7###经济新闻" /&gt;
      &lt;entry key="wenhua" value="8###文化新闻" /&gt;
      &lt;entry key="entertainment" value="9###娱乐新闻" /&gt;
      &lt;entry key="sports" value="10###体育新闻" /&gt;
      &lt;entry key="jiaoyu" value="11###教育新闻" /&gt;
      &lt;entry key="jiankang" value="12###健康新闻" /&gt;
      &lt;entry key="life" value="13###生活新闻" /&gt;
      &lt;entry key="keji" value="14###科技新闻" /&gt;
    &lt;/map&gt;
   &lt;/constructor-arg&gt;
&lt;/bean&gt;</pre>
<p> </p>
<p>  key是?category后面的值 , value是两部分 , 被###分割开 , 前面的数值是所属新闻类别的id值, 后面的文字是其类别的文字。将其保存在map中,避免不停地查询数据库。</p>
<p> </p>
<p>  分页类PageControl的代码如下:</p>
<p> </p>
<pre name="code" class="java">package com.zly.test.entity;

import java.util.List;

public class PageControl {

private int curPage ; //当前是第几页

private int maxPage ; //一共有多少页

private Long maxRowCount ; //一共有多少行

private int rowsPerPage = 8 ; //每页有多少行

private List&lt;?&gt; data;//每页的User

public int getCurPage() {
return curPage;
}

public void setCurPage(int curPage) {
this.curPage = curPage;
}

public int getMaxPage() {
return maxPage;
}

public void setMaxPage(int maxPage) {
this.maxPage = maxPage;
}

public List&lt;?&gt; getUserList() {
return data;
}

public void setUserList(List&lt;?&gt; data) {
this.data = data;
}

public Long getMaxRowCount() {
return maxRowCount;
}

public void setMaxRowCount(Long amaxRowCountxRowCount) {
this.maxRowCount = amaxRowCountxRowCount;
}

public int getRowsPerPage() {
return rowsPerPage;
}

public void setRowsPerPage(int rowsPerPage) {
this.rowsPerPage = rowsPerPage;
}

public void countMaxPage() {   //根据总行数计算总页数 
    if (this.maxRowCount % this.rowsPerPage ==0){
       this.maxPage = (int) (this.maxRowCount/this.rowsPerPage);
    }else{
       this.maxPage = (int) (this.maxRowCount/this.rowsPerPage + 1);       
    }
}

}
</pre>
<p> </p>
<p>  被许多页所包含的page.jsp代码如下:</p>
<p> </p>
<p> </p>
<pre name="code" class="java">&lt;%@ page language="java"  contentType="text/html;charset=utf-8"
    pageEncoding="utf-8"%&gt;
&lt;%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %&gt;
&lt;html&gt;
&lt;head&gt;
&lt;script language="javascript"&gt;
function jumping() {
document.pageForm.submit();
return true;
}
function gotoPage(pageNum) {
document.pageForm.jumpPage.value = pageNum ;
document.pageForm.submit();
return true;
}
&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;c:if test="${pageControl.maxPage != 1}"&gt;
&lt;form method="post" action="pageAction.action" name="pageForm"&gt;

&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;
每页${pageControl.rowsPerPage}行
&lt;/td&gt;
&lt;td&gt;
共${pageControl.maxRowCount }行
&lt;/td&gt;
&lt;td&gt;
第${pageControl.curPage }页
&lt;/td&gt;
&lt;td&gt;
共${pageControl.maxPage }页
&lt;/td&gt;
&lt;td&gt;
&lt;c:choose&gt;
&lt;c:when test="${pageControl.curPage == 1}"&gt;
首页 上一页
&lt;/c:when&gt;

&lt;c:otherwise&gt;
&lt;A HREF="javascript:gotoPage(1)"&gt;首页&lt;/A&gt;
&lt;A HREF="javascript:gotoPage(${pageControl.curPage - 1} )"&gt;上一页&lt;/A&gt;
&lt;/c:otherwise&gt;
&lt;/c:choose&gt;

&lt;c:choose&gt;
&lt;c:when test="${pageControl.curPage == pageControl.maxPage}"&gt;
下一页 尾页
&lt;/c:when&gt;

&lt;c:otherwise&gt;
&lt;A HREF="javascript:gotoPage(${pageControl.curPage + 1})"&gt;下一页&lt;/A&gt;
&lt;A HREF="javascript:gotoPage(${pageControl.maxPage })"&gt;尾页&lt;/A&gt;
&lt;/c:otherwise&gt;
&lt;/c:choose&gt;
转到第
&lt;SELECT name="jumpPage" onchange="jumping()"&gt;
&lt;c:forEach var="i" begin="1" end="${pageControl.maxPage}" step="1"&gt;
&lt;c:choose&gt;
&lt;c:when test="${i == pageControl.curPage}"&gt;
&lt;OPTION selected value="${i}"&gt;${i }&lt;/OPTION&gt;
&lt;/c:when&gt;
&lt;c:otherwise&gt;
&lt;OPTION value="${i}"&gt;${i}&lt;/OPTION&gt;
&lt;/c:otherwise&gt;
&lt;/c:choose&gt;
&lt;/c:forEach&gt;
&lt;/SELECT&gt;

&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

&lt;/form&gt;
&lt;/c:if&gt;

&lt;/body&gt;
&lt;/html&gt;
</pre>
<p> </p>
<p>   下面是struts.xml中关于页面展示新闻的配置</p>
<p> </p>
<p> </p>
<pre name="code" class="java"> &lt;action name="newsAction" class="newsAction" &gt;
&lt;result type="redirect"&gt;pageAction.action&lt;/result&gt;
&lt;/action&gt;

&lt;action name="pageAction" class="newsAction" method="pageAction"&gt;
&lt;result&gt;/result.jsp&lt;/result&gt;
&lt;/action&gt;

&lt;action name="detailAction" class="newsAction" method="showDetail"&gt;
&lt;result&gt;/detail.jsp&lt;/result&gt;
&lt;/action&gt;</pre>
<p> </p>
<p>   NewsAction代码如下:</p>
<p> </p>
<pre name="code" class="java">package com.zly.test.action;

import java.util.List;
import java.util.Map;

import com.zly.test.entity.NewsItem;
import com.zly.test.entity.PageControl;
import com.zly.test.service.NewsManager;

public class NewsAction extends BaseAction {

private static final long serialVersionUID = 7780804627621048756L;

//对应分页jsp中的跳转到第几页
private String jumpPage;
//对应url?category的值
private String category;
//对新闻数据进行处理
private NewsManager newsManager;
//保存&lt;entry key="china" value="1###国内新闻" /&gt;这样的信息
private Map&lt;String , String&gt; map;
//保存&lt;entry key="1" value="china###国内新闻" /&gt;这样的信息
private Map&lt;String , String&gt; map1;

public Map&lt;String, String&gt; getMap1() {
return map1;
}

public void setMap1(Map&lt;String, String&gt; map1) {
this.map1 = map1;
}

public Map&lt;String, String&gt; getMap() {
return map;
}

public void setMap(Map&lt;String, String&gt; map) {
this.map = map;
}

public String getJumpPage() {
return jumpPage;
}

public void setJumpPage(String jumpPage) {
this.jumpPage = jumpPage;
}

public NewsManager getNewsManager() {
return newsManager;
}

public void setNewsManager(NewsManager newsManager) {
this.newsManager = newsManager;
}

//处理newsAction.action?category=xxx
public String execute() {
//得到相应的    1###国内新闻
String typeIdInfo = map.get(category);
//这里得到的是新闻类别id
Integer typeId = Integer.parseInt(typeIdInfo.split("###")[0]);
//这里得到的是新闻类别字符串
String typeString = typeIdInfo.split("###")[1];
//将上面三个变量保存在session中,在jsp页面中显示
this.getSession().setAttribute("category", category);
this.getSession().setAttribute("typeString" , typeString);
this.getSession().setAttribute("id", typeId);
//跳转到pageAction中,处理分页
return SUCCESS;
}

public String pageAction() {
//取出新闻类别id
Integer id = (Integer) this.getSession().getAttribute("id");
//查看是不是第一次来分页,如果是,当前页设置成第一个
if(jumpPage == null) {
jumpPage = "1";
}
//从request范围内取出PageControl , 如为空,则第一次分页,创建pageControl对象
PageControl pageControl  = (PageControl) this.getRequest().getAttribute("pageControl");
if(pageControl == null) {
pageControl = new PageControl();
//第一次的时候得到相应新闻类别所对应的记录的总数
pageControl.setMaxRowCount(newsManager.getItemCounts(id));
//计算一共多少页
pageControl.countMaxPage();
}
//设置jumpPage的值为当前页
pageControl.setCurPage(Integer.parseInt(jumpPage));
//计算出hibernate中firstResult的值
int firstResult = (pageControl.getCurPage() - 1) * pageControl.getRowsPerPage() + 1;
//设置hibernate中maxResult的值
int maxResult = pageControl.getRowsPerPage();
//利用hibernate得到当前页的数据,并保存在pageControl分页实体类中
List&lt;NewsItem&gt; userList = newsManager.getNewsItemByFirstResultAndMaxResult(firstResult, maxResult , id);
pageControl.setData(userList);
//将分页实体类保存在request范围内。
this.getRequest().setAttribute("pageControl", pageControl);
//将页面视图跳转到result.jsp
return SUCCESS;
}

public String showDetail() {
//得到url中的?id=xxx
String newsId = this.getRequest().getParameter("id");
int id = Integer.parseInt(newsId);
//使用hibernate得到具体id的新闻记录
NewsItem item = newsManager.getNewsById(id);
//得到id记录所对应的新闻类型的值   map1这种形式&lt;entry key="1" value="china###国内新闻" /&gt;
int typeId = newsManager.getNewsType(id);
//得到china,添加到jsp页面的&lt;a href="newsAction?category="&gt;里面
String category = map1.get("" + typeId).split("###")[0];
//得到国内新闻,显示在jsp页面的多个位置
String typeString = map1.get("" + typeId).split("###")[1];
//将以上多个数据添加到request范围内,以便显示。
this.getRequest().setAttribute("news", item);
this.getRequest().setAttribute("category", category);
this.getRequest().setAttribute("typeString", typeString);
return SUCCESS;
}

public String getCategory() {
return category;
}

public void setCategory(String category) {
this.category = category;
}

}
</pre>
<p> </p>
<p> </p>
<p>首页页面index.jsp,里面有几个分类超链接和搜索对话框</p>
<p> </p>
<pre name="code" class="java">&lt;%@ page language="java"  pageEncoding="utf-8"%&gt;

&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"&gt;
&lt;html&gt;
 
  &lt;head&gt;
    &lt;title&gt;最快新闻网&lt;/title&gt;
    &lt;link href="css/main.css" rel="stylesheet" type="text/css" /&gt;
  &lt;/head&gt;
 
  &lt;body&gt;
   &lt;div id="mainlink"&gt;
&lt;span&gt;&lt;a href="index.jsp"&gt;最快新闻网&lt;/a&gt;&lt;/span&gt;&amp;lt;br /&gt;&lt;br /&gt;
&lt;a href="newsAction.action?category=china" target="_blank"&gt;国内&lt;/a&gt; | &lt;a href="newsAction.action?category=world" target="_blank"&gt;国际&lt;/a&gt; | &lt;a href="newsAction.action?category=society" target="_blank"&gt;社会&lt;/a&gt; | &lt;a href="newsAction.action?category=compatriot"
target="_blank"&gt;港澳&lt;/a&gt; | &lt;a href="newsAction.action?category=taiwan" target="_blank"&gt;台湾&lt;/a&gt; | &lt;a href="newsAction.action?category=huaren" target="_blank"&gt;华人&lt;/a&gt; | &lt;a href="newsAction.action?category=economic" target="_blank"&gt;经济&lt;/a&gt;
| &lt;a href="newsAction.action?category=wenhua" target="_blank"&gt;文化&lt;/a&gt; | &lt;a href="newsAction.action?category=entertainment" target="_blank"&gt;娱乐&lt;/a&gt; | &lt;a href="newsAction.action?category=sports" target="_blank"&gt;体育&lt;/a&gt; | &lt;a
href="newsAction.action?category=jiaoyu" target="_blank"&gt;教育&lt;/a&gt; | &lt;a href="newsAction.action?category=jiankang" target="_blank"&gt;健康&lt;/a&gt; | &lt;a href="newsAction.action?category=life" target="_blank"&gt;生活&lt;/a&gt; | &lt;a href="newsAction.action?category=keji"
target="_blank"&gt;IT&lt;/a&gt;&lt;br /&gt;
&lt;form action="searchAction.action" method="post" target="_blank"&gt;
本站搜索:
&lt;input type="text" name="searchParam" style="height:20px"/&gt;
&lt;select name="searchWhich"&gt;
&lt;option value="title"/&gt;标题
&lt;option value="content"/&gt;内容
&lt;/select&gt;
&lt;input type="submit" value="搜索" style="height:23px"/&gt;
&lt;/form&gt;  
   &lt;/div&gt;
  &lt;/body&gt;
&lt;/html&gt;
</pre>
<p> </p>
<p> </p>
<p> </p>
<p>  其表现形式如下:</p>
<p><img src="http://p13.freep.cn/p.aspx?u=v20_p13_p_0906242041205118_0.jpg" alt=""></p>
<p>新闻分页展示页面result.jsp代码如下:</p>
<pre name="code" class="html">&lt;%@ page language="java" contentType="text/html;charset=utf-8"
    pageEncoding="utf-8"%&gt;
&lt;%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %&gt;
&lt;%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %&gt;
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8"&gt;
&lt;title&gt;${typeString} -- 最快新闻网&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;jsp:include page="index.jsp"&gt;&lt;/jsp:include&gt;
&lt;div id="content"&gt;
&lt;font color="red" size="5"&gt;${typeString}&lt;/font&gt;
&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;
&lt;div id="newsListTitle" style="float:left;"&gt;
&lt;c:forEach items="${pageControl.data}" var="news"&gt;
&lt;div style="margin-top: 20px;"&gt;
&lt;span&gt;
&lt;a href="detailAction.action?id=${news.id }"&gt;${news.newsTitle }&lt;/a&gt;
&lt;/span&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;/c:forEach&gt;
&lt;/div&gt;

&lt;div id="newsListTime"&gt;
&lt;c:forEach items="${pageControl.data}" var="news"&gt;
&lt;div style="margin-top: 20px;"&gt;
&lt;span&gt;
&lt;fmt:formatDate value="${news.publishTime}" pattern="MM-dd HH:mm"/&gt;
&lt;/span&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;/c:forEach&gt;
&lt;/div&gt;
&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;
&lt;%@ include file="page.jsp" %&gt;
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>  显示效果如下:</p>
<p> </p>
<p> <img src="http://p13.freep.cn/p.aspx?u=v20_p13_p_0906242059023617_0.gif" alt=""></p>
<p> </p>
<p>其中点击具体超链接的效果图如下:</p>
<p> </p>
<p> </p>
<p><img src="http://p13.freep.cn/p.aspx?u=v20_p13_p_0906242102342358_0.jpg" alt=""></p>
<p> </p>
<p>任务1 到此完成,新闻显示工作结束。下面是搜索引擎部分。</p>
<p> </p>
<p>搜索的工具类放置在com.zly.indexManager包下面</p>
<p> </p>
<p>说明,本程序使用了庖丁解牛中文分词,用户使用时需要中文字典,我的字典放在了c:\dic下面,使用庖丁还需要配置环境变量PAODING_DIC_HOME , 其值为c:\dic , (就是你的字典文件所在的目录)</p>
<p> </p>
<p>代码如下:</p>
<p> </p>
<p>创建索引类IndexCreateUtil</p>
<p> </p>
<pre name="code" class="java">package com.zly.indexManager;

import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.List;

import net.paoding.analysis.analyzer.PaodingAnalyzer;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexWriter;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;
import org.hibernate.Session;
import org.htmlparser.Parser;

import com.zly.test.entity.NewsItem;

public class IndexCreateUtil {

@SuppressWarnings("unchecked")
public void createIndexForNews() throws Exception {
//存放索引的文件夹
File indexFile = new File("c:/index/news");
//使用了庖丁解牛分词器
Analyzer analyzer = new PaodingAnalyzer();
//使用索引文件夹,庖丁解牛分词器创建IndexWriter
IndexWriter indexWriter = new IndexWriter(indexFile , analyzer , true);
//从数据库中读取出所有的新闻记录以便进行索引的创建
Configuration cfg = new AnnotationConfiguration().configure();
SessionFactory factory = cfg.buildSessionFactory();
Session session = factory.openSession();
List&lt;NewsItem&gt; list = session.createQuery(" from NewsItem").list();
DateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
//对所有的新闻实体进行索引创建
for (NewsItem newsItem : list) {
//建立一个lucene文档
Document doc = new Document();
//得到新闻标题
String newsTitle = newsItem.getNewsTitle();
//得到新闻内容
String newsContent = newsItem.getNewsContent();
//得到新闻事件
String publishDate = format.format(newsItem.getPublishTime());
//得到新闻主键id
String id = newsItem.getId() + "";
//将新闻标题加入文档,因为要搜索和高亮,所以index是tokennized,TermVector是WITH_POSITIONS_OFFSETS
doc.add(new Field("title" , newsTitle , Field.Store.YES , Field.Index.TOKENIZED , Field.TermVector.WITH_POSITIONS_OFFSETS));
//利用htmlparser得到新闻内容html的纯文本
Parser parser = new Parser();
parser.setInputHTML(newsContent);
String strings = parser.parse(null).elementAt(0).toPlainTextString().trim();
//添加新闻内容至文档,与标题相似
doc.add(new Field("content" , strings , Field.Store.COMPRESS , Field.Index.TOKENIZED , Field.TermVector.WITH_POSITIONS_OFFSETS));
//添加时间至文档,因为要按照此字段降序排列排序,所以tokenzied,不用高亮所以TermVector是no就行了
doc.add(new Field("date" , publishDate , Field.Store.YES , Field.Index.TOKENIZED , Field.TermVector.NO));
//添加主键至文档,不分词,不高亮。
doc.add(new Field("id" , id , Field.Store.YES , Field.Index.NO , Field.TermVector.NO));
indexWriter.addDocument(doc);
}
//创建索引
indexWriter.optimize();
indexWriter.close();
//关闭session
session.close();
}
public static void main(String[] args) throws Exception {
IndexCreateUtil util  = new IndexCreateUtil();
util.createIndexForNews();
}
}
</pre>
<p> </p>
<p>对索引进行搜索的代码如下:</p>
<p> </p>
<p> </p>
<pre name="code" class="java">package com.zly.indexManager;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import net.paoding.analysis.analyzer.PaodingAnalyzer;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.SimpleFragmenter;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;

import com.zly.test.entity.SearchResultBean;

public class IndexSearchUtil {

public List&lt;SearchResultBean&gt; getSearchResult(String searchWhich , String searchParam , int firstResult , int maxResult) throws Exception{
//索引所在文件夹
File indexFile = new File("c:/index/news");
//读取索引的indexReader
IndexReader reader = IndexReader.open(indexFile);
//庖丁解牛分词器
Analyzer analyzer = new PaodingAnalyzer();
//指定对content还是title进行查询
QueryParser parser = new QueryParser(searchWhich , analyzer);
//创建indexSearcher
IndexSearcher searcher  = new IndexSearcher(reader);
//对用户的输入进行查询
Query query = parser.parse(searchParam);
//根据date字段进行排序,得到查询结果
Hits hits = searcher.search(query , new Sort("date" , true));
//创建list,将结果保存其中,以便在jsp页面中进行显示
List&lt;SearchResultBean&gt; list = new ArrayList&lt;SearchResultBean&gt;();
//模拟hibernate的serFirstResult和setMaxResult以便返回指定条目的结果
for (int i = firstResult - 1; i &lt; firstResult + maxResult - 1; i++) {
Document doc = hits.doc(i);
//取得该条索引文档
SearchResultBean srb = new SearchResultBean();
//从中取出标题
String title = doc.get("title");
//从中取出内容
String content = doc.get("content");
//从中取出主键id
String id = doc.get("id");
//从中取出发布时间
String date = doc.get("date");
//高亮htmlFormatter对象
SimpleHTMLFormatter sHtmlF = new SimpleHTMLFormatter("&lt;b&gt;&lt;font color='red'&gt;", "&lt;/font&gt;&lt;/b&gt;");
//高亮对象
Highlighter highlighter = new Highlighter(sHtmlF,new QueryScorer(query));
//设置高亮附近的字数
highlighter.setTextFragmenter(new SimpleFragmenter(100));
//如果查询的是标题,进行处理
if(searchWhich.equals("title")) {
String bestFragment = highlighter.getBestFragment(analyzer,searchWhich,title);
//获得高亮后的标题内容
srb.setTitle(bestFragment);
//如果内容不足150个字,全部设置
if(content.length() &lt; 150) {
srb.setContent(content);
}else {
//如果内容多于150个字,只取出前面150个字
srb.setContent(content.substring(0 , 150));
}
} else {
//如果查询的是内容字段
String bestFragment = highlighter.getBestFragment(analyzer,searchWhich,content);
//取得高亮内容并设置
srb.setContent(bestFragment);
//设置标题,全部设置
srb.setTitle(title);
}
//设置日期
srb.setDate(date);
//设置主键
srb.setId(id);
//添加到list中,以便在jsp页面上显示
list.add(srb);
}
return list;
}
//取得符合搜索条件的所有记录总数,以便分页 , 与上面方法类似
public int getResultCount(String searchWhich , String searchParam) throws Exception {
File indexFile = new File("c:/index/news");
IndexReader reader = IndexReader.open(indexFile);
Analyzer analyzer = new PaodingAnalyzer();
QueryParser parser = new QueryParser(searchWhich , analyzer);
IndexSearcher searcher  = new IndexSearcher(reader);
Query query = parser.parse(searchParam);
Hits hits = searcher.search(query);
return hits.length();
}
}
</pre>
<p> </p>
<p> </p>
<p>分页action代码如下:</p>
<pre name="code" class="java">package com.zly.test.action;

import java.util.List;

import com.zly.indexManager.IndexSearchUtil;
import com.zly.test.entity.PageControl;
import com.zly.test.entity.SearchResultBean;

public class SearchAction extends BaseAction {

private static final long serialVersionUID = -2387037924517370511L;
//查询索引实体类
private IndexSearchUtil indexSearcher;
//对应搜索字段是标题还是内容
private String searchWhich;
//对应用户输入的搜索内容
private String searchParam;
//对应分页跳转到的页面
private String jumpPage;

public String getJumpPage() {
return jumpPage;
}

public void setJumpPage(String jumpPage) {
this.jumpPage = jumpPage;
}

public String getSearchWhich() {
return searchWhich;
}

public void setSearchWhich(String searchWhich) {
this.searchWhich = searchWhich;
}

public String getSearchParam() {
return searchParam;
}

public void setSearchParam(String searchParam) {
this.searchParam = searchParam;
}

public String search() throws Exception {
//如果为空,说明第一次进入分页
if(jumpPage == null) {
jumpPage = "1";
}
//从request范围内取得pageControl对象
PageControl pageControl  = (PageControl) this.getRequest().getAttribute("pageControl");
//如果为空,则是第一次分页,创建分页对象,并且设置总的记录条数,以便设置最大页数
if(pageControl == null) {
pageControl = new PageControl();
pageControl.setMaxRowCount((long)indexSearcher.getResultCount(searchWhich, searchParam));
pageControl.countMaxPage();
}
//设置当前页
pageControl.setCurPage(Integer.parseInt(jumpPage));
//计算firstResult
int firstResult = (pageControl.getCurPage() - 1) * pageControl.getRowsPerPage() + 1;
//计算从当前条数算还有多少条记录
long left = pageControl.getMaxRowCount() - firstResult;
int maxResult = -1;
//如果剩余的记录数不如每页显示数,就设置maxResult为剩余条数
if(left &lt; pageControl.getRowsPerPage()) {
maxResult = Integer.valueOf(left + "");
//如果剩余记录数大于每页显示页数,就设置maxResult为每页条数
}else {
maxResult = pageControl.getRowsPerPage();
}
//取得查询结果集
List&lt;SearchResultBean&gt; userList = indexSearcher.getSearchResult(searchWhich, searchParam, firstResult, maxResult);
//设置为pageControl
pageControl.setData(userList);
//将pageControl设置到request范围,以便在jsp现实结果
this.getRequest().setAttribute("pageControl", pageControl);
//将searchWhich和searchParam设置到request范围,以便添加到分页jsp的form里面的hidden表单域,以便下次分页时,能够将值提交过来
this.getRequest().setAttribute("searchWhich", searchWhich);
this.getRequest().setAttribute("searchParam", searchParam);
//跳转到分页视图
return SUCCESS;

}

public IndexSearchUtil getIndexSearcher() {
return indexSearcher;
}

public void setIndexSearcher(IndexSearchUtil indexSearcher) {
this.indexSearcher = indexSearcher;
}

}
</pre>
<p> </p>
<p> </p>
<p>搜索的action在struts.xml中设置如下:</p>
<p> </p>
<pre name="code" class="xml"> &lt;action name="searchAction" class="searchAction" method="search"&gt;
&lt;result&gt;/searchResult.jsp&lt;/result&gt;
&lt;/action&gt;</pre>
<p> </p>
<p>//searchResult.jsp代码如下:</p>
<p> </p>
<pre name="code" class="html">&lt;%@ page language="java" contentType="text/html;charset=utf-8"
    pageEncoding="utf-8"%&gt;
&lt;%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %&gt;
&lt;%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %&gt;
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8"&gt;
&lt;title&gt;${searchParam} 的搜查结果 -- 最快新闻网&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;jsp:include page="index.jsp"&gt;&lt;/jsp:include&gt;
&lt;div id="content"&gt;

&lt;div id="searchResults" &gt;
&lt;c:forEach items="${pageControl.data}" var="result"&gt;
&lt;div style="margin-top: 20px;"&gt;
&lt;span&gt;
&lt;a href="detailAction.action?id=${result.id }"&gt;${result.title}&lt;/a&gt;&lt;br /&gt;
${result.content }
&lt;font color="green"&gt;http://localhost:8080/NewsWithSearch/detailAction.action?id=${result.id } ${result.date }&lt;/font&gt;
&lt;/span&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;/c:forEach&gt;
&lt;/div&gt;

&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;

&lt;%@ include file="searchPage.jsp" %&gt;
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>    其运行结果如图所示(按标题搜索):</p>
<p> </p>
<p> </p>
<p> </p>
<p><img src="http://p13.freep.cn/p.aspx?u=v20_p13_p_0906242258409633_0.jpg" alt=""></p>
<p> </p>
<p> </p>
<p>按内容搜索的运行结果如下:</p>
<p><img src="http://p13.freep.cn/p.aspx?u=v20_p13_p_0906242300302582_0.jpg" alt=""></p>
<p> </p>
<p> </p>
<p> </p>
<p>至此,本小项目的所有功能完成,虽然没有多少难度,也不是什么高科技, 俺还是在google和javaeye上查了不少资料,总算是做完了,贴出来,与大家分享,也给新手学习提供资料。</p>
<p> </p>
<p>所有的资源我都添加到了附件中,学过ssh的同学应该能够成功部署项目并运行。</p>
<p> </p>
<p>其中NewsWithSearch.rar是工程文件夹,包含了所有的代码文件和jar包,加压完直接引到MyEclipse里就行,data.rar是所有的sql语句,插入到MySQL之前应先建立数据库mynews  ,     dic.rar是庖丁解牛用到的字典文件,</p>
<p>解压成一个文件夹,并配置环境变量PAODING_DIC_HOME,其值就是你把它解压成的文件夹(例如c:\dic),最后如果你不想创建索引的话,可以把news.rar解压成一个文件夹,拷贝到c:\index\news下面。</p>
<p> </p>
</div>
<p> </p>

19 楼
antiwise
2009-08-13  
我也跑了下程序 其他都正常 但是用那个查询就出错:
严重: Servlet.service() for servlet default threw exception
java.io.FileNotFoundException: C:\Program Files\Apache Software Foundation\Tomcat 6.0\webapps\NewsWithSearch\WEB-INF\lib\paoding-analysis.jar!\paodin (系统找不到指定的路径。)
PS:没用过那个庖丁 就是冲着这个才跑你项目的 - - ! 结果还出错 。。。
环境变量也配置了
18 楼
songjingjing520
2009-08-13  
data脚本怎么是乱码啊?
17 楼
cheerfull
2009-08-13  
难道把后缀改成.html,就是传说中的静态的了?
说不定还可能是其他的穿了个.do的MJ哦
16 楼
whitesun
2009-08-13  
看着有点头晕 有时间研究下 !很不错!
15 楼
songjingjing520
2009-08-13  
我感觉写的挺好,挺适合我们新手研究和学习的!
我仔细看了一遍了,觉得代码和注释写的都不错!
14 楼
Rossalee
2009-08-13  
不得不先赞一下先。

现在我都快被退化掉了。

13 楼
yanguoyu
2009-07-22  
3Q,楼主。
拿回去研究下。
12 楼
lxclbjn
2009-07-20  
GOOD 完美运行  3Q  如果改成COMPASS 更完美
11 楼
dizdev
2009-07-15  
呵呵,请允许我说一个很严峻的问题,并且我可以肯定楼主的方案没有解决。(因为lucene的邮件列表里,大家都在致力解决这个问题)

-------------------------

请问楼主是如何确保数据库和lucene索引的一致性的。

因为,目前Lucene是不支持Xa的,那么就无法参与到two Pharse commit中去。所以ssh和index有非常大的几率存在不同步。

抱歉!评论已关闭.