SSM框架

mybatis

快速入门:

  1. 导入坐标
  1. <dependency>
  2. <groupId>org.mybatis</groupId>
  3. <artifactId>mybatis</artifactId>
  4. <version>3.4.5</version>
  5. </dependency>

  1. 建立映射文件的位置:

    1. 创建位置:必须和持久层接口在相同的包中。
    2. 名称:必须以持久层接口名称命名文件名,扩展名是.xml

  2. 映射文件的内容,指明了映射哪个实体类,下面有个例子

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

    <mapper namespace="com.itheima.dao.IUserDao">
    <!-- 配置查询所有操作 -->
    <select id="findAll" resultType="com.itheima.domain.User">
    select * from user
    </select>

  1. 主配置文件SQlMapConfig.xml

目的是连接数据库,并且写出映射文件的位置

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 配置 mybatis 的环境 -->
<environments default="mysql">
<!-- 配置 mysql 的环境 -->
<environment id="mysql">
<!-- 配置事务的类型 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置连接数据库的信息:用的是数据源(连接池) -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ee50"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</dataSource>
</environment>
</environments>
<!-- 告知 mybatis 映射配置的位置 -->
<mappers>
<mapper resource="com/itheima/dao/IUserDao.xml"/>
</mappers>
</configuration>
  1. 下面示范一个使用mybatis的步骤
/**
*
* <p>Title: MybatisTest</p>
* <p>Description: 测试 mybatis 的环境</p>
* <p>Company: http://www.itheima.com/ </p>
*/
public class MybatisTest {
public static void main(String[] args)throws Exception {
//1.读取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建 SqlSessionFactory 的构建者对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();

//3.使用构建者创建工厂对象 SqlSessionFactory,通过读取的配置文件的内容
SqlSessionFactory factory = builder.build(in);

//4.使用 SqlSessionFactory 生产 SqlSession 对象,SqlSession真正与数据库打交道
SqlSession session = factory.openSession();

//5.使用 SqlSession 创建 dao 接口的代理对象
IUserDao userDao = session.getMapper(IUserDao.class);

//6.使用代理对象执行查询所有方法
List<User> users = userDao.findAll();

for(User user : users) {
System.out.println(user);
}
//7.释放资源
session.close();
in.close();
}
}
  1. 介绍基于注解的mybatis(这个时候就要把映射文件给删除),在sqlmapconfig文件中就要告诉使用注解的类是哪一个
<!-- 告知 mybatis 映射配置的位置 -->
<mappers>
<mapper class="com.itheima.dao.IUserDao"/>
</mappers>

    注意:在使用映射文件的时候是resource,现在用的是class

自定义mybatis查询的流程分析(使用代理类对象)

一、首先理一下思路:

(1)最终我们执行的就是findAll()方法,在这里 方法中我们分为几个步骤。

1、根据sqlMapConifg配置文件创建connection对象。

2、获取预处理对象,然后根据sql语句执行查询。(这里的sql就是需要配置文件得来的)。

3、我们遍历结果集,把查到的数据封装到实体类对象中,这个对象又存在泛型数组中,通过反射创建一个实体类对象(创建的前提条件就是有这个实体类的全限定类名)

小结:这就是为什么我们需要两个配置文件,(1)sqlmapconfig.xml主要是提供数据库连接的信息,同时提供映射配置文件的信息。(2)mapper.xml提供了sql语句获取预处理对象,resultType属性告诉了封装是要封装到哪个实体类当中,用于反射实例化一个对象,这个时候就可以知道泛型数组具体是哪种类型。

在我们开发的时候绝对不止一个映射文件,一个方法,这个时候我们就可以用一个map集合,里面装一些mapper对象,这些对象有两个属性,第一个是sql语句,第二个是全限定类名。并且map的key是接口的全限定类名+方法名。

(2)第一步我们知道了执行findAll()方法的前提条件,但是findAll()必须要有一个调用他的类,现在就讨论在哪里调用的findAll()


  • 使用了动态代理,然后增强方法中调用了这个方法, 有一个getMapper的泛型方法,他的参数是一个接口的字节码,在这个方法里 使用实现接口的动态代理的方法

proxy.newProxyInstance(类加载器,代理对象要实现的接口字节数组,增强方法)。


  • 接下来就是一层一层的往上套。这里我们根据那几个步骤来写思路
