文章目录
- 三层架构
- 框架
- MyBatis框架
- mybatis主配置文件标签
- mapper映射配置文件
- MyBatis的主要类
- 动态代理
- 动态sql
- 多表查询
- 新增返回主键值
- Mybatis的懒加载
- Mybatis的缓存机制
- Mybatis的逆向工程
- Mybatis注解配置
- Spring框架
- IOC
- 对象的创建
- IOC基于XML的DI
- IOC基于注解的DI
- Spring-jdbc模块
- Spring中引入配置文件
- Spring整合各种连接池
- Spring-test模块
- spring整合mybatis
- JDK动态代理
- cglib动态代理
- AOP
- 基于xml面向切面编程
- 基于注解面向切面编程的具体使用
- 事务管理
- spring声明式事务的使用
- SpringMVC
- Spring参数类型绑定
- SpringMVC返回参数类型
- SpringMVC静态资源处理
- SpringMVC常用注解
- 文件上传和下载
- SpringMVC异常处理器
- springMVC提供的拦截器Interceptor
- tomcat提供的过滤器,监听器
- SSM整合全步骤
- 1、环境开发搭建
- 2、搭建Spring开发环境
- 3、SpringMVC环境搭建
- 4、以上两步没问题之后,开始Spring整合Spring-MVC
- 5、搭建mybatis环境
- 6、Spring整合Mybatis
- 7、Spring整合Mybatis框架配置事务
- 7、Spring整合Mybatis框架配置事务
- 以上都成功就全部整合完成!
三层架构
界面层:和用户打交道的, 接收用户的请求参数, 显示处理结果的。(jsp ,html ,servlet)
业务逻辑层:接收了界面层传递的数据,计算逻辑,调用数据库,获取数据
数据访问层:就是访问数据库, 执行对数据的查询,修改,删除等等的。
三层对应的包
界面层:controller包 (servlet)
业务逻辑层:service 包(XXXService类)
数据访问层:dao包(XXXDao类)
三层中类的交互
用户使用界面层--> 业务逻辑层--->数据访问层(持久层)-->数据库(mysql)
三层对应的处理框架
界面层---servlet---springmvc
业务逻辑层---service类--spring
数据访问层---dao类--mybatis
框架
框架是一个模版:
1.框架中定义好了一些功能。这些功能是可用的。
2.可以加入项目中自己的功能, 这些功能可以利用框架中写好的功能。
框架特点:
1. 框架一般不是全能的, 不能做所有事情
2. 框架是针对某一个领域有效。 特长在某一个方面,比如mybatis做数据库操作强,但是他不能做其它的。
3. 框架是一个半成品软件,定义好了一些基础功能,需要加入你的功能变成完整的。基础功能是可重复使用的,可升级的。
MyBatis框架
MyBatis是持久层、半自动orm框架,早期叫做ibatis, 代码在github。
mybatis是 MyBatis SQL Mapper Framework for Java(sql映射框架)(对象关系型映射框架)
1)sql mapper :sql映射,可以把数据库表中的一行数据映射为一个java对象,操作它就相当于操作表。
2)Data Access Objects(DAOs):数据访问,对数据库执行增删改查。
mybatis提供了哪些功能:
1. 提供了创建Connection ,Statement, ResultSet的能力,不用开发人员创建这些对象了
2. 提供了执行sql语句的能力,不用你执行sql
3. 提供了循环sql, 把sql的结果转为java对象,List集合的能力
4. 提供了关闭资源的能力,不用你关闭Connection,Statement,ResultSet
开发人员做的是:提供sql语句--mybatis处理sql---开发人员得到List集合或java对象(表中的数据)
总结:
mybatis是一个sql映射框架,提供的数据库的操作能力。增强的JDBC,
使用mybatis让开发人员集中精神写sql就可以了,不必关心Connection,Statement,ResultSet的创建,销毁,sql的执行。
基本步骤:
1、加入数据库驱动、mybatis依赖
2、创建Dao接口,定义操作数据的方法
3、创建mapper文件,写和mapper接口中方法对应的sql语句
4、创建mybatis的一个主配置文件:连接数据库,指定mapper文件的位置
5、使用mybatis的对象SqlSession,通过它的方法执行sql语句
mybatis主配置文件标签
这些标签有顺序要求,就是下面的顺序!
<!--properties:属性-->
作用:1.定义属性变量,通过${变量名}来获取变量
2.引入外部属性文件,通过${变量名}来获取变量值,key推荐多级目录
<properties resource="db.properties">
<property name="driver" value="com.mysql.jdbc.Driver"||${db.driver}/>
<property name="url" value="jdbc:mysql://...?useUnicode=true&characterEncoding=utf-8"||${db.url}/>
.....
</properties>
注意:
1.首先读取在 properties 元素体内指定的属性。
2.然后根据 properties 元素中的 resource 属性读取类路径下属性文件,或根据 url 属性指定的路径读取属性文件,并覆盖之前读取过的同名属性。
3.最后读取作为方法参数传递的属性,并覆盖之前读取过的同名属性。
优先级3>2>1
<!--settings:设置-->
settings标签表示mybatis框架的配置特性标签,可以做各种特殊设置:
<settings>
<setting name="logImpl" value="STDOUT_LOGGING" />//配置日志文件
<setting name="cacheEnabled" value="true"/>//配置开启缓存
....
</settings>
<!--typeAliases:类型别名-->
该标签用于为数据类型取别名的标签;
注意:一个类型的单个取别名和批量取别名只能有一个
<typeAliases>
单个取别名:
<typeAlias type="com.offcn.bean.Person" alias="pp"></typeAlias>
批量取别名:
<package name="com.offcn.bean"/>//类名就是别名
</typeAliases>
<!--typeHandlers:类型处理器(了解)-->
该标签叫做类型处理器标签,作用将数据库字段数据类型转换java对象中的属性的数据类型,或者反之;
用于注册自定义类型处理器,而mybatis里面已经提供了大量的类型处理器供我们使用,无需自定义;
<!--objectFactory:对象工厂(了解)-->
该标签的作用用于注册自定义的工厂对象,而mybatis已经提供了工厂对象,无需我们自己在创建工厂对象;
创建数据库记录封装的对象实例;
<!--plugins:插件-->
该标签叫做插件标签,用于扩展其他功能
eg:扩展分页插件:
1.引入分页插件的jar包;
2.注册分页插件
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
3.实现分页查询: PageHelper.startPage(2,3);
<!--environments:环境配置-->
//default:必须和某个environment的id值一样,它告诉mybatis使用哪个数据库的连接信息,也就是找哪个数据库
<environments default="development">
//environment:一个数据库信息的配置,叫作环境,id是一个唯一值,自定义,表示环境的名称
<environment id="development">
//transactionManager:mybatis的事务类型,
//type:JDBC表示使用jdbc中Connection对象的commit,rollback做事务处理
//type:MANAGED表示把mybatis的事务处理委托给其他的容器(一个服务器软件,一个框架(spring))
<transactionManager type="JDBC">
<property name="..." value="..."/>
</transactionManager>
//dataSource:表示数据源,连接数据库的,
//type:表示数据源的类型,POOLED表示使用连接池的;UNPOOLED表示不使用连接池,每次会创建连接然后执行sql后再关闭
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!--databaseIdProvider:数据库厂商标识-->
<!--mappers:映射器-->
该标签用于指定sql映射文件的位置,从而引入其中的sql语句,4种方式
<mappers>
1、使用相对于类路径的资源引用,从类路径开始的路径信息
<mapper resource="aaa.xml" />
2、使用完全限定资源定位符(URL)
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
3、使用映射器接口实现类的完全限定类名(必须保证接口和映射配置文件同名且同包)
<mapper class="org.mybatis.builder.AuthorMapper"/>
4、将包内的映射器接口实现全部注册为映射器(必须保证接口和映射配置文件同名且同包)
<package name="org.mybatis.builder"/>
</mappers>
xml文件中的转义字符:<![CDATA[***]]>
mapper映射配置文件
<!--cache-->
作用是开启mybatis框架的二级缓存
<!--cache-ref-->
作用是引入其他映射配置文件的缓存设置,和cache标签配合使用
<!--resultMap-->
该标签专门用于做高级映射,使用场景有两个:
1、当数据库表字段名称和javabean对象属性名称一致时,自动做高级映射
<resultMap id="结果映射的唯一标识" type="结果全限定类型" >
<id column="字段名" property="java对象属性名" ></id>//映射主键字段
<result column="字段名" property="java对象属性名"></result>//映射普通字段
</resultMap>
2、当多表查询时,做高级映射使用
<!--sql片段-->
<sql id="唯一标识" >...相同的sql语句....</sql>//表示sql变量的定义
<include refid="id" ></include>//表示sql变量的引入
<!--insert,delete,update,select-->
属性:id-->sql语句的唯一标识
所有的<select>语句都必须指定返回数据类型,有两种属性方式:
1、resultType:默认将数据库中字段名和java对象中属性相同的属性做映射
value:表示返回结果类型,sql语句执行后得到的ResultSet遍历得到的对象类型值为类型的全限定名称
返回值为Map时,最多只能返回一条记录,否则报错。
2、resultMap:自定义结果映射,一般用于查询字段名称和返回数据字段名称不一致时或自定义列值赋值给哪个属性时
value:高级映射的id
MyBatis的主要类
1、Resources:mybatis中的一个类,负责读取主配置文件
InputStream in = Resources.getResourceAsStream("主配置文件");
2、SqlSessionFactoryBuilder: 创建SqlSessionFactory对象,
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//创建SqlSessionFactory对象,它是一个接口,创建的对象是一个重量级对象,
//程序创建一个对象耗时比较长,使用资源比较多。在整个项目中,有一个就够用了。
SqlSessionFactory factory = builder.build(in);
//实现类:DefaultSqlSessionFactory
//作用:获取SqlSession对象:
SqlSession sqlSession = factory.openSession();
/*openSession()方法说明:
1. openSession():无参数的, 获取是非自动提交事务的SqlSession对象
2. openSession(boolean):openSession(true)获取自动提交事务的SqlSession对象.
openSession(false):非自动提交事务的SqlSession对象*/
4、SqlSession:
SqlSession接口:定义了操作数据的方法例如:
selectOne() ,selectList() ,insert(),update(), delete(), commit(), rollback()
实现类:DefaultSqlSession。
使用要求:
SqlSession对象不是线程安全的,需要在方法内部使用,在执行sql语句之前,使用openSession()获取SqlSession对象。在执行完sql语句后,需要关闭它,执行SqlSession.close(). 这样能保证他的使用是线程安全的。
动态代理
什么是动态代理:mybatis帮你创建dao接口的实现类,在实现类中调用SqlSession的方法执行sql语句
怎么使用动态代理:
1、获取SqlSession对象,SqlSessionFactory.open();
2、使用SqlSession.getMapper(dao接口.class) 获取某个dao接口的对象
3、使用dao接口的方法,调用方法就执行了mapper文件中的sql语句
使用动态代理的要求:
1、mapper文件中的namespace值是dao接口的全限定名称
2、mapper文件中的增删改查的id是接口中的方法名称
3、dao接口中不要使用重载方法
传入参数:从java代码中把数据传入到mapper文件的sql语句中。推荐使用1、2、3!!!其他的麻烦且易出错
1) 一个简单类型的参数:
简单类型:mybatis把java的基本数据类型和String都叫简单类型。在mapper文件中使用 #{任意字符}获取参数的值
2) 多个简单类型参数,使用@Param命名参数
3) 使用java对象,对象的属性值作为mapper文件中的参数(对象需要有无参构造和get方法)
完整方式:#{属性名,javaType="",jdbcType=""}
简化方式:#{属性名}
4)多个参数,封装到Map集合中,#{map的kye}
5) 多个参数,可以使用位置的方法:mybatis3.4之前--->#{0},#{1} mybatis3.44之后--->#{arg0},#{arg1}
# 和 $的区别
select id,name, email,age from student where id=#{studentId}
# 的结果: select id,name, email,age from student where id=?
$ 的结果:select id,name, email,age from student where id=1001
$的sql语句:String sql="select id,name, email,age from student where id=" + "1001";
使用的Statement对象执行sql, 效率比PreparedStatement低。
$:可以替换表名或者列名, 如果能确定数据是安全的。可以使用$
#点位符和 $点位符的区别
1. #使用 ?在sql语句中做占位的,使用PreparedStatement执行sql,效率高
2. #能够避免sql注入,更安全。
3. $不使用占位符,是字符串连接方式,使用Statement对象执行sql,效率低
4. $有sql注入的风险,缺乏安全性。
5. $:可以替换表名或者列名
动态sql
sql的内容是变化的,可以根据条件获取到不同的sql语句。
主要是where部分发生变化。
1)<if>是判断条件的,语法:
<if test="判断java对象的属性值">
部分sql语句
</if>
2)<where> 用来包含多个<if>的,当多个if有一个成立的, <where>会自动增加一个where关键字,并去掉if中多余的and、or等。
3)<foreach> 循环java中的数组,list集合的。 主要用在sql的in语句中。
语法:
<foreach collection="" item="" open="" close="" separator="">
#{xxx}
</foreach>
collection:表示接口中的方法参数的类型,如果是数组使用array, 如果是list集合使用list
item:自定义的,表示数组和集合成员的变量
open:循环开始时的字符
close:循环结束时的字符
separator:集合成员之间的分隔符
4)<choose><when></when><otherwise></otherwise></choose>
5)<set></set>:相当于sql当时中的set关键字,用于修改sql语句,除了修改以外,还可以自动删除多余逗号,通常搭配if动态标签使用,当if条件成立时,自动删除多余逗号。
6)<trim></trim>:可以替代where和set动态标签的,可以自动添加或删除前缀、后缀
它提供了四个属性:
prefix:指定自动添加的前缀
prefixOverrides:指定自动删除的前缀
suffix:指定自动添加的后缀
suffixOverrides:指定自动删除的后缀
多表查询
一对一嵌套结果集关系表映射:<association property="属性名" javaType="属性类型">要对应的值</association>
一对一嵌套查询关系表映射:<association column="要传入下一个sql语句的参数" select="namespace.sqlId"></association>
一对多嵌套结果集关系表映射:<collection ofType="集合中对象的数据类型">要对应的值</collection>
一对多嵌套查询关系表映射:<collection property="属性名" column="要传入下一个sql语句的参数" select=""></collection>
多对多就是特殊的一对多!
新增返回主键值
方式一:通过设置属性useGeneratedKeys返回主键
<insert id="confirmOrder" useGeneratedKeys="true" keyProperty="theOid">
insert into t_orders(pid,order_name) values(#{thePid},#{theOrderName})
</insert>
方式二:通过selectKey标签返回主键
<insert id="confirmOrder">
insert into t_orders(pid,order_name) values(#{thePid},#{theOrderName})
<selectKey resultType="_int" keyProperty="theOid">
select last_insert_id() //这是mysql中的函数--》返回最后加入的主键
</selectKey>
</insert>
Mybatis的懒加载
又叫做按需加载或者延迟加载,根据需要去加载,不需要不加载
需要:用户的需求
加载:指的是要加载要执行的sql语句
懒加载的前提:必须要有嵌套查询sql语句
设置全局懒加载:
<settings><setting name="lazyLoadingEnabled" value="true" /></settings>
局部懒加载:
在<association>和<collection>标签中设置属性fetchType的值为lazy
注意:局部懒加载的优先级高于全局懒加载
Mybatis的缓存机制
缓存:指的是一块内存空间,用于存储大量频繁访问的数据,当用户第一次读取数据库中的数据时,会将这些数据查询出来存放到该内存空间(缓存)中,当用户再次获取相同的数据时,可以直接从内存中返回,而不用再去数据库中读取,从而提高查询效率;注意:每一次新增,修改,删除数据库都会导致缓存清空。除此之外,mybatis提供了手动清空缓存的方法:sqlSession.clearCache();
mybatis提供了两种缓存机制,一级缓存和二级缓存,
一级缓存:
mybatis默认支持一级缓存,它的作用范围(生命周期)随着sqlSession的创建/销毁而创建/销毁。
二级缓存:
需要自己设置,它的作用范围在一个mapper文件中,设置也是在这个mapper中添加<cache />标签
它的生命周期随着sqlSessionFactory的创建/销毁而创建/销毁,它是跨sqlSession的缓存
Mybatis的逆向工程
引入jar包:mybatis-generator-core(还有数据库驱动jar包)
在项目目录下创建一个xml文件并进行文件的配置。
使用逆向工程API运行生成文件代码
<!--取消生成注释-->
<commentGenerator>
<property name="suppressDate" value="true" />
</commentGenerator>
<!--指定生成对象的具体位置,'.\src':表示当前项目src路径下,'.\':表示当前项目路径-->
<javaModelGenerator targetPackage="com.offcn.bean" targetProject=".\src">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!--指定生成的xml文件位置-->
<sqlMapGenerator targetPackage="com.offcn.mapper" targetProject=".\src">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!--指定生成的dao层接口停车场-->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.offcn.dao" targetProject=".\src">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<table tableName="数据库中的表" ></table>
Mybatis注解配置
以下注解都是在接口方法上配置
@Insert:用于注解新增sql语句
@Delete:用于注解删除sql语句
@Update:用于注解修改sql语句
@Select:用于注解查询sql语句
@Results:用于自定义结果映射 相当于xml中的<resultMap></resultMap>
@Result:用于字段映射 相当于xml中的<resultType></resultType>
@One:用于一对一表映射 相当于xml中的<association></association>
@Many:用于一对多表映射 相当于xml中的 <collection></collection>
Spring框架
什么是Spring:
一个轻量级,一站式用于企业级应用开发的框架,核心技术是ioc,aop,可以实现解耦合;它也是一个容器,容器中存放的是java对象。
spring是一个模块化框架,想用哪个就引入哪个
spring是一个非侵入式框架,不会因为引入spring框架就改变或者影响我们自己的代码
如何使用:
因为它是一个容器,所以把项目中需要用的对象放入到容器中,让容器完成对对象的创建,对象间关系的管理(属性赋值),而我们在程序中就直接从容器中获取需要的对象。
什么样的对象放入容器中:
dao类,controller类,工具类;spring中的对象默认都是单例的,在容器中叫这个名称的对象只有一个
什么样的对象不放入容器中:
实体类对象,因为实体类的数据来自数据库
servlet,listener,filter等,因为它们是由tomcat来创建的
如何将对象放入到容器中呢:
1.使用xml配置文件,使用<bean>标签
2.注解
IOC
ioc(控制反转,Inversion of Control):
1、理论,思想,概念:指导开发人员在容器中,代码之外管理对象,给属性赋值,管理依赖。
2、ioc技术的实现使用di(Dependency Injection依赖注入):开发人员在项目中只需提供对象的名称,对象的创建,赋值,查找都由容器内部自己实现
3、spring使用的就是di的技术,底层使用的是反射机制来创建对象
4、作用就是实现业务对象之间解耦合,例如service和dao之间的解耦合
ioc的API:
AnnotationConfigApplicationContext:通过解析注解配置方式创建工厂容器实例
ClassPathXmlApplicationContext:通过解析XML文件配置方式创建工厂容器实例
FileSystemXmlApplicationContext:通过文件路径读取配置文件,解析XML配置方式创建工厂容器实例
spring窗口创建实例的过程:
1、启动tomcat时,加载spring配置文件,创建配置文件中所有类型的实例
2、初始化实例
3、哪里需要就从容器中获取对应的实例
4、tomcat正常关闭时,spring容器销毁,实例销毁。
原理:
public class MyFactory {
//创建一个map集合,目的是存储对象
Map<String,Object> map;//在创建工厂时,创建所有的对象
public MyFactory(String propertiesName){
map = new HashMap<>();//初始化集合
ResourceBundle bundle = ResourceBundle.getBundle(propertiesName);//加载属性配置文件
Enumeration<String> enumeration = bundle.getKeys();//获取所有的key
//遍布所有的key获取所有的value并将它们加入到集合中
while (enumeration.hasMoreElements()) {
String key = enumeration.nextElement();
String value = bundle.getString(key);
//根据获取到的实例创建对象
try {
Class theClass = Class.forName(value);
Object obj = theClass.newInstance();
map.put(key,obj);
} catch (Exception e) {
e.printStackTrace();}}}
//提供获取对象方法
public Object getBeans(String key){
return map.get(key);
}
}
对象的创建
通过构造方法创建实例: <bean id="personDao" class="com.offcn.dao.PersonDaoImpl"></bean>
通过工厂方法创建对象:
工厂普通方法:
先创建工厂对象:<bean id="myfactory" class="com.offcn.util.MyFactory"></bean>
再调用方法创建对象<bean id="carDao" factory-bean="myfactory" factory-method="getCarDao1"></bean>
工厂静态方法:
<bean id="personDao1" class="com.offcn.util.MyFactory" factory-method="getPersonDao"></bean>
<bean>标签的属性配置:
id:该属性用于对spring容器中的对象做唯一标识,同一个配置文件中,id值不能重名
name:该属性和id属性一样,用于对spring容器中的对象取别名,做唯一标识,同一个配置文件中不能重复;
class:指定要创建的对象类型;
factory-bean:指定要使用的工厂对象(创建实例的工厂对象)
factory-method:指定要使用的工厂对象中的工厂方法;
init-method:用于指定创建好的实例的初始化方法(spring创建实例时,就会直接调用);
destory-method:用于指定销毁对象时的调用方法;(web项目中tomcat正常关闭时调用);
scope:指定是spring工厂容器创建的对象的作用范围,以下几个取值:
singleton(默认作用范围):表示spring容器以单例模式创建对象,并且对象作用范围在整个项目中(最常用的);
prototype:表示spring容器以多例模式创建对象,对象作用范围在自定义业务逻辑代码块中;
request:spring容器将创建的实例绑定到请求域中;
session:spring容器将创建的实例绑定到session域中;
globalSession:spring容器将创建的实例绑定到全局session中;
IOC基于XML的DI
使用步骤:
1、加入依赖 spring-context
2、创建类:接口,实现类,没有接口的类
3、创建spring的配置文件applicationContext.xml,声明(创建)要用的对象
4、使用容器中的对象,通过ApplicationContext接口和他的实现类ClassPathXmlApplication的方法getBean("bean的id");
di给属性赋值:
1、set注入:spring调用类的set方法实现属性赋值
简单类型的set注入,使用value属性或者标签:<property name="属性名" value="属性的值" />,<value>值</value>
引用类型的set注入,使用ref属性或者bean标签:<property name="属性名" ref="bean的id" />,<bean class="">...</bean>
数组类型的set注入,使用<array>标签:<array><value>值</value></array>
list集合注入,使用<list>标签:<list>...</list>
set集合注入,<set>标签:<set>....</set>
map集合注入:使用<map>标签创建map集合;使用<entry>标签创建键值对<map><entry key="" value(-ref)=""></entry></map>
2、构造注入:spring调用类的有参构造方法,只是最外层的<property>变成了<constructor-arg>,其他规则都一样。
方式一:<constructor-arg name="" value="">name属性表示构造方法的形参名。
方式二:<constructor-arg index="" value="">index属性表示构造方法形参的位置,从0开始。
引用类型的自动注入:
spring框架根据某些规则可以给!!引用类型!!赋值,简单类型只能手动注入。使用规则常用的有:
byName(按名称注入):
java类中的引用类型的属性名和spring容器中(配置文件)<bean>的id名称一样,
且数据类型是一致的,spring能够把这样的bean赋值给引用类型。
语法:<bean id="xx" class="yyy" autowire="byName">
简单类型属性赋值....
</bean>
byType(按类型注入):
java类中引用类型的数据类型和spring容器(配置文件)<bean>的class属性是同源关系的,这样的bean能够赋值给引用类型
同源就是一类的意思:
1、java类中的引用类型的数据类型和bean的class的值是一样的
2、java类中的引用类型的数据类型和bean的class的值是父子关系的
3、java类中的引用类型的数据类型和bean的class的值是接口和实现类关系的
注意:在xml配置文件中声明bean只能有一个符合条件的,有多个会报noUnique的错
语法:<bean id="xx" class="yyy" autowire="bType">
简单类型属性赋值....
</bean>
多个配置文件的优势:
1、每个文件的大小比一个文件要小很多,效率高
2、避免多人竞争带来的冲突
多文件的分配方式:
1、按功能模块,一个模块一个配置文件
2、按类的功能,数据库相关配置一个配置文件,做事务的功能一个配置文件,做service功能的一个配置文件
包含关系的配置文件:
在其他配置文件中定义各自的bean。
在主配置文件中,专门用来包含其他的配置文件,一般不定义对象,语法:
具体导入:<import resource="classpath:(其他配置文件的路径)ba/spring-school.xml" />
关键字:"classpath"表示类路径,即class文件所在目录。
在spring的配置文件中要指定其他文件的位置,需要使用classpath告诉spring到哪去加载读取文件
使用通配符*:<import resource="classpath:ba06/spring-*.xml" />
注意主配置文件名不能包含在通配符的范围内避免死循环!且配置文件必须有上级目录才行!
IOC基于注解的DI
通过注解完成java对象的创建(也是通过无参构造创建)、属性赋值
使用步骤:
1、加入maven的依赖spring-context,间接的加入spring-aop的依赖,使用注解必须使用spring-aop依赖
2、创建类,在类中加入spring的注解
3、创建spring配置文件,在配置文件中,声明组件(java对象)扫描器的标签,指明注解在项目中的位置
组件扫描器:<context:component-scan base-package="注解在项目中的包名" />//包名出错会NoSuchBeanDefinitionEx..!!!!!!!
指定多个包的三种方式:
1、写多个标签指定多个包名
2、使用分隔符;或,分隔多个包名
3、指定一个父包
component-scan工作方式:
spring会扫描遍历base-package指定包中和其子包中所有的类,找到类中的注解,按照注解的功能创建对象或给属性赋值。
4、使用注解创建对象,创建容器ApplicationContext,通过方法getBean("对象名称");
基本注解:
@Component(value = ""):用于创建对象等同于<bean>的功能
属性:value就是对象的名称,也就是bean的id值 ,value的值是唯一的,创建的对象在整个spring容器中只有一个
value可以省略(常用),也可以不指定名称由spring提供默认名称:类名的首字母小写
位置:在类的上面,表示创建该类的一个对象,名称为value的值
@Respotory:用在持久层类的上面
位置:放在dao的实现类上面,表示创建dao对象,dao对象是能访问数据库的。
@Service:用在业务层类的上面
位置:放在service的实现类上面,创建service对象,service对象是做业务处理的,可以有事务等功能的。
@Controller:用在控制器上面的
位置:放在控制器(处理器)类的上面,创建控制器对象的,控制器对象能够接收用户提交的参数,显示请求处理结果的。
以上三个注解的使用语法和@Component是一样的,都能创建对象,但是这三个注解还有额外的功能
它们三个注解是给项目的对象分层的。所以不能说以上四个注解的功能“一模一样”!
当一个类不能用以上三种方式创建对象而又需要创建对象,那么就用@Component
@Value(value=""):简单类型的属性赋值
属性:value是String类型的,表示简单类型的属性值
位置:1、在属性定义的上面,无需set方法,推荐使用
2、在set方法的上面
@Autowired:引用类型的赋值,使用的自动注入的原理, 支持byName,byType
属性:required,是一个布尔类型的,不写默认为true
require=true:表示引用类型赋值失败,程序报错,终止执行。大多数情况下建议使用true,避免空指针。
require=false:引用类型如果赋值失败,程序正常执行,引用类型是null;
位置:1、在属性定义的上面,无需set方法,推荐使用
2、在set方法上面
默认使用的是byType(找同源文件)方式自动注入
如果使用byName方式,需要做的是:
1、在属性上面加入@Autowired
2、在属性上面加@Qualifier(value="bean的id"),表示使用指定的bean完成赋值
@Resource:是jdk中的注解,spring中提供了对它功能的支持。作用也是给引用类型赋值。
使用的自动注入的原理, 支持byName,byType,默认是byName
注入规则:
先使用byName自动注入,如果byName赋值失败,再使用byType自动注入;
如果只想使用byName方式,那么就要增加一个name属性。@Resource(name="bean中的id")
位置:1、在属性定义的上面,无需set方法,推荐使用 2、在set方法上面
配置文件和注解的选择:
经常要改的就用xml配置,不常改的就用注解配置!
别人写好的类采用xml方式配置,自己定义的类采用注解配置。
注解为主,配置文件为辅
纯注解配置:
@Configuration:用于指定当前类是一个spring配置类,当创建容器时会从该类上加载注解
@ComponentScan:用于指定spring在初始化容器时要扫描的包
@PropertySource:用于加载**.properties文件中的配置
@Bean(name="它的id"):只能写在方法上,表明使用此方法创建一个实例,并且放入spring容器
@Scope:用于指定bean的作用范围,相当于<bean scope="">
Spring-jdbc模块
Spring-jdbc是由spring提供的一个持久层框架,用于和数据库做交互,spring-jdbc也提供了一个核心对象,叫做jdbcTemplate,它提供了一系列操作数据库的方法;
使用:
先导入spring-jdbc依赖-->定义dao层接口操作数据库-->使用spring-jdbc实现dao层接口-->配置spring配置文件创建对象
在使用spring-jdbc时:
为了避免重复创建jdbcTemplate,实现类可以继承JdbcDaoSupport类,JdbcDaoSupport类中有jdbcTemplate属性,
在spring的配置文件中,可不创建jdbcTemplate实例,直接将创建的xxxdao对象的属性为<property name="dataSource" ref="数据源"></property>
spring整合dbutils的使用:
导入commons-dbutils依赖-->定义dao层接口-->使用dbUtils实现dao层接口-->配置spring配置文件创建对象
先设置queryRunner属性,再创建queryRunner实例
Spring中引入配置文件
<!--引入属性配置文件-->
<context:property-placeholder location="classpath:***.properties"></context:property-placeholder>
<!--引入其他spring配置文件-->
<import resource="classpath:***.xml"></import>
Spring整合各种连接池
<!--spring整合c3p0连接池(ComboPooledDataSource)-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${db.driver}"></property></bean>
<!--spring整合druid连接池(DruidDataSource)-->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${db.driver}"></property></bean>
<!--spring整合dbcp连接池(BasicDataSource)-->
<bean id="dbcpDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${db.driver}"></property></bean>
<!--spring整合spring-jdbc自带连接池(datasource.DriverManagerDataSource)-->
<bean id="driverManagerDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${db.driver}"></property></bean>
Spring-test模块
它依赖于junit单元测试,相对于junit单元测试而言,spring单元测试可以自动加载spring配置文件,并初始化springIOC容器
使用步骤:
1、引入spring-test依赖
2、在引入的类上加注解
@RunWith(SpringJUnit4ClassRunner.class):该注解用于指定采用spring-test单元测试运行
@ContextConfiguration(locations={"classpath:applicationContext.xml","","",...} classes=xx.class)
属性:locations:表示用指定的xml配置文件 class:表示用指定的注解进行配置
spring整合mybatis
1、引入依赖mybatis、mybatis-spring、spring-context、spring-jdbc、连接池、数据库驱动
2、spring整合mybatis配置
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--创建sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--注入数据源-->
<property name="dataSource" ref="druidDataSource"></property>
<!--加载映射配置文件-->
<property name="mapperLocations" value="classpath:Mapper/*.xml"></property>
<!--加载主配置文件-->
<property name="configLocation" value="classpath:mybatisConfig.xml"></property>
<property name="typeAliasesPackage" value="com.offcn.bean"></property>
</bean>
<!--配置数据源-->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${db.driver}"></property>...
</bean>
<!--创建dao层代理类实例-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
<property name="basePackage" value="com.offcn.dao"></property>
</bean>
3、操作
JDK动态代理
jdk动态代理要求目标类必须实现接口:
使用jdk中的Proxy,Method,InvocaitonHanderl创建代理对象。
具体步骤:
1、定义能够重写任意方法的代理类:
public class JdkProxyImpl implements InvocationHandler {
//任意目标对象
private Object object;
public JdkProxyImpl() {}
public JdkProxyImpl(Object object) {this.object = object;}
//重写任意方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//新增功能
method.invoke(object,args);//任意对象执行任意方法
//新增功能
return null;
}
}
2、创建任意代理类实例
public class AccountTest {
public void test2(){
//定义要代理的目标对象
AccountServiceImpl accountServiceImpl = new AccountServiceImpl(***);
//获取任意代理类实例
InvocationHandler invocationHandler = new JdkProxyImpl(accountServiceImpl);
AccountService accountServiceProxy = (AccountService)Proxy.newProxyInstance(
accountServiceImpl.getClass().getClassLoader(),//第一个参数传目标对象类加载器
accountServiceImpl.getClass().getInterfaces(),//第二个参数目标对象实现接口
invocationHandler);//第三个参数InvocationHandler重写的目标方法
//执行代理方法
accountServiceProxy.transfer(1,2,50.0);
}
}
cglib动态代理
要求目标类不能是final的,方法也不能是final的。
第三方的工具库,创建代理对象,原理是继承。 通过继承目标类,创建子类。子类就是代理对象。
具体步骤:
1.引入cglib依赖
2、定义能够重写任意方法的代理类:
public class CjlibProxyImpl implements MethodInterceptor {
//任意目标对象
private Object object;
public JdkProxyImpl() {}
public JdkProxyImpl(Object object) {this.object = object;}
//重写任意方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//新增功能
method.invoke(object,args);//任意对象执行任意方法,注意传入对象是目标对象,不是proxy参数
//新增功能
return null;
}
}
3.创建任意代理类实例:
@Test
public void test4(){
//创建工厂对象
Enhancer enhancer =new Enhancer();
PersonServiceImpl personService = new PersonServiceImpl();
//指定目标对象
enhancer.setSuperclass(personService.getClass());
//指定重写的目标方法
enhancer.setCallback(new CglibProxyImpl(personService));
//获取动态代理类实例
PersonServiceImpl proxy=(PersonServiceImpl) enhancer.create();
proxy.insertPerson();
}
AOP
动态代理的作用:
1)在目标类源代码不改变的情况下,增加功能。
2)减少代码的重复
3)专注业务逻辑代码
4)解耦合,让你的业务功能和日志、事务等非业务功能分离。
Aspect Oriented Programming:面向切面编程,基于动态代理的,可以使用jdk,cglib两种代理方式。
Aop就是动态代理的规范化, 把动态代理的实现步骤,方式都定义好了,让开发人员用一种统一的方式,使用动态代理。
怎么理解面向切面编程 ?
1)需要在分析项目功能时,找出切面。
2)合理的安排切面的执行时间(在目标方法前, 还是目标方法后)
3)合理的安全切面执行的位置,在哪个类,哪个方法增加增强功能
术语:
1)Aspect:(切面)切入点和通知的结合。
2)JoinPoint:(连接点)连接业务方法和切面的位置,指的是某类中的业务方法。
3)Pointcut:(切入点)指多个连接点方法的集合。多个方法
4)target:(目标对象)给哪个类的方法增加功能,这个类就是目标对象
5)Advice:(通知/增强)1、表示切面功能执行的时机,既拦截到连接点之后所要做的事情。
2、表示增强的功能,完成某个非业务功能,常见的切面功能有日志,事务,统计信息,参数检查,权限验证。
通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
6)weaving:(织入)指把增加应用到目标对象来创建新的代理对象的过程。
一个切面有三个关键的要素:
1)切面的功能代码,切面干什么
2)切面的执行位置,使用Pointcut表示切面执行的位置
3)切面的执行时间,使用Advice表示时机,在目标方法之前,还是目标方法之后。
aop的技术实现框架:
1.spring:
spring在内部实现了aop规范,能做aop的工作。
spring主要在事务处理时使用aop。我们项目开发中很少使用spring的aop实现。 因为spring的aop比较笨重。
2.aspectJ:
一个开源的专门做aop的框架。spring框架中集成了aspectj框架,通过spring就能使用aspectj的功能。
aspectJ框架实现aop有两种方式:
1.使用xml的配置文件:配置全局事务
2.使用注解,我们在项目中要做aop功能,一般都使用注解, aspectj有5个注解。
aspectj框架的使用。
1)切面的执行时间, 这个执行时间在规范中叫做Advice(通知,增强)在aspectj框架中使用注解表示的。也可以使用xml配置文件中的标签
1)@Before
2)@AfterReturning
3)@Around
4)@AfterThrowing
5)@After
2)表示切面执行的位置,使用的是切入点表达式。表达式的原型是:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
execution(访问权限 方法返回值 方法声明(参数) 异常类型)
解释:
modifiers-pattern] 访问权限类型 ret-type-pattern 返回值类型 declaring-type-pattern 包名类名
name-pattern(param-pattern) 方法名(参数类型和参数个数) throws-pattern 抛出异常类型
?表示可选的部分
书写符号:
* :0-任意多个字符
..:用在方法参数中,表示任意多个参数;用在包名后,表示当前包及其子包路径
+ :用在类名后,表示当前类及其子类;用在接口后,表示当前接口及其实现类
基于xml面向切面编程
1.引入aop的相关依赖:spring-aop、spring-aspects
2.定义通知类:
public class MyAdviser {
public void beforeAdvice(){System.out.println("我是加到目标方法前的任意功能");}
public void afterAdvice(){System.out.println("我是加到目标方法后的任意功能");}
<!--spring中 ProceedingJoinPoint joinPoint 能调用目标方法-->
public void aroundAdvie(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("我是加到目标方法前的环绕前置任意功能");
//调用目标方法
joinPoint.proceed();
System.out.println("我是加到目标方法后的环绕后置任意功能");}
public void exceptionAdvice(){System.out.println("我是加到目标方法出现异常时的任意功能");}
public void returnAdvie(){System.out.println("我是加到目标方法返回时的任意功能");}
}
3、3.配置xml文件做面向切面编程:
<!--配置注解扫描包-->
<context:component-scan base-package="com.offcn"></context:component-scan>
<!--aop面向切面编程-->
<!--定义通知-->
<bean id="myAdviser" class="com.offcn.advice.MyAdviser"></bean>
<aop:config>
<!--构建切面,如果aop出不来需要增加约束-->
<aop:aspect ref="myAdviser">
<!--定义切点-->
<!--定义表达式时,可使用*表示任意返回值类型,任意包,任意类;可使用..表示任意方法入参-->
<aop:pointcut id="pt" expression="execution(void com.offcn.service.OrdersServiceImpl.*(..))"/>
<aop:before method="beforeAdvice" pointcut-ref="pt"></aop:before>
<aop:after method="afterAdvice" pointcut-ref="pt"></aop:after>
<aop:around method="aroundAdvie" pointcut-ref="pt"></aop:around>
<aop:after-returning method="returnAdvie" pointcut-ref="pt"></aop:after-returning>
<aop:after-throwing method="exceptionAdvice" pointcut-ref="pt"></aop:after-throwing>
</aop:aspect>
</aop:config>
</beans>
基于注解面向切面编程的具体使用
1.定义通知类:
public class MyAdviser {
public void beforeAdvice(){
System.out.println("我是加到目标方法前的任意功能");
}
public void afterAdvice(){
System.out.println("我是加到目标方法后的任意功能");
}
public void aroundAdvie(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("我是加到目标方法前的环绕前置任意功能");
//调用目标方法
joinPoint.proceed();
System.out.println("我是加到目标方法后的环绕后置任意功能");
}
public void exceptionAdvice(){
System.out.println("我是加到目标方法出现异常时的任意功能");
}
public void returnAdvie(){
System.out.println("我是加到目标方法返回时的任意功能");
}
}
2.基于注解做配置
@Aspect
@Component
public class MyAdviser {
@Pointcut("execution(void com.offcn.service.OrdersServiceImpl.confirm())")
public void pointcut(){}
@Before("pointcut()")
public void beforeAdvice(){System.out.println("我是加到目标方法前的任意功能");}
@After("pointcut()")
public void afterAdvice(){System.out.println("我是加到目标方法后的任意功能");}
@Around("pointcut()")
public void aroundAdvie(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("我是加到目标方法前的环绕前置任意功能");
//调用目标方法
joinPoint.proceed();
System.out.println("我是加到目标方法后的环绕后置任意功能");}
@AfterThrowing("pointcut()")
public void exceptionAdvice(){System.out.println("我是加到目标方法出现异常时的任意功能");}
@AfterReturning("pointcut()")
public void returnAdvie(){System.out.println("我是加到目标方法返回时的任意功能");}
}
3.在配置文件中添加注解驱动:
<aop:aspectj-autoproxy></aop:aspectj-autoproxy> 属性:proxy-target-class="true"表示使用cglib动态代理,spring默认使用jdk动态代理
事务管理
1.事务的概念:将多个sql语句放到一起执行,要么同时执行成功,要么同时执行失败;
2.事务的四大特性:
原子性:将事务中的多个sql语句看做一个整体,要么同时执行,要么同时不执行;
一致性:从业务角度描述,事务从一种正确的状态进入另一种正确的状态,数据始终保持一致;
隔离性:指的是事务与事务之间的隔离特性,事务与事务之间的隔离特性分为以下几个级别:
READ_UNCOMMITED:读未提交,一个事务可以读取到另一个事务还没有提交的数据;导致脏读;
READ_COMMITED:读已提交,一个事务只能读取另一个事务已经提交的数据;导致多次读取相同数据时,数据可能不一致;
REPEATABLE:可重复读,在同一个事务中,多次读取相同的数据,得到的结果是一致的;
SERILIZABLE:串行化,只能一个事务一个事务的排队执行,数据安全但是执行效率低;
持久性:可以将事务修改的数据持久化到数据库中;
3.事务的传播特性:指的是在一个方法中调用另一个方法,那么另一个方法上的事务如何传播到这个方法中;传播特性有七个:
PROPAGEATION-REQUIRED:
当A方法调用B方法时,如果在B方法上设置了该传播特性,那么不管A有事务还是没有事务,A,B都会属于同一事务中;
PROPAGEATION-SUPPORTED:
当A方法调用B方法时,如果在B方法上设置了该传播特性,那么如果A方法有事务,A,B使用A方法的事务;如果A方法没有事务,那么A,B方法都不支持事务;
PROPAGEATION-MANDATORY:
当A方法调用B方法时,如果在B方法上设置了该传播特性,那么A方法在调用B方法时,必须有事务,否则直接抛异常;
PROPAGEATION-NOTSUPPORTED:
当A方法调用B方法时,如果在B方法上设置了该传播特性,那么如果A方法有事务,当执行A方法时,以A方法的事务运行,当执行到B方法时,A方法事务挂起(失效),当B方法执行完之后,A方法事务恢复;如果A方法没有事务,则A,B方法都不使用事务;
PROPAGEATION-NEVER:
当A方法调用B方法时,如果在B方法上设置了该传播特性,那么A方法在调用B方法时必须没有事务,否则抛异常;
PROPAGEATION-REQUIRES_NEW:
当A方法调用B方法时,如果在B方法上设置了该传播特性;那么如果A方法有事务,当执行到A方法时,使用A方法的事务,当执行到B方法时,B方法会新建一个事务;会导致事务嵌套;如果A方法没有事务,当执行A方法时,以非事务方式运行,当执行到B方法时,B方法会新建一个事务,以事务方式运行,当B执行完毕,回到A方法,A方法继续以非事务方式运行;
PROPAGEATION-NESTED:
当A方法调用B方法时,如果在B方法上设置了该传播特性,那么如果A方法有事务,会导致事务嵌套;如果A方法没有事务,B方法会创建一个事务,让A,B方法属于同一个事务中;
事务嵌套:外部事务出现异常,会同时回滚外部事务和内部事务;而内部事务出现异常,只会回滚内部事务本身;
spring声明式事务的使用
1、引入依赖spring-jdbc、spring-tx
2、在配置文件文件中创建spring事务管理对象
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="datasource" ref="xxxx"></property>
</bean>
3、在想要加事务的方法上面加上注解
@Transactional
4、在配置文件中加入tx约束
5、开启事务注解驱动<tx:annotation-driven></tx:annotation-driven>
(了解)纯xml方式配置事务:
<tx:advice id="transacManager" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="transfer" isolation="DEFAULT" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--构建事务切面-->
<aop:config>
<aop:pointcut id="txpt" expression="execution(void com.offcn.service.AccountServiceImpl.transfer(..))"/>
<aop:advisor advice-ref="transacManager" pointcut-ref="txpt"></aop:advisor>
</aop:config>
SpringMVC
SpringMVC是基于MVC设计模式中,应用在控制层的框架,用于处理请求,响应数据;
DisPatcherServlet:核心处理器
handlerMapping:处理器映射器,根据请求路径到controller层中匹配是否有对应处理请求的映射路径和方法
handlerAdapter:处理器适配器,执行控制层处理请求的方法
ViewResolver:视图解析器,根据视图解析器找到对应的页面,视图解析器可以设置返回属性:前缀(prefix)后缀(suffix)
全部流程:
1、用户向服务器发送请求,《tomcat请求前过滤器执行》,然后请求被DispatcherServlet捕获
2、核心处理器对URL进行解析,得到请求资源标识符URI,然后根据URI调用HanderMapping获得该Handler配置的所有相关对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExcutionChain对象的形式返回
3、核心处理器根据获取的Handler,《控制层方法执行前拦截器执行》选择一个合适的HandlerAdapter。
4、提取Request中的模型数据,调用《类型转换器执行》转换数据并填充Handler入参,开始执行Handler(Controller、service、dao)做业务处理和数据库交互,《方法返回时拦截器执行》。
在填充Handler的入参过程中,根据配置,Spring将做一些额外的工具:HttpMessageConveter-->将请求消息(json/xml...)转换成一个对象,将对象转换为指定的响应信息
数据转换:对请求消息进行数据转换,如String转成Integer\Double
数据格式化:对请求消息进行数据格式化。如请字符串转换成格式化数字或者格式化日期
数据验证:验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
5、Handler执行完成后,向核心处理器返回一个ModelAndView对象《方法结束后拦截器执行》
6、根据返回的ModeAndView,选择一个合适的已经注册到Spring容器中的ViewResolver返回给核心处理器
7、视图解析器结合Model和View来渲染视图
8、将渲染结果返回给客户端
web项目步骤:
1、创建web项目
2、引入依赖spring-webmvc\spring-web
3、配置web.xml,配置处理请求的springMVC提供的servlet对象、配置编码过滤器
<!--配置servlet-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<!--配置编码过滤器-->
<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、配置springmvc.xml,创建handlerMapping实例、handlerAdapter处理器适配器实例、viewresolver视图解析器实例
<!--创建handlerMapping映射器实例-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>
<!--创建handlerAdapter处理器适配器实例-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean>
<!--创建ViewResolver视图解析器实例-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
5、根据配置文件初始化DispatcherServlet
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
6、创建页面,设置跳转
7、创建控制层及类,并加上控制层实例注解,在类上定义请求映射路径("param")
在控制层中定义具体的业务逻辑请求RequestMapping("test1")
8、配置注解扫描包
<context:component-scan base-package="com.offcn.controller"></context:component-scan>
9、新增一个成功页面,方法返回到成功页面
10、发布项目
Spring参数类型绑定
普通类型参数绑定:
保证传入参数名称和绑定参数名称一致
@RequestMapping("test2")
public String test_2(String pname,int page){System.out.println(pname+""+page);return "main";}
对象类型参数绑定:
保证传入参数名称和对象属性名称一致:
@RequestMapping("test3")
public String test3(Person person){System.out.println(person);return "main";}
复杂类型参数绑定:
set集合必须先初始化,其他的就保证传入参数名称和对象属性名称一致,参数就属性名.对象属性形式eg:
set车1:车名:<input name="carSet[0].cname" type="text">车价格:
<input name="carSet[0].cprice" type="text">
默认类型参数绑定:
1.servletAPI默认参数绑定:
@RequestMapping("test5")
public void test5(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("我在请求转发");
request.getRequestDispatcher("/main.jsp").forward(request,response);}
2.ModelAndView,ModelMap,Model,Map这些参数类型,springMVC都可以自动绑定:
作用:自动将参数绑定到请求域,其中ModelAndView还可以指定视图名称
@RequestMapping("test6")
public ModelAndView test6(ModelAndView modelAndView, ModelMap modelMap, Model model, Map map){
modelAndView.addObject("aa","11");
modelMap.addAttribute("bb","22");
model.addAttribute("cc","33");
map.put("dd","44");
modelAndView.setViewName("main");
return modelAndView;
}
自定义类型参数绑定(以日期为例子):
//1、自定义日期转换类,实现Converter<S,T>接口
public class MyDateConverter implements Converter<String, Date> {
public Date convert(String source) {
Date date = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
date = sdf.parse(source);
return date;}}
//2、注册自定义类类型转换器
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>//同种类型的转换只能有一个
<bean class="com.offcn.utils.MyDateConverter"></bean>
</set>
</property>
</bean>
//3、默认会创建多种处理器映射器和处理器适配器,和注解解析对象实例,之前的两个要注释掉
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
SpringMVC返回参数类型
返回void参数类型:只有一种情况,当使用默认的servletAPI处理请求响应数据时使用
返回String类型:
1.将返回字符串看做视图名称处理;
@RequestMapping("test1")
public String test1(){
System.out.println("我在处理请求");
return "main";
}
2.String类型实现请求转发:必须返回字符串"forward:请求转发路径"
@RequestMapping("test8")
public String test8(){
System.out.println("我在请求转发");
return "forward:/param/test6";
}
3.String类型实现重定向:必须返回字符串"redirect:请求路径"
@RequestMapping("test9")
public String test9(){
System.out.println("我在重定向");
return "redirect:/param/test6";
}
4.springMVC中重定向携带参数:提供一个专门传递重定向参数的对象:RedirectAttributes
@RequestMapping("test9")
public String test9(String pname, RedirectAttributes redirectAttributes){
System.out.println("我在重定向"+pname);
//将要重定向的参数传递到redirectAttributes中
// redirectAttributes.addAttribute("pname",pname);
//如果需要将重定向携带的参数隐藏,需要使用addFlushAttribute()方法添加参数
//这种传参方式,获取重定向参数时,需要加上注解@ModelAttribute
redirectAttributes.addFlashAttribute("pname",pname);
return "redirect:/param/test6";
}
返回ModelAndView数据类型:
作用:将请求参数绑定到请求域,并指定返回视图名称:
@RequestMapping("test6")
public ModelAndView test6(ModelAndView modelAndView, ModelMap modelMap, Model model, Map map){
modelAndView.addObject("aa","11");
modelMap.addAttribute("bb","22");
model.addAttribute("cc","33");
map.put("dd","44");
modelAndView.setViewName("main");
return modelAndView;
}
返回任意对象类型:
引入jackson转化依赖:jackson-databind、jackson-core
在控制层方法上加注解@ReponseBody,在配置文件中加上<mvc:annotation-driven conversion-service="">标签
tomcat插件发布
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<!--指定编码格式-->
<uriEncoding>utf-8</uriEncoding>
<!--指定项目启动后的访问路径-->
<path>/</path>
<!--指定访问端口号-->
<port>8888</port>
</configuration>
</plugin>
</plugins>
</build>
SpringMVC静态资源处理
静态资源处理配置,选一
方式一(最优):
将静态资源交给默认sevlet处理,在配置文件中配置<mvc:default-servlet-handler>标签
方式二:指定静态资源访问路径
<mvc:resources mapping="请求路径eg:/html/**" location="资源路径eg:/html/"></mvc:resources>
/和/*的区别:
/*:表示匹配所有的请求;
/:表示匹配除.jsp和.jspx以外的请求;(/表示除了能匹配的请求以外的其他请求)
SpringMVC常用注解
@RequestMapping:
该注解用于在控制层定义请求路径的映射路径;可以注解在类上或者方法上;
@RequestParam:
作用:
把请求中指定名称的参数给控制器中的形参赋值。
属性:
value:请求参数中的名称。
defaultvalue:指定当页面参数没有传值的默认参数值
required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错。
@RequestBody:
作用:
用于获取请求体内容。直接使用得到是 key=value&key=value...结构的数据。
get 请求方式不适用。
属性:
required:是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。如果取值
为 false,get 请求得到是 null。
@PathVaribale:
作用:
用于绑定 url 中的占位符。例如:请求 url 中 /delete/{id},这个{id}就是 url 占位符。
url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持restful风格 URL 的一个重要标志。
restful风格中用:POST表示新增操作;GET表示查询操作;Delete表示删除操作;PUT表示修改操作;
需要配置web.xml请求方式转换过滤器:<filter-class>....HiddenHttpMethodFilter</filter-class><url-pattern>/*<url-pattern>
属性:
value:用于指定 url 中占位符名称。
required:是否必须提供占位符。
@RequestHeader:
作用:
用于获取请求消息头。
属性:
value:提供消息头名称
required:是否必须有此消息头
注:在实际开发中一般不怎么用。
@CookieValue:
作用:
用于把指定 cookie 名称的值传入控制器方法参数。
属性:
value:指定 cookie 的名称。
required:是否必须有此 cookie。
@ModelAttribute:
作用:
该注解是 SpringMVC4.3 版本以后新加入的。它可以用于修饰方法和参数。
出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可以修饰有具体返回值的方法。
出现在参数上,获取指定的数据给参数赋值。
属性:
value:用于获取数据的 key。key 可以是 POJO 的属性名称,也可以是 map 结构的 key。
应用场景:
当表单提交数据不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据。
@SessionAttribute:
作用:
用于多次执行控制器方法间的参数共享。
属性:
value:用于指定存入的属性名称
type:用于指定存入的数据类型
文件上传和下载
只要涉及到文件的上传下载,无论单一还是批量:
1、必须要加上commons-fileupload依赖
2、必须要在配置文件中初始化文件上传对象(固定写法,包括id="multipartResolver",class="***.CommonsMultipartResolver")
单一文件:
1、先引入依赖commons-fileupload
2、构建页面定义文件上传入口:
注意要加属性 enctype,请求方式也只能是Post
<form action="file/uploadFile" enctype="multipart/form-data" method="post">
<input type="file" name="file">
<input type="submit" value="上传">
</form>
3.在控制层处理文件上传:
@RequestMapping("uploadFile")
public String uploadFile(MultipartFile file){
String fileName = file.getOriginalFilename();//获取文件上传名
File fileTo = new File("F:\\JAVA\\IDEA_WorkSpace\\cloudFile\\"+fileName);//创建文件对象
file.transferTo(fileTo);//上传文件,并处理异常
return "main";
}
4.在配置文件中初始化文件上传对象(固定写法,包括id):
<!--创建文件上传下载对象-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
批量上传(处理方式有差异,是数组,并且必须加上请求参数注解):
@RequestMapping("uploadFiles")
public String uploadFiles(@RequestParam("files") MultipartFile[] files){//数组对象
if (files != null && files.length>0){
for (MultipartFile file :files) {
String fileName = file.getOriginalFilename();
File fileTo = new File("F:\\JAVA\\IDEA_WorkSpace\\cloudFile\\"+fileName);
file.transferTo(fileTo);
}
}
return "main";
}
文件下载:
下载都是将下载内容序列化为字节数组之后封装到响应体中返回给浏览器,
即下载返回的数据类型都是响应体ResponseEntity,响应体包括:内容 、响应头、状态码
步骤:
1、定义文件下载入口:
<a href="file/downLoad?filePath=E:/uploadfile/desk.jpg&fileName=desk.jpg">下载图片</a>
2、处理文件下载:
@RequestMapping("downloadFile")
public ResponseEntity<byte[]> downloadFile(String filePath,String fileName) throws IOException {
File file = new File(filePath);//将要下载的文件封装到file对象中
HttpHeaders httpHeaders = new HttpHeaders();
//告诉浏览器下载的内容返回内容是流类型
httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
//告诉浏览器以下载方式打开fileName,attachment固定写法
httpHeaders.setContentDispositionFormData("attachment",fileName);
//FileUtils.readFileToByteArray(file)将文件转为数组,httpHeaders响应头,HttpStatus.OK状态码
return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),httpHeaders, HttpStatus.OK);
}
3.在配置文件中初始化文件上传对象(固定写法,包括id):
<!--创建文件上传下载对象-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
SpringMVC异常处理器
springMVC提供了异常处理器接口 HandlerExceptionResolver ,如果要对异常做自定义处理可以通过该接口实现;
步骤:
1、自定义异常类实现 HandlerExceptionResolver 接口
public class MyExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
System.out.println("我正在处理异常");
ex.printStackTrace();
//创建并指定出错跳转页面
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("error");
return modelAndView;
}
}
2、注册异常处理实例<bean class="自定义异常类"></bean>
springMVC提供的拦截器Interceptor
拦截器是属于springMVC的,依赖于springMVC框架,通过代理模式来实现,重写目标方法接口,新增额外的功能;
步骤:
1.自定义拦截器工具类重写拦截器接口HandlerInterceptor的方法:
public class MyIntercetpor implements HandlerInterceptor {
请求前拦截器:public boolean preHandle(*)
返回true表示请求继续往下执行,由控制层方法处理
返回false请求中断,不再执行控制层方法
控制层方法返回时拦截器:public void postHandle(*):
控制层方法结束后的拦截器:public void afterCompletion(*)
}
2.注册拦截器:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/annotation/login"/>//不拦截的请求
<bean class="自定义拦截器"></bean>
</mvc:interceptor>
</mvc:interceptors>
多个拦截器注册时,拦截器方法执行顺序就是注册拦截器的顺序;
tomcat提供的过滤器,监听器
过滤器是有tomcat提供的,过滤器依赖于tomcat,tomcat处理每一个请求之前都会调用过滤器处理请求,请求处理完之后会继续回到过滤器方法中;
使用过滤器步骤:
1、自定义过滤器实现tomcat过滤器接口Filter:
public class MyFilter implements Filter {
public void init(*){}:初始化filter实例时调用方法//filter实例在tomcat启动时初始化
public void doFilter(**){
System.out.println("我是servlet处理请求前的过滤器处理");
chain.doFilter(request,response);//此方法存在表示将请求交给servlet处理,否则就不交给servlet处理!
System.out.println("我是servlet处理请求后的过滤器处理");
}:每次请求到达tomcat,tomcat都会根据请求映射来调用doFilter()方法处理请求
public void destroy(){}:过滤器对象销毁时调用的方法
}
2、web.xml中注册过滤器
<filter>
<filter-name>myFilter</filter-name>
<filter-class>com.offcn.util.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
SSM整合全步骤
1、环境开发搭建
1、首先创建数据库及表
2、创建maven项目
3、在pom文件中加入依赖坐标,最好是将版本锁定
<properties>
<!--版本锁定-->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.2.5.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><!--aop相关技术-->
<version>1.6.8</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId><!--AOP-->
<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><!--springMVC-->
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId><!--springMVC-->
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId><!--单元测试-->
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId><!--单元测试-->
<version>4.12</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId><!--事务-->
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId><!--jdbc模板技术-->
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId><!--mysql驱动-->
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId><!--servletAPI-->
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId><!--servlet一起的-->
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId><!--el,jstl表达式-->
<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><!--日志api-->
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId><!--日志-->
<version>${slf4j.version}</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId><!--mybatis-->
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId><!--spring整合mybatis-->
<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>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<!--指定编码格式-->
<uriEncoding>utf-8</uriEncoding>
<!--指定项目启动后的访问路径-->
<path>/</path>
<!--指定访问端口号-->
<port>8888</port>
</configuration>
</plugin>
</plugins>
</build>
4、创建标准目录结构
5、创建bean包及三层包:bean,dao,service,controller
6、在bean中创建实体类,生成get/set方法
在持久层dao中创建接口,提供方法
在业务层service中写接口及实现类,接口中的方法和dao中方法相同,在实现类方法中写条简单测试语句
在表现层controller中编写controller类
2、搭建Spring开发环境
1、创建并配置spring的配置文件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.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--1、开户注解扫描,只需要处理service和dao,controller不需要spring框架去处理-->
<context:component-scan base-package="com.offcn">
<!--配置哪些注解不扫描-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
</beans>
2、在service实现类上加上@Service注解,并取个名字(即将这个类交给ioc容器进行管理)
@Service("accountService")
public class AccountServiceImpl implements AccountService {
public List<Account> findAll() {
System.out.println("业务层查询所有账户...");
return null;
}
public void saveAccount(Account account) {
System.out.println("业务层保存账户....");
}
}
3、在test中测试此模块是否可用
public class TestSpring {
@Test
public void run1(){
//加载配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取对象
AccountService as = (AccountService) ac.getBean("accountService");
调用方法
as.findAll();
}
}
3、SpringMVC环境搭建
1、配置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">
<!--1、配置前端控制器-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--1.1、加载springMVC.xml配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springMVC.xml</param-value><!--文件现在没有,等会写-->
</init-param>
<!--1.2、启动服务器创建该servlet-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--2、配置解决中文乱码的过滤器-->
<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>
</web-app>
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">
<!--1、开启注解扫描,只扫描Controller注解-->
<context:component-scan base-package="com.offcn">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--2、配置视图解析器对象-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--3、配置过滤器,过滤静态资源-->
<mvc:resources mapping="/css/**" location="/css/"/>
<mvc:resources mapping="/images/**" location="/images/"/>
<mvc:resources mapping="/js/**" location="/js/"/>
<!--4、开启SpringMVC注解的支持-->
<mvc:annotation-driven/>
</beans>
3、创建页面,请求Controler中的方法
页面:<a href="/account/findAll">测试</a>
Controller:
@Controller
@RequestMapping("/account")
public class AccountController {
@RequestMapping("/findAll")
public String findAll(){
System.out.println("表现层:查询所有账户...");
return "list";
}
}
4、以上两步没问题之后,开始Spring整合Spring-MVC
怎样才算整合成功呢?
点击链接发送请求,执行controller中的方法,在controller方法中要去调用service的方法,如果能成功调用即代表整合成功!
解决方案:
启动Tomcat服务器的时候,需要加载spring的配置文件,怎么实现加载呢:
ServletContext域对象-->
需要在服务器启动的时候创建ServletContext对象,服务器关闭的时候才销毁-->
一类监听器,监听ServletContext域对象的创建和销毁,只执行一次,服务器启动执行-->
由监听器去加载Spring的配置文件,创建web版本的工厂,存储ServletContext对象。
在引入的spring-web依赖中有一个监听器类ContextLoaderListener
1、在web.xml中配置监听器ContextLoaderListener
<!--配置监听器,默认只加载WEB-INF目录下的applicationContext.xml配置文件,所以需要设置配置文件路径-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--设置配置文件的路径-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
2、在controller中创建service对象并调用方法
@Controller
@RequestMapping("/account")
public class AccountController {
//自动类型注入创建对象
@Autowired
private AccountService accountService;
@RequestMapping("/findAll")
public String findAll(){
System.out.println("表现层:查询所有账户...");
//调用service中的方法
List<Account> list = accountService.findAll();
return "list";
}
}
3、测试结果是否表现层和业务层都执行,是则整合成功
5、搭建mybatis环境
1、在dao层接口的方法上面添加注解
public interface AccountDao {
@Select("select * from t_account")
public List<Account> findAll();
@Insert("insert into t_account(name,money) values(#{name},#{money})")
public void saveAccount(Account account);
}
2、创建mybatis核心配置文件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>
<!--导入属性配置文件-->
<properties resource="jdbc.properties"></properties>
<!--开启日志,可以不配-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!--配置环境-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
</dataSource>
</environment>
</environments>
<!--引入映射配置文件-->
<mappers>
<!--如果是映射配置文件就是resources,如果是注解就是class-->
<!--<mapper class="com.offcn.dao.AccountDao"/>-->
<!--但是为了防止多次引入,可以使用package方式-->
<package name="com.offcn.dao"/>
</mappers>
</configuration>
3、测试mybatis环境是否搭建成功
public class TestMybatis {
@Test
public void test1() throws Exception {
//加载主配置文件
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
//创建SqlSession对象
SqlSession sqlsession = factory.openSession();
//获取代理对象
AccountDao accountDao = sqlsession.getMapper(AccountDao.class);
//调用方法
List<Account> accountList = accountDao.findAll();
accountList.forEach(account -> System.out.println(account));
//如果不是查询需要提交事务,sqlsession.commit();
//释放资源
sqlsession.close();
is.close();
}
}
如果运行结果正常即环境搭建完成
6、Spring整合Mybatis
怎样才算整合成功呢?
点击链接发送请求,先执行controller中的方法,在controller方法中要去调用service的方法,service中的方法要去调用dao中的方法,如果service成功的调用了dao中的方法即代表整合成功!
解决方案:
将dao的代理类存到ioc容器中,再在service中注入dao对象
1、在applicationContext.xml配置文件中去整合MyBatis框架
<!--Spring整合MyBatis框架-->
<!--1、配置连接池,就是把mybatis的配置内容转移到spring配置文件中-->
<!--1.1引入配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--1.2创建数据源-->
<!--配置C3P0连接池-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${db.driver}"></property>
<property name="jdbcUrl" value="${db.url}"></property>
<property name="password" value="${db.password}"></property>
<property name="user" value="${db.username}"></property>
</bean>
<!--2、配置SqlSessionFactory工厂-->
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--3、配置dao接口所在的包-->
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.offcn.dao"></property>
</bean>
整合了MyBatis之后,mybatis的主配置文件就可以删除了,因为这里已经对其进行了整合!
2、在dao接口上加上@Repository注解,将其交给ioc容器管理
@Repository
public interface AccountDao {
@Select("select * from t_account")
public List<Account> findAll();
@Insert("insert into t_account(name,money) values(#{name},#{money})")
public void saveAccount(Account account);
}
3、在service实现类中注入dao接口
@Service("accountService")
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
public List<Account> findAll() {
System.out.println("业务层查询所有账户...");
return accountDao.findAll();
}
public void saveAccount(Account account) {
System.out.println("业务层保存账户....");
accountDao.saveAccount(account);
}
}
4、测试整合是否成功,例如将结果发送到页面
控制层拿到数据进行处理
@Controller
@RequestMapping("/account")
public class AccountController {
@Autowired
private AccountService accountService;
@RequestMapping("/findAll")
public String findAll(Model model){
System.out.println("表现层:查询所有账户...");
//调用service方法
List<Account> accountList = accountService.findAll();
model.addAttribute("list",accountList);//通过model将accountList发送到页面中
return "list";
}
}
list页面取数据
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><!--引入jstl标签库-->
<html>
<head><title>Title</title></head>
<body>
<h3>查询了所有的账户信息</h3>
<c:forEach var="l" items="${list}"><!--循环取出数据-->
${l.id}---${l.name}---${l.money}<br>
</c:forEach>
</body>
</html>
7、Spring整合Mybatis框架配置事务
1、在spring的配置文件applicationContext.xml中配置Spring框架声明式事务管理
<!--配置Spring框架声明式事务管理-->
<!--1、配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--2、配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="find*" read-only="true"/><!--所有find开头的方法适用-->
<tx:method name="*" isolation="DEFAULT"/><!--除了上面的方法其他的都适用-->
</tx:attributes>
</tx:advice>
<!--3、配置AOP增强-->
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.offcn.service.impl.*ServiceImpl.*(..))"/>
</aop:config>
2、测试保存是否能成功
在index.jsp中写上一个表单
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>首页</title></head>
<body>
<a href="/account/findAll">测试</a>
<form action="/account/save" method="post">
账户名:<input type="text" name="name">
金额:<input type="text" name="money">
<input type="submit" value="保存">
</form>
</body>
</html>
在视图层新增保存方法
@RequestMapping("/save")
public void save(Account account, HttpServletRequest request, HttpServletResponse response) throws IOException {
System.out.println("表现层:保存数据中...");
//调用service方法
accountService.saveAccount(account);
//重定向到查询所有的方法上去
response.sendRedirect(request.getContextPath()+"/account/findAll");
return;
}
###### list页面取数据
```jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><!--引入jstl标签库-->
<html>
<head><title>Title</title></head>
<body>
<h3>查询了所有的账户信息</h3>
<c:forEach var="l" items="${list}"><!--循环取出数据-->
${l.id}---${l.name}---${l.money}<br>
</c:forEach>
</body>
</html>
7、Spring整合Mybatis框架配置事务
1、在spring的配置文件applicationContext.xml中配置Spring框架声明式事务管理
<!--配置Spring框架声明式事务管理-->
<!--1、配置事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--2、配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="find*" read-only="true"/><!--所有find开头的方法适用-->
<tx:method name="*" isolation="DEFAULT"/><!--除了上面的方法其他的都适用-->
</tx:attributes>
</tx:advice>
<!--3、配置AOP增强-->
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.offcn.service.impl.*ServiceImpl.*(..))"/>
</aop:config>
2、测试保存是否能成功
在index.jsp中写上一个表单
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>首页</title></head>
<body>
<a href="/account/findAll">测试</a>
<form action="/account/save" method="post">
账户名:<input type="text" name="name">
金额:<input type="text" name="money">
<input type="submit" value="保存">
</form>
</body>
</html>
在视图层新增保存方法
@RequestMapping("/save")
public void save(Account account, HttpServletRequest request, HttpServletResponse response) throws IOException {
System.out.println("表现层:保存数据中...");
//调用service方法
accountService.saveAccount(account);
//重定向到查询所有的方法上去
response.sendRedirect(request.getContextPath()+"/account/findAll");
return;
}