首页 > 其他分享 >使用JPA+Struts2+Spring 在 google Appengine开发应用

使用JPA+Struts2+Spring 在 google Appengine开发应用

时间:2023-05-24 13:02:40浏览次数:41  
标签:google entityClass JPA Spring jar spring return null public



本文同时发表在我在google Appengine 上的搭建的博客:[url]http://blogfor11lu.appspot.com/articleaction_view.action?article.id=agtibG9nZm9yMTFsdXIPCxIHQXJ0aWNsZRjBtQMM[/url]

之前用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-class="true" ,否则就不能将这个类注入。也就是会出现上面的信息。具体设置是:<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>。
由于我的英文实在是差,没搞明白proxy-target-class="true"设置在哪,也搞不懂注解方式这个如何设,最终是试着放在这的。我想,如果不是用注解方式,可以放在<bean/>里。

再次运行,提试CGLIB要复制到CLASSPAH下,在spring的Lib目录中找到,复制好就OK了。

下面我把用到的Jar包列出,另外我把我测试用的project也上传到,大家可以下载看看。
我写的记录了我的整个过程,这个过程,我用了好几个晚上的功夫,文字有点哆嗦。

解释一下为什么@Transaction的类,会出现上述错误,在spring中@Transaction是通过AOP实现的,而spring对AOP有两种实现方式,一种是动态代理,它是通过接口方式实现的,要求所代理的类一定是实现了某一个接口,对一般的类就无法代理,spring默认是这种;通过设置proxy-target-class="true",则是使用CGLIB实现AOP,CGLIB直接生成二进制码,使得普通类也可以实现AOP。在没有设置proxy-target-class="true"时,使用动态代理,是一个临时生成的类,如proxy17,它不是@Resource指定的类,因此出现了上述错误。

<?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"
		class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"
		lazy-init="true">
		<property name="persistenceUnitName" value="transactions-optional" />
	</bean>


	<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>

	<bean
		class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
	<!-- Activates @Transactional for DefaultImageDatabase -->
	<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>


</beans>




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;


@Transactional

public  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

[color=red][b]spring-aop.jar

spring-beans.jar

spring-context.jar

spring-core.jar

spring-jdbc.jar

spring-orm.jar

spring-tx.jar

spring-web.jar[/b][/color]

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


标签:google,entityClass,JPA,Spring,jar,spring,return,null,public
From: https://blog.51cto.com/u_3871599/6338654

相关文章

  • Appengine部署springMVC3.1
    参考:[url]http://sikeh.iteye.com/blog/364043[/url]获得springMVC的方法:[url]http://panyongzheng.iteye.com/blog/1759912[/url][b]1.mvnarchetype:create-DgroupId=com.pandy-DartifactId=study[/b][b]2.cdstudy[/b]需要做一些另外的事情,然......
  • 使用spring初始化器创建出来的gradle项目,gradle.build.ks文件extra报错的解决方法
    有关讨论:https://github.com/spring-io/initializr/issues/922https://github.com/spring-io/start.spring.io/issues/581springboot生成器:https://start.spring.io/......
  • 自定义注解实现数据序列化时进行数据脱敏(基于springboot默认jackjson)、消息转换器
    消息转换器fastjson与jackjson问题在springboot中使用fastjson的@jsonField无效原因:在springboot默认有json(jackjson)解析工具,所以使用fastjson不会生效解决方案替换默认的解析工具(笔者不推荐,这里根据自己项目决定)fastjson替换默认的jackjson第一种方法bean方法packagecom......
  • springboot~对应sharding-jdbc实现分库分表
    原因当mysql数据库单表大于1千万以后,查询的性能就不能保证了,我们必须考虑分库,分表的方案了,还好,sharding-jdbc可以很优雅的与springboot对接,完成对mysql的分库和分表。依赖整理为了不影响其它小容量的表,所有添加了动态数据源,只对需要分库分表的进行配置即可com.baomidou:dyna......
  • SpringBoot中使用枚举类、switch、常量类(声明并初始化map)实现类策略者模式,接口返回
    场景SpringBoot中策略模式+工厂模式业务实例(接口传参-枚举类查询策略映射关系-执行不同策略)规避大量if-else:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/130503707SpringBoot+@Validate+全局异常拦截实现自定义规则参数校验(校验get请求参数不能为空且在指定......
  • 微服务框架SpringCloud微-2-服务拆分及远程调用-demo黑马
    微服务框架SpringCloud微服务架构2服务拆分及远程调用2.1案例Demo2.1.1服务拆分注意事项 这里四个模块,拆成四个服务就行了 单一职责:不同微服务,不要重复开发相同业务【不能像以前那样了】数据独立:不要访问其它微服务的数据库 3.面向服务:将自己的业务暴......
  • springboot框架实现网站权限管理系统
    技术架构技术框架:springboot+layui+shiro+activiti+thymeleaf+mybatis运行环境:jdk8+IntelliJIDEA+maven3+宝塔面板宝塔部署教程回到IDEA,点击编辑器右侧maven图标,执行package,完成后就会在根目录里生成一个target目录,在里面会打包出一个jar文件。宝塔新建一个......
  • Java语言springboot框架实现的停车位管理系统
    技术架构技术框架:jQuery+MySQL5.7+mybatis+shiro+Layui+HTML+CSS+JS+thymeleaf运行环境:jdk8+IntelliJIDEA+maven3+宝塔面板宝塔部署教程1.回到IDEA,点击编辑器右侧maven图标,执行package,完成后就会在根目录里生成一个target目录,在里面会打包出一个jar文件......
  • SpringBoot中操作Redis解析JsonArray数据为对象List(ruoyi字典值sys_dict为例)
    场景若依前后端分离版手把手教你本地搭建环境并运行项目:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/108465662在上面搭建系统的基础上,会将系统的字典值缓存进redis中。看数据格式存储的是Json数组,如何从redis中读取并解析成对象的list从而进行数据处理。注......
  • 基于springboot+vue数码论坛系统设计与实现、论坛管理系统,附源码+数据库+lw文档+PPT
    1、项目介绍考虑到实际生活中在数码论坛方面的需要以及对该系统认真的分析,将系统权限按管理员和用户这两类涉及用户划分。(1)系统功能需求登录系统后,主要模块包括首页、数码板块、数码评价、数码论坛、畅聊板块、新闻资讯、个人中心、后台管理等功能。系统功能用例图如图3-1所示......