照着v512 刘伟老师做了一个ssh 集成compass 的小程序 最后的感觉是compass 很好很强大,我把我其中遇到的问题写出来,也许大家也会遇到,省下不必要的麻烦。
我的类库是 struts2+ hibernate3.2+spring2.5+ compass2.1
第一个问题,也是让我最崩溃的问题
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'compassIndexBuilder' defined in ServletContext resource [/WEB-INF/applicationContext-compass.xml]: Cannot resolve reference to bean 'compassGps' while setting bean property 'compassGps'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'compassGps' defined in ServletContext resource [/WEB-INF/applicationContext-compass.xml]: Cannot resolve reference to bean 'compass' while setting bean property 'compass'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'compass' defined in ServletContext resource [/WEB-INF/applicationContext-compass.xml]: Cannot resolve reference to bean 'transactionManager' while setting bean property 'transactionManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Invocation of init method failed; nested exception is java.lang.NoSuchMethodError: org.objectweb.asm.ClassVisitor.visit(IILjava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)V
看到这么长的错,我首先感觉到的就是,自己的代码有问题,死劲的找没找到。在网上搜了一下发现原来这错挺常见,我就按别人的提示一个一个的试,最终在http://atao.iteye.com/blog/281282 找到了答案,是由于Spring中的“asm-2.2.3.jar”和Hibernate中的“asm.jar”包冲突。解决办法是移除Spring2.5 AOP Libraries中的“asm-2.2.3.jar”即可 。可是让我头痛的是怎么移除呢?MyEclipse 6.5 上要想单独移除asm-2.2.3 是不可能的,只能连spring 2.5 aop Libraries 一块移除,然后重新添加,这次选择直接添加.jar文件到lib 目录,但是我就怎么呀找到那个选择直接添加.jar文件的窗口选项在哪里,后来没办法只好在发布以后删除发布完成以后tomcat 对应目录下的asm-2.2.3.jar 。第一个问题就这样勉强的解决了。
第二个问题,
java.lang.IllegalArgumentException: Original must not be null
有了这个问题,基本就能确定是spring 不能将对象注入的原因 一般是找不到对应的set 方法,我的错误是没写下面红颜色的set 方法。
package com.cntion.example.action;
import java.util.List;
import com.cntion.example.model.Product;
import com.cntion.example.service.ProductManager;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.ServletActionContext;
/**
* @author hsmiel
*
*/
public class ProductAction extends ActionSupport {
private ProductManager productManager;
private Product product;
private String queryString;
public ProductManager getProductManager() {
return productManager;
}
public void setProductManager(ProductManager productManager) {
this.productManager = productManager;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
public String getQueryString() {
return queryString;
}
public void setQueryString(String queryString) {
this.queryString = queryString;
}
public String insert(){
productManager.insertProduct(product);
return SUCCESS;
}
public String search(){
List result=productManager.searchProduct(queryString);
ServletActionContext.getRequest().setAttribute("searchresults",result);
return SUCCESS;
}
}
下面是我实现的关键代码
1 每次启动自动生成索引 CompassIndexBuilder.java
package com.cntion.example.service.impl;
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 {
// 是否需要建立索引,可被设置为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...");
long beginTime = System.currentTimeMillis();
// 重建索引.
// 如果compass实体中定义的索引文件已存在,索引过程中会建立临时索引,
// 索引完成后再进行覆盖.
compassGps.index();
long costTime = System.currentTimeMillis() - beginTime;
System.out.println("compss index finished.");
System.out.println("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 spring 配置文件 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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd" default-lazy-init="true">
<!-- 定义数据源的Bean ,给Hibernate的sessionFactory-->
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName"
value="oracle.jdbc.driver.OracleDriver">
</property>
<property name="url"
value="jdbc:oracle:thin:@localhost:1521:hsmile">
</property>
<property name="username" value="scott"></property>
<property name="password" value="tiger"></property>
</bean>
<!-- 定义Hibernate的sessionFactory,通过该Bean,可以获得Hibernate的Session-->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.Oracle9Dialect
</prop>
<!--设置二级缓冲-->
<prop key="hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider
</prop>
<!--设置二级缓冲,打开查询缓冲-->
<prop key="hibernate.cache.use_query_cache">true</prop>
<!--设置显示Hibernate操作的SQL语句-->
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>
com/cntion/example/model/Product.hbm.xml
</value>
</list>
</property>
</bean>
<!-- 注入依赖类 -->
<bean id="productDao" class="com.cntion.example.dao.hibernate.ProductDaoHibernate">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<bean id="productManager" class="com.cntion.example.service.impl.ProductManagerImpl">
<property name="productDao" ref="productDao"></property>
<property name="compassTemplate" ref="compassTemplate"></property>
</bean>
<bean id="productBean" class="com.cntion.example.action.ProductAction" scope="prototype">
<property name="productManager" ref="productManager"></property>
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory"/>
</property>
</bean>
<!-- 配置事务特性 ,配置add、delete和update开始的方法,事务传播特性为required-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 配置那些类的方法进行事务管理,当前cn.com.jobedu.oa.service包中的子包、类中所有方法需要,还需要参考tx:advice的设置 -->
<aop:config>
<aop:pointcut id="allManagerMethod" expression="execution (* com.cntion.example.service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="allManagerMethod"/>
</aop:config>
</beans>
3 sprint 集成 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>
<!-- org.compass.spring.LocalCompassBean -->
<bean id="compass" class="org.compass.spring.LocalCompassBean">
<property name="resourceDirectoryLocations">
<list>
<value>classpath:com/cntion</value>
</list>
</property>
<property name="connection">
<value>/lucene/indexes</value>
</property>
<property name="classMappings">
<list>
<value>com.cntion.example.model.Product</value>
</list>
</property>
<property name="compassConfiguration"
ref="annotationConfiguration" />
<property name="compassSettings">
<props>
<prop key="compass.transaction.factory">
org.compass.spring.transaction.SpringSyncTransactionFactory
</prop>
<prop
key="compass.engine.analyzer.MMAnalyzer.CustomAnalyzer">
net.paoding.analysis.analyzer.PaodingAnalyzer
</prop>
</props>
</property>
<property name="transactionManager" ref="transactionManager" />
</bean>
<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.cntion.example.service.impl.CompassIndexBuilder"
lazy-init="false">
<property name="compassGps" ref="compassGps" />
<property name="buildIndex" value="true" />
<property name="lazyTime" value="10" />
</bean>
</beans>
4 struts.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.objectFactory" value="spring" />
<include file="struts-default.xml" />
<package name="product" extends="struts-default"
namespace="/product">
<!-- 配置Struts2的Action,class值要与applicationContext*.xml中的id的值一致。 -->
<action name="insert" class="productBean" method="insert">
<result>insertOk.jsp</result>
</action>
<action name="search" class="productBean" method="search">
<result>searchResults.jsp</result>
</action>
</package>
</struts>
5 收索方法 红颜色的地方是表示按照商品名称收索
public List searchProduct(String queryString) {
Compass compass=compassTemplate.getCompass();
CompassSession session=compass.openSession();
CompassHits hits=session.queryBuilder().queryString("name:"+queryString).toQuery().hits();
List list=new ArrayList();
for(int i=0;i<hits.length();i++){
Product hit=(Product)hits.data(i);
list.add(hit);
}
return list;
}
6 实体类
package com.cntion.example.model;
import org.compass.annotations.*;
/**
* Product entity.
*
* @author MyEclipse Persistence Tools
*/
@Searchable
public class Product implements java.io.Serializable {
// Fields
@SearchableId
private String id;
@SearchableProperty(name="name")
private String name;
@SearchableProperty(name="price")
private Double price;
@SearchableProperty(name="brand")
private String brand;
@SearchableProperty(name="description")
private String description;
// Constructors
/** default constructor */
public Product() {
}
/** full constructor */
public Product(String name, Double price, String brand, String description) {
this.name = name;
this.price = price;
this.brand = brand;
this.description = description;
}
// Property accessors
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Double getPrice() {
return this.price;
}
public void setPrice(Double price) {
this.price = price;
}
public String getBrand() {
return this.brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
}
其中很多地方我还是不太明白。.....继续努力。