在myeclipse下,利用myeclipse自带的功能,为项目添加struts、jpa、spring的功能,可以极大的缩短开发时间。
本文是利用struts为表现层,jpa为持久层,spring为业务层,利用spring的依赖注入管理struts的action和jpa的entityManager、jpa的事务管理。
记录学习的脚步,!!!!!
1.在myeclipse下新建web project,名为SSJTest,并添加oracle 11g的驱动jar包,如下
2.为SSJTest项目添加spring功能,如下
点击install spring facet后,下一步如下
修改运行的目标环境后,其他的默认即可,一直点next,直至完成.
完成后 效果如下
打开web.xml文件中会发现 添加了如下配置信息
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
上面的ContextLoaderListener监听器用于初始化spring容器,此监听器会查找contextConfigLocation参数,然后获取其值作为spring容器的配置文件,如果不指定contextConfigLocation参数的话,则默认会查找
/WEB-INF/applicationContext.xml
下面的配置文件
3.给 SSJTest添加jpa功能,与添加sping功能很类似,并且利用myeclipse自带的jpa工程翻转,将oracle下面的stus表进行实体映射,并生成其数据访问层和数据访问层接口,
部分截图如下
jpa翻转
配置dao,并交由spring来进行管理
其他步骤,均下一步即可.最终效果
此时为了spring为jpa管理其事务,还需在StusDao上加入@Transactional注解,以便于spring容器进行事务管理
在添加struts功能之前,测试下spring与jpa的整合是否成功,于是添加junit test
测试代码:
package com.undergrowth;
import static org.junit.Assert.*;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class StusDAOTest {
private static ApplicationContext ac;
private static IStusDAO isd;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
//初始化spring容器
ac=new ClassPathXmlApplicationContext("applicationContext.xml");
//获取stus的dao
isd=(IStusDAO) ac.getBean("StusDAO");
}
@Test
public void testSave() {
Stus stus=new Stus(UUID.randomUUID().toString(), "马化腾", 45.0, Timestamp.valueOf(new Date().toLocaleString()));
isd.save(stus);
}
@Test
public void testDelete() {
fail("Not yet implemented");
}
@Test
public void testUpdate() {
fail("Not yet implemented");
}
@Test
public void testFindAll() {
List<Stus> listStus=isd.findAll();
for (Stus stus : listStus) {
System.out.println(stus);
}
}
}
先运行testSave然后运行testFindAll,控制台输出
log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
[EL Info]: 2014-02-16 15:24:51.512--ServerSession(31211440)--EclipseLink, version: Eclipse Persistence Services - 2.4.2.v20130514-5956486
[EL Info]: connection: 2014-02-16 15:24:52.123--ServerSession(31211440)--file:/D:/learnsoftware/java/AndroidDevelop/myeclipse_2014_1_23/SSJTest/build/classes/_SSJTest login successful
Stus [stuId=b31494c8-1806-49b5-b490-49e8a57e38e3, stuName=马化腾, stuAge=45.0, stuBirthday=2014-02-16 15:24:34.0]
表明spring与jpa合成没有问题
4.为其添加struts功能,添加struts功能之后,在struts.xml配置文件中加入以下配置信息
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<!-- 打开调试模式,获取更多的调试信息 -->
<constant name="struts.devMode" value="true"></constant>
<!-- 使用spring容器来管理struts的action -->
<constant name="struts.objectFactory" value="spring"></constant>
<package name="stus" namespace="/stus" extends="struts-default">
<!-- 使用*占位符来扩展多个方法 -->
<action name="stus_*" class="stusAction" method="{1}">
<result name="list">/WEB-INF/page/stusList.jsp</result>
</action>
</package>
</struts>
spring的配置文件信息如下:
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"
xmlns:tx="http://www.springframework.org/schema/tx">
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="SSJTest" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!-- 用于jpa的事务管理 -->
<tx:annotation-driven transaction-manager="transactionManager" />
<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">
</bean>
<bean
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor">
</bean>
<bean id="StusDAO" class="com.undergrowth.StusDAO"></bean>
<bean id="stusAction" class="com.undergrowth.action.StusAction">
<!-- 注入数据访问层 -->
<property name="stusDAO" ref="StusDAO"></property>
</bean>
</beans>
中转的action为
package com.undergrowth.action;
import java.util.List;
import com.undergrowth.IStusDAO;
import com.undergrowth.Stus;
public class StusAction {
private List<Stus> listPerson;
private IStusDAO stusDAO;
public IStusDAO getStusDAO() {
return stusDAO;
}
public void setStusDAO(IStusDAO stusDAO) {
this.stusDAO = stusDAO;
}
public List<Stus> getListPerson() {
return listPerson;
}
public void setListPerson(List<Stus> listPerson) {
this.listPerson = listPerson;
}
public String getList()
{
this.listPerson=stusDAO.findAll();
return "list";
}
}
页面前段显示的界面,如下
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>信息列表</title>
</head>
<body>
<s:iterator value="listPerson">
<s:property/>
</s:iterator>
</body>
</html>
package com.undergrowth;
import java.sql.Timestamp;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* Stus entity. @author MyEclipse Persistence Tools
*/
@Entity
@Table(name = "STUS", schema = "UNDER")
public class Stus implements java.io.Serializable {
// Fields
private String stuId;
private String stuName;
private Double stuAge;
private Timestamp stuBirthday;
// Constructors
/** default constructor */
public Stus() {
}
/** full constructor */
public Stus(String stuId, String stuName, Double stuAge,
Timestamp stuBirthday) {
this.stuId = stuId;
this.stuName = stuName;
this.stuAge = stuAge;
this.stuBirthday = stuBirthday;
}
// Property accessors
@Id
@Column(name = "STU_ID", unique = true, nullable = false, length = 50)
public String getStuId() {
return this.stuId;
}
public void setStuId(String stuId) {
this.stuId = stuId;
}
@Column(name = "STU_NAME", nullable = false, length = 30)
public String getStuName() {
return this.stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
@Column(name = "STU_AGE", nullable = false, precision = 0)
public Double getStuAge() {
return this.stuAge;
}
public void setStuAge(Double stuAge) {
this.stuAge = stuAge;
}
@Column(name = "STU_BIRTHDAY", nullable = false, length = 7)
public Timestamp getStuBirthday() {
return this.stuBirthday;
}
public void setStuBirthday(Timestamp stuBirthday) {
this.stuBirthday = stuBirthday;
}
@Override
public String toString() {
return "Stus [stuId=" + stuId + ", stuName=" + stuName + ", stuAge="
+ stuAge + ", stuBirthday=" + stuBirthday + "]";
}
}
数据访问层StusDao.java
package com.undergrowth;
import java.sql.Timestamp;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
/**
* A data access object (DAO) providing persistence and search support for Stus
* entities. Transaction control of the save(), update() and delete() operations
* can directly support Spring container-managed transactions or they can be
* augmented to handle user-managed Spring transactions. Each of these methods
* provides additional information for how to configure it for the desired type
* of transaction control.
*
* @see com.undergrowth.Stus
* @author MyEclipse Persistence Tools
*/
@Transactional
@Repository
public class StusDAO implements IStusDAO {
private static final Log logger = LogFactory.getLog(StusDAO.class);
// property constants
public static final String STU_NAME = "stuName";
public static final String STU_AGE = "stuAge";
private EntityManager entityManager;
@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
private EntityManager getEntityManager() {
return entityManager;
}
/**
* Perform an initial save of a previously unsaved Stus entity. All
* subsequent persist actions of this entity should use the #update()
* method. This operation must be performed within the a database
* transaction context for the entity's data to be permanently saved to the
* persistence store, i.e., database. This method uses the
* {@link javax.persistence.EntityManager#persist(Object)
* EntityManager#persist} operation.
* <p>
* User-managed Spring transaction example:
*
* <pre>
* TransactionStatus txn = txManager
* .getTransaction(new DefaultTransactionDefinition());
* StusDAO.save(entity);
* txManager.commit(txn);
* </pre>
*
* @see <a href =
* "http://www.myeclipseide.com/documentation/quickstarts/jpaspring#containermanaged">Spring
* container-managed transaction examples</a>
* @param entity
* Stus entity to persist
* @throws RuntimeException
* when the operation fails
*/
public void save(Stus entity) {
logger.info("saving Stus instance");
try {
getEntityManager().persist(entity);
logger.info("save successful");
} catch (RuntimeException re) {
logger.error("save failed", re);
throw re;
}
}
/**
* Delete a persistent Stus entity. This operation must be performed within
* the a database transaction context for the entity's data to be
* permanently deleted from the persistence store, i.e., database. This
* method uses the {@link javax.persistence.EntityManager#remove(Object)
* EntityManager#delete} operation.
* <p>
* User-managed Spring transaction example:
*
* <pre>
* TransactionStatus txn = txManager
* .getTransaction(new DefaultTransactionDefinition());
* StusDAO.delete(entity);
* txManager.commit(txn);
* entity = null;
* </pre>
*
* @see <a href =
* "http://www.myeclipseide.com/documentation/quickstarts/jpaspring#containermanaged">Spring
* container-managed transaction examples</a>
* @param entity
* Stus entity to delete
* @throws RuntimeException
* when the operation fails
*/
public void delete(Stus entity) {
logger.info("deleting Stus instance");
try {
entity = getEntityManager().getReference(Stus.class,
entity.getStuId());
getEntityManager().remove(entity);
logger.info("delete successful");
} catch (RuntimeException re) {
logger.error("delete failed", re);
throw re;
}
}
/**
* Persist a previously saved Stus entity and return it or a copy of it to
* the sender. A copy of the Stus entity parameter is returned when the JPA
* persistence mechanism has not previously been tracking the updated
* entity. This operation must be performed within the a database
* transaction context for the entity's data to be permanently saved to the
* persistence store, i.e., database. This method uses the
* {@link javax.persistence.EntityManager#merge(Object) EntityManager#merge}
* operation.
* <p>
* User-managed Spring transaction example:
*
* <pre>
* TransactionStatus txn = txManager
* .getTransaction(new DefaultTransactionDefinition());
* entity = StusDAO.update(entity);
* txManager.commit(txn);
* </pre>
*
* @see <a href =
* "http://www.myeclipseide.com/documentation/quickstarts/jpaspring#containermanaged">Spring
* container-managed transaction examples</a>
* @param entity
* Stus entity to update
* @return Stus the persisted Stus entity instance, may not be the same
* @throws RuntimeException
* if the operation fails
*/
public Stus update(Stus entity) {
logger.info("updating Stus instance");
try {
Stus result = getEntityManager().merge(entity);
logger.info("update successful");
return result;
} catch (RuntimeException re) {
logger.error("update failed", re);
throw re;
}
}
public Stus findById(String id) {
logger.info("finding Stus instance with id: " + id);
try {
Stus instance = getEntityManager().find(Stus.class, id);
return instance;
} catch (RuntimeException re) {
logger.error("find failed", re);
throw re;
}
}
/**
* Find all Stus entities with a specific property value.
*
* @param propertyName
* the name of the Stus property to query
* @param value
* the property value to match
* @return List<Stus> found by query
*/
@SuppressWarnings("unchecked")
public List<Stus> findByProperty(String propertyName, final Object value) {
logger.info("finding Stus instance with property: " + propertyName
+ ", value: " + value);
try {
final String queryString = "select model from Stus model where model."
+ propertyName + "= :propertyValue";
Query query = getEntityManager().createQuery(queryString);
query.setParameter("propertyValue", value);
return query.getResultList();
} catch (RuntimeException re) {
logger.error("find by property name failed", re);
throw re;
}
}
public List<Stus> findByStuName(Object stuName) {
return findByProperty(STU_NAME, stuName);
}
public List<Stus> findByStuAge(Object stuAge) {
return findByProperty(STU_AGE, stuAge);
}
/**
* Find all Stus entities.
*
* @return List<Stus> all Stus entities
*/
@SuppressWarnings("unchecked")
public List<Stus> findAll() {
logger.info("finding all Stus instances");
try {
final String queryString = "select model from Stus model";
Query query = getEntityManager().createQuery(queryString);
return query.getResultList();
} catch (RuntimeException re) {
logger.error("find all failed", re);
throw re;
}
}
public static IStusDAO getFromApplicationContext(ApplicationContext ctx) {
return (IStusDAO) ctx.getBean("StusDAO");
}
}
5.测试效果如下
数据库中截图
以上步骤即是struts、spring、jpa的集成,当然相应的添加、修改、删除操作也是类似的,就不写了
6.遇到的问题
严重: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'stusAction' defined in class path resource [applicationContext.xml]: Initialization of bean failed; nested exception is org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type '$Proxy21 implementing com.undergrowth.IStusDAO,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised' to required type 'com.undergrowth.StusDAO' for property 'stusDAO'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [$Proxy21 implementing com.undergrowth.IStusDAO,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [com.undergrowth.StusDAO] for property 'stusDAO': no matching editors or conversion strategy found
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:527)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:385)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:284)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:111)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4939)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5434)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:633)
at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1113)
at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:1671)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
at java.util.concurrent.FutureTask.run(FutureTask.java:166)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
Caused by: org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type '$Proxy21 implementing com.undergrowth.IStusDAO,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised' to required type 'com.undergrowth.StusDAO' for property 'stusDAO'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [$Proxy21 implementing com.undergrowth.IStusDAO,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [com.undergrowth.StusDAO] for property 'stusDAO': no matching editors or conversion strategy found
at org.springframework.beans.BeanWrapperImpl.convertIfNecessary(BeanWrapperImpl.java:485)
上面的错误是说在StusAction进行依赖注入的时候stusDao的类型不匹配,原因在于spring容器在进行注入的时候,为stusDao生成代理对象的时候,采用的是jdk的动态代理,但是jdk的动态代理有一个前提就是,目标对象和代理对象有一个共同的接口,所以会造成类型不匹配
解决方案如下: