1. SSH 配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 外部化 Bean 配置信息 --> <context:property-placeholder location="classpath:c3p0.properties" /> <!-- 配置数据源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="${user}" /> <property name="password" value="${password}" /> <property name="jdbcUrl" value="${url}" /> <property name="driverClass" value="${driver}" /> <property name="minPoolSize" value="5" /> <property name="initialPoolSize" value="2" /> <property name="maxPoolSize" value="20" /> <property name="acquireIncrement" value="2" /> </bean> <!-- 配置 Hibernate 的 SessionFactory 对象 --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="configLocation" value="classpath:hibernate.cfg.xml"></property> </bean> <!-- 配置 Bean --> <bean id="user" class="com.tieba.hibernate.domain.User"></bean> <bean id="article" class="com.tieba.hibernate.domain.Article"></bean> <!-- 配置 DAO --> <bean id="userDao" class="com.tieba.hibernate.dao.UserDao"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <bean id="articleDao" class="com.tieba.hibernate.dao.ArticleDao"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <bean id="articleIndexDao" class="com.tieba.hibernate.dao.ArticleIndexDao"> <property name="compass" ref="compass" /> <property name="compassTemplate" ref="compassTemplate" /> </bean> <!-- 配置 Action --> <!-- 用户 --> <bean name="/user-add" class="com.tieba.web.struts.action.UserAction"> <property name="userDao" ref="userDao" /> </bean> <!-- 文章管理 --> <bean name="/article" class="com.tieba.web.struts.action.ArticleAction"> <property name="articleDao" ref="articleDao" /> </bean> <!-- 搜索文章 --> <bean name="/searchArticle" class="com.tieba.web.struts.action.SearchArticleAction"> <property name="articleIndexDao" ref="articleIndexDao"/> </bean> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <!-- 1. 配置基于 注解的事务驱动 <tx:annotation-driven transaction-manager="transactionManager"/> --> <!-- 2.1 声明事物通知 方法使用哪些事物属性 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!-- 配置事务属性 为那些方法配置事物属性,eg:事物传播性(REQUIRED(常用), REQUIERS_NEW),事物的隔离级别, 设置事物的回滚属性(运行异常, 检查异常(IOException)),事物超时回滚时间, 事物是否只读 --> <tx:method name="findAll*" propagation="REQUIRED" read-only="true"/> <tx:method name="*"/> </tx:attributes> </tx:advice> <!-- 2.2 配置事务的应用 配置对哪些类的哪些方法使用事物管理 --> <aop:config proxy-target-class="true"> <aop:pointcut expression="execution(* com.tieba.hibernate.dao.*.*(..))" id="txPontCut" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPontCut" /> </aop:config> <!-- 配置拦截器 --> <bean name="logger" class="com.tieba.spring.aop.LoggingInterceptor" /> <!-- 配置拦截器代理 --> <bean name="loggingAutoProxy" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames"> <list> <value>/article</value> </list> </property> <property name="interceptorNames"> <list> <value>logger</value> </list> </property> </bean> </beans>
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- SQL 方言 --> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <!-- sql 格式化 --> <property name="show_sql">true</property> <!-- Drop and re-create the database schema on startup create-drop --> <property name="hbm2ddl.auto">update</property> <!-- SSH中使用getCurrentSession()获得session 需要配置如下属性 <property name="current_session_context_class">thread</property> --> <!-- 使用二级缓存 <property name="hibernate.cache.use_second_level_cache">true</property> <property name="hibernate.cache.use_query_cache">true</property> <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property> --> <mapping resource="com/tieba/hibernate/domain/User.hbm.xml"/> <mapping resource="com/tieba/hibernate/domain/Article.hbm.xml"/> <!-- <class-cache class="com.tieba.hibernate.domain.Article" usage="read-only"/> --> </session-factory> </hibernate-configuration>
user=root password=rootroot driver=com.mysql.jdbc.Driver url=jdbc\:mysql\:///tieba
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" "http://struts.apache.org/dtds/struts-config_1_3.dtd"> <struts-config> <form-beans> <form-bean name="userForm" type="com.tieba.web.struts.from.UserForm" /> <form-bean name="articleFrom" type="com.tieba.web.struts.from.ArticleFrom"/> <form-bean name="searchArticleActionForm" type="com.tieba.web.struts.from.SearchArticleActionForm"/> </form-beans> <action-mappings> <!-- 初始化 --> <action path="/init" type="cn.itcast.lucene.init.InitAction"> <forward name="toListTopic" path="/article.do?method=listTopic" redirect="true"></forward> </action> <action path="/user-add" name="userForm" parameter="method" scope="request" type="org.springframework.web.struts.DelegatingActionProxy" input="/register.jsp"> <forward name="success" path="/success.jsp" /> </action> <!-- 贴子管理 --> <action path="/article" name="articleFrom" parameter="method" scope="request" type="org.springframework.web.struts.DelegatingActionProxy" validate="false"> <forward name="listTopic" path="/WEB-INF/pages/article/listTopic.jsp" /> <forward name="toListTopic" path="/article.do?method=listTopic" redirect="true" /> <forward name="showTopic" path="/WEB-INF/pages/article/showTopic.jsp" /> </action> <action path="/searchArticle" name="searchArticleActionForm" parameter="method" scope="request" type="org.springframework.web.struts.DelegatingActionProxy" input="/register.jsp"> <forward name="showResult" path="/WEB-INF/pages/search/showResult.jsp"></forward> </action> </action-mappings> <message-resources parameter="com.tieba.web.struts.resource.ApplicationResources" /> </struts-config>
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>tieba</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/classes/applicationContext*.xml</param-value> </context-param> <!-- 注册Spring的监听 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- Standard Action Servlet Configuration --> <servlet> <servlet-name>action</servlet-name> <servlet-class>org.apache.struts.action.ActionServlet</servlet-class> <init-param> <param-name>config</param-name> <param-value>/WEB-INF/classes/struts-config.xml</param-value> </init-param> <load-on-startup>2</load-on-startup> </servlet> <!-- Standard Action Servlet Mapping --> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <!-- spring的字符集过滤器 --> <filter> <filter-name>springCharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>springCharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- Log4Init --> <servlet> <servlet-name>log</servlet-name> <servlet-class>com.tieba.web.servlet.Log4Init</servlet-class> <load-on-startup>1</load-on-startup> </servlet> </web-app>
2. compass 配置.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd" default-lazy-init="true"> <!-- 用注解的方式 索引 --> <bean id="annotationConfiguration" class="org.compass.annotations.config.CompassAnnotationsConfiguration"></bean> <!-- 配置 Compass --> <bean id="compass" class="org.compass.spring.LocalCompassBean"> <!-- <property name="resourceDirectoryLocations"> <list> <value>classpath:com</value> </list> </property> --> <!-- 设置索引目录 --> <property name="connection"> <value>/lucene/indexes</value> </property> <!-- 配置建立索引的类 --> <property name="classMappings"> <list> <value>com.tieba.hibernate.domain.Article</value> </list> </property> <property name="compassConfiguration" ref="annotationConfiguration" /> <!-- 设置 分词器 高亮器 摘要长度 等信息 --> <property name="compassSettings"> <props> <prop key="compass.transaction.factory"> org.compass.spring.transaction.SpringSyncTransactionFactory </prop> <!-- 庖丁 分解器 中文分词器:jeasy.analysis.MMAnalyzer --> <prop key="compass.engine.analyzer.MMAnalyzer.CustomAnalyzer"> net.paoding.analysis.analyzer.PaodingAnalyzer </prop> <!-- 指定摘要的文本长度 --> <prop key="compass.engine.highlighter.default.fragmenter.simple.size">100</prop> <!-- 配置高亮效果的前缀 <用<替代 >用>替代 --> <prop key="compass.engine.highlighter.default.formatter.simple.pre"><span style='color:red; font-weight:900'></prop> <!-- 配置高亮效果的后缀 --> <prop key="compass.engine.highlighter.default.formatter.simple.post"></span></prop> </props> </property> <property name="transactionManager" ref="transactionManager" /> </bean> <!--hibernate驱动 链接compass和hibernate --> <bean id="hibernateGpsDevice" class="org.compass.gps.device.hibernate.HibernateGpsDevice"> <property name="name"> <value>hibernateDevice</value> </property> <property name="sessionFactory" ref="sessionFactory" /> <property name="mirrorDataChanges"> <value>true</value> </property> </bean> <!-- 同步更新索引 --> <bean id="compassGps" class="org.compass.gps.impl.SingleCompassGps" init-method="start" destroy-method="stop"> <property name="compass" ref="compass" /> <property name="gpsDevices"> <list> <bean class="org.compass.spring.device.SpringSyncTransactionGpsDeviceWrapper"> <property name="gpsDevice" ref="hibernateGpsDevice" /> </bean> </list> </property> </bean> <bean id="compassTemplate" class="org.compass.core.CompassTemplate"> <property name="compass" ref="compass" /> </bean> <!-- 定时重建索引(利用quartz)或随Spring ApplicationContext启动而重建索引 --> <bean id="compassIndexBuilder" class="com.tieba.web.service.CompassIndexBuilder" lazy-init="false"> <property name="compassGps" ref="compassGps" /> <!-- 每次起动时是否重建索引 true重建, false不重建 --> <property name="buildIndex" value="true" /> <property name="lazyTime" value="10" /> </bean> </beans>
3. 主要方法.
package com.tieba.web.service; import org.apache.log4j.Logger; import org.compass.gps.CompassGps; import org.springframework.beans.factory.InitializingBean; /** * 通过quartz定时调度定时重建索引或自动随Spring ApplicationContext启动而重建索引的Builder. * 会启动后延时数秒新开线程调用compassGps.index()函数. * 默认会在Web应用每次启动时重建索引,可以设置buildIndex属性为false来禁止此功能. * 也可以不用本Builder, 编写手动调用compassGps.index()的代码. * */ public class CompassIndexBuilder implements InitializingBean { Logger log = Logger.getLogger(InitializingBean.class); // 是否需要建立索引,可被设置为false使本Builder失效. private boolean buildIndex = false; // 索引操作线程延时启动的时间,单位为秒 private int lazyTime = 10; // Compass封装 private CompassGps compassGps; // 索引线程 private Thread indexThread = new Thread() { @Override public void run() { try { Thread.sleep(lazyTime * 1000); // System.out.println("begin compass index....."); log.info("begin compass index....."); long beginTime = System.currentTimeMillis(); // 重建索引. // 如果compass实体中定义的索引文件已存在,索引过程中会建立临时索引, // 索引完成后再进行覆盖. compassGps.index(); long costTime = System.currentTimeMillis() - beginTime; // System.out.println("compss index finished."); // System.out.println("costed " + costTime + " milliseconds"); log.info("compss index finished."); log.info("costed " + costTime + " milliseconds"); } catch (InterruptedException e) { e.printStackTrace(); } } }; /** * 实现<code>InitializingBean</code>接口,在完成注入后调用启动索引线程. * * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() */ public void afterPropertiesSet() throws Exception { if (buildIndex) { indexThread.setDaemon(true); indexThread.setName("Compass Indexer"); indexThread.start(); } } public void setBuildIndex(boolean buildIndex) { this.buildIndex = buildIndex; } public void setLazyTime(int lazyTime) { this.lazyTime = lazyTime; } public void setCompassGps(CompassGps compassGps) { this.compassGps = compassGps; } }
/** * 搜索 * @param quertyString 关键词 * @return */ public List<Article> find(String queryString){ CompassSession session = compass.openSession(); CompassHits hits = null; List<Article> list = new ArrayList<Article>(); try { hits = session.find(queryString); for (int i = 0; i < hits.length(); i++) { Article article = (Article) hits.data(i); // ====================================== 使用高亮器 // 如果在高亮的属性值中没有出现关键词,就返回null String title = hits.highlighter(i).fragment("title"); String content = hits.highlighter(i).fragment("content"); if (title != null) { article.setTitle(title); } if (content != null) { article.setContent(content); } list.add(article); } } catch (Exception e) { e.printStackTrace(); } finally { session.close(); } return list; }