1. SSH 配置
- 1). applicationContext.xml
<?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>
- 2). hibernate.cfg.xml
<?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>
- 3). c3po.properties
user=root password=rootroot driver=com.mysql.jdbc.Driver url=jdbc\:mysql\:///tieba
- 4). struts-config.xml
<?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>
- 5). web.xml
<?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 配置.
- applicationContext-compass.xml
<?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. 主要方法.
- 1). CompassIndexBuild.java
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;
}
}
- 2). 搜索方法 ArticleIndexDaoImpl.java
/**
* 搜索
* @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;
}