使用JPA+Struts2+Spring 在 google Appengine开发应用
http://blog.csdn.net/lucom11/article/details/5805500
本文同时发表在我在google Appengine 上的搭建的博客:http://blogfor11lu.appspot.com/articleaction_view.action?article.id=agtibG9nZm9yMTFsdXIPCxIHQXJ0aWNsZRjBtQMM
之前用JDO 和 Struts2 在google Appengine 上试着写了一个简单的blog程序,但我还是希望使用Spring的依赖注入和事务管理等方面的功能,于是着手搭建环境。
这里,我使用了GAE1.3.5 Spring2.5.6 Struts2.1.8
首先是测试了一下JPA,在Eclipse开发环境下,GAE已经把相应的包都放到了Lib目录下了,只要在src/META-INF下建立persistence.xml文件就可以了,具体内容从GAE文档中复制过来就OK了。写一个简单的的类,测试一下,这个比较简单,GAE文档中都有。很快就成功了。
接下来,我把spring和struts的相关jar包拷到lib目录下,并配置好相关xml,总会出现或这或那的错误,这都是由于jar包不完整或者是jar包之间的版本不配比造成的,还再次出现了上一次集成struts和gae时提示xalan这个jar包没有的错误。后来发现是struts和spring-struts-plugin的版本不一致造成的(这个错误的出现有两种,一个是ongl没处理,一个就是版本不配比)。
经过一大堆错误,最后还是决定一个一个来集成。先集成struts,把前次的jar包拷贝过来,简单做一个action,测试一下,OK。
复制spring的jar包,根据网上的提示,不用all in on的那个,主要是因为GAE在file.io方面不能写文件,使用modules下面的jar包,凭感觉挑了一些,然后,再复制lib目录下需要使用的一些jar包,这个基本参考网上和以前SSH整合时用的jar包。不断测试,根据提示把jar包补齐。一般的,提示没找到指定的类错误,是没有相应jar包,提示没有指定的方法,是jar包的版本不一致。最后要把spring-struts-plugin2.1.8.jar复制到lib目录下。
集成测试了,在集成测试时,测试了@Controller、@Resource、@Transaction等几个注解,首先测的是@Controller,这个测试比较顺利。接着用@Resource 注入一个DAO操作的类。问题出来了:错误信息如下:
Error creating bean with name 'personAction': Injection of resource fields failed; nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'personService' must be of type [com_11lu.GAE.PersonService], but was actually of type [$Proxy17]
最开始,我并没有PersonService,而是直接使用DaoSupport,这是一个抽象类实现Dao接口,DaoSupport是从网上拷来的,当我注意到是抽象类时,把它的abstract去掉,错误依旧,再次,把PersonService继承DaoSupport,还是一样的错误。从这个错误信息我们可以看出,大致的意思的bean的type不对。于是在google上找,说到这个找,关键词很重要,最先是找Injection of resource fields failed这个,没有得到合适的内容。后来找must be of type but was actually of type,在一个外国论坛上看到了答案。问题出在@Transaction注解,在spring的文档中,实际上有说明,对@Transaction的类,要设置proxy-target-,否则就不能将这个类注入。也就是会出现上面的信息。具体设置是:<tx:annotation-driven transaction-manager="transactionManager" proxy-target-name="code"><?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:context="http://www.springframework.org/schema/context"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/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"><context:component-scan base-package="com_11lu.GAE" /><bean id="entityManagerFactory"value="transactions-optional" /></bean><bean id="transactionManager" ref="entityManagerFactory" /></bean><bean/><!-- Activates @Transactional for DefaultImageDatabase --><tx:annotation-driven transaction-manager="transactionManager" proxy-target-name="code">package com_11lu.GAE;import java.beans.Introspector;import java.beans.PropertyDescriptor;import java.lang.reflect.Method;import java.util.LinkedHashMap;import javax.persistence.EmbeddedId;import javax.persistence.Entity;import javax.persistence.EntityManager;import javax.persistence.PersistenceContext;import javax.persistence.Query;import org.springframework.transaction.annotation.Propagation;import org.springframework.transaction.annotation.Transactional;@Transactionalpublic abstract class DaoSupport<T> implements DAO{@PersistenceContext protected EntityManager em;public void clear(){em.clear();}public <T> void delete(Class<T> entityClass,Object entityid) {delete(entityClass, new Object[]{entityid});}public <T> void delete(Class<T> entityClass,Object[] entityids) {for(Object id : entityids){em.remove(em.getReference(entityClass, id));}}@Transactional(readOnly=true,propagation=Propagation.NOT_SUPPORTED)public <T> T find(Class<T> entityClass, Object entityId) {return em.find(entityClass, entityId);}public void save(Object entity) {em.persist(entity);}@Transactional(readOnly=true,propagation=Propagation.NOT_SUPPORTED)public <T> long getCount(Class<T> entityClass) {return (Long)em.createQuery("select count("+ getCountField(entityClass) +") from "+ getEntityName(entityClass)+ " o").getSingleResult();}public void update(Object entity) {em.merge(entity);}@Transactional(readOnly=true,propagation=Propagation.NOT_SUPPORTED)public <T> QueryResult<T> getScrollData(Class<T> entityClass,int firstindex, int maxresult, LinkedHashMap<String, String> orderby) {return getScrollData(entityClass,firstindex,maxresult,null,null,orderby);}@Transactional(readOnly=true,propagation=Propagation.NOT_SUPPORTED)public <T> QueryResult<T> getScrollData(Class<T> entityClass,int firstindex, int maxresult, String wherejpql, Object[] queryParams) {return getScrollData(entityClass,firstindex,maxresult,wherejpql,queryParams,null);}@Transactional(readOnly=true,propagation=Propagation.NOT_SUPPORTED)public <T> QueryResult<T> getScrollData(Class<T> entityClass, int firstindex, int maxresult) {return getScrollData(entityClass,firstindex,maxresult,null,null,null);}@Transactional(readOnly=true,propagation=Propagation.NOT_SUPPORTED)public <T> QueryResult<T> getScrollData(Class<T> entityClass) {return getScrollData(entityClass, -1, -1);}@SuppressWarnings("unchecked")@Transactional(readOnly=true,propagation=Propagation.NOT_SUPPORTED)public <T> QueryResult<T> getScrollData(Class<T> entityClass, int firstindex, int maxresult, String wherejpql, Object[] queryParams,LinkedHashMap<String, String> orderby) {QueryResult qr = new QueryResult<T>();String entityname = getEntityName(entityClass);Query query = em.createQuery("select o from "+ entityname+ " o "+(wherejpql==null? "": "where "+ wherejpql)+ buildOrderby(orderby));setQueryParams(query, queryParams);if(firstindex!=-1 && maxresult!=-1) query.setFirstResult(firstindex).setMaxResults(maxresult);qr.setResultlist(query.getResultList());query = em.createQuery("select count("+ getCountField(entityClass)+ ") from "+ entityname+ " o "+(wherejpql==null? "": "where "+ wherejpql));setQueryParams(query, queryParams);qr.setTotalrecord((Long)query.getSingleResult());return qr;}protected void setQueryParams(Query query, Object[] queryParams){if(queryParams!=null && queryParams.length>0){for(int i=0; i<queryParams.length; i++){query.setParameter(i+1, queryParams[i]);}}}/** * 组装order by语句 * @param orderby * @return */protected String buildOrderby(LinkedHashMap<String, String> orderby){StringBuffer orderbyql = new StringBuffer("");if(orderby!=null && orderby.size()>0){orderbyql.append(" order by ");for(String key : orderby.keySet()){orderbyql.append("o.").append(key).append(" ").append(orderby.get(key)).append(",");}orderbyql.deleteCharAt(orderbyql.length()-1);}return orderbyql.toString();}/** * 获取实体的名称 * @param <T> * @param entityClass 实体类 * @return */protected <T> String getEntityName(Class<T> entityClass){String entityname = entityClass.getSimpleName();Entity entity = entityClass.getAnnotation(Entity.class);if(entity.name()!=null && !"".equals(entity.name())){entityname = entity.name();}return entityname;}protected <T> String getCountField(Class<T> clazz){String out = "o";try {PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(clazz).getPropertyDescriptors();for(PropertyDescriptor propertydesc : propertyDescriptors){Method method = propertydesc.getReadMethod();if(method!=null && method.isAnnotationPresent(EmbeddedId.class)){PropertyDescriptor[] ps = Introspector.getBeanInfo(propertydesc.getPropertyType()).getPropertyDescriptors();out = "o."+ propertydesc.getName()+ "." + (!ps[1].getName().equals("class")? ps[1].getName(): ps[0].getName());break;}}} catch (Exception e) {e.printStackTrace();} return out;}}
问题:
1.在一个service连对一个实例两次保存
SystemUser user = (SystemUser) getSystemUser();initSystemDao.save(user);initSystemDao.save(user);
引起:TransactionOptions.Builder.withXGfound both Element
解决:在persistence.xml增加
<property name="datanucleus.appengine.datastoreEnableXGTransactions" value="true"/>
antlr-2.7.6.jar
aopalliance.jar
appengine-api-1.0-sdk-1.3.5.jar
appengine-api-labs-1.3.5.jar
appengine-jsr107cache-1.3.5.jar
cglib-nodep-2.1_3.jar
commons-beanutils.jar
commons-collections.jar
commons-fileupload-1.2.1.jar
commons-io-1.3.2.jar
commons-lang.jar
commons-logging-1.0.4.jar
commons-logging.jar
datanucleus-appengine-1.0.7.final.jar
datanucleus-core-1.1.5.jar
datanucleus-jpa-1.1.5.jar
freemarker-2.3.13.jar
geronimo-jpa_3.0_spec-1.1.1.jar
geronimo-jta_1.1_spec-1.1.1.jar
jdo2-api-2.3-eb.jar
jsr107cache-1.1.jar
ognl-2.6.11.jar
slf4j-api-1.5.8.jar
slf4j-simple-1.5.8.jar
spring-aop.jar
spring-beans.jar
spring-context.jar
spring-core.jar
spring-jdbc.jar
spring-orm.jar
spring-tx.jar
spring-web.jar
struts2-core-2.1.8.1.jar
struts2-gae-0.1.jar
struts2-spring-plugin-2.1.8.1.jar
xwork-core-2.1.6.jar