2.1. sshjava
Struts/Struts2 Spring Hibernatemysql
2.2. ssmweb
SpringMVC Spring MyBatisspring
2.3. ssjsql
Struts2 Spring JPA數據庫
SpringMVC Spring JPAapache
SpringMVC Spring Data JPAtomcat
Spring4 + Struts2 + jpa/hibernate4app
建議:先完成Spring與jpa的集成框架
3.1. 建立動態web工程:
注意修改classpath路徑,建立web文件取名爲webapp
3.2. 拷貝Spring共16的jar文件
11個spring的jar文件
spring-framework-3.2.0.RELEASE-dependencies搜索dbcp,pool,aop,wea,logging
3.3. 拷貝JPA共11的jar文件
hibernate-release-4.3.8.Final\lib\jpa\*.jar
hibernate-release-4.3.8.Final\lib\required\*.jar
3.4. 拷貝數據庫驅動1個jar文件
Spring+jpa+驅動共28個jar文件
3.5. 寫一個domain對象,配置JPA映射
@Entity
@Table(name = "t_product")
public class Product {
@Id
@GeneratedValue
private Long id;
private String name;
3.6. Spring的配置文件
3.6.1. Bean對象注入的順序
jdbc.properties->dataSource->entityManagerFactory->dao->service->junit->action
3.6.2. 加載jdbc.properties
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///ssj
jdbc.username=root
jdbc.password=root
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 加載jdbc.properties -->
<context:property-placeholder location="jdbc.properties" />
3.6.3. 配置鏈接池dataSource
<!-- 配置鏈接池dataSource -->
<!-- destroy-method="close當前bean銷燬的時候,會先調用close方法,關閉鏈接" -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- 依賴注入鏈接池須要的屬性 -->
<!-- property name="是BasicDataSource的set方法,本質屬性" -->
<!-- property value="是jdbc.properties配置文件的key" -->
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
3.7. 配置entityManagerFactory
3.7.1. Spring-Reference_2.5_zh_CN.chm
12.6.1.3. LocalContainerEntityManagerFactoryBean
3.7.2. 配置信息
<!-- org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter引入默認entityManagerFactory名稱 -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<!-- 1.注入DataSource -->
<property name="dataSource" ref="dataSource" />
<!-- 2.從哪一個包去掃描@Entity,domain包 -->
<!-- public void setPackagesToScan(String... packagesToScan) { -->
<property name="packagesToScan" value="cn.itsource.ssj.domain" />
<!-- 3.配置JPA的實現 -->
<!-- private JpaVendorAdapter jpaVendorAdapter; -->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<!-- org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter -->
<!-- private boolean showSql = false;是否顯示sql語句 -->
<property name="showSql" value="true" />
<!-- private boolean generateDdl = false;是否建表 -->
<property name="generateDdl" value="true" />
<!-- private String databasePlatform;原來方言 -->
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
</bean>
</property>
</bean>
3.8. IProductDao
public interface IProductDao {
void save(Product product);
void update(Product product);
void delete(Long id);
Product get(Long id);
List<Product> getAll();
}
3.9. ProductDaoImpl
@Repository
public class ProductDaoImpl implements IProductDao {
// @Autowired 不能使用這個注入
@PersistenceContext // 持久層上下文管理器
private EntityManager entityManager;
@Override
public void save(Product product) {
entityManager.persist(product);
}
@Override
public void update(Product product) {
entityManager.merge(product);
}
@Override
public void delete(Long id) {
Product product = get(id);
if (product != null) {
entityManager.remove(product);
}
}
@Override
public Product get(Long id) {
return entityManager.find(Product.class, id);
}
@Override
public List<Product> getAll() {
String jpql = "select o from Product o";
return entityManager.createQuery(jpql).getResultList();
}
}
3.10. 組件掃描
<!-- 掃描dao、service、action組件 -->
<!-- 能夠處理@Repository, @Service, and @Controller,@Autowired,@PersistenceContext 註解-->
<context:component-scan base-package="cn.itsource.ssj" />
3.11. IProductService
public interface IProductService {
void save(Product product);
void update(Product product);
void delete(Long id);
Product get(Long id);
List<Product> getAll();
}
3.12. ProductServiceImpl
@Service
public class ProductServiceImpl implements IProductService {
@Autowired
private IProductDao productDao;
@Override
public void save(Product product) {
productDao.save(product);
}
@Override
public void update(Product product) {
productDao.update(product);
}
@Override
public void delete(Long id) {
productDao.delete(id);
}
@Override
public Product get(Long id) {
return productDao.get(id);
}
@Override
public List<Product> getAll() {
return productDao.getAll();
}
}
3.13. 聲明式事務管理(註解版本)
在spring的配置文件添加一點事務配置,而且在service層類上面添加一些註解,就能夠實現事務管理
3.13.1. 添加一個tx命名空間
<?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: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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
3.13.2. 添加事務配置
<!-- 配置事務管理器 -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!-- 開啓註解事務管理 ,解析@Transactional事務註解 -->
<!-- transaction-manager="transactionManager"默認找bean.id=transactionManager事務管理器 -->
<tx:annotation-driven />
3.13.3. ProductServiceImpl
@Service
// 默認事務配置
// @Transactional
// 上面配置等價於下面配置
@Transactional(propagation = Propagation.REQUIRED)
public class ProductServiceImpl implements IProductService {
@Autowired
private IProductDao productDao;
@Override
public void save(Product product) {
productDao.save(product);
}
@Override
public void update(Product product) {
productDao.update(product);
}
@Override
public void delete(Long id) {
productDao.delete(id);
}
@Override
@Transactional(readOnly=true,propagation=Propagation.SUPPORTS)
public Product get(Long id) {
return productDao.get(id);
}
@Override
@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public List<Product> getAll() {
return productDao.getAll();
}
}
3.14. Junit
@Autowired
IProductService productService;
@Test
public void save() throws Exception {
System.out.println("代理類:" + productService.getClass());
Product product = new Product();
product.setName("蘋果的弟弟");
productService.save(product);
}
代理類:class com.sun.proxy.$Proxy23
4.1. 添加struts2的12個jar文件
沒有導入javassist-3.11.0.GA.jar
4.2. 配置web.xml
<!-- 添加struts核心過濾器 -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
4.3. 配置struts.xml
<package name="default" namespace="/" extends="struts-default">
<!-- action表明一個控制器, name="對應的訪問的url地址" method="返回action的方法" -->
<!-- spring集成struts以後,class能夠寫全限定類名,也能夠寫bean.id -->
<!-- product 沒有寫_的時候,默認就是訪問當前action的execute -->
<!-- product_*寫了_input,訪問input方法 ,對應後面method={1} -->
<action name="product_*" class="cn.itsource.ssj.action.ProductAction" method="{1}">
<!-- 顯示列表頁面 -->
<result>/WEB-INF/views/product.jsp</result>
<!-- 顯示添加獲取修改頁面 -->
<result name="input">/WEB-INF/views/product_input.jsp</result>
<!-- 保存或者刪除以後進行重定向 -->
<result name="reload" type="redirectAction">product</result>
</action>
</package>
4.4. ProductAction
public class ProductAction extends ActionSupport {
@Autowired
IProductService productService;
@Override
public String execute() throws Exception {
ActionContext.getContext().put("products", productService.getAll());
return SUCCESS;
}
}
4.5. 配置好,啓動tomcat,拋出一下異常
4.5.1. 具體異常信息
嚴重: Exception starting filter struts2
Class: com.opensymphony.xwork2.spring.SpringObjectFactory
File: SpringObjectFactory.java
Method: getClassInstance
Line: 245 - com/opensymphony/xwork2/spring/SpringObjectFactory.java:245:-1
at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:493)
at org.apache.struts2.dispatcher.ng.InitOperations.initDispatcher(InitOperations.java:74)
at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.init(StrutsPrepareAndExecuteFilter.java:57)
at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:279)
at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:260)
at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:105)
at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4700)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5340)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1408)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1398)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException
at com.opensymphony.xwork2.spring.SpringObjectFactory.getClassInstance(SpringObjectFactory.java:245)
at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.verifyResultType(XmlConfigurationProvider.java:608)
at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.addResultTypes(XmlConfigurationProvider.java:578)
at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.addPackage(XmlConfigurationProvider.java:534)
at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.loadPackages(XmlConfigurationProvider.java:295)
at org.apache.struts2.config.StrutsXmlConfigurationProvider.loadPackages(StrutsXmlConfigurationProvider.java:112)
at com.opensymphony.xwork2.config.impl.DefaultConfiguration.reloadContainer(DefaultConfiguration.java:264)
at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:67)
at org.apache.struts2.dispatcher.Dispatcher.getContainer(Dispatcher.java:967)
at org.apache.struts2.dispatcher.Dispatcher.init_PreloadConfiguration(Dispatcher.java:435)
at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:479)
... 14 more
4.5.2. 爲何會出現異常?
由於原來struts2的對象都是由xwork的對象處理,如今添加struts2-spring-plugin-2.3.20.jar文件,以後由spring接管了對原來struts2對象的建立
緣由是在struts2-spring-plugin-2.3.20.jar文件裏面有這個配置struts-plugin.xml
<struts>
<bean type="com.opensymphony.xwork2.ObjectFactory" name="spring" class="org.apache.struts2.spring.StrutsSpringObjectFactory" />
<!-- Make the Spring object factory the automatic default -->
<constant name="struts.objectFactory" value="spring" />
<constant name="struts.class.reloading.watchList" value="" />
<constant name="struts.class.reloading.acceptClasses" value="" />
<constant name="struts.class.reloading.reloadConfig" value="false" />
<package name="spring-default">
<interceptors>
<interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
</interceptors>
</package>
</struts>
而spring容器並無被啓動
4.5.3. 在web.xml添加一個監聽器,來實例化spring容器
<!-- 添加一個監聽器,來實例化spring容器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
4.5.4. 再次啓動tomcat,又拋出異常
Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/applicationContext.xml]
at org.springframework.web.context.support.ServletContextResource.getInputStream(ServletContextResource.java:141)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:330)
... 21 more
默認會去WEB-INF下面找配置文件,而此路徑沒有
4.5.5. 在web.xml添加一個上下文的初始化參數,來告訴spring從哪裏加載配置文件
<!-- 添加一個上下文的初始化參數 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
4.5.6. 怎樣快速找contextConfigLocation名字
找監聽器ContextLoaderListener的父類ContextLoader
有一個常量配置
public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation";
4.5.7. 不能加載jdbc.properties異常
Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/jdbc.properties]
4.5.8. 修改spring的配置文件
<!-- 加載jdbc.properties -->
<!-- 跑web必須在前面添加classpath:前綴 -->
<context:property-placeholder location="classpath:jdbc.properties" />
4.5.9. 再次啓動tomcat,沒有異常
4.5.10. 訪問http://localhost/product,出現404異常,
由於沒有寫jsp頁面,此jsp頁面和原來寫JPA集成Struts2的jsp是一致的。
4.5.11. product.jsp
<body>
<table border="1">
<tr>
<th>編號</th>
<th>產品名稱</th>
<!-- <th>產品類型名稱</th> -->
<th>操做</th>
</tr>
<s:iterator value="#products">
<tr>
<td>${id}</td>
<td>${name}</td>
<%-- <td>${dir.name}</td> --%>
<td><a href="product_input?product.id=${id}">修改</a> <a
href="product_delete?product.id=${id}">刪除</a></td>
</tr>
</s:iterator>
</table>
<a href="product_input">添加</a>
</body>
5.1. 添加產品類型模型
模型ProductDir,修改Product添加@ManyToOne
寫dao,service
5.2. 修改web.xml,解決延遲加載的異常
<!-- 添加關閉entityManger過濾器,必須在struts2過濾器以前 -->
<filter>
<filter-name>OpenEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>OpenEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
6.1. struts2加載配置文件順序
struts2-core-2.3.20.jar\org\apache\struts2\default.properties
struts2-core-2.3.20.jar\struts-default.xml
struts2-spring-plugin-2.3.20.jar\struts-plugin.xml
...
classpath:struts.xml
6.2. struts2-spring-plugin-2.3.20.jar struts-plugin.xml
沒有使用這個jar文件,struts2的對象建立是由xwork處理
添加這個這個jar文件以後struts2的對象就由spring建立
<bean type="com.opensymphony.xwork2.ObjectFactory" name="spring" class="org.apache.struts2.spring.StrutsSpringObjectFactory" />
<!-- Make the Spring object factory the automatic default -->
<constant name="struts.objectFactory" value="spring" />
6.3. default.properties
默認狀況下在struts.xml的action節點裏面class屬性寫全限定類名是按照byName注入
### valid values are: name, type, auto, and constructor (name is the default)
struts.objectFactory.spring.autoWire = name
6.4. class屬性
6.4.1. 方案1 建議使用,填寫spring的bean id,
注意xml版本配置scope=’prototype’
註解版本配置@Scope(「prototype」)
好處1:可使用小寫的url地址,從使用通配符
<package name="default" namespace="/" extends="struts-default">
<!-- action表明一個控制器, name="對應的訪問的url地址" method="返回action的方法" -->
<!-- spring集成struts以後,class能夠寫全限定類名,也能夠寫bean.id -->
<!-- *_* 請求的url_請求的方法 -->
<!-- 第1個*表明url地址,好比如今product,後面使用{1}來代替,url地址小寫開頭,正好對應action的bean.id的定義 -->
<!-- 第2個*表明訪問action的方法,好比如今product_input,後面使用{2}來代替 -->
<action name="*_*" class="{1}Action" method="{2}">
<!-- 顯示列表頁面 -->
<result>/WEB-INF/views/{1}.jsp</result>
<!-- 顯示添加獲取修改頁面 -->
<result name="input">/WEB-INF/views/{1}_input.jsp</result>
<!-- 保存或者刪除以後進行重定向 -->
<result name="reload" type="redirectAction">{1}</result>
</action>
</package>
好處2:由於使用action是由spring管理
能夠對action添加aop額外處理
壞處:spring配置文件寫action的配置
@Controller//bean.id=productAction
@Scope("prototype")//配置多例
public class ProductAction extends ActionSupport {
6.4.2. 方案2 填寫全限定類名,
若是填寫全限定類名,則返回是小寫url的地址,要求cn.itsource.ssj.action.ProductAction,類名對應要小寫,不符合java命名規範;不能使用*_*通配符
@Autowired先按照類型,若是接口有2個實現,會報錯
能夠添加@Qualifier("productServiceImpl")名稱來進行注入
public class ProductAction extends ActionSupport {
@Autowired
private IProductService productService;
7.1. 重點
Ssj集成必須寫熟練,1遍,2遍,3遍
7.2. 難點
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: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/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">
<!-- jdbc.properties->dataSource->entityManagerFactory->dao->service->junit->action -->
<!-- 掃描dao、service、action組件 -->
<!-- @Repository, @Service, and @Controller,@Autowired,@PersistenceContext -->
<context:component-scan base-package="cn.itsource.ssj" />
<!-- 加載jdbc.properties -->
<!-- 跑web必須在前面添加classpath:前綴 -->
<context:property-placeholder location="classpath:jdbc.properties" />
<!-- 配置鏈接池dataSource -->
<!-- destroy-method="close當前bean銷燬的時候,會先調用close方法,關閉鏈接" -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- 依賴注入鏈接池須要的屬性 -->
<!-- property name="是BasicDataSource的set方法,本質屬性" -->
<!-- property value="是jdbc.properties配置文件的key" -->
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<!-- org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter引入默認entityManagerFactory名稱 -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<!-- 1.注入DataSource -->
<property name="dataSource" ref="dataSource" />
<!-- 2.從哪一個包去掃描@Entity,domain包 -->
<!-- public void setPackagesToScan(String... packagesToScan) { -->
<property name="packagesToScan" value="cn.itsource.ssj.domain" />
<!-- 3.配置JPA的實現 -->
<!-- private JpaVendorAdapter jpaVendorAdapter; -->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<!-- org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter -->
<!-- private boolean showSql = false;是否顯示sql語句 -->
<property name="showSql" value="true" />
<!-- private boolean generateDdl = false;是否建表 -->
<property name="generateDdl" value="true" />
<!-- private String databasePlatform;原來方言 -->
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
</bean>
</property>
</bean>
<!-- 配置事務管理器 -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!-- 開啓註解事務管理 ,解析@Transactional註解 -->
<!-- transaction-manager="transactionManager"默認找bean.id=transactionManager事務管理器 -->
<tx:annotation-driven />
</beans>
事務沒有配置成功
沒有配置<tx:annotation-driven />
Could not autowire field: private cn.itsource.ssj.service.IProductService cn.itsource.ssj.action.ProductAction.productService; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of
type [cn.itsource.ssj.service.IProductService] is defined: expected single matching bean but found 2: productServiceImpl,productServiceImpl2
接口有2個實現