首先介绍一下用到的类:
        Resources 用于加载配置文件的类
        SqlSessionFactoryBuilder 构建者的类,里面的builde方法就是根据从配置文件得到的内容来构建
            SqlSessionFactory工厂的,然后在这个方法里调用了一个工具类的方法
          (不用深究,主要是加载配置文件内容的),这个方法的目的就是把获取了内容,
            把driver,url,username,password封装到一个Configuration类中。

        Configuration类,自定义的mybatis的配置类,里面的属性有:
                driver,url,username,password,mappers(map集合,就是用于存储上面说的sql语句和全限定类名)。

        SqlSessionFactory 是一个接口,里面有一个opensession方法,用于打开新的ssqlsession对象
        DefaultSqlSessionFactory 是SqlSessionFactory的实现类,里面有configuration对象,意思就是这个工厂有了数据库的一套消息和要操作的实体类,里面实现的opensession()方法直接new一个真正操作数据库的DefaultSqlSession(对象,这里一定不要忘了把那个配置类传进去,因为他有整套信息。

    SqlSession 是一个接口,他是整个mybatis和数据库交互的核心类,它里面主要负责根据dao接口的字节码创建一个代理对象,和释放资源。
    DefaultSqlSession 是 SqlSession接口的实现类,是一个操作数据库的对象,有两个属性,Configuration,Connection。创建DefaultSqlSessionFactory的时候,把Configuration传进来了,然后根据Configuration,创建链接。对于创建代理对象的方法,直接返回一个具有增强方法的代理类对象(其中增强方法的类是MapperProxy,实现了InvocationHandle的invoke方法)。对于释放资源的方法,把链接关闭就可以了。

    MapperProxy实现了InvocationHandle,两个属性:mappers,conn。调用这个构造器的时候就要把所说的那个集合给传进来,用于增强方法的时候组合key,然后通过这个key找到要封装的mapper,这个mapper就有sql语句,和实体类的全限定类名。
    这个时候就可以调用工具类的selectList()方法了,把查到的mapper,conn传进去就ok了。


//1.读取配置文件,这里使用类加载器读取主配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");

//2.创建 SqlSessionFactory 的构建者对象,这个构建者主要是用于创建SqlSessionFactory工厂的
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();

//3.使用构建者创建工厂对象 SqlSessionFactory,其实我们返回一个DefaultSqlSessionFactory,
并且他还有数据库和sql语句,全限定类名一套信息。
SqlSessionFactory factory = builder.build(in);

//4.使用 SqlSessionFactory 生产 SqlSession 对象,这里其实已经是DefaultSqlSessionFactory了,
然后他有了一套信息,返回一个操作一个数据库的对象,这个可操作数据库的对象应该得到刚才的
配置信息同时创建一个链接。
SqlSession session = factory.openSession();

//5.使用 SqlSession 创建 dao 接口的代理对象,这里我们就是用了动态代理,
就有了一个代理对象,getMapper根据传进来的字节码然后创建代理对象,
同时这个代理对象有了一个增强方法。
IUserDao userDao = session.getMapper(IUserDao.class);

//6.使用代理对象执行查询所有方法
List<User> users = userDao.findAll();
for(User user : users) {
System.out.println(user);
}
//7.释放资源
session.close();
in.close();

二、涉及的设计模式。


  1. 构建者模式:暂时不是很理解什么是分离‘复杂对象的构建算法’和‘部件及组装方式’,在自定义的框架里,他的用法就是为了创建一个工厂SqlSessionFactory。

  2. 工厂模式,主要是用于实例化对象,用工厂方法代替new操作,降低了程序的耦合,增加了程序的可扩展性和以后更少的修改量。这里SqlSessionFactory 生产 SqlSession 对象就是。

  3. 代理模式,动态代理,减少了代码的冗余,我们返回一个代理对象,它里面含有具体的增强方法,例如上面的session.getMapper(IUserDao.class);就是创建了一个iuserdao的代理对象,他有了增强的方法,可以具体操作某个方法。

mybatis的一些配置(记录一下每个配置,方便以后忘了可以查)


  • SqlMapConfig.xml主配置文件
    • 首先写一下配置的内容
-properties(属性)
    --property
-settings(全局配置参数)
    --setting
-typeAliases(类型别名)
    --typeAliase
    --package
-typeHandlers(类型处理器)
-objectFactory(对象工厂)
-plugins(插件)
-environments(环境集合属性对象)
    --environment(环境子属性对象)
        ---transactionManager(事务管理)
        ---dataSource(数据源)
-mappers(映射器)
    --mapper
    --package

下面是一个示例,方便看
<!--  mybatis的主配置文件  -->
<configuration>
<!--  配置properties
        可以在标签内部配置连接数据库的信息。也可以通过属性引用外部配置文件信息
        resource属性: 常用的
            用于指定配置文件的位置,是按照类路径的写法来写,并且必须存在于类路径下。
                resource="jdbc.properties",    建议使用这个
        url属性:
            是要求按照Url的写法来写地址
            URL:Uniform Resource Locator 统一资源定位符。它是可以唯一标识一个资源的位置。
            它的写法:
                http://localhost:8080/mybatisserver/demo1Servlet
                协议      主机     端口       URI

            URI:Uniform Resource Identifier 统一资源标识符。它是在应用中可以唯一定位一个资源的。
     -->
<properties url="file:///D:/IdeaProjects/day02_eesy_01mybatisCRUD/src/main/resources/jdbcConfig.properties">
<!--  <property name="driver" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/eesy_mybatis"></property>
        <property name="username" value="root"></property>
        <property name="password" value="1234"></property> -->
</properties>
<!-- 使用typeAliases配置别名,它只能配置domain中类的别名  -->
<typeAliases>
<!-- typeAlias用于配置别名。type属性指定的是实体类全限定类名。alias属性指定别名,当指定了别名就再区分大小写 
        <typeAlias type="com.itheima.domain.User" alias="user"></typeAlias> -->
<!--  用于指定要配置别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名,不再区分大小写 -->
<package name="com.itheima.domain"/>
</typeAliases>
<!-- 配置环境 -->
<environments default="mysql">
<!--  配置mysql的环境 -->
<environment id="mysql">
<!--  配置事务  -->
<transactionManager type="JDBC"/>
<!-- 配置连接池 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!--  配置映射文件的位置  -->
<mappers>
<!-- <mapper resource="com/itheima/dao/IUserDao.xml"></mapper> -->
<!--  package标签是用于指定dao接口所在的包,当指定了之后就不需要在写mapper以及resource或者class了,resource用于指定映射文件,class指定接口  -->
<package name="com.itheima.dao"/>
</mappers>
</configuration>
  • sqlmapconfig.xml配置数据源,深入数据源
<!-- 配置数据源(连接池)信息 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
MyBatis 在初始化时,根据<dataSource>的 type 属性来创建相应类型的的数据源 DataSource,即:
type=”POOLED”:MyBatis 会创建 PooledDataSource 实例,连接池实例
type=”UNPOOLED” : MyBatis 会创建 UnpooledDataSource 实例,不用连接池
type=”JNDI”:MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用

    分析POOLED:它使用了数据库连接池,当我们真正创建了sqlsession对象并且执行sql语句的时候才会去调用datasource对象去创建链接,当我们用完了就归还给连接池,是一个懒加载。

  • (Mapper.xml)映射文件的配置

    • resultType:把结果封装成什么类型(如果字段名和属性名一样用这个)

    • resultMap:把结果封装成什么类型(字段名和属性名不一样)
      • 具体的用法是建立表和类的对应关系
<!-- 建立 User 实体和数据库表的对应关系
type 属性:指定实体类的全限定类名
id 属性:给定一个唯一标识,是给查询 select 标签引用用的。
-->
<resultMap type="com.itheima.domain.User" id="userMap">
<id column="id" property="userId"/>
<result column="username" property="userName"/>
<result column="sex" property="userSex"/>
<result column="address" property="userAddress"/>
<result column="birthday" property="userBirthday"/>
</resultMap>
id 标签:用于指定主键字段
result 标签:用于指定非主键字段
column 属性:用于指定数据库列名
property 属性:用于指定实体类属性名称

映射配置
<!-- 配置查询所有操作 -->
<select id="findAll" resultMap="userMap">//这里resultMap就指向了上面定义的
select * from user
</select>

  • parameterType:传入参数的类型

  • #{} sql语句使用这个字符,它相当于jdbc的占位符,具体的数据由里面的内容决定。
    • {}内的写法主要是用该ognl表达式 格式:对象.对象 例如#{user.username} 他就是去user对象中找getUsername(),如果我们在parameterType声明了这个user,就可以省略user.直接写username就可以了。

  • keyColumn:列名,keyProperty:属性名。

  • 配置动态sql语句 ```xml if标签 我们根据实体类的不同取值,使用不同的 SQL 语句来进行查询。比如在 id 如果不为空时可以根据 id 查询,如果 username 不同空时还要加入用户名作为条件。这种情况在我们的多条件组合查询中经常会碰到。
注意:标签的 test 属性中写的是对象的属性名,如果是包装类的对象要使用 OGNL 表达式的写法。 另外要注意 where 1=1 的作用~! where标签 SQL 语句: select 字段 from user where id in (?) 标签用于遍历集合,它的属性: collection:代表要遍历的集合元素,注意编写时不要写#{} open:代表语句的开始部分 close:代表结束部分 item:代表遍历集合的每个元素,生成的变量名 sperator:代表分隔符 - <br />几个扩展的问题: - 当我们插入一个数据的时候,我们需要返回他自动增长的id的时候我们要将自动增长的值返回就可以了,具体实现如下xml select last_insert_id(); insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address}) - 模糊查询的两个方法xml

我们在上面将原来的#{}占位符,改成了${value}。注意如果用模糊查询的这种写法,那么${value}的写 法就是固定的,不能写成其它名字。

#{}表示一个占位符号

通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换,

{}可以有效防止 sql 注入。 #{}可以接收简单类型值或 pojo 属性值。 如果 parameterType 传输单个简单类型值,#{}括号中可以是 value 或其它名称。

${}表示拼接 sql 串

通过${}可以将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换, ${}可以接收简 单类型值或 pojo 属性值,${}括号中只能是 value。



4. <br />
<a name="654ea41e"></a>
### mybatis的一对一,一对多以及事务控制

   - <br />![](/tmp/evince-15951/image.OUJ6U0.png#id=uIdPI&originalType=binary&status=done&style=none)
   - <br />事务控制:本身也是用JDBC的setAutoCommit()来设者事务提交方式的,我们观察上面这个图发现我们每次cud操作的时候都必须手动进行事物的提交,原因是setAutoCommit()方法,在执行时它的值被设置为 false 了,所以我们在 CUD 操作中,必须通过 sqlSession.commit()方法来执行提交操作。那我们在创建session对象的时候,设为true就可以了。`**_factory.openSession(true);_**`
   - <br />一对一的查询
      - 方式一:(推荐)用户的个实体类作为账户的子类,这样返回的时候就有了账户的那几个属性



```java
/**
*
* <p>Title: Account</p>
* <p>Description: 账户的实体类</p>
* <p>Company: http://www.itheima.com/ </p>
*/
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
@Override
public String toString() {
return "Account [id=" + id + ", uid=" + uid + ", money=" + money + "]";
}
}

/**
*
* <p>Title: AccountUser</p>
* <p>Description: 它是 account 的子类,包括了父类的属性</p>
* <p>Company: http://www.itheima.com/ </p>
*/
public class AccountUser extends Account implements Serializable {
private String username;
private String address;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return super.toString() + "
AccountUser [username=" + username + ",
address=" + address + "]";
}
}


/**
*
* <p>Title: IAccountDao</p>
* <p>Description: 账户的持久层接口</p>
* <p>Company: http://www.itheima.com/ </p>
*/
public interface IAccountDao {
/**
* 查询所有账户,同时获取账户的所属用户名称以及它的地址信息
* @return
*/
List<AccountUser> findAll();
}


