一、什么是三大框架
1.ssh
- Struts2 Spring Hibernate
2.ssm
- SpringMVC Spring MyBatis
3.ssj
- Struts2 Spring JPA
- SpringMVC Spring JPA(今天学习)
- SpringMVC Spring Data JPA
二、SSJ集成的步骤分析:
- 1.创建项目&导包
- 2.搭建spring的运行环境
- 3.集成springMVC
- 4.三层架构(表现层、业务层、数据层)
- 5.数据层集成JPA
- 6.业务层添加AOP实现事务管理
- 7.Tomact运行项目,浏览器测试访问
三、集成
一、创建maven的web项目
二、导入jar包
- 导入jar包
- Spring的4个核心包
- SpringMVC的两个包
- Spring-aop
- Spring-test
- Hibernate核心包和JPA支持包
- mySQL驱动包
- 连接池DBCP
- Spring与JPA集成的ORM和JDBC包
- Spring的事务管理包spring-tx
- SpringMVC转JSON的jackson
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- 导入Spring的核心包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- Spring的单元测试 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- 导入mySQL的驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.13</version>
</dependency>
<!-- 导入数据库连接池的包 -->
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.5.6</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.2.1</version>
</dependency>
<!-- 导入SpringMVC的核心包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- orm映射 jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- Hibernate核心包-->
<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>
<!-- jackson核心包【SpringMVC返回json数据】 -->
<dependency>
<groupId>jackson</groupId>
<artifactId>jackson-all</artifactId>
<version>1.7.6</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.7</version>
</dependency>
</dependencies>
三、搭建spring的运行环境:spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
<!-- 扫描包
@Controller @Service @Repository @Component
-->
<context:component-scan base-package="cn.itsource"/>
<!-- 开启Spring的注解支持 -->
<context:annotation-config/>
<!--
1)配置数据库连接池
dbcp.properties
2)配置JPA的EntityManagerFactory,使用FactoryBean的方式配置
3)支持全注解的事务管理 在Service层的实现类或者方法上面添加@Transactional注解即可
-->
<!--引入dbcp.properties文件-->
<context:property-placeholder location="classpath:dbcp.properties"/>
<!--配置dbcp连接池-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<!--通常情况下以下四个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>
<!--配置JPA的EntityManagerFactory【FactoryBean方式配置】-->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<!--引用一个数据库连接池-->
<property name="dataSource" ref="dataSource"/>
<!--指定我们的domain实体类【加了@Entity注解的实体类】在哪个包-->
<property name="packagesToScan" value="cn.itsource.domain"/>
<!--指定一个适配器-->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<!--配置方言-->
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/>
<!--建表策略-->
<property name="generateDdl" value="false"/>
<!--是否显示SQL-->
<property name="showSql" value="true"/>
</bean>
</property>
</bean>
<!-- Service层添加事务管理【全注解添加事务管理】 -->
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<!--
开启注解直接AOP
tx:annotation-driven 表示开启注解支持Spring的事务管理【AOP】,会查找默认的bean名称:transactionManager
transaction-manager属性可以指定事务管理器的bean名称,如果不指定默认找transactionManager
-->
<tx:annotation-driven transaction-manager="txManager" />
</beans>
dbcp.properties
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///jpql
jdbc.username=root
jdbc.password=root
四、DAO层和Service层
- 1.接口和实现类来一套
- 2.实现类上添加@Service和@Repository注解
- 3.建立依赖关系【写一个字段添加@Autowired注解】
@Autowired
private IEmployeeDao employeeDao;
- 4.Dao层实现类中不能使用@Autowired,而是要用@PersistenceContext注解
/**
* @PersistenceContext
* 在持久化上下文范围内查找一个EntityManager对象进行注入,
* 如果找不到bean,就调用entityManagerFactory的createEntityManager方法帮我们创建一个
* 如果你在Service层添加了事务管理,此对象不是在这儿创建的,而是在Service层就已经创建好了
* @Autowired
* 在spring容器中查找目标对象,找不到就直接抛异常
*/
@PersistenceContext
private EntityManager entityManager;
5.Service层:开启事务管理
/**
* @Transactional 表示开启事务管理的注解
* 写在类上,表示全局配置,适用于当前类中所有方法
* 写在方法上,表示局部配置,只对当前方法有效
* readOnly 表示是否只读 默认false【可以读写】
* false 表示可以读写,增删改查都可以
* true 表示只读,只能查询
* propagation 事务传播机制【事务管理的范围大小】
* Propagation.SUPPORTS 默认值 你怎么写的它就怎么传播
* Propagation.NEVER 从不传播【一般不用】
* Propagation.REQUIRED 包含
* Propagation.REQUIRES_NEW 包含并且新开一个事务
*
*/
@Service
@Transactional(readOnly = false,propagation = Propagation.SUPPORTS)
public class EmployeeServiceImpl implements IEmployeeService {
@Autowired
private IEmployeeDao employeeDao;
......
五、集成SpringMVC
- 1.准备一个SpringMVC.xml
- 扫描包 @Controller
- 开启SpringMVC的注解支持
- 视图解析器
- 文件上传解析器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 扫描@Controller -->
<context:component-scan base-package="cn.itsource.controller"/>
<!--
开启SpringMVC的注解支持【默认就开启】
@RequestMapping
@ResponseBody
@RequestParam
@PathVariable
-->
<mvc:annotation-driven/>
<!-- 配置一个视图解析器 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- 文件上传解析器[暂时先不配置] -->
</beans>
- 2.修改web.xml
- DispatcherServlet核心控制器
- 初始化参数指定配置文件路径和名称
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1">
<display-name>Archetype Created Web Application</display-name>
<!--
集成Spring+SpringMVC
-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring.xml</param-value>
</context-param>
<!-- 解决no session问题 -->
<filter>
<filter-name>noSessionFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>noSessionFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--
配置SpringMVC的核心控制器
SpringMVC的配置文件默认必须放在WEB-INF之下,与web.xml同级,而且名称必须叫 SpringMVC-servlet.xml
如果文件路径或者名称不对,就必须使用初始化参数来指定路径和名称
-->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springMVC.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
六、配置Tomcat,启动&测试访问
- 复制easyui
七、三大必然出现的问题
- 1.no session
- 原因:因为懒加载,提取关联对象的属性值的时候发现EntityManager已经被关闭,就报no session
- 解决办法:将关闭EntityManager的动作延后
- 具体做法
- 在web.xml中添加一个过滤器OpenEntityManagerInViewFilter
<!-- 解决no session问题 -->
<filter>
<filter-name>noSessionFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>noSessionFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- 2.转JSON的死循环
- 原因:SpringMVC自动转JSON的时候自动调用对象的属性的get方法,双向关联会形成死循环
- 解决办法:转JSON的时候让关联对象忽略属性
- 具体做法:@JsonIgnore
package cn.itsource.domain;
import com.fasterxml.jackson.annotation.JsonIgnore;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name="department")
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private String provice;
private String city;
private String street;
//多个部门被同一个部门经理管理【单向多对一】
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="manager_id")
@JsonIgnore//@JsonIgnore 转化为JSON字符串的时候请忽略此属性
private Employee manager;
private String sn;
//当前部门下的员工集合
@JsonIgnore
@OneToMany(fetch = FetchType.LAZY,mappedBy = "department")
private List<Employee> employees = new ArrayList<>();
......
- 3.No Serializer
- 原因:懒加载原理中生成的子类除了重写属性的get方法之外,还额外添加了三个字段,但是没有提供属性的get方法
- 解决办法:转JSON时忽略这三个属性
- @JsonIgnoreProperties(value={“hibernateLazyInitializer”,“handler”, “fieldHandler”})
package cn.itsource.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import javax.persistence.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Entity
@Table(name="employee")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
//多个员工属于同一个部门【单向多对一】
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="department_id")
//@JsonIgnoreProperties 表示转化为JSON的时候忽略指定的属性
@JsonIgnoreProperties(value={"hibernateLazyInitializer","handler", "fieldHandler"})
private Department department;
private BigDecimal salary;
private Date hireDate;
get,set......
- 补充:
- 前台表格显示的时间问题:
/**
* @JsonFormat 表示转化为JSON字符串的时候处理一下日期格式
* 转化为JSON的时候会自动调用属性的get方法
* @return
*/
@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
public Date getHireDate() {
return hireDate;
}