1.什么是三大框架
Spring4 + SpringMVC+ jpa/hibernate4
2.Spring集成JPA
先完成Spring与jpa的集成
pom.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.itsource</groupId>
<artifactId>ssj_demo</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--spring+springmvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<!--springjdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<!--spring+jpa整合包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.3.8.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.3.8.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!--连接池-->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<!--json-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.6.5</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
3.写一个domain对象,配置JPA映射
@Entity//声明该类是一个实体类
@Table(name = "t_product")//用来命名实体类对应数据库的名称
public class Product {
@Id//主键字段
@GeneratedValue//主键生成策略
private Long id;
private String name;
4.Bean对象注入的顺序
jdbc.properties->dataSource->entityManagerFactory->dao->service->junit->action
5.加载jdbc.properties
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///ssj
jdbc.username=root
jdbc.password=123456
<!-- 加载jdbc.properties -->
<context:property-placeholder location="jdbc.properties" />
6.配置连接池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>
7.配置entityManagerFactory
<!-- 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; setJpaVendorAdapter() private OtherBean otherBean -->
<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.4. IProductDao
package cn.itsource.ssj.dao;
import cn.itsource.ssj.domain.Product;
import java.util.List;
//产品接口
public interface IProductDao {
//保存
public void save(Product product);
//修改
public void update(Product product);
//删除
public void delete(Long id);
//查询
public Product findOne(Long id);
//查询所有
public List<Product> findAll();
}
3.5. ProductDaoImpl
package cn.itsource.ssj.dao.impl;
import cn.itsource.ssj.dao.IProductDao;
import cn.itsource.ssj.domain.Product;
import org.springframework.stereotype.Repository;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.util.List;
//产品接口实现类
@Repository//将dao层的类扫描到Spring的bean容器中。
public class ProductDaoImpl implements IProductDao {
//把spring拿到EntityManagerFactory,从里面得到该对象
@PersistenceContext//注入的是实体管理器,执行持久化操作,操作数据。
private EntityManager entityManager;
//保存
public void save(Product product) {
entityManager.persist(product);
}
//修改
public void update(Product product) {
entityManager.merge(product);
}
//删除
public void delete(Long id) {
Product product = entityManager.find(Product.class, id);
//判断值是否为空
if (product!=null){
entityManager.remove(product);
}
}
//查询
public Product findOne(Long id) {
return entityManager.find(Product.class, id);
}
//查询所有
public List<Product> findAll() {
//jbql 查询表所有数据 操作对象
String jbql = "select o from Product o";
//执行查询语句 得到查询结果的对象
Query query = entityManager.createQuery(jbql);
//返回查询结果对象的结果集 结果输出列表
return query.getResultList();
}
}
3.6. 组件扫描
<!-- 扫描dao、service、action组件 -->
<!-- 可以处理@Repository, @Service, and @Controller,@Autowired,@PersistenceContext 注解-->
<context:component-scan base-package="cn.itsource.ssj" />
3.7. IProductService
```java
package cn.itsource.ssj.service;
import cn.itsource.ssj.domain.Product;
//服务层接口
import java.util.List;
public interface IProductService {
//保存
public void save(Product product);
//修改
public void update(Product product);
//删除
public void delete(Long id);
//查询
public Product findOne(Long id);
//查询所有
public List<Product> findAll();
}
3.8. ProductServiceImpl
package cn.itsource.ssj.service.impl;
import cn.itsource.ssj.dao.IProductDao;
import cn.itsource.ssj.domain.Product;
import cn.itsource.ssj.service.IProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
//服务层接口实现类
import java.util.List;
@Service//service层使用该注解 下面的类将自动注入到spring
//在spring的配置文件添加一点事务配置,并且在service层类上面添加一些注解,就可以实现事务管理
//事务一般是放到service层 dao层只专注对数据库的操作 查询没有事务 增加修改删除都有事务
//事务传播机制 如果下面的方法有事务 就使用事务运行 如果没有事务 就用非事务运行
@Transactional(propagation = Propagation.SUPPORTS,readOnly = true)
public class ProductServicelmpl implements IProductService {
//对类成员变量、方法及构造函数进行标注,完成自动装配的工作。
@Autowired
private IProductDao productDao;
//保存
@Transactional// 如果当前存在事务,就沿用当前事务,否则新建一个事务运行子方法
public void save(Product product) {
productDao.save(product);
}
//修改
@Transactional//事务方式运行
public void update(Product product) {
productDao.update(product);
}
//删除
@Transactional//事务方式运行
public void delete(Long id) {
productDao.delete(id);
}
//查询
public Product findOne(Long id) {
return productDao.findOne(id);
}
//查询所有
public List<Product> findAll() {
return productDao.findAll();
}
}
3.9. 声明式事务管理(注解版本)
在spring的配置文件添加一点事务配置,并且在service层类上面添加一些注解,就可以实现事务管理
3.9.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
http://www.springframework.org/schema/tx/spring-tx.xsd">
3.9.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.9.3. ProductServiceImpl
package cn.itsource.ssj.service.impl;
import cn.itsource.ssj.dao.IProductDao;
import cn.itsource.ssj.domain.Product;
import cn.itsource.ssj.service.IProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
//服务层接口实现类
import java.util.List;
@Service//service层使用该注解 下面的类将自动注入到spring
//在spring的配置文件添加一点事务配置,并且在service层类上面添加一些注解,就可以实现事务管理
//事务一般是放到service层 dao层只专注对数据库的操作 查询没有事务 增加修改删除都有事务
//事务传播机制 如果下面的方法有事务 就使用事务运行 如果没有事务 就用非事务运行
@Transactional(propagation = Propagation.SUPPORTS,readOnly = true)
public class ProductServicelmpl implements IProductService {
//对类成员变量、方法及构造函数进行标注,完成自动装配的工作。
@Autowired
private IProductDao productDao;
//保存
@Transactional// 如果当前存在事务,就沿用当前事务,否则新建一个事务运行子方法
public void save(Product product) {
productDao.save(product);
}
//修改
@Transactional//事务方式运行
public void update(Product product) {
productDao.update(product);
}
//删除
@Transactional//事务方式运行
public void delete(Long id) {
productDao.delete(id);
}
//查询
public Product findOne(Long id) {
return productDao.findOne(id);
}
//查询所有
public List<Product> findAll() {
return productDao.findAll();
}
}
3.10. Junit
package cn.itsource.ssj;
import cn.itsource.ssj.domain.Product;
import cn.itsource.ssj.domain.ProductDir;
import cn.itsource.ssj.service.IProductDirService;
import cn.itsource.ssj.service.IProductService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
//让测试运行于Spring测试环境
@RunWith(SpringJUnit4ClassRunner.class)
//Spring整合JUnit4测试时,使用注解引入多个配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class TestJpa {
@Autowired
private IProductService productService;
@Autowired
private IProductDirService productDirService;
@Test
public void testName()throws Exception{
Product product = new Product();
product.setName("西瓜");
ProductDir dir = new ProductDir();
dir.setName("水果类");
//给水果设置种类
product.setDir(dir);
productDirService.save(dir);
productService.save(product);
}
}
4. Spring集成SpringMVC **配置web.xml**
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--监听器 Listener javaweb 可以监听四大作用生命周期 和 作用域属性操作
就可以读取的配置文件 contextConfigLocation 为key value applicationContext.xml
-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 核心控制器配置-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-mvc.xml</param-value>
</init-param>
<!-- 优先加载servlet-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--编码过滤器配置-->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 配置过滤器 解决懒加载延迟关闭问题-->
<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>
</web-app>
4.2. 配置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: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">
<!-- 扫描 可以处理@Repository, @Service, and @Controller,@Autowired,@PersistenceContext 注解 -->
<context:component-scan base-package="cn.itsource.ssj"></context:component-scan>
<!--读取配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--连接池-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<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>
<!--entityManagerFactory-->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<!-- 注入连接池-->
<property name="dataSource" ref="dataSource"></property>
<!--扫描注解 entity-->
<property name="packagesToScan" value="cn.itsource.ssj.domain"></property>
<!-- 方言 是否显示sql 建表策略-->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<!-- private boolean generateDdl = true;底层使用update策略-->
<property name="generateDdl" value="true" />
<!-- private String databasePlatform;原来方言 -->
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
</bean>
</property>
</bean>
<!-- 事务控制 id必须这样取名 底层就是找名字 -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"></property>
</bean>
<!-- 扫描的注解 @Transaction-->
<tx:annotation-driven ></tx:annotation-driven>
</beans>
4.3. ProductController
package cn.itsource.ssj.web.controller;
import cn.itsource.ssj.domain.Product;
import cn.itsource.ssj.service.IProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller//用于标记在一个类上,使用它标记的类就是一个SpringMvc Controller对象,
// 分发处理器会扫描使用该注解的类的方法,并检测该方法是否使用了@RequestMapping注解。
@RequestMapping("/product")//访问资源路径 将 HTTP 请求映射到 MVC 和 REST 控制器的处理方法上。
public class ProductController {
@Autowired
private IProductService productService;
//跳转页面
@RequestMapping("/index")
public String index() {
return "product";//返回到这个product.jsp页面
}
//返回json格式的数据
@RequestMapping("/list")
@ResponseBody
public List<Product> list() {
return productService.findAll();
}
}
5. 以同样的方式添加产品类型
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>
配置:
在Product类里面配置
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="dir_id")
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
private ProductDir productDir;