映射文件的信息
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.dao.IAccountDao">
<!-- 配置查询所有操作-->
<select id="findAll" resultType="accountuser">
select a.*,u.username,u.address from account a,user u where a.uid =u.id;
</select>
</mapper>
注意:因为上面查询的结果中包含了账户信息同时还包含了用户信息,所以我们的返回值类型 returnType的值设置为 AccountUser 类型,这样就可以接收账户信息和用户信息了。
  - 方式二:resultMap专门定义一对一查询,思路是把User作为Account的一个属性
/**
*
* <p>Title: Account</p>
* <p>Description: 账户的实体类</p>
* <p>Company: http://www.itheima.com/ </p>
*/
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
@Override
public String toString() {
return "Account [id=" + id + ", uid=" + uid + ", money=" + money + "]";
}
}

/**
*
* <p>Title: IAccountDao</p>
* <p>Description: 账户的持久层接口</p>
* <p>Company: http://www.itheima.com/ </p>
*/
public interface IAccountDao {
/**
* 查询所有账户,同时获取账户的所属用户名称以及它的地址信息
* @return
*/
List<Account> findAll();
}
注意:第二种方式,将返回值改 为了 Account 类型。
因为 Account 类中包含了一个 User 类的对象,它可以封装账户所对应的用户信息。

修改映射文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.dao.IAccountDao">
<!-- 建立对应关系 -->
<resultMap type="account" id="accountMap">
    <id column="aid" property="id"/>
    <result column="uid" property="uid"/>
    <result column="money" property="money"/>
<!-- 它是用于指定从表方的引用实体属性的 -->
    <association property="user" javaType="user">
        <id column="id" property="id"/>
            <result column="username" property="username"/>
            <result column="sex" property="sex"/>
            <result column="birthday" property="birthday"/>
            <result column="address" property="address"/>
    </association>
</resultMap>

    <select id="findAll" resultMap="accountMap">
        select u.*,a.id as aid,a.uid,a.money from account a,user u where a.uid =u.id;
    </select>
</mapper>
  • 一对多查询(这个时候就只能用刚才的映射关系,mybatis已经做好了和集合的关系)
/**
*
* <p>Title: User</p>
* <p>Description: 用户的实体类</p>
* <p>Company: http://www.itheima.com/ </p>
*/
public class User implements Serializable {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
private List<Account> accounts;
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", birthday=" + birthday
+ ", sex=" + sex + ", address="
+ address + "]";
}
}



<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.dao.IUserDao">

<resultMap type="user" id="userMap">
    <id column="id" property="id"></id>
    <result column="username" property="username"/>
    <result column="address" property="address"/>
    <result column="sex" property="sex"/>
    <result column="birthday" property="birthday"/>
<!-- collection 是用于建立一对多中集合属性的对应关系 ofType 用于指定集合元素的数据类型-->
    <collection property="accounts" ofType="account">
        <id column="aid" property="id"/>
        <result column="uid" property="uid"/>
        <result column="money" property="money"/>
    </collection>
</resultMap>
<!-- 配置查询所有操作 -->
<select id="findAll" resultMap="userMap">
select u.*,a.id as aid ,a.uid,a.money from user u left outer join account
a on u.id =a.uid
</select>
</mapper>

collection部分定义了用户关联的账户信息。表示关联查询结果集
property="accList" :关联查询的结果集存储在 User 对象的上哪个属性。
ofType="account" :指定关联查询的结果集中的对象类型即 List 中的对象类型。此处可以使用别名,也可以使用全限定名。

一级缓存和二级缓存

一级缓存

一级查询缓存是针对与SqlSession类的实例对象中,当第一次查询某个数据的时候,SqlSession类的实例对象会将该数据存入一级缓存区域,在没有收到改变该数据的请求(执行了commit操作,即增 删 改)之前,用户再次查询该数据都是从缓存中获取数据,而不是再次连接池数据库进行查询。

二级缓存

一级缓存是针对SqlSession对象的、二级缓存是针对于Mapper实例的,当多个SqlSession类的实例对象加载的是同一个Mapper文件配置的IuserDao.class(就是sqlsession.getMapper(相同的接口.class))的时候,那么他们就共享一个Mapper缓存。

Spring


  • Spring快速入门


    • 1、拷贝必要的jar包到lib,或者maven导入依赖。

    • 2、在类路径下创建bean.xml(什么名字都可以,这是一个管理容器的配置文件)。

      • ```xml 导入约束(必备的)

<?xml version=”1.0” encoding=”UTF-8”?>

- <br />3、主类测试有没有成功java / 模拟一个表现层 @author 黑马程序员 @Company http://www.ithiema.com @Version 1.0 */ public class Client { / 使用 main 方法获取容器测试执行 / public static void main(String[] args) { //1.使用 ApplicationContext 接口,就是在获取 spring 容器 ApplicationContext ac = new ClassPathXmlApplicationContext(“bean.xml”); //2.根据 bean 的 id 获取对象 IAccountService aService = (IAccountService) ac.getBean(“accountService”); System.out.println(aService); IAccountDao aDao = (IAccountDao) ac.getBean(“accountDao”); System.out.println(aDao); } } 运行结果如下: <a name="T727W"></a> ### Spring基于XML的IOC的细节(重点) <a name="V9qQ7"></a> #### 工厂类的结构图 - <br />![](https://cdn.nlark.com/yuque/0/2021/png/12512246/1618747491877-b6fbb211-fb86-4ff7-aa51-cad8ff2b1af4.png#clientId=u15cba31a-ce04-4&from=paste&height=408&id=uafef90cf&margin=%5Bobject%20Object%5D&originHeight=408&originWidth=574&originalType=binary&size=121534&status=done&style=none&taskId=u5524852d-330a-49aa-bd37-57e1c148e76&width=574) <a name="qAfta"></a> ##### BeanFactory 和 ApplicationContext 的区别 BeanFactory是顶层接口,ApplicationContext是字节口,BeanFactory是懒加载,什么时候使用什么时候创建ioc容器,ApplicationContext是立即创建ioc容器。<br />ApplicationContext接口的实现类:<br /> ClassPathXmlApplicationContext:<br /> 它是从类的根路径下加载配置文件 推荐使用这种<br /> FileSystemXmlApplicationContext:<br /> 它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。<br /> AnnotationConfigApplicationContext:<br /> 当我们使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解。 <a name="ogxjq"></a> #### IOC中bean标签的细节 - <br />作用:就是创建对象(默认情况是调用类中的无参构造器,如果没有就不成功) - <br />**属性**: - id:给对象在容器提供一个唯一标识,用于获取对象。 - class:指定类的全限定类名,拿来反射创建对象,默认情况调用无参构造器。 - scope:指定对象的作用范围 - singleton:单例,默认值 - prototype:多例 - request :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中. - session :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中. - global session<br />:WEB 项目中,应用在 Portlet 环境.如果没有 Portlet 环境那么globalSession 相当于 session. - init-method:指定类中的初始化方法名称。 - destroy-method:指定类中销毁方法名称。 - <br />**bean的作用范围和生命周期** - scope="singleton" - 单例的,作用范围是整个应用。 - 生命周期:(就是和容器的状态是一样的) - 对象出生:当应用加载,读取文件创建容器的时候对象就被创建了 - 对象活着:只要容器在,对象就一直活着 - 对象死亡:销毁容器时,对象就被销毁了 - scope="prototype" - 每次访问对象时,就会重新创建(不归容器管),就当时有点用 - 生命周期: - 对象出生:当使用对象时,创建新的对象实例。 - 对象活着:只要对象在使用中,就一直活着。 - 对象死亡:当对象长时间不用时,由垃圾回收器回收。 - <br />**实例化Bean的三种方式** - <br />第一种:就是调用默认无参构造器 - <br />xml - <br />第二种:静态工厂,然后bean标签里这个工厂的静态方法 - <br />xml 第二种方式:spring 管理静态工厂-使用静态工厂的方法创建对象 / 模拟一个静态工厂,创建业务层实现类 / public class StaticFactory { public static IAccountService createAccountService(){ return new AccountServiceImpl(); } } - <br />第三种:实例化工厂,然后用实例化工厂的方法创建对象 - <br />xml / 模拟一个实例工厂,创建业务层实现类 此工厂创建对象,必须现有工厂实例对象,再调用方法 / public class InstanceFactory { public IAccountService createAccountService(){ return new AccountServiceImpl(); } } <a name="666480c3"></a> ### **Spring的依赖注入(IOC)** - 概念:其实就是我们之前已经把对象交给spring处理了,我们就可以用spring操作这个对象,给这个对象注入我们想给它的值。 <a name="kuhOS"></a> #### XML配置IOC - 构造函数注入:xml - set方法注入xml 顾名思义,就是在类中提供需要注入成员的 set 方法。具体代码如下: /** / public class AccountServiceImpl implements IAccountService { private String name; private Integer age; private Date birthday; public void setName(String name) { this.name = name; } public void setAge(Integer age) { this.age = age; } public void setBirthday(Date birthday) { this.birthday = birthday; } @Override public void saveAccount() { System.out.println(name+”,”+age+”,”+birthday); } } - 使用p名称空间注入数据(本质还是调用set方法,所以要提供set方法) - 而且还多一个p约束,就在第二行xml - <br />注入集合的数据(不像上面就是基本类型或者某个实体类) - <br />xml AAA BBB CCC AAA BBB CCC AAA BBB CCC aaa bbb bbb <a name="MSsZA"></a> #### 基于注解的IOC配置(当我们使用注解注入的时候,set方法可以不用写,一般用这个) - <br />快速环境搭建: - 1、多了一个jar包:spring-aop-5.0.2.RELEAS.jar - 2、把需要放入到容器中的类加上Component(当不属于三层的时候可以用这个) - 3、创建bean.xml文件,基于注解的时候我们要多导约束,下面是注解的xml的一个例子xml <?xml version=”1.0” encoding=”UTF-8”?> - <br />几个Spring常用的注解介绍: - <br />用于创建对象的:@Component,@Controller,@Service,@Repository,用于把注解的这个类放到容器中。 - <br />用于注入数据的: - @Autowired:动按照类型注入。当使用注解注入属性时,set 方法可以省 略。它只能注入其他 bean 类型。当有多个类型匹配时,使用要注入的对象 变量名 称作为 bean 的 id,在 spring 容器查找,找到了也可以注入成功。找不到就报错。下面描述一下这个注解的匹配过程。 ![](https://cdn.nlark.com/yuque/0/2021/png/12512246/1618747666268-4d772d28-f58a-4b94-b371-7bdfbc160c3c.png#clientId=u15cba31a-ce04-4&from=paste&height=519&id=u77592285&margin=%5Bobject%20Object%5D&originHeight=519&originWidth=1327&originalType=binary&size=39612&status=done&style=none&taskId=u4f4b26a1-5cfe-426d-99da-0d471bef5a2&width=1327) - <br />@Qualifier: 作用:在自动按照类型注入的基础之上,再按照 Bean 的 id 注入。它在给字段注入时不能独立使用,必须和[@Autowire ](/Autowire ) 一起使用;但是给方法参数注入时,可以独立使用。属性: value:指定 bean 的 id。 - <br />@Resource:作用: 直接按照 Bean 的 id 注入。它也只能注入其他 bean 类型。属性:name:指定 bean 的 id。 - <br />@Value作用:注入基本数据类型和 String 类型数据的属性:value:用于指定值 - <br />用于改变作用范围的: - @Scope作用:指定 bean 的作用范围。属性:value:指定范围的值。取值:singleton prototype request session globalsession - <br />和生命周期相关的:(了解) - [@PostConstruct ](/PostConstruct ) 作用:用于指定初始化方法。 - @PreDestroy作用:用于指定销毁方法。 - <br />**XML和注解的选择问题:** - 注解的优势: 配置简单,维护方便(我们找到类,就相当于找到了对应的配置)。 XML 的优势: 修改时,不用改源码。不涉及重新编译和部署。 - 管理bean方式的比较: ![](https://cdn.nlark.com/yuque/0/2021/png/12512246/1618747876878-e7e64a9c-ade0-47a1-8201-04b0664adb3e.png#clientId=ua53dfbd0-63b3-4&from=paste&height=555&id=uf8db36cf&margin=%5Bobject%20Object%5D&originHeight=555&originWidth=611&originalType=binary&size=358007&status=done&style=none&taskId=uc4f7d85c-ae00-4cba-850b-d3bb4dd7cb8&width=611) - <br /> <a name="e64710cd"></a> ### **Spring整合Junit(掌握)** - <br />为什么要整合Junit?因为我们想在测试类中,直接注入某些对象,方便测试,而不是每个测试方法都包含以下两行代码: 针对这个问题,我们如果能自动 创建spring容器就可以解决了,但是junit他不知道有没有spring框架跟别说创建容器了,不过他有一个注解,这个注解可以让我们替换掉他的运行器,刚好spring提供了一个运行器,可以读取配置文件来创建容器,我们只要告诉这个运行器配置文件在哪里就可以了。java ApplicationContext ac = new ClassPathXmlApplicationContext(“bean.xml”); IAccountService as = ac.getBean(“accountService”,IAccountService.class); 获取了容器之后,再创建相应的对象。 - <br />配置步骤:java 1、导入一个spring中aop的jar包。 2、使用@RunWith注解替换原有的运行器 / 测试类 @author 黑马程序员 @Company http://www.ithiema.com @Version 1.0 */ @RunWith(SpringJUnit4ClassRunner.class) public class AccountServiceTest { } 3、使用@ContextConfiguration指定Spring配置文件的位置 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations= {“classpath:bean.xml”}) @ContextConfiguration 注解: locations 属性:用于指定配置文件的位置。如果是类路径下,需要用 classpath:表明 classes 属性:用于指定注解的类。当不使用 xml 配置时,需要用此属性指定注解类的位置。 public class AccountServiceTest { } - <br /> <a name="Dkk8X"></a> ### Spring中的aop <a name="IWU9V"></a> #### 动态代理 <a name="ByhoB"></a> ##### jdk动态代理java package com.itheima.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; / 模拟一个消费者 / public class Client { public static void main(String[] args) { Producer producer = new Producer(); / 动态代理: 特点:字节码随用随创建,随用随加载 作用:不修改源码的基础上对方法增强 分类: 基于接口的动态代理 基于子类的动态代理 基于接口的动态代理: 涉及的类:Proxy 提供者:JDK官方 如何创建代理对象: 使用Proxy类中的newProxyInstance方法 创建代理对象的要求: 被代理类最少实现一个接口,如果没有则不能使用 newProxyInstance方法的参数: ClassLoader:类加载器 它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器。固定写法。 Class[]:字节码数组 它是用于让代理对象和被代理对象有相同方法。固定写法。 InvocationHandler:用于提供增强的代码 它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。 此接口的实现类都是谁用谁写。 / IProducer proxyProducer = (IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(), producer.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //提供增强的代码 Object returnValue = null; //1.判断当前方法是不是销售 if(“saleProduct”.equals(method.getName())) { System.out.println(args[0]); //2.获取方法执行的参数 Float money = (Float) args[0]; returnValue = method.invoke(producer, money*0.8f); } return returnValue; } }); proxyProducer.saleProduct(10000f); } } package com.itheima.proxy; / 对生产厂家要求的接口 / public interface IProducer { / 销售 @param money */ public void saleProduct(float money); / 售后 @param money / public void afterService(float money); } package com.itheima.proxy; /** 一个生产者 / public class Producer implements IProducer{ @Override public void saleProduct(float money) { System.out.println(“拿到钱”+money); } @Override public void afterService(float money) { System.out.println(“—-afterService”); } } <a name="USeZp"></a> ##### cglib动态代理java package com.itheima.cglib; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** 模拟一个消费者 / public class Client { public static void main(String[] args) { final Producer producer = new Producer(); /** 动态代理: 特点:字节码随用随创建,随用随加载 作用:不修改源码的基础上对方法增强 分类: 基于接口的动态代理 基于子类的动态代理 基于子类的动态代理: 涉及的类:Enhancer 提供者:第三方cglib库 如何创建代理对象: 使用Enhancer类中的create方法 创建代理对象的要求: 被代理类不能是最终类 create方法的参数: Class:字节码 它是用于指定被代理对象的字节码。 Callback:用于提供增强的代码 它是让我们写如何代理。我们一般都是些一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。 此接口的实现类都是谁用谁写。 我们一般写的都是该接口的子接口实现类:MethodInterceptor / Producer cglibProducer = (Producer)Enhancer.create(producer.getClass(), new MethodInterceptor() { /** 执行被代理对象的任何方法都会经过该方法 @param proxy @param method @param args 以上三个参数和基于接口的动态代理中invoke方法的参数是一样的 @param methodProxy :当前执行方法的代理对象 @return returnValue 是方法的返回值 @throws Throwable / @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { //提供增强的代码 Object returnValue = null; //1.获取方法执行的参数 Float money = (Float)args[0]; //2.判断当前方法是不是销售 if(“saleProduct”.equals(method.getName())) { returnValue = method.invoke(producer, money0.8f); } System.out.println(“———->”+returnValue); return returnValue; } }); cglibProducer.saleProduct(12000f); } } package com.itheima.cglib; /** 一个生产者 / public class Producer { /** 销售 @param money / public Integer saleProduct(float money){ System.out.println(“销售产品,并拿到钱:”+money); Integer integer = new Integer(1); return integer; } /* 售后 @param money / public void afterService(float money){ System.out.println(“提供售后服务,并拿到钱:”+money); } } - <br /> <a name="hRW5Z"></a> #### AOP相关术语: - Joinpoint(链接点):通俗点就是方法 - PointCut(切入点):就是说明我们要对那些方法进行拦截 - Advice(增强/通知):就是对拦截的方法进行一系列操作,就叫通知。分为:前置、后置、异常、最终、环绕、异常。 - Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方法或 Field。 - Target(目标对象):代理的目标对象。 - Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。 - Proxy(代理):一个类被 AOP 织入增强后,就产生一个结果代理类。 - Aspect(切面):是切入点和通知(引介)的结合。 - <br /> <a name="AcZAM"></a> #### 基于XML的AOP配置 - 首先导入相应的jar包 ![](https://cdn.nlark.com/yuque/0/2021/png/12512246/1618747982366-bf89a2f4-1f88-4ecb-9456-810e0a38bced.png#clientId=ua53dfbd0-63b3-4&from=paste&height=702&id=u42d8badd&margin=%5Bobject%20Object%5D&originHeight=702&originWidth=815&originalType=binary&size=184967&status=done&style=none&taskId=ue5516b71-8aa5-40cb-a8dd-ddd30001b20&width=815) - 导入aop的的约束xml 此处要导入 aop 的约束 <?xml version=”1.0” encoding=”UTF-8”?> - <br />配置步骤:通过实例来更清楚的描述 单独说一下环绕通知xml //表示开始aop的配置 //注意:环绕通知和其他几个通知不能一起用,我这里是为了好看 把他们的注释都打开了。

这里把切入点表达式好好说明一下 属性: id:表达式的唯一标识 expression:表达式,就是拦截那些方法。 表达式语法:execution([修饰符] 返回值类型 包名.类名.方法名(参数)) 修饰符可以省略,返回值可以用 ,表示可以返回任意值,包名,方法名也可以这样用,不过有几级包就有几个 ,参数列表中使用 .. 表示参数可以是任意数据类型,有参数可以使任意类型,如果使用 * 标识参数可以是任何类型,但是必须有参数。

所以一般来说我们都是对业务层的恶方法增强,所以切入点表达式都是切到业务层实现类的哪个包 execution( com.itheima.service.impl..*(..))



```java
/**
* 环绕通知
* @param pjp
* spring 框架为我们提供了一个接口:ProceedingJoinPoint,它可以作为环绕通知的方法参数。
* 在环绕通知执行时,spring 框架会为我们提供该接口的实现类对象,我们直接使用就行。
* @return
*/
public Object transactionAround(ProceedingJoinPoint pjp) {
//定义返回值
Object rtValue = null;
try {
//获取方法执行所需的参数
Object[] args = pjp.getArgs();
//前置通知:开启事务
beginTransaction();
//执行方法
rtValue = pjp.proceed(args);
//后置通知:提交事务
commit();
}catch(Throwable e) {
//异常通知:回滚事务
rollback();
e.printStackTrace();
}finally {
//最终通知:释放资源
release();
}
return rtValue;
}

基于注解的aop配置

  • 1、还是导入上面的jar包,在配置文件中导入context的名称空间,开启spring对注解的支持,和配置要扫描的包
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">


    <!--  配置spring创建容器时要扫描的包 -->
<context:component-scan base-package="com.itheima"/>
<!--  配置spring开启注解AOP的支持  -->
<aop:aspectj-autoproxy/>
    </beans>
  • 2、在通知类上使用@Aspect注解他是一个切面类,然后在增强的方法上使用注解配置他是什么通知,这里用示例描述
/**
* 事务控制类
* @author 黑马程序员
* @Company http://www.ithiema.com
* @Version 1.0
*/
@Component("txManager")
@Aspect//表明当前类是一个切面类
public class TransactionManager {
//定义一个 DBAssit
@Autowired
private DBAssit dbAssit ;
}
@Before
作用:
把当前方法看成是前置通知。
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。
//开启事务
@Before("execution(* com.itheima.service.impl.*.*(..))")
public void beginTransaction() {
try {
dbAssit.getCurrentConnection().setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
@AfterReturning
作用:
把当前方法看成是后置通知。
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用
//提交事务
@AfterReturning("execution(* com.itheima.service.impl.*.*(..))")
public void commit() {
try {
dbAssit.getCurrentConnection().commit();
} catch (SQLException e) {
e.printStackTrace();
}
}

@AfterThrowing
作用:
把当前方法看成是异常通知。
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用
//回滚事务
@AfterThrowing("execution(* com.itheima.service.impl.*.*(..))")
public void rollback() {
try {
dbAssit.getCurrentConnection().rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}

@After
作用:
把当前方法看成是最终通知。
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用
//释放资源
@After("execution(* com.itheima.service.impl.*.*(..))")
public void release() {
try {
dbAssit.releaseConnection();
} catch (Exception e) {
e.printStackTrace();
}
}

@Around
作用:
把当前方法看成是环绕通知。
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。
/**
* 环绕通知
* @param pjp
* @return
*/
@Around("execution(* com.itheima.service.impl.*.*(..))")
public Object transactionAround(ProceedingJoinPoint pjp) {
//定义返回值
Object rtValue = null;
try {
//获取方法执行所需的参数
Object[] args = pjp.getArgs();
//前置通知:开启事务
beginTransaction();
//执行方法
rtValue = pjp.proceed(args);
//后置通知:提交事务
commit();
}catch(Throwable e) {
//异常通知:回滚事务
rollback();
e.printStackTrace();
}finally {
//最终通知:释放资源
release();
}
return rtValue;
}




针对于环绕通知,这个时候也可以像上面一样直接在后面写切入点表达式,但是我这里介绍另一种方式,就是在一个方法上面使用@Pointcut注解写表达式,然后@Around在引用这个方法
@Pointcut("execution(* com.itheima.service.impl.*.*(..))")
private void pt1() {}
引用方式:
/**
* 环绕通知
* @param pjp
* @return
*/
@Around("pt1()")//注意:千万别忘了写括号
public Object transactionAround(ProceedingJoinPoint pjp) {
//定义返回值
Object rtValue = null;
try {
//获取方法执行所需的参数
Object[] args = pjp.getArgs();
//前置通知:开启事务
beginTransaction();
//执行方法
rtValue = pjp.proceed(args);
//后置通知:提交事务
commit();
}catch(Throwable e) {
//异常通知:回滚事务
rollback();
e.printStackTrace();
}finally {
//最终通知:释放资源
release();
}
return rtValue;
}

Spring中的声明式事务控制

1、拷贝必要的jar包

SSM框架(只适用于快速上手) - 图1

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: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.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>

(xml配置方式)重点


配置步骤:

(1)配置事务管理器
<!--  配置业务层 -->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
<!--  配置账户的持久层 -->
<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--  配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/eesy"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</bean>
<!--  spring中基于XML的声明式事务控制配置步骤
        1、配置事务管理器
        2、配置事务的通知
                此时我们需要导入事务的约束 tx名称空间和约束,同时也需要aop的
                使用tx:advice标签配置事务通知
                    属性:
                        id:给事务通知起一个唯一标识
                        transaction-manager:给事务通知提供一个事务管理器引用
        3、配置AOP中的通用切入点表达式
        4、建立事务通知和切入点表达式的对应关系
        5、配置事务的属性
               是在事务的通知tx:advice标签的内部

      -->
<!-- 第一步: 配置事务管理器  -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

<!--  第二部:配置事务的通知  引用事务管理器内的方法来管理事
                        务,该通知可以对特定的方法进行特定的事务控制 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager"> //这里引用一个事务管理器引用

<!--  第五步:配置事务的属性
                isolation:用于指定事务的隔离级别。默认值是DEFAULT,表示使用数据库的默认隔离级别。
                propagation:用于指定事务的传播行为。默认值是REQUIRED,表示一定会有事务,增删改的选择。查询方法可以选择SUPPORTS。
                read-only:用于指定事务是否只读。只有查询方法才能设置为true。默认值是false,表示读写。
                timeout:用于指定事务的超时时间,默认值是-1,表示永不超时。如果指定了数值,以秒为单位。
                rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务不回滚。没有默认值。表示任何异常都回滚。
                no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚。没有默认值。表示任何异常都回滚。
         -->
<tx:attributes>
        <tx:method name="*" propagation="REQUIRED" read-only="false"/>//增删改操作
        <tx:method name="find*" propagation="SUPPORTS" read-only="true"/>//查询操作,优先检索这个
</tx:attributes>

</tx:advice>

<!--  第三步:配置aop -->
<aop:config>
<!--  配置切入点表达式 -->
        <aop:pointcut id="pt1" expression="execution(* com.itheima.service.impl.*.*(..))"/>

<!--第四步: 建立切入点表达式和事务通知的对应关系  -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"/>
</aop:config>
</beans>

基于注解的配置方式

1、导入坐标

2、配置扫描的包,开启spring对注解的支持


<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 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/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!--  配置spring创建容器时要扫描的包 -->
<context:component-scan base-package="com.itheima"/>

<!--  前提:配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/eesy"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</bean>
<!--  spring中基于注解 的声明式事务控制配置步骤
        1、配置事务管理器
        2、开启spring对注解事务的支持
        3、在需要事务支持的地方使用@Transactional注解,相当于已经告诉了aop中要拦截的方法,和事务建立起关系

      -->
<!-- 第一步: 配置事务管理器 ,并注入数据源 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
</bean>

<!--  第二步:开启spring对注解事务的支持 -->
     <tx:annotation-driven transaction-manager="transactionManager"/>

</beans>

@Service("accountService")
//第三步:事务支持的地方使用注解
@Transactional(readOnly=true,propagation=Propagation.SUPPORTS)  //只读  事务传播行为
public class AccountServiceImpl implements IAccountService {
@Autowired
private IAccountDao accountDao;
@Override
public Account findAccountById(Integer id) {
return accountDao.findAccountById(id);
}

@Override
@Transactional(readOnly=false,propagation=Propagation.REQUIRED)
public void transfer(String sourceName, String targeName, Float money) {
//1.根据名称查询两个账户
Account source = accountDao.findAccountByName(sourceName);
Account target = accountDao.findAccountByName(targeName);

//2.修改两个账户的金额
source.setMoney(source.getMoney()-money);//转出账户减钱
target.setMoney(target.getMoney()+money);//转入账户加钱
//3.更新两个账户
accountDao.updateAccount(source);
//int i=1/0;
accountDao.updateAccount(target);

   /*该注解的属性和 xml 中的属性含义一致。该注解可以出现在接口上,类上和方法上。
出现接口上,表示该接口的所有实现类都有事务支持。
出现在类上,表示类中所有方法有事务支持
出现在方法上,表示方法有事务支持。
以上三个位置的优先级:方法>类>接口*/

SpringMVC

1、快速入门

        **1.1、导入坐标,引入开发jar包,具体坐标**
<!-- 版本锁定 -->
<properties>
<spring.version>5.0.2.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
    **1.2  配置核心的控制器(DispatcherServlet)**

        1.2.1在web.xml中配置文件中核心控制器DispatcherServlet
<!-- SpringMVC的核心控制器 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置Servlet的初始化参数,读取springmvc的配置文件,创建spring容器 -->
<init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:springmvc.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>
**1.3 编写springmvc.xml的配置文件**(这里面就可以创建容器,配置视图解析器,开启注解)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置spring创建容器时要扫描的包 -->
<context:component-scan base-package="com.itheima"></context:component-scan>
<!-- 配置视图解析器 -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>    //前缀
<property name="suffix" value=".jsp"></property>    //后缀
</bean>
<!-- 配置spring开启注解mvc的支持
<mvc:annotation-driven></mvc:annotation-driven>-->
</beans>
**1.4 编写index.jsp和HelloController控制器类**
index.jsp

<body>
<h3>入门案例</h3>
<a href="${ pageContext.request.contextPath }/hello">入门案例</a>
</body>
HelloController

package cn.itcast.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 控制器
* @author rt
*/
@Controller
public class HelloController {
/**
* 接收请求
* @return
*/
@RequestMapping(path="/hello")
public String sayHello() {
System.out.println("Hello SpringMVC!!");
return "success";
}
}
**1.5 因为在视图解析器配置的前缀是web-inf/pages  后缀是.jsp,所以我们在web-inf下面创建pages文件夹然后编写jsp页面**
<body>
<h3>入门成功!!</h3>
</body>
**1.6小结,分析执行过程**

    (1)启动Tomcat服务器的时候,因为配置了load-on-startup标签,可以加载对象,DispatchaerServlet对象便是这个servlet加载时的对象,同时给它配置了初始化参数,这个参数就是classpath:springmvc.xml,就可以加载这个配置文件了。

    (2)springmvc.xml中开启了spring对注解的支持,同时扫描了包,HelloController对象就会被加到容器中。

    (3)index.jsp发送请求的时候,请求先到DIsPatcherServlet核心控制器,然后再根据@RequestMapping注解找到具体执行的方法。

    (4)根据返回值,再根据配置的视图解析器,然后去就去指定目录下查找指定的jsp文件。

    (5)TomCat服务器渲染页面做出响应

SSM框架(只适用于快速上手) - 图2

2、请求参数的绑定

1.**绑定说明:**

        1.1 表单提交的数据都是k=v格式的

        1.2 springmvc的参数绑定过程是把表单提交的请求参数,作为控制器种方法的参数进行绑定的

        1.3 要求: 提交的表单的name要和参数的名称相同(区分大小写)

2、支持的数据类型

        2.1 基本数据类型和字符串类型

        2.2 实体类型(JavaBean)

            2.2.1 提交表单的name和JavaBean的属性名要一致

            2.2.2 如果一个javabean类中包含其他引用类型,表单的name属性就要写成:对象.属性

                        例如:address.name

        2.3  集合数据类型(List、map集合等)

                2.3.1  jsp页面的编写方式 List[0].属性

 **3、请求参数中文乱码的解决**

        在web.xml中配置spring提供的过滤器类
<!-- 配置过滤器,解决中文乱码的问题 -->
<filter>
<filter-name>characterEncodingFilter</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>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
**4、自定义类型转换器(表单提交的数据都是字符串类型,spring内部会默认进行数据类型转换)**

        1、如果我们想把字符串转换成日期就可以自定义一个类型转换器
package cn.itcast.utils;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.core.convert.converter.Converter;
/**
* 把字符串转换成日期的转换器,实现接口Converter
* @author rt
*/
public class StringToDateConverter implements Converter<String, Date>{
/**
* 进行类型转换的方法
*/
public Date convert(String source) {
        // 判断
        if(source == null) {
        throw new RuntimeException("参数不能为空");
    }try {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        // 解析字符串
        Date date = df.parse(source);
        return date;
    } catch (Exception e) {
            throw new RuntimeException("类型转换错误");
    }
    }
}
    2、注册自定义类型转换器,在springmvc.xml配置文件中编写配置
<!-- 注册自定义类型转换器 -->
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="cn.itcast.utils.StringToDateConverter"/>
</set>
</property>
</bean>
<!-- 开启Spring对MVC注解的支持 -->
<mvc:annotation-driven conversion-service="conversionService"/>

3、常用的注解

1. RequestParam注解

    1.1 作用:把请求中的指定名称的参数传递给控制器中的形参赋值

    1.2 属性

                    1.2.1 value:请求参数中的名称

                    1.2.2 required:请求参数中是否必须提供此参数,默认值是true,必须提供

    1.3 代码
/**
* 接收请求
* @return
*/
@RequestMapping(path="/hello")
public String sayHello(@RequestParam(value="username",required=false)String name) {
System.out.println("aaaa");
System.out.println(name);
return "success";
}

  1. RequestBody注解
    1. 作用:用于获取请求体的内容(注意:get方法不可以)
    2. 属性
    3. required:是否必须有请求体,默认值是true
    4. 代码如下
/**
* 接收请求
* @return
*/
@RequestMapping(path="/hello")
public String sayHello(@RequestBody String body) {
System.out.println("aaaa");
System.out.println(body);
return "success";
}

  1. PathVariable注解

    1. 作用:拥有绑定url中的占位符的。例如:url中有/delete/{id},{id}就是占位符

    2. 属性
      1. value:指定url中的占位符名称

  1. 代码如下
<a href="user/hello/1">入门案例</a>
/**
* 接收请求
* @return
*/
@RequestMapping(path="/hello/{id}")
public String sayHello(@PathVariable(value="id") String id) {
System.out.println(id);
return "success";
}

  1. RequestHeader注解
    1. 作用:获取指定请求头的值
    2. 属性
      1. value:请求头的名称
  1. 代码如下
@RequestMapping(path="/hello")
public String sayHello(@RequestHeader(value="Accept") String header) {
System.out.println(header);
return "success";
}

  1. CookieValue注解
    1. 作用:用于获取指定cookie的名称的值
    2. 属性
      1. value:cookie的名称
  1. 代码
@RequestMapping(path="/hello")
public String sayHello(@CookieValue(value="JSESSIONID") String cookieValue) {
System.out.println(cookieValue);
return "success";
}

  1. ModelAttribute注解

    1. 作用
      1. 出现在方法上:表示当前方法会在控制器方法执行前线执行。
      2. 出现在参数上:获取指定的数据给参数赋值。

  1. 应用场景

  1. 当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据。

  2. 具体的代码

    1. 修饰的方法有返回值 ```java /**
  • 作用在方法,先执行
  • @param name
  • @return / @ModelAttribute public User showUser(String name) { System.out.println(“showUser执行了…”); // 模拟从数据库中查询对象 User user = new User(); user.setName(“哈哈”); user.setPassword(“123”); user.setMoney(100d); return user; } /*
  • 修改用户的方法
  • @param cookieValue
  • @return */ @RequestMapping(path=”/updateUser”) public String updateUser(User user) { System.out.println(user); return “success”; } ```


    1. 修饰的方法没有返回值 ```java /**
  • 作用在方法,先执行
  • @param name
  • @return / @ModelAttribute public void showUser(String name,Map map) { System.out.println(“showUser执行了…”); // 模拟从数据库中查询对象 User user = new User(); user.setName(“哈哈”); user.setPassword(“123”); user.setMoney(100d); map.put(“abc”, user); } /*
  • 修改用户的方法
  • @param cookieValue
  • @return */@RequestMapping(path=”/updateUser”) public String updateUser(@ModelAttribute(value=”abc”) User user) { System.out.println(user); return “success”; } ```


    1. SessionAttributes注解
      1. 作用:用于多次执行控制器方法间的参数共享
      2. 属性
        1. value:指定存入属性的名称

  1. 代码如下
    @Controller
    @RequestMapping(path="/user")
    @SessionAttributes(value= {"username","password","age"},types=
    {String.class,Integer.class})
    // 把数据存入到session域对象中
    public class HelloController {
    /**
    * 向session中存入值
    * @return
    */
    @RequestMapping(path="/save")
    public String save(Model model) {
    System.out.println("向session域中保存数据");
    model.addAttribute("username", "root");
    model.addAttribute("password", "123");
    model.addAttribute("age", 20);
    return "success";
    }
    /**
    * 从session中获取值
    * @return
    */
    @RequestMapping(path="/find")
    public String find(ModelMap modelMap) {
    String username = (String) modelMap.get("username");
    String password = (String) modelMap.get("password");
    Integer age = (Integer) modelMap.get("age");
    System.out.println(username + " : "+password +" : "+age);
    return "success";
    }
    /**
    * 清除值
    * @return
    */
    @RequestMapping(path="/delete")
    public String delete(SessionStatus status) {status.setComplete();
    return "success";
    }
    }
    

2、Sprinmvc的响应数据和结果视图

        **2.1 返回值分类**

                2.1.1 字符串:controller  方法返回字符串是指定了逻辑视图名,通过视图解析器解析为物理视图地址

                2.1.2 void  :这个时候可以在这个方法上面加上request和response就像原生web一样,重定向或者转发

                2.1.3  ModelAndView: 是SpringMvc为我们提供的一个对象,该对象可以作为控制器方法的返回值,然后他就会存在request中,setViewName,就是返回的那个页面,同时他是以map的形式存在,下面有示例代码。
@RequestMapping("/testReturnModelAndView")
public ModelAndView testReturnModelAndView() {
ModelAndView mv = new ModelAndView();
mv.addObject("username", "张三");
mv.setViewName("success");
return mv;
}

jsp使用el表达式获取
${requestScope.username}
        **2.2 转发和重定向**

                2.2.1: forward转发,就是springmvc提供的默认值,使用的格式
return "forward:/WEB-INF/pages/success.jsp";
//注意,这里就要像原生web一样了写真正的url
                2.2.2: Redirect重定向,使用格式
return "redirect: request.getContextPath()+"/index.jsp";
    //和原生重定向一样不能访问web-inf下的目录
        **2.3 ResponseBody响应json数据**

                作用:    该注解用于将 Controller 的方法返回的对象,通过 HttpMessageConverter 接口转换为指定格式的

                                数据如:json,xml 等,通过 Response 响应给客户端。

                在使用之前要导入三个jar包

                    ![](/home/djc/.config/Typora/typora-user-images/image-20201202195845413.png#id=R17g6&originalType=binary&status=done&style=none)

            下面通过代码更好的展示
jsp 中的代码:
<script
type="text/javascript"
src="${pageContext.request.contextPath}/js/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
$("#testJson").click(function(){
$.ajax({
    type:"post",
    url:"${pageContext.request.contextPath}/testResponseJson",
    contentType:"application/json;charset=utf-8",
    data:'{"id":1,"name":"test","money":999.0}',
    dataType:"json",

    success:function(data){
            alert(data);
}
});
});
})
</script>
<!-- 测试异步请求 -->
<input type="button" value=" 测试 ajax 请求 json 和响应 json" id="testJson"/>
控制器中的代码:
/**
* 响应 json 数据的控制器
* @author 黑马程序员
* @Company http://www.ithiema.com
* @Version 1.0
*/
@Controller("jsonController")
public class JsonController {
/**
* 测试响应 json 数据
*/
@RequestMapping("/testResponseJson")
public @ResponseBody Account testResponseJson(@RequestBody Account account) {
System.out.println("异步请求:"+account);
return account;
}
}

运行结果如图:
                            ![](/home/djc/.config/Typora/typora-user-images/image-20201202195953770.png#id=gTKWQ&originalType=binary&status=done&style=none)

3、SpringMvc中的异常处理

        1、处理的思路:dao、service、controller出现异常都往上跑,最后由springmvc前端控制器交给异常处理器进行异常处理。

        2、这里实现一个异常处理

                2.1 编写一个异常类和错误页面
异常类
/**
* 自定义异常
* @author 黑马程序员
* @Company http://www.ithiema.com
* @Version 1.0
*/
public class CustomException extends Exception {
    private String message;
    public CustomException(String message) {
        this.message = message;
    }
    public String getMessage() {
    return message;
    }
}
                    jsp页面
jsp 页面:
<%@
page
language="java"
contentType="text/html;
charset=UTF-8"
pageEncoding="UTF-8"%>
<!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>
执行失败!
        ${message }
</body>
</html>
                2.2 自定义异常处理器
/**
* 自定义异常处理器
* @author 黑马程序员
* @Company http://www.ithiema.com
* @Version 1.0
*/
public class CustomExceptionResolver implements HandlerExceptionResolver {
        @Override
        public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
        ex.printStackTrace();
        CustomException customException = null;
        //如果抛出的是系统自定义异常则直接转换
        if(ex instanceof CustomException){
            customException = (CustomException)ex;
        }else{
            //如果抛出的不是系统自定义异常则重新构造一个系统错误异常。
            customException = new CustomException("系统错误,请与系统管理 员联系!");
        }
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.addObject("message", customException.getMessage());
            modelAndView.setViewName("error");
            return modelAndView;//返回error这个页面
        }
}
                2.3 配置异常处理器
<!-- 配置自定义异常处理器 -->
<bean id="handlerExceptionResolver"
class="com.itheima.exception.CustomExceptionResolver"/>

运行结果:

SSM框架(只适用于快速上手) - 图3

4、SpringMvc中的拦截器

        **1、作用:**

                他是springmvc独有的,只有使用了Springmvc才能使用。它只会拦截访问的控制器的方法,如果访问的jsp、html、css、js这些静态资源的时候他不会拦截。(和过滤器很像)

        **2、自定义拦截器**(这里的每个方法具体说明了就是再说拦截器链的放行的顺序)

                2.1 编写一个普通类实现HandlerInterceptor接口
/**
* 自定义拦截器
* @author 黑马程序员
* @Company http://www.ithiema.com
* @Version 1.0
*/
public class HandlerInterceptorDemo1 implements HandlerInterceptor {

    /*
        按拦截器定义的顺序调用
        只要配置了都会调用
        决定是否调用其他拦截器或者直接去控制器层法
    */
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponseresponse, Object handler) throws Exception {
        System.out.println("preHandle 拦截器拦截了");
        return true;
}

    /*
        按拦截器定义逆序调用
        在拦截器链内所有拦截器成功后调用
        在控制层处理完请求后,这里主要是对request请求进行处理,在DispatcherServlet向客户端返回响应钱被调用
    */
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle 方法执行了");
}

   /*
           按拦截器定义逆序调用
           只有当前的这个了preHandle返回true才会调用
           在DispatcherServlet完全处理完请求后背盗用,一般处理资源清理的操作
   */
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
        System.out.println("afterCompletion 方法执行了");
}
}
多个拦截器的执行顺序:

SSM框架(只适用于快速上手) - 图4

                2.2 配置拦截器
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>        <!-- 表示对所有的访问都拦截-->
<bean id="handlerInterceptorDemo1"
class="com.itheima.web.interceptor.HandlerInterceptorDemo1"></bean>
</mvc:interceptor>
</mvc:interceptors>
                运行结果:

SSM框架(只适用于快速上手) - 图5

4、SSM整合框架 (xml+注解)

**1、整合的思路:**

    (1)先搭建整合的环境(就是导入坐标,需要的jar包)

    (2)先把Spring的配置搭建完成

    (3)Spring整合SpringMvc

    (4)Spring整合Mybatis

**2、创建Maven的工程,并导入相关的依赖**

    (1)创建ssm_parent父工程(打包方式选择pom,必须的)

    (2)创建ssm_web子模块(打包方式是war包

    (3)创建ssm_service子模块(打包方式是jar包

    (4)创建ssm_dao子模块(打包方式是jar包

    (5)创建ssm_domain子模块(打包方式是jar包

    (6)web依赖于service,service依赖于dao,dao依赖于domain

    (7)在ssm_parent的pom.xml文件中引入坐标依赖
<properties>
<spring.version>5.0.2.RELEASE</spring.version>
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
<mysql.version>5.1.6</mysql.version>
<mybatis.version>3.4.5</mybatis.version>
</properties>
<dependencies><!-- spring -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.8</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version><scope>compile</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- log start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- log end -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency><dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<finalName>ssm</finalName>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<showWarnings>true</showWarnings>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
**3、搭建Spring框架**

        (1)在ssm_web项目中创建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: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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 开启注解扫描,要扫描的是service和dao层的注解,要忽略web层注解,因为web层让SpringMVC框架
去管理 -->
<context:component-scan base-package="cn.itcast">
<!-- 配置要忽略的注解 -->
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
</beans>

4、搭建SpringMvc框架

(1)在web.xml中配置Dispatcher前端控制器
<!-- 配置前端控制器:服务器启动必须加载,需要加载springmvc.xml配置文件 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置初始化参数,创建完DispatcherServlet对象,加载springmvc.xml配置文件 -->
<init-param><param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!-- 服务器启动的时候,让DispatcherServlet对象创建 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

<!-- 配置解决中文乱码的过滤器 -->
<filter>
<filter-name>characterEncodingFilter</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>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
    (2)创建SpringMvc.xml并进行相关配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 扫描controller的注解,别的不扫描 -->
<context:component-scan base-package="cn.itcast">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 配置视图解析器 -->
<bean id="viewResolver"class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- JSP文件所在的目录 -->
<property name="prefix" value="/WEB-INF/pages/" />
<!-- 文件的后缀名 -->
<property name="suffix" value=".jsp" />
</bean>
<!-- 设置静态资源不过滤 -->
<mvc:resources location="/css/" mapping="/css/**" />
<mvc:resources location="/images/" mapping="/images/**" />
<mvc:resources location="/js/" mapping="/js/**" />
<!-- 开启对SpringMVC注解的支持 -->
<mvc:annotation-driven />
</beans>

5、Spring整合SpringMvc框架

(1)怎么知道我们整合成功了,只要我们controller成功调用service对象的方法就可以了(说明注入成功了)

(2)当我们项目启动的时候,web.xml已经会去访问springmvc.xml了,这个时候我们我们其实只差ApplicationContext.xml了,我们想办法加载他就可以了。
在web.xml中配置ContextLoaderListener监听器(该监听器只能加载WEB-INF目录下的applicationContext.xml的配置文
件)。

<!-- 配置Spring的监听器 -->
<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>

6、Spring整合MyBatis框架(在Application.xml就可以了)

(1)我们其实只需要把SqlMapConfig.xml的内容配置到Application.xml就可以了
<!-- 配置C3P0的连接池对象 -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql:///ssm" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<!-- 配置SqlSession的工厂,可以创建一个真正的sqlsession ,然后sqlsession就可以创建代理对象存到ioc容器中-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置扫描dao的包  接口 将Mapper接口生成代理注入到Spring-->
<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.itcast.dao"/>
</bean>

7、最后的applicationContext,xml的内容

<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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 开启注解的扫描,希望处理service和dao,controller不需要Spring框架去处理 -->
<context:component-scan base-package="cn.itcast">
<!-- 配置哪些注解不扫描 -->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- Spring整合MyBatis框架 -->
<!-- 配置连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql:///ssm"/>
<property name="user" value="root"/>
<property name="password" value="root"/>
</bean>
<!-- 配置SqlSessionFactory工厂 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置AccountDao接口所在包 -->
<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.itcast.dao"/>
</bean>

</beans>

springmvc.xml的内容

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" 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/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 开启注解扫描,只扫描Controller注解 -->
<context:component-scan base-package="cn.itcast">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 配置的视图解析器对象 -->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- 过滤静态资源 -->
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/images/" mapping="/images/**"/>
<mvc:resources location="/js/" mapping="/js/**"/>
<!-- 开启SpringMVC注解的支持 -->
<mvc:annotation-driven/>
</beans>